<commit_before>#include <znc/main.h>
#include <znc/User.h>
#include <znc/IRCNetwork.h>
#include <znc/Modules.h>
#include <znc/Nick.h>
#include <znc/Chan.h>
#include <znc/IRCSock.h>
#include <znc/version.h>

#include <limits>

#include "twitchtmi.h"
#include "jload.h"

#if (VERSION_MAJOR < 1) || (VERSION_MAJOR == 1 && VERSION_MINOR < 7)
#error This module needs at least ZNC 1.7.0 or later.
#endif

TwitchTMI::~TwitchTMI()
{

}

bool TwitchTMI::OnLoad(const CString& sArgsi, CString& sMessage)
{
	OnBoot();

	if(GetNetwork())
	{
		for(CChan *ch: GetNetwork()->GetChans())
		{
			ch->SetTopic(CString());

			CString chname = ch->GetName().substr(1);
			CThreadPool::Get().addJob(new TwitchTMIJob(this, chname));
		}
	}

	if(GetArgs().Token(0) != "FrankerZ")
		lastFrankerZ = std::numeric_limits<decltype(lastFrankerZ)>::max();

	PutIRC("CAP REQ :twitch.tv/membership");
	PutIRC("CAP REQ :twitch.tv/commands");
	PutIRC("CAP REQ :twitch.tv/tags");

	return true;
}

bool TwitchTMI::OnBoot()
{
	initCurl();

	timer = new TwitchTMIUpdateTimer(this);
	AddTimer(timer);

	return true;
}

void TwitchTMI::OnIRCConnected()
{
	PutIRC("CAP REQ :twitch.tv/membership");
	PutIRC("CAP REQ :twitch.tv/commands");
	PutIRC("CAP REQ :twitch.tv/tags");
}

CModule::EModRet TwitchTMI::OnUserRaw(CString &sLine)
{
	if(sLine.Left(5).Equals("WHO #"))
		return CModule::HALT;

	if(sLine.Left(5).Equals("AWAY "))
		return CModule::HALT;

	if(sLine.Left(12).Equals("TWITCHCLIENT"))
		return CModule::HALT;

	if(sLine.Left(9).Equals("JTVCLIENT"))
		return CModule::HALT;

	return CModule::CONTINUE;
}

CModule::EModRet TwitchTMI::OnRawMessage(CMessage &msg)
{
	if(msg.GetCommand().Equals("HOSTTARGET"))
	{
		return CModule::HALT;
	}
	else if(msg.GetCommand().Equals("CLEARCHAT"))
	{
		msg.SetCommand("NOTICE");
		if(msg.GetParam(1) != "")
		{
			msg.SetParam(1, msg.GetParam(1) + " was timed out.");
		}
		else
		{
			msg.SetParam(1, "Chat was cleared by a moderator.");
		}
	}
	else if(msg.GetCommand().Equals("USERSTATE"))
	{
		return CModule::HALT;
	}
	else if(msg.GetCommand().Equals("ROOMSTATE"))
	{
		return CModule::HALT;
	}
	else if(msg.GetCommand().Equals("RECONNECT"))
	{
		return CModule::HALT;
	}
	else if(msg.GetCommand().Equals("GLOBALUSERSTATE"))
	{
		return CModule::HALT;
	}
	else if(msg.GetCommand().Equals("WHISPER"))
	{
		msg.SetCommand("PRIVMSG");
	}
	else if(msg.GetCommand().Equals("USERNOTICE"))
	{
		//TODO: Translate Tags to useful message
		msg.SetCommand("PRIVMSG");
		msg.SetParam(1, "<<<RESUB>>> " + msg.GetParam(1));
	}

	CString realNick = msg.GetTag("display-name").Trim_n();
	if(realNick != "")
		msg.GetNick().SetNick(realNick);

	return CModule::CONTINUE;
}

CModule::EModRet TwitchTMI::OnUserJoin(CString& sChannel, CString& sKey)
{
	CString chname = sChannel.substr(1);
	CThreadPool::Get().addJob(new TwitchTMIJob(this, chname));

	return CModule::CONTINUE;
}

CModule::EModRet TwitchTMI::OnPrivMessage(CTextMessage &Message)
{
	if(Message.GetNick().GetNick().Equals("jtv"))
		return CModule::HALT;

	return CModule::CONTINUE;
}

void TwitchTMI::PutUserChanMessage(CChan *chan, const CString &from, const CString &msg)
{
	std::stringstream ss;
	ss << ":" << from << " PRIVMSG " << chan->GetName() << " :";
	CString s = ss.str();

	PutUser(s + msg);

	if(!chan->AutoClearChanBuffer() || !GetNetwork()->IsUserOnline() || chan->IsDetached())
		chan->AddBuffer(s + "{text}", msg);
}

CModule::EModRet TwitchTMI::OnChanMessage(CTextMessage &Message)
{
	if(Message.GetNick().GetNick().Equals("jtv"))
		return CModule::HALT;

	if(Message.GetText() == "FrankerZ" && std::time(nullptr) - lastFrankerZ > 10)
	{
		std::stringstream ss;
		CString mynick = GetNetwork()->GetIRCNick().GetNickMask();
		CChan *chan = Message.GetChan();

		ss << "PRIVMSG " << chan->GetName() << " :FrankerZ";
		PutIRC(ss.str());

		CThreadPool::Get().addJob(new GenericJob([]() {}, [this, chan, mynick]()
		{
			PutUserChanMessage(chan, mynick, "FrankerZ");
		}));

		lastFrankerZ = std::time(nullptr);
	}

	return CModule::CONTINUE;
}

bool TwitchTMI::OnServerCapAvailable(const CString &sCap)
{
	if(sCap == "twitch.tv/membership")
		return true;
	else if(sCap == "twitch.tv/tags")
		return true;
	else if(sCap == "twitch.tv/commands")
		return true;

	return false;
}

CModule::EModRet TwitchTMI::OnUserTextMessage(CTextMessage &msg)
{
	if(msg.GetTarget().Left(1).Equals("#"))
		return CModule::CONTINUE;

	msg.SetText(msg.GetText().insert(0, " ").insert(0, msg.GetTarget()).insert(0, "/w "));
	msg.SetTarget("#jtv");

	return CModule::CONTINUE;
}

TwitchTMIUpdateTimer::TwitchTMIUpdateTimer(TwitchTMI *tmod)
	:CTimer(tmod, 30, 0, "TwitchTMIUpdateTimer", "Downloads Twitch information")
	,mod(tmod)
{
}

void TwitchTMIUpdateTimer::RunJob()
{
	if(!mod->GetNetwork())
		return;

	for(CChan *chan: mod->GetNetwork()->GetChans())
	{
		CString chname = chan->GetName().substr(1);
		CThreadPool::Get().addJob(new TwitchTMIJob(mod, chname));
	}
}

void TwitchTMIJob::runThread()
{
	std::stringstream ss, ss2;
	ss << "https://api.twitch.tv/kraken/channels/" << channel;
	ss2 << "https://api.twitch.tv/kraken/streams/" << channel;

	CString url = ss.str();
	CString url2 = ss2.str();

	Json::Value root = getJsonFromUrl(url.c_str(), "Accept: application/vnd.twitchtv.v3+json");
	Json::Value root2 = getJsonFromUrl(url2.c_str(), "Accept: application/vnd.twitchtv.v3+json");

	if(!root.isNull())
	{
		Json::Value &titleVal = root["status"];
		title = CString();

		if(!titleVal.isString())
			titleVal = root["title"];

		if(titleVal.isString())
		{
			title = titleVal.asString();
			title.Trim();
		}
	}

	live = false;

	if(!root2.isNull())
	{
		Json::Value &streamVal = root2["stream"];

		if(!streamVal.isNull())
			live = true;
	}
}

void TwitchTMIJob::runMain()
{
	if(title.empty())
		return;

	CChan *chan = mod->GetNetwork()->FindChan(CString("#") + channel);

	if(!chan)
		return;

	if(chan->GetTopic() != title)
	{
		chan->SetTopic(title);
		chan->SetTopicOwner("jtv");
		chan->SetTopicDate((unsigned long)time(nullptr));

		std::stringstream ss;
		ss << ":jtv TOPIC #" << channel << " :" << title;

		mod->PutUser(ss.str());
	}

	auto it = mod->liveChannels.find(channel);
	if(it != mod->liveChannels.end())
	{
		if(!live)
		{
			mod->liveChannels.erase(it);
			mod->PutUserChanMessage(chan, "jtv", ">>> Channel just went offline! <<<");
		}
	}
	else
	{
		if(live)
		{
			mod->liveChannels.insert(channel);
			mod->PutUserChanMessage(chan, "jtv", ">>> Channel just went live! <<<");
		}
	}
}

template<> void TModInfo<TwitchTMI>(CModInfo &info)
{
	info.SetWikiPage("Twitch");
	info.SetHasArgs(true);
}

NETWORKMODULEDEFS(TwitchTMI, "Twitch IRC helper module")
<commit_msg>Update to v5 API<commit_after>#include <znc/main.h>
#include <znc/User.h>
#include <znc/IRCNetwork.h>
#include <znc/Modules.h>
#include <znc/Nick.h>
#include <znc/Chan.h>
#include <znc/IRCSock.h>
#include <znc/version.h>

#include <limits>

#include "twitchtmi.h"
#include "jload.h"

#if (VERSION_MAJOR < 1) || (VERSION_MAJOR == 1 && VERSION_MINOR < 7)
#error This module needs at least ZNC 1.7.0 or later.
#endif

TwitchTMI::~TwitchTMI()
{

}

bool TwitchTMI::OnLoad(const CString& sArgsi, CString& sMessage)
{
	OnBoot();

	if(GetNetwork())
	{
		for(CChan *ch: GetNetwork()->GetChans())
		{
			ch->SetTopic(CString());

			CString chname = ch->GetName().substr(1);
			CThreadPool::Get().addJob(new TwitchTMIJob(this, chname));
		}
	}

	if(GetArgs().Token(0) != "FrankerZ")
		lastFrankerZ = std::numeric_limits<decltype(lastFrankerZ)>::max();

	PutIRC("CAP REQ :twitch.tv/membership");
	PutIRC("CAP REQ :twitch.tv/commands");
	PutIRC("CAP REQ :twitch.tv/tags");

	return true;
}

bool TwitchTMI::OnBoot()
{
	initCurl();

	timer = new TwitchTMIUpdateTimer(this);
	AddTimer(timer);

	return true;
}

void TwitchTMI::OnIRCConnected()
{
	PutIRC("CAP REQ :twitch.tv/membership");
	PutIRC("CAP REQ :twitch.tv/commands");
	PutIRC("CAP REQ :twitch.tv/tags");
}

CModule::EModRet TwitchTMI::OnUserRaw(CString &sLine)
{
	if(sLine.Left(5).Equals("WHO #"))
		return CModule::HALT;

	if(sLine.Left(5).Equals("AWAY "))
		return CModule::HALT;

	if(sLine.Left(12).Equals("TWITCHCLIENT"))
		return CModule::HALT;

	if(sLine.Left(9).Equals("JTVCLIENT"))
		return CModule::HALT;

	return CModule::CONTINUE;
}

CModule::EModRet TwitchTMI::OnRawMessage(CMessage &msg)
{
	if(msg.GetCommand().Equals("HOSTTARGET"))
	{
		return CModule::HALT;
	}
	else if(msg.GetCommand().Equals("CLEARCHAT"))
	{
		msg.SetCommand("NOTICE");
		if(msg.GetParam(1) != "")
		{
			msg.SetParam(1, msg.GetParam(1) + " was timed out.");
		}
		else
		{
			msg.SetParam(1, "Chat was cleared by a moderator.");
		}
	}
	else if(msg.GetCommand().Equals("USERSTATE"))
	{
		return CModule::HALT;
	}
	else if(msg.GetCommand().Equals("ROOMSTATE"))
	{
		return CModule::HALT;
	}
	else if(msg.GetCommand().Equals("RECONNECT"))
	{
		return CModule::HALT;
	}
	else if(msg.GetCommand().Equals("GLOBALUSERSTATE"))
	{
		return CModule::HALT;
	}
	else if(msg.GetCommand().Equals("WHISPER"))
	{
		msg.SetCommand("PRIVMSG");
	}
	else if(msg.GetCommand().Equals("USERNOTICE"))
	{
		//TODO: Translate Tags to useful message
		msg.SetCommand("PRIVMSG");
		msg.SetParam(1, "<<<RESUB>>> " + msg.GetParam(1));
	}

	CString realNick = msg.GetTag("display-name").Trim_n();
	if(realNick != "")
		msg.GetNick().SetNick(realNick);

	return CModule::CONTINUE;
}

CModule::EModRet TwitchTMI::OnUserJoin(CString& sChannel, CString& sKey)
{
	CString chname = sChannel.substr(1);
	CThreadPool::Get().addJob(new TwitchTMIJob(this, chname));

	return CModule::CONTINUE;
}

CModule::EModRet TwitchTMI::OnPrivMessage(CTextMessage &Message)
{
	if(Message.GetNick().GetNick().Equals("jtv"))
		return CModule::HALT;

	return CModule::CONTINUE;
}

void TwitchTMI::PutUserChanMessage(CChan *chan, const CString &from, const CString &msg)
{
	std::stringstream ss;
	ss << ":" << from << " PRIVMSG " << chan->GetName() << " :";
	CString s = ss.str();

	PutUser(s + msg);

	if(!chan->AutoClearChanBuffer() || !GetNetwork()->IsUserOnline() || chan->IsDetached())
		chan->AddBuffer(s + "{text}", msg);
}

CModule::EModRet TwitchTMI::OnChanMessage(CTextMessage &Message)
{
	if(Message.GetNick().GetNick().Equals("jtv"))
		return CModule::HALT;

	if(Message.GetText() == "FrankerZ" && std::time(nullptr) - lastFrankerZ > 10)
	{
		std::stringstream ss;
		CString mynick = GetNetwork()->GetIRCNick().GetNickMask();
		CChan *chan = Message.GetChan();

		ss << "PRIVMSG " << chan->GetName() << " :FrankerZ";
		PutIRC(ss.str());

		CThreadPool::Get().addJob(new GenericJob([]() {}, [this, chan, mynick]()
		{
			PutUserChanMessage(chan, mynick, "FrankerZ");
		}));

		lastFrankerZ = std::time(nullptr);
	}

	return CModule::CONTINUE;
}

bool TwitchTMI::OnServerCapAvailable(const CString &sCap)
{
	if(sCap == "twitch.tv/membership")
		return true;
	else if(sCap == "twitch.tv/tags")
		return true;
	else if(sCap == "twitch.tv/commands")
		return true;

	return false;
}

CModule::EModRet TwitchTMI::OnUserTextMessage(CTextMessage &msg)
{
	if(msg.GetTarget().Left(1).Equals("#"))
		return CModule::CONTINUE;

	msg.SetText(msg.GetText().insert(0, " ").insert(0, msg.GetTarget()).insert(0, "/w "));
	msg.SetTarget("#jtv");

	return CModule::CONTINUE;
}

TwitchTMIUpdateTimer::TwitchTMIUpdateTimer(TwitchTMI *tmod)
	:CTimer(tmod, 30, 0, "TwitchTMIUpdateTimer", "Downloads Twitch information")
	,mod(tmod)
{
}

void TwitchTMIUpdateTimer::RunJob()
{
	if(!mod->GetNetwork())
		return;

	for(CChan *chan: mod->GetNetwork()->GetChans())
	{
		CString chname = chan->GetName().substr(1);
		CThreadPool::Get().addJob(new TwitchTMIJob(mod, chname));
	}
}

void TwitchTMIJob::runThread()
{
	std::stringstream ss, ss2;
	ss << "https://api.twitch.tv/kraken/channels/" << channel;
	ss2 << "https://api.twitch.tv/kraken/streams/" << channel;

	CString url = ss.str();
	CString url2 = ss2.str();

	Json::Value root = getJsonFromUrl(url.c_str(), "Accept: application/vnd.twitchtv.v5+json");
	Json::Value root2 = getJsonFromUrl(url2.c_str(), "Accept: application/vnd.twitchtv.v5+json");

	if(!root.isNull())
	{
		Json::Value &titleVal = root["status"];
		title = CString();

		if(!titleVal.isString())
			titleVal = root["title"];

		if(titleVal.isString())
		{
			title = titleVal.asString();
			title.Trim();
		}
	}

	live = false;

	if(!root2.isNull())
	{
		Json::Value &streamVal = root2["stream"];

		if(!streamVal.isNull())
			live = true;
	}
}

void TwitchTMIJob::runMain()
{
	if(title.empty())
		return;

	CChan *chan = mod->GetNetwork()->FindChan(CString("#") + channel);

	if(!chan)
		return;

	if(chan->GetTopic() != title)
	{
		chan->SetTopic(title);
		chan->SetTopicOwner("jtv");
		chan->SetTopicDate((unsigned long)time(nullptr));

		std::stringstream ss;
		ss << ":jtv TOPIC #" << channel << " :" << title;

		mod->PutUser(ss.str());
	}

	auto it = mod->liveChannels.find(channel);
	if(it != mod->liveChannels.end())
	{
		if(!live)
		{
			mod->liveChannels.erase(it);
			mod->PutUserChanMessage(chan, "jtv", ">>> Channel just went offline! <<<");
		}
	}
	else
	{
		if(live)
		{
			mod->liveChannels.insert(channel);
			mod->PutUserChanMessage(chan, "jtv", ">>> Channel just went live! <<<");
		}
	}
}

template<> void TModInfo<TwitchTMI>(CModInfo &info)
{
	info.SetWikiPage("Twitch");
	info.SetHasArgs(true);
}

NETWORKMODULEDEFS(TwitchTMI, "Twitch IRC helper module")
<|endoftext|>


<commit_before>// Copyright 2017-2020 The Verible Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// verilog_format is a command-line utility to format verilog source code
// for a given file.
//
// Example usage:
// verilog_format original-file > new-file
//
// Exit code:
//   0: stdout output can be used to replace original file
//   nonzero: stdout output (if any) should be discarded

#include <fstream>
#include <iostream>
#include <memory>
#include <sstream>  // IWYU pragma: keep  // for ostringstream
#include <string>   // for string, allocator, etc
#include <vector>

#include "absl/flags/flag.h"
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "absl/strings/str_split.h"
#include "absl/strings/string_view.h"
#include "common/util/file_util.h"
#include "common/util/init_command_line.h"
#include "common/util/interval_set.h"
#include "common/util/logging.h"  // for operator<<, LOG, LogMessage, etc
#include "verilog/formatting/format_style.h"
#include "verilog/formatting/formatter.h"

using absl::StatusCode;
using verilog::formatter::ExecutionControl;
using verilog::formatter::FormatStyle;
using verilog::formatter::FormatVerilog;

// Pseudo-singleton, so that repeated flag occurrences accumulate values.
//   --flag x --flag y yields [x, y]
struct LineRanges {
  // need to copy string, cannot just use string_view
  typedef std::vector<std::string> storage_type;
  static storage_type values;
};

LineRanges::storage_type LineRanges::values;  // global initializer

bool AbslParseFlag(absl::string_view flag_arg, LineRanges* /* unused */,
                   std::string* error) {
  auto& values = LineRanges::values;
  // Pre-split strings, so that "--flag v1,v2" and "--flag v1 --flag v2" are
  // equivalent.
  const std::vector<absl::string_view> tokens = absl::StrSplit(flag_arg, ',');
  values.reserve(values.size() + tokens.size());
  for (const auto& token : tokens) {
    // need to copy string, cannot just use string_view
    values.push_back(std::string(token.begin(), token.end()));
  }
  // Range validation done later.
  return true;
}

std::string AbslUnparseFlag(LineRanges /* unused */) {
  const auto& values = LineRanges::values;
  return absl::StrJoin(values.begin(), values.end(), ",",
                       absl::StreamFormatter());
}

// TODO(fangism): Provide -i alias, as it is canonical to many formatters
ABSL_FLAG(bool, inplace, false,
          "If true, overwrite the input file on successful conditions.");
ABSL_FLAG(std::string, stdin_name, "<stdin>",
          "When using '-' to read from stdin, this gives an alternate name for "
          "diagnostic purposes.  Otherwise this is ignored.");
ABSL_FLAG(LineRanges, lines, {},
          "Specific lines to format, 1-based, comma-separated, inclusive N-M "
          "ranges, N is short for N-N.  By default, left unspecified, "
          "all lines are enabled for formatting.  (repeatable, cumulative)");

ABSL_FLAG(int, show_largest_token_partitions, 0,
          "If > 0, print token partitioning and then "
          "exit without formatting output.");
ABSL_FLAG(bool, show_token_partition_tree, false,
          "If true, print diagnostics after token partitioning and then "
          "exit without formatting output.");
ABSL_FLAG(bool, show_inter_token_info, false,
          "If true, along with show_token_partition_tree, include inter-token "
          "information such as spacing and break penalties.");
ABSL_FLAG(bool, show_equally_optimal_wrappings, false,
          "If true, print when multiple optimal solutions are found (stderr), "
          "but continue to operate normally.");
ABSL_FLAG(int, max_search_states, 100000,
          "Limits the number of search states explored during "
          "line wrap optimization.");

// These flags exist in the short term to disable formatting of some regions.
ABSL_FLAG(bool, format_module_port_declarations, false,
          "If true, format module declarations' list of port declarations, "
          "else leave them unformatted.");

int main(int argc, char** argv) {
  const auto usage = absl::StrCat("usage: ", argv[0],
                                  " [options] <file>\n"
                                  "To pipe from stdin, use '-' as <file>.");
  const auto file_args = verible::InitCommandLine(usage, &argc, &argv);

  // Currently accepts only one file positional argument.
  // TODO(fangism): Support multiple file names.
  QCHECK_GT(file_args.size(), 1)
      << "Missing required positional argument (filename).";
  const absl::string_view filename = file_args[1];

  const bool inplace = FLAGS_inplace.Get();
  const bool is_stdin = filename == "-";
  const auto& stdin_name = FLAGS_stdin_name.Get();

  if (inplace && is_stdin) {
    std::cerr << "--inplace is incompatible with stdin.  Ignoring --inplace "
                 "and writing to stdout."
              << std::endl;
  }
  absl::string_view diagnostic_filename = filename;
  if (is_stdin) {
    diagnostic_filename = stdin_name;
  }

  // Parse LineRanges into a line set, to validate the --lines flag(s)
  verilog::formatter::LineNumberSet lines_to_format;
  if (!verible::ParseInclusiveRanges(
          &lines_to_format, LineRanges::values.begin(),
          LineRanges::values.end(), &std::cerr, '-')) {
    std::cerr << "Error parsing --lines." << std::endl;
    std::cerr << "Got: --lines=" << AbslUnparseFlag(LineRanges()) << std::endl;
    return 1;
  }

  // Read contents into memory first.
  std::string content;
  if (!verible::file::GetContents(filename, &content)) return 1;

  // TODO(fangism): When requesting --inplace, verify that file
  // is write-able, and fail-early if it is not.

  // TODO(fangism): support style configuration from flags.
  FormatStyle format_style;

  // Handle special debugging modes.
  ExecutionControl formatter_control;
  {
    // execution control flags
    formatter_control.stream = &std::cout;  // for diagnostics only
    formatter_control.show_largest_token_partitions =
        FLAGS_show_largest_token_partitions.Get();
    formatter_control.show_token_partition_tree =
        FLAGS_show_token_partition_tree.Get();
    formatter_control.show_inter_token_info = FLAGS_show_inter_token_info.Get();
    formatter_control.show_equally_optimal_wrappings =
        FLAGS_show_equally_optimal_wrappings.Get();
    formatter_control.max_search_states = FLAGS_max_search_states.Get();

    // formatting style flags
    format_style.format_module_port_declarations =
        FLAGS_format_module_port_declarations.Get();
  }

  std::ostringstream stream;
  const auto format_status =
      FormatVerilog(content, diagnostic_filename, format_style, stream,
                    lines_to_format, formatter_control);

  const std::string& formatted_output(stream.str());
  if (!format_status.ok()) {
    if (!inplace) {
      // Fall back to printing original content regardless of error condition.
      std::cout << content;
    }
    // Print the error message last so it shows up in user's console.
    std::cerr << format_status.message();
    switch (format_status.code()) {
      case StatusCode::kCancelled:
      case StatusCode::kInvalidArgument:
        break;
      case StatusCode::kDataLoss:
        std::cerr << "Problematic formatter output is:\n"
                  << formatted_output << "<<EOF>>" << std::endl;
        break;
      default:
        std::cerr << "[other error status]" << std::endl;
        break;
    }
    return 1;
  }

  // Safe to write out result, having passed above verification.
  int exit_code = 0;
  std::ostream* output_stream = &std::cout;
  std::ofstream inplace_file;
  if (inplace && !is_stdin) {
    inplace_file.open(std::string(filename));
    if (inplace_file.good()) {
      output_stream = &inplace_file;
    } else {
      std::cerr << "Error writing to file: " << filename << std::endl;
      std::cerr << "Printing to stdout instead." << std::endl;
      exit_code = 1;
    }
  }
  *output_stream << formatted_output;

  return exit_code;
}
<commit_msg>Add missing newline in diagnostic.<commit_after>// Copyright 2017-2020 The Verible Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// verilog_format is a command-line utility to format verilog source code
// for a given file.
//
// Example usage:
// verilog_format original-file > new-file
//
// Exit code:
//   0: stdout output can be used to replace original file
//   nonzero: stdout output (if any) should be discarded

#include <fstream>
#include <iostream>
#include <memory>
#include <sstream>  // IWYU pragma: keep  // for ostringstream
#include <string>   // for string, allocator, etc
#include <vector>

#include "absl/flags/flag.h"
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "absl/strings/str_split.h"
#include "absl/strings/string_view.h"
#include "common/util/file_util.h"
#include "common/util/init_command_line.h"
#include "common/util/interval_set.h"
#include "common/util/logging.h"  // for operator<<, LOG, LogMessage, etc
#include "verilog/formatting/format_style.h"
#include "verilog/formatting/formatter.h"

using absl::StatusCode;
using verilog::formatter::ExecutionControl;
using verilog::formatter::FormatStyle;
using verilog::formatter::FormatVerilog;

// Pseudo-singleton, so that repeated flag occurrences accumulate values.
//   --flag x --flag y yields [x, y]
struct LineRanges {
  // need to copy string, cannot just use string_view
  typedef std::vector<std::string> storage_type;
  static storage_type values;
};

LineRanges::storage_type LineRanges::values;  // global initializer

bool AbslParseFlag(absl::string_view flag_arg, LineRanges* /* unused */,
                   std::string* error) {
  auto& values = LineRanges::values;
  // Pre-split strings, so that "--flag v1,v2" and "--flag v1 --flag v2" are
  // equivalent.
  const std::vector<absl::string_view> tokens = absl::StrSplit(flag_arg, ',');
  values.reserve(values.size() + tokens.size());
  for (const auto& token : tokens) {
    // need to copy string, cannot just use string_view
    values.push_back(std::string(token.begin(), token.end()));
  }
  // Range validation done later.
  return true;
}

std::string AbslUnparseFlag(LineRanges /* unused */) {
  const auto& values = LineRanges::values;
  return absl::StrJoin(values.begin(), values.end(), ",",
                       absl::StreamFormatter());
}

// TODO(fangism): Provide -i alias, as it is canonical to many formatters
ABSL_FLAG(bool, inplace, false,
          "If true, overwrite the input file on successful conditions.");
ABSL_FLAG(std::string, stdin_name, "<stdin>",
          "When using '-' to read from stdin, this gives an alternate name for "
          "diagnostic purposes.  Otherwise this is ignored.");
ABSL_FLAG(LineRanges, lines, {},
          "Specific lines to format, 1-based, comma-separated, inclusive N-M "
          "ranges, N is short for N-N.  By default, left unspecified, "
          "all lines are enabled for formatting.  (repeatable, cumulative)");

ABSL_FLAG(int, show_largest_token_partitions, 0,
          "If > 0, print token partitioning and then "
          "exit without formatting output.");
ABSL_FLAG(bool, show_token_partition_tree, false,
          "If true, print diagnostics after token partitioning and then "
          "exit without formatting output.");
ABSL_FLAG(bool, show_inter_token_info, false,
          "If true, along with show_token_partition_tree, include inter-token "
          "information such as spacing and break penalties.");
ABSL_FLAG(bool, show_equally_optimal_wrappings, false,
          "If true, print when multiple optimal solutions are found (stderr), "
          "but continue to operate normally.");
ABSL_FLAG(int, max_search_states, 100000,
          "Limits the number of search states explored during "
          "line wrap optimization.");

// These flags exist in the short term to disable formatting of some regions.
ABSL_FLAG(bool, format_module_port_declarations, false,
          "If true, format module declarations' list of port declarations, "
          "else leave them unformatted.");

int main(int argc, char** argv) {
  const auto usage = absl::StrCat("usage: ", argv[0],
                                  " [options] <file>\n"
                                  "To pipe from stdin, use '-' as <file>.");
  const auto file_args = verible::InitCommandLine(usage, &argc, &argv);

  // Currently accepts only one file positional argument.
  // TODO(fangism): Support multiple file names.
  QCHECK_GT(file_args.size(), 1)
      << "Missing required positional argument (filename).";
  const absl::string_view filename = file_args[1];

  const bool inplace = FLAGS_inplace.Get();
  const bool is_stdin = filename == "-";
  const auto& stdin_name = FLAGS_stdin_name.Get();

  if (inplace && is_stdin) {
    std::cerr << "--inplace is incompatible with stdin.  Ignoring --inplace "
                 "and writing to stdout."
              << std::endl;
  }
  absl::string_view diagnostic_filename = filename;
  if (is_stdin) {
    diagnostic_filename = stdin_name;
  }

  // Parse LineRanges into a line set, to validate the --lines flag(s)
  verilog::formatter::LineNumberSet lines_to_format;
  if (!verible::ParseInclusiveRanges(
          &lines_to_format, LineRanges::values.begin(),
          LineRanges::values.end(), &std::cerr, '-')) {
    std::cerr << "Error parsing --lines." << std::endl;
    std::cerr << "Got: --lines=" << AbslUnparseFlag(LineRanges()) << std::endl;
    return 1;
  }

  // Read contents into memory first.
  std::string content;
  if (!verible::file::GetContents(filename, &content)) return 1;

  // TODO(fangism): When requesting --inplace, verify that file
  // is write-able, and fail-early if it is not.

  // TODO(fangism): support style configuration from flags.
  FormatStyle format_style;

  // Handle special debugging modes.
  ExecutionControl formatter_control;
  {
    // execution control flags
    formatter_control.stream = &std::cout;  // for diagnostics only
    formatter_control.show_largest_token_partitions =
        FLAGS_show_largest_token_partitions.Get();
    formatter_control.show_token_partition_tree =
        FLAGS_show_token_partition_tree.Get();
    formatter_control.show_inter_token_info = FLAGS_show_inter_token_info.Get();
    formatter_control.show_equally_optimal_wrappings =
        FLAGS_show_equally_optimal_wrappings.Get();
    formatter_control.max_search_states = FLAGS_max_search_states.Get();

    // formatting style flags
    format_style.format_module_port_declarations =
        FLAGS_format_module_port_declarations.Get();
  }

  std::ostringstream stream;
  const auto format_status =
      FormatVerilog(content, diagnostic_filename, format_style, stream,
                    lines_to_format, formatter_control);

  const std::string& formatted_output(stream.str());
  if (!format_status.ok()) {
    if (!inplace) {
      // Fall back to printing original content regardless of error condition.
      std::cout << content;
    }
    // Print the error message last so it shows up in user's console.
    std::cerr << format_status.message() << std::endl;
    switch (format_status.code()) {
      case StatusCode::kCancelled:
      case StatusCode::kInvalidArgument:
        break;
      case StatusCode::kDataLoss:
        std::cerr << "Problematic formatter output is:\n"
                  << formatted_output << "<<EOF>>" << std::endl;
        break;
      default:
        std::cerr << "[other error status]" << std::endl;
        break;
    }
    return 1;
  }

  // Safe to write out result, having passed above verification.
  int exit_code = 0;
  std::ostream* output_stream = &std::cout;
  std::ofstream inplace_file;
  if (inplace && !is_stdin) {
    inplace_file.open(std::string(filename));
    if (inplace_file.good()) {
      output_stream = &inplace_file;
    } else {
      std::cerr << "Error writing to file: " << filename << std::endl;
      std::cerr << "Printing to stdout instead." << std::endl;
      exit_code = 1;
    }
  }
  *output_stream << formatted_output;

  return exit_code;
}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/video_engine/vie_base_impl.h"

#include <sstream>
#include <string>

#include "webrtc/engine_configurations.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
#include "webrtc/modules/video_coding/main/interface/video_coding.h"
#include "webrtc/modules/video_processing/main/interface/video_processing.h"
#include "webrtc/modules/video_render/include/video_render.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/trace.h"
#include "webrtc/video_engine/include/vie_errors.h"
#include "webrtc/video_engine/vie_channel.h"
#include "webrtc/video_engine/vie_channel_manager.h"
#include "webrtc/video_engine/vie_defines.h"
#include "webrtc/video_engine/vie_encoder.h"
#include "webrtc/video_engine/vie_impl.h"
#include "webrtc/video_engine/vie_input_manager.h"
#include "webrtc/video_engine/vie_shared_data.h"

namespace webrtc {

ViEBase* ViEBase::GetInterface(VideoEngine* video_engine) {
  if (!video_engine) {
    return NULL;
  }
  VideoEngineImpl* vie_impl = static_cast<VideoEngineImpl*>(video_engine);
  ViEBaseImpl* vie_base_impl = vie_impl;
  (*vie_base_impl)++;  // Increase ref count.

  return vie_base_impl;
}

int ViEBaseImpl::Release() {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo, shared_data_.instance_id(),
               "ViEBase::Release()");
  (*this)--;  // Decrease ref count.

  int32_t ref_count = GetCount();
  if (ref_count < 0) {
    WEBRTC_TRACE(kTraceWarning, kTraceVideo, shared_data_.instance_id(),
                 "ViEBase release too many times");
    shared_data_.SetLastError(kViEAPIDoesNotExist);
    return -1;
  }
  WEBRTC_TRACE(kTraceInfo, kTraceVideo, shared_data_.instance_id(),
               "ViEBase reference count: %d", ref_count);
  return ref_count;
}

ViEBaseImpl::ViEBaseImpl(const Config& config)
    : shared_data_(config) {
  WEBRTC_TRACE(kTraceMemory, kTraceVideo, shared_data_.instance_id(),
               "ViEBaseImpl::ViEBaseImpl() Ctor");
}

ViEBaseImpl::~ViEBaseImpl() {
  WEBRTC_TRACE(kTraceMemory, kTraceVideo, shared_data_.instance_id(),
               "ViEBaseImpl::ViEBaseImpl() Dtor");
}

int ViEBaseImpl::Init() {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo, shared_data_.instance_id(),
               "Init");
  return 0;
}

int ViEBaseImpl::SetVoiceEngine(VoiceEngine* voice_engine) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_.instance_id()),
               "%s", __FUNCTION__);
  if (shared_data_.channel_manager()->SetVoiceEngine(voice_engine) != 0) {
    shared_data_.SetLastError(kViEBaseVoEFailure);
    return -1;
  }
  return 0;
}

int ViEBaseImpl::CreateChannel(int& video_channel) {  // NOLINT
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_.instance_id()),
               "%s", __FUNCTION__);
  if (shared_data_.channel_manager()->CreateChannel(&video_channel) == -1) {
    WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_.instance_id()),
                 "%s: Could not create channel", __FUNCTION__);
    video_channel = -1;
    shared_data_.SetLastError(kViEBaseChannelCreationFailed);
    return -1;
  }
  WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(shared_data_.instance_id()),
               "%s: channel created: %d", __FUNCTION__, video_channel);
  return 0;
}

int ViEBaseImpl::CreateChannel(int& video_channel,  // NOLINT
                               int original_channel) {
  return CreateChannel(video_channel, original_channel, true);
}

int ViEBaseImpl::CreateReceiveChannel(int& video_channel,  // NOLINT
                                      int original_channel) {
  return CreateChannel(video_channel, original_channel, false);
}

int ViEBaseImpl::DeleteChannel(const int video_channel) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_.instance_id()),
               "%s(%d)", __FUNCTION__, video_channel);
  {
    ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
    ViEChannel* vie_channel = cs.Channel(video_channel);
    if (!vie_channel) {
      WEBRTC_TRACE(kTraceError, kTraceVideo,
                   ViEId(shared_data_.instance_id()),
                   "%s: channel %d doesn't exist", __FUNCTION__, video_channel);
      shared_data_.SetLastError(kViEBaseInvalidChannelId);
      return -1;
    }

    // Deregister the ViEEncoder if no other channel is using it.
    ViEEncoder* vie_encoder = cs.Encoder(video_channel);
    if (cs.ChannelUsingViEEncoder(video_channel) == false) {
      ViEInputManagerScoped is(*(shared_data_.input_manager()));
      ViEFrameProviderBase* provider = is.FrameProvider(vie_encoder);
      if (provider) {
        provider->DeregisterFrameCallback(vie_encoder);
      }
    }
  }

  if (shared_data_.channel_manager()->DeleteChannel(video_channel) == -1) {
    WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_.instance_id()),
                 "%s: Could not delete channel %d", __FUNCTION__,
                 video_channel);
    shared_data_.SetLastError(kViEBaseUnknownError);
    return -1;
  }
  WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(shared_data_.instance_id()),
               "%s: channel deleted: %d", __FUNCTION__, video_channel);
  return 0;
}

int ViEBaseImpl::ConnectAudioChannel(const int video_channel,
                                     const int audio_channel) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_.instance_id()),
               "%s(%d)", __FUNCTION__, video_channel);
  ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
  if (!cs.Channel(video_channel)) {
    WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_.instance_id()),
                 "%s: channel %d doesn't exist", __FUNCTION__, video_channel);
    shared_data_.SetLastError(kViEBaseInvalidChannelId);
    return -1;
  }

  if (shared_data_.channel_manager()->ConnectVoiceChannel(video_channel,
                                                          audio_channel) != 0) {
    shared_data_.SetLastError(kViEBaseVoEFailure);
    return -1;
  }
  return 0;
}

int ViEBaseImpl::DisconnectAudioChannel(const int video_channel) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_.instance_id()),
               "%s(%d)", __FUNCTION__, video_channel);
  ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
  if (!cs.Channel(video_channel)) {
    WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_.instance_id()),
                 "%s: channel %d doesn't exist", __FUNCTION__, video_channel);
    shared_data_.SetLastError(kViEBaseInvalidChannelId);
    return -1;
  }

  if (shared_data_.channel_manager()->DisconnectVoiceChannel(
      video_channel) != 0) {
    shared_data_.SetLastError(kViEBaseVoEFailure);
    return -1;
  }
  return 0;
}

int ViEBaseImpl::StartSend(const int video_channel) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
               ViEId(shared_data_.instance_id(), video_channel),
               "%s(channel: %d)", __FUNCTION__, video_channel);

  ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_channel) {
    WEBRTC_TRACE(kTraceError, kTraceVideo,
                 ViEId(shared_data_.instance_id(), video_channel),
                 "%s: Channel %d does not exist", __FUNCTION__, video_channel);
    shared_data_.SetLastError(kViEBaseInvalidChannelId);
    return -1;
  }

  ViEEncoder* vie_encoder = cs.Encoder(video_channel);
  assert(vie_encoder != NULL);
  if (vie_encoder->Owner() != video_channel) {
    WEBRTC_TRACE(kTraceError, kTraceVideo,
                 ViEId(shared_data_.instance_id(), video_channel),
                 "Can't start ssend on a receive only channel.");
    shared_data_.SetLastError(kViEBaseReceiveOnlyChannel);
    return -1;
  }

  // Pause and trigger a key frame.
  vie_encoder->Pause();
  int32_t error = vie_channel->StartSend();
  if (error != 0) {
    vie_encoder->Restart();
    WEBRTC_TRACE(kTraceError, kTraceVideo,
                 ViEId(shared_data_.instance_id(), video_channel),
                 "%s: Could not start sending on channel %d", __FUNCTION__,
                 video_channel);
    if (error == kViEBaseAlreadySending) {
      shared_data_.SetLastError(kViEBaseAlreadySending);
    }
    shared_data_.SetLastError(kViEBaseUnknownError);
    return -1;
  }
  vie_encoder->SendKeyFrame();
  vie_encoder->Restart();
  return 0;
}

int ViEBaseImpl::StopSend(const int video_channel) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
               ViEId(shared_data_.instance_id(), video_channel),
               "%s(channel: %d)", __FUNCTION__, video_channel);

  ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_channel) {
    WEBRTC_TRACE(kTraceError, kTraceVideo,
                 ViEId(shared_data_.instance_id(), video_channel),
                 "%s: Channel %d does not exist", __FUNCTION__, video_channel);
    shared_data_.SetLastError(kViEBaseInvalidChannelId);
    return -1;
  }

  int32_t error = vie_channel->StopSend();
  if (error != 0) {
    WEBRTC_TRACE(kTraceError, kTraceVideo,
                 ViEId(shared_data_.instance_id(), video_channel),
                 "%s: Could not stop sending on channel %d", __FUNCTION__,
                 video_channel);
    if (error == kViEBaseNotSending) {
      shared_data_.SetLastError(kViEBaseNotSending);
    } else {
      shared_data_.SetLastError(kViEBaseUnknownError);
    }
    return -1;
  }
  return 0;
}

int ViEBaseImpl::StartReceive(const int video_channel) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
               ViEId(shared_data_.instance_id(), video_channel),
               "%s(channel: %d)", __FUNCTION__, video_channel);

  ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_channel) {
    WEBRTC_TRACE(kTraceError, kTraceVideo,
                 ViEId(shared_data_.instance_id(), video_channel),
                 "%s: Channel %d does not exist", __FUNCTION__, video_channel);
    shared_data_.SetLastError(kViEBaseInvalidChannelId);
    return -1;
  }
  if (vie_channel->StartReceive() != 0) {
    shared_data_.SetLastError(kViEBaseUnknownError);
    return -1;
  }
  return 0;
}

int ViEBaseImpl::StopReceive(const int video_channel) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
               ViEId(shared_data_.instance_id(), video_channel),
               "%s(channel: %d)", __FUNCTION__, video_channel);

  ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_channel) {
    WEBRTC_TRACE(kTraceError, kTraceVideo,
                 ViEId(shared_data_.instance_id(), video_channel),
                 "%s: Channel %d does not exist", __FUNCTION__, video_channel);
    shared_data_.SetLastError(kViEBaseInvalidChannelId);
    return -1;
  }
  if (vie_channel->StopReceive() != 0) {
    shared_data_.SetLastError(kViEBaseUnknownError);
    return -1;
  }
  return 0;
}

int ViEBaseImpl::GetVersion(char version[1024]) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_.instance_id()),
               "GetVersion(version=?)");
  assert(kViEVersionMaxMessageSize == 1024);
  if (!version) {
    shared_data_.SetLastError(kViEBaseInvalidArgument);
    return -1;
  }

  // Add WebRTC Version.
  std::stringstream version_stream;
  version_stream << "VideoEngine 3.32.0" << std::endl;

  // Add build info.
  version_stream << "Build: svn:" << WEBRTC_SVNREVISION << " " << BUILDINFO
                 << std::endl;

#ifdef WEBRTC_EXTERNAL_TRANSPORT
  version_stream << "External transport build" << std::endl;
#endif
  int version_length = version_stream.tellp();
  assert(version_length < 1024);
  memcpy(version, version_stream.str().c_str(), version_length);
  version[version_length] = '\0';

  WEBRTC_TRACE(kTraceStateInfo, kTraceVideo,
               ViEId(shared_data_.instance_id()), "GetVersion() => %s",
               version);
  return 0;
}

int ViEBaseImpl::LastError() {
  return shared_data_.LastErrorInternal();
}

int ViEBaseImpl::CreateChannel(int& video_channel,  // NOLINT
                               int original_channel, bool sender) {
  ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
  if (!cs.Channel(original_channel)) {
    WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_.instance_id()),
                 "%s - original_channel does not exist.", __FUNCTION__,
                 shared_data_.instance_id());
    shared_data_.SetLastError(kViEBaseInvalidChannelId);
    return -1;
  }

  if (shared_data_.channel_manager()->CreateChannel(&video_channel,
                                                    original_channel,
                                                    sender) == -1) {
    WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_.instance_id()),
                 "%s: Could not create channel", __FUNCTION__);
    video_channel = -1;
    shared_data_.SetLastError(kViEBaseChannelCreationFailed);
    return -1;
  }
  WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(shared_data_.instance_id()),
               "%s: channel created: %d", __FUNCTION__, video_channel);
  return 0;
}

}  // namespace webrtc
<commit_msg>Updated WebRTC version to 3.33<commit_after>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/video_engine/vie_base_impl.h"

#include <sstream>
#include <string>

#include "webrtc/engine_configurations.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
#include "webrtc/modules/video_coding/main/interface/video_coding.h"
#include "webrtc/modules/video_processing/main/interface/video_processing.h"
#include "webrtc/modules/video_render/include/video_render.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/trace.h"
#include "webrtc/video_engine/include/vie_errors.h"
#include "webrtc/video_engine/vie_channel.h"
#include "webrtc/video_engine/vie_channel_manager.h"
#include "webrtc/video_engine/vie_defines.h"
#include "webrtc/video_engine/vie_encoder.h"
#include "webrtc/video_engine/vie_impl.h"
#include "webrtc/video_engine/vie_input_manager.h"
#include "webrtc/video_engine/vie_shared_data.h"

namespace webrtc {

ViEBase* ViEBase::GetInterface(VideoEngine* video_engine) {
  if (!video_engine) {
    return NULL;
  }
  VideoEngineImpl* vie_impl = static_cast<VideoEngineImpl*>(video_engine);
  ViEBaseImpl* vie_base_impl = vie_impl;
  (*vie_base_impl)++;  // Increase ref count.

  return vie_base_impl;
}

int ViEBaseImpl::Release() {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo, shared_data_.instance_id(),
               "ViEBase::Release()");
  (*this)--;  // Decrease ref count.

  int32_t ref_count = GetCount();
  if (ref_count < 0) {
    WEBRTC_TRACE(kTraceWarning, kTraceVideo, shared_data_.instance_id(),
                 "ViEBase release too many times");
    shared_data_.SetLastError(kViEAPIDoesNotExist);
    return -1;
  }
  WEBRTC_TRACE(kTraceInfo, kTraceVideo, shared_data_.instance_id(),
               "ViEBase reference count: %d", ref_count);
  return ref_count;
}

ViEBaseImpl::ViEBaseImpl(const Config& config)
    : shared_data_(config) {
  WEBRTC_TRACE(kTraceMemory, kTraceVideo, shared_data_.instance_id(),
               "ViEBaseImpl::ViEBaseImpl() Ctor");
}

ViEBaseImpl::~ViEBaseImpl() {
  WEBRTC_TRACE(kTraceMemory, kTraceVideo, shared_data_.instance_id(),
               "ViEBaseImpl::ViEBaseImpl() Dtor");
}

int ViEBaseImpl::Init() {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo, shared_data_.instance_id(),
               "Init");
  return 0;
}

int ViEBaseImpl::SetVoiceEngine(VoiceEngine* voice_engine) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_.instance_id()),
               "%s", __FUNCTION__);
  if (shared_data_.channel_manager()->SetVoiceEngine(voice_engine) != 0) {
    shared_data_.SetLastError(kViEBaseVoEFailure);
    return -1;
  }
  return 0;
}

int ViEBaseImpl::CreateChannel(int& video_channel) {  // NOLINT
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_.instance_id()),
               "%s", __FUNCTION__);
  if (shared_data_.channel_manager()->CreateChannel(&video_channel) == -1) {
    WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_.instance_id()),
                 "%s: Could not create channel", __FUNCTION__);
    video_channel = -1;
    shared_data_.SetLastError(kViEBaseChannelCreationFailed);
    return -1;
  }
  WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(shared_data_.instance_id()),
               "%s: channel created: %d", __FUNCTION__, video_channel);
  return 0;
}

int ViEBaseImpl::CreateChannel(int& video_channel,  // NOLINT
                               int original_channel) {
  return CreateChannel(video_channel, original_channel, true);
}

int ViEBaseImpl::CreateReceiveChannel(int& video_channel,  // NOLINT
                                      int original_channel) {
  return CreateChannel(video_channel, original_channel, false);
}

int ViEBaseImpl::DeleteChannel(const int video_channel) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_.instance_id()),
               "%s(%d)", __FUNCTION__, video_channel);
  {
    ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
    ViEChannel* vie_channel = cs.Channel(video_channel);
    if (!vie_channel) {
      WEBRTC_TRACE(kTraceError, kTraceVideo,
                   ViEId(shared_data_.instance_id()),
                   "%s: channel %d doesn't exist", __FUNCTION__, video_channel);
      shared_data_.SetLastError(kViEBaseInvalidChannelId);
      return -1;
    }

    // Deregister the ViEEncoder if no other channel is using it.
    ViEEncoder* vie_encoder = cs.Encoder(video_channel);
    if (cs.ChannelUsingViEEncoder(video_channel) == false) {
      ViEInputManagerScoped is(*(shared_data_.input_manager()));
      ViEFrameProviderBase* provider = is.FrameProvider(vie_encoder);
      if (provider) {
        provider->DeregisterFrameCallback(vie_encoder);
      }
    }
  }

  if (shared_data_.channel_manager()->DeleteChannel(video_channel) == -1) {
    WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_.instance_id()),
                 "%s: Could not delete channel %d", __FUNCTION__,
                 video_channel);
    shared_data_.SetLastError(kViEBaseUnknownError);
    return -1;
  }
  WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(shared_data_.instance_id()),
               "%s: channel deleted: %d", __FUNCTION__, video_channel);
  return 0;
}

int ViEBaseImpl::ConnectAudioChannel(const int video_channel,
                                     const int audio_channel) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_.instance_id()),
               "%s(%d)", __FUNCTION__, video_channel);
  ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
  if (!cs.Channel(video_channel)) {
    WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_.instance_id()),
                 "%s: channel %d doesn't exist", __FUNCTION__, video_channel);
    shared_data_.SetLastError(kViEBaseInvalidChannelId);
    return -1;
  }

  if (shared_data_.channel_manager()->ConnectVoiceChannel(video_channel,
                                                          audio_channel) != 0) {
    shared_data_.SetLastError(kViEBaseVoEFailure);
    return -1;
  }
  return 0;
}

int ViEBaseImpl::DisconnectAudioChannel(const int video_channel) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_.instance_id()),
               "%s(%d)", __FUNCTION__, video_channel);
  ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
  if (!cs.Channel(video_channel)) {
    WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_.instance_id()),
                 "%s: channel %d doesn't exist", __FUNCTION__, video_channel);
    shared_data_.SetLastError(kViEBaseInvalidChannelId);
    return -1;
  }

  if (shared_data_.channel_manager()->DisconnectVoiceChannel(
      video_channel) != 0) {
    shared_data_.SetLastError(kViEBaseVoEFailure);
    return -1;
  }
  return 0;
}

int ViEBaseImpl::StartSend(const int video_channel) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
               ViEId(shared_data_.instance_id(), video_channel),
               "%s(channel: %d)", __FUNCTION__, video_channel);

  ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_channel) {
    WEBRTC_TRACE(kTraceError, kTraceVideo,
                 ViEId(shared_data_.instance_id(), video_channel),
                 "%s: Channel %d does not exist", __FUNCTION__, video_channel);
    shared_data_.SetLastError(kViEBaseInvalidChannelId);
    return -1;
  }

  ViEEncoder* vie_encoder = cs.Encoder(video_channel);
  assert(vie_encoder != NULL);
  if (vie_encoder->Owner() != video_channel) {
    WEBRTC_TRACE(kTraceError, kTraceVideo,
                 ViEId(shared_data_.instance_id(), video_channel),
                 "Can't start ssend on a receive only channel.");
    shared_data_.SetLastError(kViEBaseReceiveOnlyChannel);
    return -1;
  }

  // Pause and trigger a key frame.
  vie_encoder->Pause();
  int32_t error = vie_channel->StartSend();
  if (error != 0) {
    vie_encoder->Restart();
    WEBRTC_TRACE(kTraceError, kTraceVideo,
                 ViEId(shared_data_.instance_id(), video_channel),
                 "%s: Could not start sending on channel %d", __FUNCTION__,
                 video_channel);
    if (error == kViEBaseAlreadySending) {
      shared_data_.SetLastError(kViEBaseAlreadySending);
    }
    shared_data_.SetLastError(kViEBaseUnknownError);
    return -1;
  }
  vie_encoder->SendKeyFrame();
  vie_encoder->Restart();
  return 0;
}

int ViEBaseImpl::StopSend(const int video_channel) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
               ViEId(shared_data_.instance_id(), video_channel),
               "%s(channel: %d)", __FUNCTION__, video_channel);

  ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_channel) {
    WEBRTC_TRACE(kTraceError, kTraceVideo,
                 ViEId(shared_data_.instance_id(), video_channel),
                 "%s: Channel %d does not exist", __FUNCTION__, video_channel);
    shared_data_.SetLastError(kViEBaseInvalidChannelId);
    return -1;
  }

  int32_t error = vie_channel->StopSend();
  if (error != 0) {
    WEBRTC_TRACE(kTraceError, kTraceVideo,
                 ViEId(shared_data_.instance_id(), video_channel),
                 "%s: Could not stop sending on channel %d", __FUNCTION__,
                 video_channel);
    if (error == kViEBaseNotSending) {
      shared_data_.SetLastError(kViEBaseNotSending);
    } else {
      shared_data_.SetLastError(kViEBaseUnknownError);
    }
    return -1;
  }
  return 0;
}

int ViEBaseImpl::StartReceive(const int video_channel) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
               ViEId(shared_data_.instance_id(), video_channel),
               "%s(channel: %d)", __FUNCTION__, video_channel);

  ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_channel) {
    WEBRTC_TRACE(kTraceError, kTraceVideo,
                 ViEId(shared_data_.instance_id(), video_channel),
                 "%s: Channel %d does not exist", __FUNCTION__, video_channel);
    shared_data_.SetLastError(kViEBaseInvalidChannelId);
    return -1;
  }
  if (vie_channel->StartReceive() != 0) {
    shared_data_.SetLastError(kViEBaseUnknownError);
    return -1;
  }
  return 0;
}

int ViEBaseImpl::StopReceive(const int video_channel) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
               ViEId(shared_data_.instance_id(), video_channel),
               "%s(channel: %d)", __FUNCTION__, video_channel);

  ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_channel) {
    WEBRTC_TRACE(kTraceError, kTraceVideo,
                 ViEId(shared_data_.instance_id(), video_channel),
                 "%s: Channel %d does not exist", __FUNCTION__, video_channel);
    shared_data_.SetLastError(kViEBaseInvalidChannelId);
    return -1;
  }
  if (vie_channel->StopReceive() != 0) {
    shared_data_.SetLastError(kViEBaseUnknownError);
    return -1;
  }
  return 0;
}

int ViEBaseImpl::GetVersion(char version[1024]) {
  WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_.instance_id()),
               "GetVersion(version=?)");
  assert(kViEVersionMaxMessageSize == 1024);
  if (!version) {
    shared_data_.SetLastError(kViEBaseInvalidArgument);
    return -1;
  }

  // Add WebRTC Version.
  std::stringstream version_stream;
  version_stream << "VideoEngine 3.33.0" << std::endl;

  // Add build info.
  version_stream << "Build: svn:" << WEBRTC_SVNREVISION << " " << BUILDINFO
                 << std::endl;

#ifdef WEBRTC_EXTERNAL_TRANSPORT
  version_stream << "External transport build" << std::endl;
#endif
  int version_length = version_stream.tellp();
  assert(version_length < 1024);
  memcpy(version, version_stream.str().c_str(), version_length);
  version[version_length] = '\0';

  WEBRTC_TRACE(kTraceStateInfo, kTraceVideo,
               ViEId(shared_data_.instance_id()), "GetVersion() => %s",
               version);
  return 0;
}

int ViEBaseImpl::LastError() {
  return shared_data_.LastErrorInternal();
}

int ViEBaseImpl::CreateChannel(int& video_channel,  // NOLINT
                               int original_channel, bool sender) {
  ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
  if (!cs.Channel(original_channel)) {
    WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_.instance_id()),
                 "%s - original_channel does not exist.", __FUNCTION__,
                 shared_data_.instance_id());
    shared_data_.SetLastError(kViEBaseInvalidChannelId);
    return -1;
  }

  if (shared_data_.channel_manager()->CreateChannel(&video_channel,
                                                    original_channel,
                                                    sender) == -1) {
    WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_.instance_id()),
                 "%s: Could not create channel", __FUNCTION__);
    video_channel = -1;
    shared_data_.SetLastError(kViEBaseChannelCreationFailed);
    return -1;
  }
  WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(shared_data_.instance_id()),
               "%s: channel created: %d", __FUNCTION__, video_channel);
  return 0;
}

}  // namespace webrtc
<|endoftext|>


<commit_before>#ifndef CAT2MAP_HPP
#define CAT2MAP_HPP

#include <fstream>
#include <iostream>
#include <exception>
#include <vector>
#include <cmath>
#include <cassert>

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include <boost/log/trivial.hpp>
#include <boost/tokenizer.hpp>

#include <healpix_map.h>
#include <pointing.h>
#include <healpix_map_fitsio.h>
#include <datatypes.h>

class Cat2Map
{
public:
    typedef boost::property_tree::ptree propertyTreeType;
    typedef Healpix_Map<double> mapType;

    static const constexpr double deg2rad = M_PI/double(180);
    static const constexpr double rotPhi = double(0);

    Cat2Map(std::string const& iniFileName)
    {
        BOOST_LOG_TRIVIAL(info) << std::string("Reading the ini file ") + std::string(iniFileName);
        boost::property_tree::ini_parser::read_ini(iniFileName,mPropTree);

        // set the output maps
        BOOST_LOG_TRIVIAL(info) << "Resulution of the output map is "<<mPropTree.get<std::string>("output.n_side");

        int nSide = mPropTree.get<int>("output.n_side");
        mMapN.SetNside(nSide,RING);
        mMapE1.SetNside(nSide,RING);
        mMapE2.SetNside(nSide,RING);

        mMapN.fill(double(0));
        mMapE1.fill(double(0));
        mMapE1.fill(double(0));

        // read the mask
        read_Healpix_map_from_fits(mPropTree.get<std::string>("input.mask_file_name"),mMask);

        try
        {
            std::string testMapFileName = mPropTree.get<std::string>("test.map_file_name");

            BOOST_LOG_TRIVIAL(info) << "Test map file specified as "<< testMapFileName;

            read_Healpix_map_from_fits(testMapFileName,mTestE1,int(2),int(2));
            read_Healpix_map_from_fits(testMapFileName,mTestE2,int(3),int(2));

            mDoTest = true;
        }
        catch(std::exception)
        {
            BOOST_LOG_TRIVIAL(info) << "No test map file specified.";
            mDoTest = false;
        }

        mMisMatchCountE1 = size_t(0);
        mMisMatchCountE2 = size_t(0);
    }

    void accumulate()
    {
        // open file for reading
        std::ifstream inputCatFile;
        inputCatFile.open( mPropTree.get<std::string>("input.catlogue_file_name").c_str(),std::ios::in );

        if(inputCatFile.is_open())
        {

            BOOST_LOG_TRIVIAL(info) << "Accumulating objects";
            BOOST_LOG_TRIVIAL(info) << "Number of rows to be skipped = " << mPropTree.get<std::string>("input.skip_rows");
            BOOST_LOG_TRIVIAL(info) << "Delimiter for separation is "<< mPropTree.get<std::string>("input.delimiter");

            size_t col_ra =  mPropTree.get<size_t>("input.col_ra");
            size_t col_dec =  mPropTree.get<size_t>("input.col_dec");
            size_t col_z = mPropTree.get<size_t>("input.col_z");
            size_t col_ellip_1 = mPropTree.get<size_t>("input.col_ellip_1");
            size_t col_ellip_2 = mPropTree.get<size_t>("input.col_ellip_2");

            BOOST_LOG_TRIVIAL(info) << "Column of ra values = "<< col_ra;
            BOOST_LOG_TRIVIAL(info) << "Column of dec values = "<< col_dec;
            BOOST_LOG_TRIVIAL(info) << "Column of z values = "<< col_z;
            BOOST_LOG_TRIVIAL(info) << "Column of ellip_1 values = "<< col_ellip_1;
            BOOST_LOG_TRIVIAL(info) << "Column of ellip_2 values = "<< col_ellip_2;

            size_t line_id = 0;
            while(!inputCatFile.eof())
            {
                std::string line;

                std::getline(inputCatFile,line);

                ++line_id;

                if(line_id > mPropTree.get<size_t>("input.skip_rows"))
                {
                    typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
                    boost::char_separator<char> sep(mPropTree.get<std::string>("input.delimiter").c_str());
                    tokenizer tokens(line, sep);

                    std::vector<double> ents;
                    for(tokenizer::iterator tokIter = tokens.begin(); tokIter !=tokens.end(); ++tokIter)
                    {
                        ents.push_back(boost::lexical_cast<double>(*tokIter));
                    }

                    if(ents.size()>0)
                    {
                        assert(col_ra<ents.size());
                        assert(col_dec<ents.size());
                        assert(col_ellip_1<ents.size());
                        assert(col_ellip_2<ents.size());

                        double ra = ents[col_ra];
                        double dec = ents[col_dec];
                        double e1 = ents[col_ellip_1];
                        double e2 = ents[col_ellip_2];

                        double theta = -deg2rad*dec + M_PI*double(0.5);
                        double phi = deg2rad*(ra - rotPhi);

                        auto pix = mMapE1.ang2pix(pointing(theta,phi));

                        // check if the pixel falls in the masked region
                        if(mMask[pix]>0)
                        {

                            if(mDoTest)
                            {
                                // if testing accumulate the miss-match
                                // between pixel values
                                if(std::abs( (e1 - mTestE1[pix])/e1 ) >= 1e-5)
                                {
                                    mMisMatchCountE1 += size_t(1);
                                }

                                if(std::abs( (e2 - mTestE2[pix])/e2 ) > 1e-5)
                                {
                                    mMisMatchCountE2 += size_t(1);
                                }
                            }

                            // do accumulation
                            mMapN[pix] += double(1);
                            mMapE1[pix] += e1;
                            mMapE2[pix] += e2;
                        }

                    }

                }
                else
                {
                    BOOST_LOG_TRIVIAL(info) << "Skipping line " << line_id;
                }
            }

            // make it the average
            for(auto pix = 0; pix<mMapN.Npix(); ++pix)
            {
                if(mMapN[pix]>0) // TODO how many gals we need to make an estimate
                {
                    mMapE1[pix] /= mMapN[pix];
                    mMapE2[pix] /= mMapN[pix];
                }
                else
                {
                    // make the new mask
                    mMask[pix] = 0;
                }
            }

            // if testing print the mismatch stats
            if(mDoTest)
            {
                size_t nPix = (size_t) mTestE1.Npix();
                double fracMissMatchE1 = (double)mMisMatchCountE1 / (double)nPix;
                double fracMissMatchE2 = (double)mMisMatchCountE2 / (double)nPix;

                BOOST_LOG_TRIVIAL(warning) << "Pixel value miss-match for e1 = "<<fracMissMatchE1;
                BOOST_LOG_TRIVIAL(warning) << "Pixel value miss-match for e2 = "<<fracMissMatchE2;
            }
        }
        else
        {
            std::string msg = std::string("Input catalogue file ")
                + std::string(mPropTree.get<std::string>("input.catlogue_file_name"))
                + std::string(" failed to open.");
            BOOST_LOG_TRIVIAL(error) << msg;
            throw std::runtime_error(msg);
        }

    }

    void writeMaps()
    {
        BOOST_LOG_TRIVIAL(info) << "Output data map file name :  "
            << mPropTree.get<std::string>("output.data_map_file_name");

        write_Healpix_map_to_fits(std::string("!")+mPropTree.get<std::string>("output.data_map_file_name"),
            mMapN,mMapE1,mMapE2,planckType<double>());

        BOOST_LOG_TRIVIAL(info) << "Output augmented mask file name :  "
            << mPropTree.get<std::string>("output.augmented_mask_file_name");

        write_Healpix_map_to_fits(std::string("!")+mPropTree.get<std::string>("output.augmented_mask_file_name"),
            mMask,planckType<double>());
    }

private:
    propertyTreeType mPropTree;
    mapType mMapN;
    mapType mMapE1;
    mapType mMapE2;
    mapType mMask;

    mapType mTestE1;
    mapType mTestE2;
    bool mDoTest;
    size_t mMisMatchCountE1;
    size_t mMisMatchCountE2;

};

#endif //CAT2MAP_HPP
<commit_msg>sky fraction now an output<commit_after>#ifndef CAT2MAP_HPP
#define CAT2MAP_HPP

#include <fstream>
#include <iostream>
#include <exception>
#include <vector>
#include <cmath>
#include <cassert>

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include <boost/log/trivial.hpp>
#include <boost/tokenizer.hpp>

#include <healpix_map.h>
#include <pointing.h>
#include <healpix_map_fitsio.h>
#include <datatypes.h>

class Cat2Map
{
public:
    typedef boost::property_tree::ptree propertyTreeType;
    typedef Healpix_Map<double> mapType;

    static const constexpr double deg2rad = M_PI/double(180);
    static const constexpr double rotPhi = double(0);

    Cat2Map(std::string const& iniFileName)
    {
        BOOST_LOG_TRIVIAL(info) << std::string("Reading the ini file ") + std::string(iniFileName);
        boost::property_tree::ini_parser::read_ini(iniFileName,mPropTree);

        // set the output maps
        BOOST_LOG_TRIVIAL(info) << "Resulution of the output map is "<<mPropTree.get<std::string>("output.n_side");

        int nSide = mPropTree.get<int>("output.n_side");
        mMapN.SetNside(nSide,RING);
        mMapE1.SetNside(nSide,RING);
        mMapE2.SetNside(nSide,RING);

        mMapN.fill(double(0));
        mMapE1.fill(double(0));
        mMapE1.fill(double(0));

        // read the mask
        read_Healpix_map_from_fits(mPropTree.get<std::string>("input.mask_file_name"),mMask);

        try
        {
            std::string testMapFileName = mPropTree.get<std::string>("test.map_file_name");

            BOOST_LOG_TRIVIAL(info) << "Test map file specified as "<< testMapFileName;

            read_Healpix_map_from_fits(testMapFileName,mTestE1,int(2),int(2));
            read_Healpix_map_from_fits(testMapFileName,mTestE2,int(3),int(2));

            mDoTest = true;
        }
        catch(std::exception)
        {
            BOOST_LOG_TRIVIAL(info) << "No test map file specified.";
            mDoTest = false;
        }

        mMisMatchCountE1 = size_t(0);
        mMisMatchCountE2 = size_t(0);
        mNumObsPix = size_t(0);
    }

    void accumulate()
    {
        // open file for reading
        std::ifstream inputCatFile;
        inputCatFile.open( mPropTree.get<std::string>("input.catlogue_file_name").c_str(),std::ios::in );

        if(inputCatFile.is_open())
        {

            BOOST_LOG_TRIVIAL(info) << "Accumulating objects";
            BOOST_LOG_TRIVIAL(info) << "Number of rows to be skipped = " << mPropTree.get<std::string>("input.skip_rows");
            BOOST_LOG_TRIVIAL(info) << "Delimiter for separation is "<< mPropTree.get<std::string>("input.delimiter");

            size_t col_ra =  mPropTree.get<size_t>("input.col_ra");
            size_t col_dec =  mPropTree.get<size_t>("input.col_dec");
            size_t col_z = mPropTree.get<size_t>("input.col_z");
            size_t col_ellip_1 = mPropTree.get<size_t>("input.col_ellip_1");
            size_t col_ellip_2 = mPropTree.get<size_t>("input.col_ellip_2");

            BOOST_LOG_TRIVIAL(info) << "Column of ra values = "<< col_ra;
            BOOST_LOG_TRIVIAL(info) << "Column of dec values = "<< col_dec;
            BOOST_LOG_TRIVIAL(info) << "Column of z values = "<< col_z;
            BOOST_LOG_TRIVIAL(info) << "Column of ellip_1 values = "<< col_ellip_1;
            BOOST_LOG_TRIVIAL(info) << "Column of ellip_2 values = "<< col_ellip_2;

            size_t line_id = 0;
            while(!inputCatFile.eof())
            {
                std::string line;

                std::getline(inputCatFile,line);

                ++line_id;

                if(line_id > mPropTree.get<size_t>("input.skip_rows"))
                {
                    typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
                    boost::char_separator<char> sep(mPropTree.get<std::string>("input.delimiter").c_str());
                    tokenizer tokens(line, sep);

                    std::vector<double> ents;
                    for(tokenizer::iterator tokIter = tokens.begin(); tokIter !=tokens.end(); ++tokIter)
                    {
                        ents.push_back(boost::lexical_cast<double>(*tokIter));
                    }

                    if(ents.size()>0)
                    {
                        assert(col_ra<ents.size());
                        assert(col_dec<ents.size());
                        assert(col_ellip_1<ents.size());
                        assert(col_ellip_2<ents.size());

                        double ra = ents[col_ra];
                        double dec = ents[col_dec];
                        double e1 = ents[col_ellip_1];
                        double e2 = ents[col_ellip_2];

                        double theta = -deg2rad*dec + M_PI*double(0.5);
                        double phi = deg2rad*(ra - rotPhi);

                        auto pix = mMapE1.ang2pix(pointing(theta,phi));

                        // check if the pixel falls in the masked region
                        if(mMask[pix]>0)
                        {

                            if(mDoTest)
                            {
                                // if testing accumulate the miss-match
                                // between pixel values
                                if(std::abs( (e1 - mTestE1[pix])/e1 ) >= 1e-5)
                                {
                                    mMisMatchCountE1 += size_t(1);
                                }

                                if(std::abs( (e2 - mTestE2[pix])/e2 ) > 1e-5)
                                {
                                    mMisMatchCountE2 += size_t(1);
                                }
                            }

                            // do accumulation
                            mMapN[pix] += double(1);
                            mMapE1[pix] += e1;
                            mMapE2[pix] += e2;
                            mNumObsPix += size_t(1);
                        }

                    }

                }
                else
                {
                    BOOST_LOG_TRIVIAL(info) << "Skipping line " << line_id;
                }
            }

            // make it the average
            for(auto pix = 0; pix<mMapN.Npix(); ++pix)
            {
                if(mMapN[pix]>0) // TODO how many gals we need to make an estimate
                {
                    mMapE1[pix] /= mMapN[pix];
                    mMapE2[pix] /= mMapN[pix];
                }
                else
                {
                    // make the new mask
                    mMask[pix] = 0;
                }
            }

            // output the sky fraction of the augmented mask
            size_t nPix = (size_t) mTestE1.Npix();
            double fKsy = (double)mNumObsPix / (double)nPix;
            BOOST_LOG_TRIVIAL(info) << "Sky fraction " << fKsy;

            // if testing print the mismatch stats
            if(mDoTest)
            {

                double fracMissMatchE1 = (double)mMisMatchCountE1 / (double)mNumObsPix;
                double fracMissMatchE2 = (double)mMisMatchCountE2 / (double)mNumObsPix;

                BOOST_LOG_TRIVIAL(warning) << "Pixel value miss-match for e1 = "<<fracMissMatchE1;
                BOOST_LOG_TRIVIAL(warning) << "Pixel value miss-match for e2 = "<<fracMissMatchE2;
            }
        }
        else
        {
            std::string msg = std::string("Input catalogue file ")
                + std::string(mPropTree.get<std::string>("input.catlogue_file_name"))
                + std::string(" failed to open.");
            BOOST_LOG_TRIVIAL(error) << msg;
            throw std::runtime_error(msg);
        }

    }

    void writeMaps()
    {
        BOOST_LOG_TRIVIAL(info) << "Output data map file name :  "
            << mPropTree.get<std::string>("output.data_map_file_name");

        write_Healpix_map_to_fits(std::string("!")+mPropTree.get<std::string>("output.data_map_file_name"),
            mMapN,mMapE1,mMapE2,planckType<double>());

        BOOST_LOG_TRIVIAL(info) << "Output augmented mask file name :  "
            << mPropTree.get<std::string>("output.augmented_mask_file_name");

        write_Healpix_map_to_fits(std::string("!")+mPropTree.get<std::string>("output.augmented_mask_file_name"),
            mMask,planckType<double>());
    }

private:
    propertyTreeType mPropTree;
    mapType mMapN;
    mapType mMapE1;
    mapType mMapE2;
    mapType mMask;

    mapType mTestE1;
    mapType mTestE2;
    bool mDoTest;
    size_t mMisMatchCountE1;
    size_t mMisMatchCountE2;
    size_t mNumObsPix;

};

#endif //CAT2MAP_HPP
<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (C) 2006 by Ingo Kloecker <kloecker@kde.org>                *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as       *
 *   published by the Free Software Foundation; either version 2 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this program; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
 ***************************************************************************/
#include <QDebug>

#include "akonadi.h"
#include "akonadiconnection.h"
#include "storagebackend.h"
#include "storage/datastore.h"
#include "storage/entity.h"

#include "create.h"
#include "response.h"

using namespace Akonadi;

Create::Create(): Handler()
{
}

Create::~Create()
{
}

bool Create::handleLine(const QByteArray& line )
{
    // parse out the reference name and mailbox name
    const int startOfCommand = line.indexOf( ' ' ) + 1;
    const int startOfMailbox = line.indexOf( ' ', startOfCommand ) + 1;
    QByteArray mailbox = stripQuotes( line.right( line.size() - startOfMailbox ) );

    // strip off a trailing '/'
    if ( !mailbox.isEmpty() && mailbox[0] == '/' )
      mailbox = mailbox.right( mailbox.size() - 1 );

    // Responses:
    // OK - create completed
    // NO - create failure: can't create mailbox with that name
    // BAD - command unknown or arguments invalid
    Response response;
    response.setTag( tag() );

    if ( mailbox.isEmpty() || mailbox.contains( "//" ) ) {
        response.setError();
        response.setString( "Invalid argument" );
        emit responseAvailable( response );
    }
    else {
        DataStore *db = connection()->storageBackend();
        const int startOfLocation = mailbox.indexOf( '/' ) + 1;
        const QByteArray resourceName = mailbox.left( startOfLocation - 1 );
        const QByteArray locationName = mailbox.right( startOfLocation );
        qDebug() << "Create: " << locationName
                 << " in resource: " << resourceName;
        Resource resource = db->getResourceByName( resourceName );
        // first check whether location already exists
        if ( db->getLocationByName( resource, locationName ).isValid() ) {
            response.setFailure();
            response.setString( "A folder with that name does already exist");
            emit responseAvailable( response );
        }
        // we have to create all superior hierarchical folders, so look for the
        // starting point
        QList<QByteArray> foldersToCreate;
        foldersToCreate.append( locationName );
        for ( int endOfSupFolder = locationName.lastIndexOf( '/', locationName.size() - 1 );
              endOfSupFolder > 0;
              endOfSupFolder = locationName.lastIndexOf( '/', endOfSupFolder - 2 ) ) {
            // check whether the superior hierarchical folder exists
            qDebug() << "Does " << locationName.left( endOfSupFolder )
                     << " exist in " << resourceName;
            if ( !db->getLocationByName( resource, locationName.left( endOfSupFolder ) ).isValid() ) {
                // the superior folder does not exist, so it has to be created
                foldersToCreate.prepend( locationName.left( endOfSupFolder ) );
            }
            else {
                // the superior folder exists, so we can stop here
                break;
            }
        }
        // now we try to create all necessary folders
        // first check whether the existing superior folder can contain subfolders
        const int endOfSupFolder = foldersToCreate[0].lastIndexOf( '/' );
        if ( endOfSupFolder > 0 ) {
            bool canContainSubfolders = false;
            const QList<MimeType> mimeTypes = db->getMimeTypesForLocation( db->getLocationByName( resource, locationName.left( endOfSupFolder ) ).getId() );
            foreach ( MimeType m, mimeTypes ) {
                if ( m.getMimeType().toLower() == "directory/inode" ) {
                    canContainSubfolders = true;
                    break;
                }
            }
            if ( !canContainSubfolders ) {
                response.setFailure();
                response.setString( "Superior folder cannot contain subfolders" );
                emit responseAvailable( response );
                deleteLater();
                return true;
            }
        }
        // everything looks good, now we create the folders
        foreach ( QByteArray folderName, foldersToCreate ) {
            int locationId = 0;
            db->appendLocation( folderName, resource, &locationId );
            //db->appendMimeTypeForLocation( locationId, MimeType( "directory/inode" ) );
        }
    }

    response.setSuccess();
    response.setString( "Completed" );
    emit responseAvailable( response );

    deleteLater();
    return true;
}

<commit_msg>It's right( len ), not right( start ). So I simply use mid( start ) instead.<commit_after>/***************************************************************************
 *   Copyright (C) 2006 by Ingo Kloecker <kloecker@kde.org>                *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as       *
 *   published by the Free Software Foundation; either version 2 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this program; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
 ***************************************************************************/
#include <QDebug>

#include "akonadi.h"
#include "akonadiconnection.h"
#include "storagebackend.h"
#include "storage/datastore.h"
#include "storage/entity.h"

#include "create.h"
#include "response.h"

using namespace Akonadi;

Create::Create(): Handler()
{
}

Create::~Create()
{
}

bool Create::handleLine(const QByteArray& line )
{
    // parse out the reference name and mailbox name
    const int startOfCommand = line.indexOf( ' ' ) + 1;
    const int startOfMailbox = line.indexOf( ' ', startOfCommand ) + 1;
    QByteArray mailbox = stripQuotes( line.right( line.size() - startOfMailbox ) );

    // strip off a trailing '/'
    if ( !mailbox.isEmpty() && mailbox[0] == '/' )
      mailbox = mailbox.right( mailbox.size() - 1 );

    // Responses:
    // OK - create completed
    // NO - create failure: can't create mailbox with that name
    // BAD - command unknown or arguments invalid
    Response response;
    response.setTag( tag() );

    if ( mailbox.isEmpty() || mailbox.contains( "//" ) ) {
        response.setError();
        response.setString( "Invalid argument" );
        emit responseAvailable( response );
    }
    else {
        DataStore *db = connection()->storageBackend();
        const int startOfLocation = mailbox.indexOf( '/' ) + 1;
        const QByteArray resourceName = mailbox.left( startOfLocation - 1 );
        const QByteArray locationName = mailbox.mid( startOfLocation );
        qDebug() << "Create: " << locationName
                 << " in resource: " << resourceName;
        Resource resource = db->getResourceByName( resourceName );
        // first check whether location already exists
        if ( db->getLocationByName( resource, locationName ).isValid() ) {
            response.setFailure();
            response.setString( "A folder with that name does already exist");
            emit responseAvailable( response );
        }
        // we have to create all superior hierarchical folders, so look for the
        // starting point
        QList<QByteArray> foldersToCreate;
        foldersToCreate.append( locationName );
        for ( int endOfSupFolder = locationName.lastIndexOf( '/', locationName.size() - 1 );
              endOfSupFolder > 0;
              endOfSupFolder = locationName.lastIndexOf( '/', endOfSupFolder - 2 ) ) {
            // check whether the superior hierarchical folder exists
            qDebug() << "Does " << locationName.left( endOfSupFolder )
                     << " exist in " << resourceName << "?";
            if ( !db->getLocationByName( resource, locationName.left( endOfSupFolder ) ).isValid() ) {
                // the superior folder does not exist, so it has to be created
                qDebug() << "No, it has to be created";
                foldersToCreate.prepend( locationName.left( endOfSupFolder ) );
            }
            else {
                // the superior folder exists, so we can stop here
                qDebug() << "Yes, it exists";
                break;
            }
        }
        // now we try to create all necessary folders
        // first check whether the existing superior folder can contain subfolders
        const int endOfSupFolder = foldersToCreate[0].lastIndexOf( '/' );
        if ( endOfSupFolder > 0 ) {
            bool canContainSubfolders = false;
            const QList<MimeType> mimeTypes = db->getMimeTypesForLocation( db->getLocationByName( resource, locationName.left( endOfSupFolder ) ).getId() );
            foreach ( MimeType m, mimeTypes ) {
                if ( m.getMimeType().toLower() == "directory/inode" ) {
                    canContainSubfolders = true;
                    break;
                }
            }
            if ( !canContainSubfolders ) {
                response.setFailure();
                response.setString( "Superior folder cannot contain subfolders" );
                emit responseAvailable( response );
                deleteLater();
                return true;
            }
        }
        // everything looks good, now we create the folders
        foreach ( QByteArray folderName, foldersToCreate ) {
            int locationId = 0;
            db->appendLocation( folderName, resource, &locationId );
            //db->appendMimeTypeForLocation( locationId, MimeType( "directory/inode" ) );
        }
    }

    response.setSuccess();
    response.setString( "Completed" );
    emit responseAvailable( response );

    deleteLater();
    return true;
}

<|endoftext|>


<commit_before>/*
 * ReaderWriterMutex.hpp
 *
 * Copyright (C) 2019 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant to the terms of a commercial license agreement
 * with RStudio, then this program is licensed to you under the following terms:
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */

#ifndef SHARED_CORE_READER_WRITER_MUTEX_HPP
#define SHARED_CORE_READER_WRITER_MUTEX_HPP

#include "PImpl.hpp"

#include <boost/thread/exceptions.hpp>

namespace rstudio {
namespace core {
namespace thread {

/**
 * @brief Reentrant reader-writer mutex implementation. This implementation is write-preferring.
 */
class ReaderWriterMutex
{
public:
   /**
    * @brief Constructor.
    */
   ReaderWriterMutex();

   /**
    * @brief Move constructor.
    *
    * @param in_other   The mutex to move to this mutex.
    */
   ReaderWriterMutex(ReaderWriterMutex&& in_other) noexcept;

   /**
    * @brief Deleted copy constructor to prevent copy.
    */
   ReaderWriterMutex(const ReaderWriterMutex&) = delete;

   /**
    * @brief Deleted assignment operator to prevent copy.
    */
   ReaderWriterMutex& operator=(const ReaderWriterMutex&) = delete;

   /**
    * @brief Locks the mutex for read.
    *
    * Note: unlockRead() must be called once for each time lockRead() was called.
    */
   void lockRead();

   /**
    * @brief Locks the mutex for write.
    *
    * Note: unlockWrite() must be called once for each time lockWrite() was called.
    */
   void lockWrite();

   /**
    * @brief Unlocks the mutex after a read operation.
    *
    * Note: unlockRead() must be called once for each time lockRead() was called.
    */
   void unlockRead();

   /**
    * @brief Unlocks the mutex after a write operation.
    *
    * Note: unlockWrite() must be called once for each time lockWrite() was called.
    */
   void unlockWrite();

private:

   PRIVATE_IMPL(m_impl);
};

/**
 * @brief RAII class which allows you to lock a ReaderWriterMutex for read.
 */
class ReaderLock
{
public:
   /**
    * @brief Constructor. Locks the specified mutex for read.
    *
    * @param in_mutex    The mutex to lock for read.
    */
   explicit ReaderLock(ReaderWriterMutex& in_mutex);

   /**
    * @brief Destructor.
    */
   ~ReaderLock();

private:
   // The mutex this lock manages.
   ReaderWriterMutex& m_mutex;
};

/**
 * @brief RAII class which allows you to lock a ReaderWriterMutex for write.
 */
class WriterLock
{
public:
   /**
    * @brief Constructor. Locks the specified mutex for write.
    *
    * @param in_mutex    The mutex to lock for write.
    */
   explicit WriterLock(ReaderWriterMutex& in_mutex);

   /**
    * @brief Destructor.
    */
   ~WriterLock();

private:
   // The mutex this lock manages.
   ReaderWriterMutex& m_mutex;
};

} // namespace thread
} // namespace core
} // namespace rstudio

#define READ_LOCK_BEGIN(mutex)                        \
   try                                                \
   {                                                  \
      rstudio::core::thread::ReaderLock lock(mutex);  \

#define WRITE_LOCK_BEGIN(mutex)                       \
   try                                                \
   {                                                  \
      rstudio::core::thread::WriterLock lock(mutex);  \

#define RW_LOCK_END(tryLog)                                                                     \
   }                                                                                \
   catch (const boost::thread_resource_error& e)                                             \
   {                                                                                \
      if (tryLog)                                                                            \
         log::logErrorMessage("Failed to acquire lock: thread resource error",               \
                              ERROR_LOCATION);                                               \
   }                                                                                \
   catch (const std::exception& e)                                                           \
   {                                                                                \
      if (tryLog)                                                                            \
         log::logErrorMessage(std::string("Unexpected exception: ") + e.what(),              \
                              ERROR_LOCATION);                                               \
   }                                                                                \
   catch (...)                                                                               \
   {                                                                                \
      if (tryLog)                                                                            \
         log::logErrorMessage("Unknown exception while trying to acquire lock.");            \
   }                                                                                \

#endif //SHARED_CORE_READER_WRITER_MUTEX_HPP
<commit_msg>fix a whitespacing issue<commit_after>/*
 * ReaderWriterMutex.hpp
 *
 * Copyright (C) 2019 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant to the terms of a commercial license agreement
 * with RStudio, then this program is licensed to you under the following terms:
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */

#ifndef SHARED_CORE_READER_WRITER_MUTEX_HPP
#define SHARED_CORE_READER_WRITER_MUTEX_HPP

#include "PImpl.hpp"

#include <boost/thread/exceptions.hpp>

namespace rstudio {
namespace core {
namespace thread {

/**
 * @brief Reentrant reader-writer mutex implementation. This implementation is write-preferring.
 */
class ReaderWriterMutex
{
public:
   /**
    * @brief Constructor.
    */
   ReaderWriterMutex();

   /**
    * @brief Move constructor.
    *
    * @param in_other   The mutex to move to this mutex.
    */
   ReaderWriterMutex(ReaderWriterMutex&& in_other) noexcept;

   /**
    * @brief Deleted copy constructor to prevent copy.
    */
   ReaderWriterMutex(const ReaderWriterMutex&) = delete;

   /**
    * @brief Deleted assignment operator to prevent copy.
    */
   ReaderWriterMutex& operator=(const ReaderWriterMutex&) = delete;

   /**
    * @brief Locks the mutex for read.
    *
    * Note: unlockRead() must be called once for each time lockRead() was called.
    */
   void lockRead();

   /**
    * @brief Locks the mutex for write.
    *
    * Note: unlockWrite() must be called once for each time lockWrite() was called.
    */
   void lockWrite();

   /**
    * @brief Unlocks the mutex after a read operation.
    *
    * Note: unlockRead() must be called once for each time lockRead() was called.
    */
   void unlockRead();

   /**
    * @brief Unlocks the mutex after a write operation.
    *
    * Note: unlockWrite() must be called once for each time lockWrite() was called.
    */
   void unlockWrite();

private:

   PRIVATE_IMPL(m_impl);
};

/**
 * @brief RAII class which allows you to lock a ReaderWriterMutex for read.
 */
class ReaderLock
{
public:
   /**
    * @brief Constructor. Locks the specified mutex for read.
    *
    * @param in_mutex    The mutex to lock for read.
    */
   explicit ReaderLock(ReaderWriterMutex& in_mutex);

   /**
    * @brief Destructor.
    */
   ~ReaderLock();

private:
   // The mutex this lock manages.
   ReaderWriterMutex& m_mutex;
};

/**
 * @brief RAII class which allows you to lock a ReaderWriterMutex for write.
 */
class WriterLock
{
public:
   /**
    * @brief Constructor. Locks the specified mutex for write.
    *
    * @param in_mutex    The mutex to lock for write.
    */
   explicit WriterLock(ReaderWriterMutex& in_mutex);

   /**
    * @brief Destructor.
    */
   ~WriterLock();

private:
   // The mutex this lock manages.
   ReaderWriterMutex& m_mutex;
};

} // namespace thread
} // namespace core
} // namespace rstudio

#define READ_LOCK_BEGIN(mutex)                        \
   try                                                \
   {                                                  \
      rstudio::core::thread::ReaderLock lock(mutex);  \

#define WRITE_LOCK_BEGIN(mutex)                       \
   try                                                \
   {                                                  \
      rstudio::core::thread::WriterLock lock(mutex);  \

#define RW_LOCK_END(tryLog)                                                                  \
   }                                                                                \
   catch (const boost::thread_resource_error& e)                                             \
   {                                                                                \
      if (tryLog)                                                                            \
         log::logErrorMessage("Failed to acquire lock: thread resource error",               \
                              ERROR_LOCATION);                                               \
   }                                                                                \
   catch (const std::exception& e)                                                           \
   {                                                                                \
      if (tryLog)                                                                            \
         log::logErrorMessage(std::string("Unexpected exception: ") + e.what(),              \
                              ERROR_LOCATION);                                               \
   }                                                                                \
   catch (...)                                                                               \
   {                                                                                \
      if (tryLog)                                                                            \
         log::logErrorMessage("Unknown exception while trying to acquire lock.");            \
   }                                                                                \

#endif //SHARED_CORE_READER_WRITER_MUTEX_HPP
<|endoftext|>