<commit_before>#include <algorithm> // random_shuffle, transform
#include <cassert>
#include <chrono>
#include <random>
#include <utility>  // pair

//#include <sdd/sdd.hh>
#include <sdd/order/strategies/force.hh>

#include "mc/make_order.hh"

namespace pnmc { namespace mc {

using sdd_conf = sdd::conf1;

/*------------------------------------------------------------------------------------------------*/

struct mk_order_visitor
  : public boost::static_visitor<std::pair<std::string, sdd::order_builder<sdd_conf>>>
{
  using order_identifier = sdd::order_identifier<sdd_conf>;
  using result_type = std::pair<order_identifier, sdd::order_builder<sdd_conf>>;
  using order_builder = sdd::order_builder<sdd_conf>;

  const conf::pnmc_configuration& conf;
  mutable unsigned int artificial_id_counter;

  mk_order_visitor(const conf::pnmc_configuration& c)
    : conf(c), artificial_id_counter(0)
  {}

  // Place: base case of the recursion, there's no more possible nested hierarchies.
  result_type
  operator()(const pn::place* p)
  const noexcept
  {
    return std::make_pair(order_identifier(p->id), order_builder());
  }

  // Hierarchy.
  result_type
  operator()(const pn::module_node& m)
  const noexcept
  {
    assert(not m.nested.empty());

    std::deque<result_type> tmp;

    for (const auto& h : m.nested)
    {
      const auto res = boost::apply_visitor(*this, *h);
      tmp.push_back(res);
    }

    std::size_t height = 0;
    for (const auto& p : tmp)
    {
      if (not p.second.empty())
      {
        height += p.second.height();
      }
      else
      {
        height += 1; // place
      }
    }

    order_builder ob;
    if (height <= conf.order_min_height)
    {
      order_identifier id;
      for (const auto& p : tmp)
      {
        if (not p.second.empty())
        {
          ob = p.second << ob;
        }
        else // place
        {
          ob.push(p.first, p.second);
        }
      }
      return result_type(id, ob);
    }
    else
    {
      for (const auto& p : tmp)
      {
        ob.push(p.first, p.second);
      }
    }

    return std::make_pair(order_identifier(m.id) , ob);
  }
};

/*------------------------------------------------------------------------------------------------*/

sdd::order<sdd_conf>
make_order(const conf::pnmc_configuration& conf, statistics& stats, const pn::net& net)
{
  if (conf.order_ordering_force)
  {
    std::chrono::time_point<std::chrono::system_clock> start = std::chrono::system_clock::now();
    using identifier_type = sdd_conf::Identifier;
    using vertex = sdd::force::vertex<identifier_type>;
    using hyperedge = sdd::force::hyperedge<identifier_type>;

    sdd::force::hypergraph<sdd_conf> graph;
    std::vector<identifier_type> identifiers;
    for (const auto& transition : net.transitions())
    {
      for (const auto& arc : transition.pre)
      {
        identifiers.emplace_back(arc.first);
      }

      for (const auto& arc : transition.post)
      {
        identifiers.emplace_back(arc.first);
      }
      graph.add_hyperedge(identifiers.cbegin(), identifiers.cend());
      identifiers.clear();
    }
    force_ordering(graph);
    const auto o = sdd::order<sdd_conf>(sdd::order_builder<sdd_conf>(graph.cbegin(), graph.cend()));
    stats.force_duration = std::chrono::system_clock::now() - start;
    return o;
  }
  else if (not conf.order_force_flat and net.modules)
  {
    return sdd::order<sdd_conf>(boost::apply_visitor(mk_order_visitor(conf), *net.modules).second);
  }
  else
  {
    sdd::order_builder<sdd_conf> ob;
    if (conf.order_random)
    {
      std::vector<std::string> tmp;
      tmp.reserve(net.places().size());
      std::transform( net.places().cbegin(), net.places().cend(), std::back_inserter(tmp)
                    , [](const pn::place& p){return p.id;});
      std::random_device rd;
      std::mt19937 g(rd());
      std::shuffle(tmp.begin(), tmp.end(), g);
      for (const auto& id : tmp)
      {
        ob.push(id);
      }
    }
    else
    {
      for (const auto& place : net.places())
      {
        ob.push(place.id);
      }
    }
    return sdd::order<sdd_conf>(ob);
  }
}

/*------------------------------------------------------------------------------------------------*/

}} // namespace pnmc::mc
<commit_msg>Take ahamez/libsdd@ca005577fc into account.<commit_after>#include <algorithm> // random_shuffle, transform
#include <cassert>
#include <chrono>
#include <random>
#include <utility>  // pair

#include <sdd/order/order.hh>
#include <sdd/order/strategies/force.hh>

#include "mc/make_order.hh"

namespace pnmc { namespace mc {

using sdd_conf = sdd::conf1;

/*------------------------------------------------------------------------------------------------*/

struct mk_order_visitor
  : public boost::static_visitor<std::pair<std::string, sdd::order_builder<sdd_conf>>>
{
  using order_identifier = sdd::order_identifier<sdd_conf>;
  using result_type = std::pair<order_identifier, sdd::order_builder<sdd_conf>>;
  using order_builder = sdd::order_builder<sdd_conf>;

  const conf::pnmc_configuration& conf;
  mutable unsigned int artificial_id_counter;

  mk_order_visitor(const conf::pnmc_configuration& c)
    : conf(c), artificial_id_counter(0)
  {}

  // Place: base case of the recursion, there's no more possible nested hierarchies.
  result_type
  operator()(const pn::place* p)
  const noexcept
  {
    return std::make_pair(order_identifier(p->id), order_builder());
  }

  // Hierarchy.
  result_type
  operator()(const pn::module_node& m)
  const noexcept
  {
    assert(not m.nested.empty());

    std::deque<result_type> tmp;

    for (const auto& h : m.nested)
    {
      const auto res = boost::apply_visitor(*this, *h);
      tmp.push_back(res);
    }

    std::size_t height = 0;
    for (const auto& p : tmp)
    {
      if (not p.second.empty())
      {
        height += p.second.height();
      }
      else
      {
        height += 1; // place
      }
    }

    order_builder ob;
    if (height <= conf.order_min_height)
    {
      order_identifier id;
      for (const auto& p : tmp)
      {
        if (not p.second.empty())
        {
          ob = p.second << ob;
        }
        else // place
        {
          ob.push(p.first, p.second);
        }
      }
      return result_type(id, ob);
    }
    else
    {
      for (const auto& p : tmp)
      {
        ob.push(p.first, p.second);
      }
    }

    return std::make_pair(order_identifier(m.id) , ob);
  }
};

/*------------------------------------------------------------------------------------------------*/

sdd::order<sdd_conf>
make_order(const conf::pnmc_configuration& conf, statistics& stats, const pn::net& net)
{
  if (conf.order_ordering_force)
  {
    std::chrono::time_point<std::chrono::system_clock> start = std::chrono::system_clock::now();
    using identifier_type = sdd_conf::Identifier;
    using vertex = sdd::force::vertex<identifier_type>;
    using hyperedge = sdd::force::hyperedge<identifier_type>;

    sdd::force::hypergraph<sdd_conf> graph;
    std::vector<identifier_type> identifiers;
    for (const auto& transition : net.transitions())
    {
      for (const auto& arc : transition.pre)
      {
        identifiers.emplace_back(arc.first);
      }

      for (const auto& arc : transition.post)
      {
        identifiers.emplace_back(arc.first);
      }
      graph.add_hyperedge(identifiers.cbegin(), identifiers.cend());
      identifiers.clear();
    }
    const auto o = force_ordering(graph);
    stats.force_duration = std::chrono::system_clock::now() - start;
    return sdd::order<sdd_conf>(o);
  }
  else if (not conf.order_force_flat and net.modules)
  {
    return sdd::order<sdd_conf>(boost::apply_visitor(mk_order_visitor(conf), *net.modules).second);
  }
  else
  {
    sdd::order_builder<sdd_conf> ob;
    if (conf.order_random)
    {
      std::vector<std::string> tmp;
      tmp.reserve(net.places().size());
      std::transform( net.places().cbegin(), net.places().cend(), std::back_inserter(tmp)
                    , [](const pn::place& p){return p.id;});
      std::random_device rd;
      std::mt19937 g(rd());
      std::shuffle(tmp.begin(), tmp.end(), g);
      for (const auto& id : tmp)
      {
        ob.push(id);
      }
    }
    else
    {
      for (const auto& place : net.places())
      {
        ob.push(place.id);
      }
    }
    return sdd::order<sdd_conf>(ob);
  }
}

/*------------------------------------------------------------------------------------------------*/

}} // namespace pnmc::mc
<|endoftext|>


<commit_before>#define THEWIZARDPLUSPLUS_WIZARD_PARSER_PARSER_MACROSES

#include "vendor/better-enums/enum_strict.hpp"
#include "vendor/range/v3/view/drop.hpp"
#include "vendor/range/v3/view/transform.hpp"
#include "vendor/fmt/format.hpp"
#include "vendor/range/v3/view/chunk.hpp"
#include "vendor/range/v3/to_container.hpp"
#include "vendor/range/v3/numeric/accumulate.hpp"
#include "vendor/docopt/docopt.hpp"
#include "vendor/range/v3/algorithm/find_if.hpp"
#include <thewizardplusplus/wizard_parser/exceptions/unexpected_entity_exception.hpp>
#include <thewizardplusplus/wizard_parser/lexer/lexeme.hpp>
#include <thewizardplusplus/wizard_parser/lexer/tokenize.hpp>
#include <thewizardplusplus/wizard_parser/parser/rule_parser.hpp>
#include <thewizardplusplus/wizard_parser/parser/parsers.hpp>
#include <thewizardplusplus/wizard_parser/parser/ast_node.hpp>
#include <thewizardplusplus/wizard_parser/exceptions/positional_exception.hpp>
#include <thewizardplusplus/wizard_parser/parser/parse.hpp>
#include <thewizardplusplus/wizard_parser/utilities/utilities.hpp>
#include <cstddef>
#include <functional>
#include <vector>
#include <cstdint>
#include <regex>
#include <unordered_map>
#include <string>
#include <stdexcept>
#include <string_view>
#include <cstdlib>
#include <iostream>
#include <iterator>
#include <sstream>
#include <limits>
#include <iomanip>
#include <exception>

using namespace thewizardplusplus::wizard_parser;
using namespace thewizardplusplus::wizard_parser::parser::operators;
using namespace std::literals::string_literals;

struct function final {
	const std::size_t arity;
	const std::function<double(const std::vector<double>&)> handler;
};

BETTER_ENUM(entity_type, std::uint8_t,
	node = exceptions::entity_type::_size(),
	constant,
	function
)

template<entity_type::_integral type>
using unexpected_entity_exception =
	exceptions::base_unexpected_entity_exception<entity_type, type>;

const auto usage =
R"(Usage:
  ./example [options] [--] [<expression>]

Options:
  -h, --help                           - show this message;
  -t TARGET, --target TARGET           - preliminary target of processing
                                       (allowed: tokens, cst);
  -p PRECISION, --precision PRECISION  - precision of a result;
  -s, --stdin                          - read an expression from stdin;
  -V, --verbose                        - mark an error.)";
const auto lexemes = lexer::lexeme_group{
	{std::regex{R"(\+)"}, "plus"},
	{std::regex{R"(-)"}, "minus"},
	{std::regex{R"(\*)"}, "star"},
	{std::regex{R"(/)"}, "slash"},
	{std::regex{R"(%)"}, "percent"},
	{std::regex{R"(\()"}, "opening_parenthesis"},
	{std::regex{R"(\))"}, "closing_parenthesis"},
	{std::regex{R"(,)"}, "comma"},
	{std::regex{R"(\d+(\.\d+)?(e-?\d+)?)"}, "number"},
	{std::regex{R"([A-Za-z_]\w*)"}, "identifier"},
	{std::regex{R"(\s+)"}, "whitespace"}
};
const auto lexemes_exceptions = lexer::type_group{"whitespace"};
// precision is taken from Boost 1.70.0, Math Toolkit 2.9.0
const auto constants = std::unordered_map<std::string, double>{
	{"pi", 3.141592653589793238462643383279502884},
	{"e", 2.718281828459045235360287471352662497}
};
const auto functions = std::unordered_map<std::string, function>{
	{"+", {2, [] (const auto& args) { return args[0] + args[1]; }}},
	{"-", {2, [] (const auto& args) { return args[0] - args[1]; }}},
	{"*", {2, [] (const auto& args) { return args[0] * args[1]; }}},
	{"/", {2, [] (const auto& args) { return args[0] / args[1]; }}},
	{"%", {2, [] (const auto& args) { return std::fmod(args[0], args[1]); }}},
	{"floor", {1, [] (const auto& args) { return std::floor(args[0]); }}},
	{"ceil", {1, [] (const auto& args) { return std::ceil(args[0]); }}},
	{"trunc", {1, [] (const auto& args) { return std::trunc(args[0]); }}},
	{"round", {1, [] (const auto& args) { return std::round(args[0]); }}},
	{"sin", {1, [] (const auto& args) { return std::sin(args[0]); }}},
	{"cos", {1, [] (const auto& args) { return std::cos(args[0]); }}},
	{"tn", {1, [] (const auto& args) { return std::tan(args[0]); }}},
	{"arcsin", {1, [] (const auto& args) { return std::asin(args[0]); }}},
	{"arccos", {1, [] (const auto& args) { return std::acos(args[0]); }}},
	{"arctn", {1, [] (const auto& args) { return std::atan(args[0]); }}},
	{"angle", {2, [] (const auto& args) { return std::atan2(args[1], args[0]); }}},
	{"pow", {2, [] (const auto& args) { return std::pow(args[0], args[1]); }}},
	{"sqrt", {1, [] (const auto& args) { return std::sqrt(args[0]); }}},
	{"exp", {1, [] (const auto& args) { return std::exp(args[0]); }}},
	{"ln", {1, [] (const auto& args) { return std::log(args[0]); }}},
	{"lg", {1, [] (const auto& args) { return std::log10(args[0]); }}},
	{"abs", {1, [] (const auto& args) { return std::abs(args[0]); }}},
};

parser::rule_parser::pointer make_parser() {
	const auto expression_dummy = parser::dummy();
	RULE(function_call) = "identifier"_t >> &"("_v >>
		-(expression_dummy % &","_v)
	>> &")"_v;
	RULE(atom) = "number"_t
		| function_call
		| "identifier"_t
		| (&"("_v >> expression_dummy >> &")"_v);
	RULE(unary) = *("-"_v) >> atom;
	RULE(product) = unary % ("*"_v | "/"_v | "%"_v);
	RULE(sum) = product % ("+"_v | "-"_v);
	expression_dummy->set_parser(sum);

	return sum;
}

double evaluate_ast_node(
	const parser::ast_node& ast,
	const std::unordered_map<std::string, double>& constants,
	const std::unordered_map<std::string, function>& functions
) {
	const auto inspect_sequence = [] (const auto& ast) -> const auto& {
		return ast.children[0].children;
	};
	const auto evaluate_with_context = [&] (const auto& ast) {
		return evaluate_ast_node(ast, constants, functions);
	};

	if (ast.type == "number") {
		return std::stod(ast.value, nullptr);
	} else if (ast.type == "identifier") {
		try {
			return constants.at(ast.value);
		} catch (const std::out_of_range& exception) {
			const auto offset = parser::get_offset(ast);
			throw unexpected_entity_exception<entity_type::constant>{offset};
		}
	} else if (ast.type == "atom") {
		const auto type = (+parser::ast_node_type::sequence)._to_string();
		const auto first_child = ast.children[0].type == type
			? inspect_sequence(ast)[0]
			: ast.children[0];
		return evaluate_with_context(first_child);
	} else if (ast.type == "unary") {
		const auto result = evaluate_with_context(inspect_sequence(ast).back());
		const auto sign = (inspect_sequence(ast).size() - 1) % 2 ? -1 : 1;
		return sign * result;
	} else if (ast.type == "function_call") {
		try {
			const auto name = inspect_sequence(ast)[0].value;
			const auto arguments = inspect_sequence(ast)
				| ranges::view::drop(1)
				| ranges::view::transform([&] (const auto& ast) {
					return evaluate_with_context(ast);
				});
			const auto function = functions.at(name);
			if (arguments.size() != function.arity) {
				const auto unit = function.arity == 1 ? "argument" : "arguments";
				const auto description =
					fmt::format("function requires {:d} {:s}", function.arity, unit);
				const auto offset = parser::get_offset(ast);
				throw exceptions::positional_exception{description, offset};
			}

			return function.handler(arguments);
		} catch (const std::out_of_range& exception) {
			const auto offset = parser::get_offset(ast);
			throw unexpected_entity_exception<entity_type::function>{offset};
		}
	} else if (ast.type == "product" || ast.type == "sum") {
		const auto first_operand = evaluate_with_context(inspect_sequence(ast)[0]);
		const auto children_chunks = inspect_sequence(ast)
			| ranges::view::drop(1)
			| ranges::view::chunk(2)
			| ranges::view::transform([] (const auto& chunk) {
				return chunk | ranges::to_<parser::ast_node_group>();
			});
		return ranges::accumulate(
			children_chunks,
			first_operand,
			[&] (const auto& result, const auto& chunk) {
				const auto name = chunk[0].value;
				const auto second_operand = evaluate_with_context(chunk[1]);
				return functions.at(name).handler({result, second_operand});
			}
		);
	} else {
		const auto offset = parser::get_offset(ast);
		throw unexpected_entity_exception<entity_type::node>{offset};
	}
}

std::runtime_error enrich_exception(
	const exceptions::positional_exception& exception,
	const std::string_view& code,
	const std::size_t& mark_length
) {
	const auto mark_offset = std::string(exception.offset, ' ');
	const auto mark = std::string(mark_length, '^');
	return std::runtime_error{fmt::format(
		"{:s}\n| \"{:s}\"\n|  {:s}{:s}",
		exception.what(),
		code,
		mark_offset,
		mark
	)};
}

int main(int argc, char* argv[]) {
	const auto exit = [] (const auto& code, const auto& message) {
		(code == EXIT_SUCCESS ? std::cout : std::cerr) << message << '\n';
		std::exit(code);
	};

	try {
		const auto options = docopt::docopt(usage, {argv+1, argv+argc}, true);
		const auto expression = options.at("<expression>")
			? options.at("<expression>").asString()
			: "";
		const auto code = options.at("--stdin").asBool()
			? std::string{std::istreambuf_iterator<char>{std::cin}, {}}
			: expression;
		const auto enrich = options.at("--verbose").asBool()
			? std::function{enrich_exception}
			: [] (
				const exceptions::positional_exception& exception,
				const std::string_view& code,
				const std::size_t& mark_length
			) { return exception; };
		try {
			auto tokens = lexer::tokenize_all(lexemes, lexemes_exceptions, code);
			if (options.at("--target") == "tokens"s) {
				exit(EXIT_SUCCESS, tokens);
			}

			const auto eoi = exceptions::entity_type::eoi;
			try {
				const auto ast = parser::parse_all(make_parser(), tokens);
				if (options.at("--target") == "cst"s) {
					exit(EXIT_SUCCESS, ast);
				}

				auto buffer = std::ostringstream{};
				const auto precision = options.at("--precision")
					? options.at("--precision").asLong()
					: std::numeric_limits<double>::max_digits10;
				const auto result = evaluate_ast_node(ast, constants, functions);
				buffer << std::setprecision(precision) << result;

				exit(EXIT_SUCCESS, buffer.str());
			} catch (const exceptions::unexpected_entity_exception<eoi>& exception) {
				const auto offset = exception.offset == utilities::integral_infinity
					? code.size()
					: exception.offset;
				throw exceptions::unexpected_entity_exception<eoi>{offset};
			} catch (const exceptions::positional_exception& exception) {
				const auto token = ranges::find_if(tokens, [&] (const auto& token) {
					return token.offset == exception.offset;
				});
				throw enrich(exception, code, token->value.size());
			}
		} catch (const exceptions::positional_exception& exception) {
			throw enrich(exception, code, 1);
		}
	} catch (const std::exception& exception) {
		exit(EXIT_FAILURE, fmt::format("error: {:s}", exception.what()));
	}
}
<commit_msg>Refactor of the example, `enrich_exception()` function: make it local for the `main()` function<commit_after>#define THEWIZARDPLUSPLUS_WIZARD_PARSER_PARSER_MACROSES

#include "vendor/better-enums/enum_strict.hpp"
#include "vendor/range/v3/view/drop.hpp"
#include "vendor/range/v3/view/transform.hpp"
#include "vendor/fmt/format.hpp"
#include "vendor/range/v3/view/chunk.hpp"
#include "vendor/range/v3/to_container.hpp"
#include "vendor/range/v3/numeric/accumulate.hpp"
#include "vendor/range/v3/view/join.hpp"
#include "vendor/docopt/docopt.hpp"
#include "vendor/range/v3/algorithm/find_if.hpp"
#include <thewizardplusplus/wizard_parser/exceptions/unexpected_entity_exception.hpp>
#include <thewizardplusplus/wizard_parser/lexer/lexeme.hpp>
#include <thewizardplusplus/wizard_parser/lexer/tokenize.hpp>
#include <thewizardplusplus/wizard_parser/parser/rule_parser.hpp>
#include <thewizardplusplus/wizard_parser/parser/parsers.hpp>
#include <thewizardplusplus/wizard_parser/parser/ast_node.hpp>
#include <thewizardplusplus/wizard_parser/exceptions/positional_exception.hpp>
#include <thewizardplusplus/wizard_parser/parser/parse.hpp>
#include <thewizardplusplus/wizard_parser/utilities/utilities.hpp>
#include <cstddef>
#include <functional>
#include <vector>
#include <cstdint>
#include <regex>
#include <unordered_map>
#include <string>
#include <stdexcept>
#include <cstdlib>
#include <iostream>
#include <iterator>
#include <sstream>
#include <limits>
#include <iomanip>
#include <exception>

using namespace thewizardplusplus::wizard_parser;
using namespace thewizardplusplus::wizard_parser::parser::operators;
using namespace std::literals::string_literals;

struct function final {
	const std::size_t arity;
	const std::function<double(const std::vector<double>&)> handler;
};

BETTER_ENUM(entity_type, std::uint8_t,
	node = exceptions::entity_type::_size(),
	constant,
	function
)

template<entity_type::_integral type>
using unexpected_entity_exception =
	exceptions::base_unexpected_entity_exception<entity_type, type>;

const auto usage =
R"(Usage:
  ./example [options] [--] [<expression>]

Options:
  -h, --help                           - show this message;
  -t TARGET, --target TARGET           - preliminary target of processing
                                       (allowed: tokens, cst);
  -p PRECISION, --precision PRECISION  - precision of a result;
  -s, --stdin                          - read an expression from stdin;
  -V, --verbose                        - mark an error.)";
const auto lexemes = lexer::lexeme_group{
	{std::regex{R"(\+)"}, "plus"},
	{std::regex{R"(-)"}, "minus"},
	{std::regex{R"(\*)"}, "star"},
	{std::regex{R"(/)"}, "slash"},
	{std::regex{R"(%)"}, "percent"},
	{std::regex{R"(\()"}, "opening_parenthesis"},
	{std::regex{R"(\))"}, "closing_parenthesis"},
	{std::regex{R"(,)"}, "comma"},
	{std::regex{R"(\d+(\.\d+)?(e-?\d+)?)"}, "number"},
	{std::regex{R"([A-Za-z_]\w*)"}, "identifier"},
	{std::regex{R"(\s+)"}, "whitespace"}
};
const auto lexemes_exceptions = lexer::type_group{"whitespace"};
// precision is taken from Boost 1.70.0, Math Toolkit 2.9.0
const auto constants = std::unordered_map<std::string, double>{
	{"pi", 3.141592653589793238462643383279502884},
	{"e", 2.718281828459045235360287471352662497}
};
const auto functions = std::unordered_map<std::string, function>{
	{"+", {2, [] (const auto& args) { return args[0] + args[1]; }}},
	{"-", {2, [] (const auto& args) { return args[0] - args[1]; }}},
	{"*", {2, [] (const auto& args) { return args[0] * args[1]; }}},
	{"/", {2, [] (const auto& args) { return args[0] / args[1]; }}},
	{"%", {2, [] (const auto& args) { return std::fmod(args[0], args[1]); }}},
	{"floor", {1, [] (const auto& args) { return std::floor(args[0]); }}},
	{"ceil", {1, [] (const auto& args) { return std::ceil(args[0]); }}},
	{"trunc", {1, [] (const auto& args) { return std::trunc(args[0]); }}},
	{"round", {1, [] (const auto& args) { return std::round(args[0]); }}},
	{"sin", {1, [] (const auto& args) { return std::sin(args[0]); }}},
	{"cos", {1, [] (const auto& args) { return std::cos(args[0]); }}},
	{"tn", {1, [] (const auto& args) { return std::tan(args[0]); }}},
	{"arcsin", {1, [] (const auto& args) { return std::asin(args[0]); }}},
	{"arccos", {1, [] (const auto& args) { return std::acos(args[0]); }}},
	{"arctn", {1, [] (const auto& args) { return std::atan(args[0]); }}},
	{"angle", {2, [] (const auto& args) { return std::atan2(args[1], args[0]); }}},
	{"pow", {2, [] (const auto& args) { return std::pow(args[0], args[1]); }}},
	{"sqrt", {1, [] (const auto& args) { return std::sqrt(args[0]); }}},
	{"exp", {1, [] (const auto& args) { return std::exp(args[0]); }}},
	{"ln", {1, [] (const auto& args) { return std::log(args[0]); }}},
	{"lg", {1, [] (const auto& args) { return std::log10(args[0]); }}},
	{"abs", {1, [] (const auto& args) { return std::abs(args[0]); }}},
};

parser::rule_parser::pointer make_parser() {
	const auto expression_dummy = parser::dummy();
	RULE(function_call) = "identifier"_t >> &"("_v >>
		-(expression_dummy % &","_v)
	>> &")"_v;
	RULE(atom) = "number"_t
		| function_call
		| "identifier"_t
		| (&"("_v >> expression_dummy >> &")"_v);
	RULE(unary) = *("-"_v) >> atom;
	RULE(product) = unary % ("*"_v | "/"_v | "%"_v);
	RULE(sum) = product % ("+"_v | "-"_v);
	expression_dummy->set_parser(sum);

	return sum;
}

double evaluate_ast_node(
	const parser::ast_node& ast,
	const std::unordered_map<std::string, double>& constants,
	const std::unordered_map<std::string, function>& functions
) {
	const auto inspect_sequence = [] (const auto& ast) -> const auto& {
		return ast.children[0].children;
	};
	const auto evaluate_with_context = [&] (const auto& ast) {
		return evaluate_ast_node(ast, constants, functions);
	};

	if (ast.type == "number") {
		return std::stod(ast.value, nullptr);
	} else if (ast.type == "identifier") {
		try {
			return constants.at(ast.value);
		} catch (const std::out_of_range& exception) {
			const auto offset = parser::get_offset(ast);
			throw unexpected_entity_exception<entity_type::constant>{offset};
		}
	} else if (ast.type == "atom") {
		const auto type = (+parser::ast_node_type::sequence)._to_string();
		const auto first_child = ast.children[0].type == type
			? inspect_sequence(ast)[0]
			: ast.children[0];
		return evaluate_with_context(first_child);
	} else if (ast.type == "unary") {
		const auto result = evaluate_with_context(inspect_sequence(ast).back());
		const auto sign = (inspect_sequence(ast).size() - 1) % 2 ? -1 : 1;
		return sign * result;
	} else if (ast.type == "function_call") {
		try {
			const auto name = inspect_sequence(ast)[0].value;
			const auto arguments = inspect_sequence(ast)
				| ranges::view::drop(1)
				| ranges::view::transform([&] (const auto& ast) {
					return evaluate_with_context(ast);
				});
			const auto function = functions.at(name);
			if (arguments.size() != function.arity) {
				const auto unit = function.arity == 1 ? "argument" : "arguments";
				const auto description =
					fmt::format("function requires {:d} {:s}", function.arity, unit);
				const auto offset = parser::get_offset(ast);
				throw exceptions::positional_exception{description, offset};
			}

			return function.handler(arguments);
		} catch (const std::out_of_range& exception) {
			const auto offset = parser::get_offset(ast);
			throw unexpected_entity_exception<entity_type::function>{offset};
		}
	} else if (ast.type == "product" || ast.type == "sum") {
		const auto first_operand = evaluate_with_context(inspect_sequence(ast)[0]);
		const auto children_chunks = inspect_sequence(ast)
			| ranges::view::drop(1)
			| ranges::view::chunk(2)
			| ranges::view::transform([] (const auto& chunk) {
				return chunk | ranges::to_<parser::ast_node_group>();
			});
		return ranges::accumulate(
			children_chunks,
			first_operand,
			[&] (const auto& result, const auto& chunk) {
				const auto name = chunk[0].value;
				const auto second_operand = evaluate_with_context(chunk[1]);
				return functions.at(name).handler({result, second_operand});
			}
		);
	} else {
		const auto offset = parser::get_offset(ast);
		throw unexpected_entity_exception<entity_type::node>{offset};
	}
}

int main(int argc, char* argv[]) {
	const auto exit = [] (const auto& code, const auto& message) {
		(code == EXIT_SUCCESS ? std::cout : std::cerr) << message << '\n';
		std::exit(code);
	};
	const auto enrich =
		[] (const auto& exception, const auto& code, const auto& token_size) {
			const auto mark_offset = std::string(exception.offset, ' ');
			const auto mark = std::string(token_size, '^');
			const auto description_lines = std::vector<std::string>{
				exception.what(),
				fmt::format(R"(| "{:s}")", code),
				fmt::format(R"(|  {:s}{:s})", mark_offset, mark)
			};
			return std::runtime_error{description_lines | ranges::view::join('\n')};
		};

	try {
		const auto options = docopt::docopt(usage, {argv+1, argv+argc}, true);
		const auto expression = options.at("<expression>")
			? options.at("<expression>").asString()
			: "";
		const auto code = options.at("--stdin").asBool()
			? std::string{std::istreambuf_iterator<char>{std::cin}, {}}
			: expression;
		const auto verbose = options.at("--verbose").asBool();
		try {
			auto tokens = lexer::tokenize_all(lexemes, lexemes_exceptions, code);
			if (options.at("--target") == "tokens"s) {
				exit(EXIT_SUCCESS, tokens);
			}

			const auto eoi = exceptions::entity_type::eoi;
			try {
				const auto ast = parser::parse_all(make_parser(), tokens);
				if (options.at("--target") == "cst"s) {
					exit(EXIT_SUCCESS, ast);
				}

				auto buffer = std::ostringstream{};
				const auto precision = options.at("--precision")
					? options.at("--precision").asLong()
					: std::numeric_limits<double>::max_digits10;
				const auto result = evaluate_ast_node(ast, constants, functions);
				buffer << std::setprecision(precision) << result;

				exit(EXIT_SUCCESS, buffer.str());
			} catch (const exceptions::unexpected_entity_exception<eoi>& exception) {
				const auto offset = exception.offset == utilities::integral_infinity
					? code.size()
					: exception.offset;
				throw exceptions::unexpected_entity_exception<eoi>{offset};
			} catch (const exceptions::positional_exception& exception) {
				const auto token = ranges::find_if(tokens, [&] (const auto& token) {
					return token.offset == exception.offset;
				});
				const auto token_size = token->value.size();
				throw verbose
					? enrich(exception, code, token_size)
					: std::runtime_error{exception};
			}
		} catch (const exceptions::positional_exception& exception) {
			throw verbose ? enrich(exception, code, 1) : std::runtime_error{exception};
		}
	} catch (const std::exception& exception) {
		exit(EXIT_FAILURE, fmt::format("error: {:s}", exception.what()));
	}
}
<|endoftext|>


<commit_before>#include "mediamanager.h"

#include "filtergraph.h"
#include "rtpstreamer.h"
#include "filter.h"
#include "framedsourcefilter.h"
#include "rtpsinkfilter.h"
#include "gui/videoviewfactory.h"
#include "sip/sdptypes.h"

#include <QHostAddress>
#include <QtEndian>
#include <QDebug>

MediaManager::MediaManager():
  stats_(nullptr),
  fg_(new FilterGraph()),
  session_(nullptr),
  streamer_(new RTPStreamer()),
  mic_(true),
  camera_(true)
{}

MediaManager::~MediaManager()
{
  fg_->running(false);
  fg_->uninit();
}

void MediaManager::init(std::shared_ptr<VideoviewFactory> viewfactory, StatisticsInterface *stats)
{
  qDebug() << "Iniating media manager";
  viewfactory_ = viewfactory;
  streamer_->init(stats);
  streamer_->start();
  fg_->init(viewfactory_->getVideo(0), stats); // 0 is the selfview index. The view should be created by GUI
}

void MediaManager::uninit()
{
  qDebug() << "Destroying media manager";
  // first filter graph, then streamer because of the rtpfilters
  fg_->running(false);
  fg_->uninit();

  streamer_->stop();
  streamer_->uninit();
}

void MediaManager::updateSettings()
{
  fg_->updateSettings();
  fg_->camera(camera_); // kind of a hack to make sure the camera/mic state is preserved
  fg_->mic(mic_);
}

void MediaManager::addParticipant(uint32_t sessionID, std::shared_ptr<SDPMessageInfo> peerInfo,
                    const std::shared_ptr<SDPMessageInfo> localInfo)
{
  // TODO: support stop-time and start-time as recommended by RFC 4566 section 5.9

  if(peerInfo->startTime != 0 || localInfo->startTime != 0)
  {
    qWarning() << "ERROR: Non zero start-time not supported!";
  }

  if(peerInfo->stopTime != 0 || localInfo->stopTime != 0)
  {
    qWarning() << "ERROR: Non zero stop-time not supported!";
  }

  if(peerInfo->connection_nettype == "IN")
  {
    QHostAddress address;
    address.setAddress(peerInfo->connection_address);

    if(peerInfo->connection_addrtype == "IP4")
    {
      in_addr ip;
      ip.S_un.S_addr = qToBigEndian(address.toIPv4Address());

      // TODO: Make it possible to have a separate ip address for each mediastream by fixing this.
      if(!streamer_->addPeer(ip, sessionID))
      {
        qCritical() << "Error creating RTP peer. Simultaneous destruction?";
        return;
      }
    }
    else if(peerInfo->connection_addrtype == "IP6")
    {
      qDebug() << "ERROR: IPv6 not supported in media creation";
      return;
    }
  }
  else
  {
    qWarning() << "ERROR: What are we using if not the internet!?";
    return;
  }

  // create each agreed media stream
  for(auto media : peerInfo->media)
  {
    createOutgoingMedia(sessionID, media);
  }

  for(auto media : localInfo->media)
  {
    createIncomingMedia(sessionID, media);
  }

  fg_->print();
}

void MediaManager::createOutgoingMedia(uint32_t sessionID, const MediaInfo& remoteMedia)
{
  if(remoteMedia.activity == A_RECVONLY || remoteMedia.activity == A_SENDRECV)
  {
    Q_ASSERT(remoteMedia.receivePort);
    Q_ASSERT(!remoteMedia.rtpNums.empty());

    QString codec = rtpNumberToCodec(remoteMedia);

    if(remoteMedia.proto == "RTP/AVP")
    {
      std::shared_ptr<Filter> framedSource = streamer_->addSendStream(sessionID, remoteMedia.receivePort,
                                                                      codec, remoteMedia.rtpNums.at(0));
      if(remoteMedia.type == "audio")
      {
        fg_->sendAudioTo(sessionID, std::shared_ptr<Filter>(framedSource));
      }
      else if(remoteMedia.type == "video")
      {
        fg_->sendVideoto(sessionID, std::shared_ptr<Filter>(framedSource));
      }
      else
      {
        qDebug() << "ERROR: Unsupported media type in :" << remoteMedia.type;
      }
    }
    else
    {
      qDebug() << "ERROR: SDP transport protocol not supported.";
    }
  }
  else
  {
    qDebug() << "Not creating media because they don't seem to want any according to attribute";
  }
}

void MediaManager::createIncomingMedia(uint32_t sessionID, const MediaInfo &localMedia)
{
  if(localMedia.activity == A_RECVONLY || localMedia.activity == A_SENDRECV)
  {
    Q_ASSERT(localMedia.receivePort);
    Q_ASSERT(!localMedia.rtpNums.empty());

    QString codec = rtpNumberToCodec(localMedia);

    qDebug() << "Creating incoming media with codec:" << codec;

    if(localMedia.proto == "RTP/AVP")
    {
      std::shared_ptr<Filter> rtpSink = streamer_->addReceiveStream(sessionID, localMedia.receivePort,
                                                                    localMedia.codecs.at(0).codec, localMedia.rtpNums.at(0));
      if(localMedia.type == "audio")
      {
        fg_->receiveAudioFrom(sessionID, std::shared_ptr<Filter>(rtpSink));
      }
      else if(localMedia.type == "video")
      {
        fg_->receiveVideoFrom(sessionID, std::shared_ptr<Filter>(rtpSink), viewfactory_->getVideo(sessionID));
      }
      else
      {
        qDebug() << "ERROR: Unsupported media type in :" << localMedia.type;
      }
    }
    else
    {
      qDebug() << "ERROR: SDP transport protocol not supported.";
    }
  }
  else
  {
    qDebug() << "Not creating media because they don't seem to want any according to attribute";
  }
}

void MediaManager::removeParticipant(uint32_t sessionID)
{
  fg_->removeParticipant(sessionID);
  fg_->camera(camera_); // if the last participant was destroyed, restore camera state
  fg_->mic(mic_);
  streamer_->removePeer(sessionID);
  qDebug() << "Session " << sessionID << " media removed.";
}

void MediaManager::endAllCalls()
{
  fg_->removeAllParticipants();
  streamer_->removeAllPeers();

  fg_->camera(camera_); // if the last participant was destroyed, restore camera state
  fg_->mic(mic_);
}

bool MediaManager::toggleMic()
{
  mic_ = !mic_;
  fg_->mic(mic_);
  return mic_;
}

bool MediaManager::toggleCamera()
{
  camera_ = !camera_;
  fg_->camera(camera_);
  return camera_;
}

QString MediaManager::rtpNumberToCodec(const MediaInfo& info)
{
  // If we are not using raw.
  // This is the place where all other preset audio video codec numbers should be set
  // but its unlikely that we will support any besides raw pcmu.
  if(info.rtpNums.at(0) != 0)
  {
    Q_ASSERT(!info.codecs.empty());
    if(!info.codecs.empty())
    {
      return info.codecs.at(0).codec;
    }
  }
  return "pcmu";
}
<commit_msg>The printing of filter graphs didn't work, disabling it prevents crashing. Currently the SDP generation doesn't seem to be up to bar, because the media creation complains about start and stop-times.<commit_after>#include "mediamanager.h"

#include "filtergraph.h"
#include "rtpstreamer.h"
#include "filter.h"
#include "framedsourcefilter.h"
#include "rtpsinkfilter.h"
#include "gui/videoviewfactory.h"
#include "sip/sdptypes.h"

#include <QHostAddress>
#include <QtEndian>
#include <QDebug>

MediaManager::MediaManager():
  stats_(nullptr),
  fg_(new FilterGraph()),
  session_(nullptr),
  streamer_(new RTPStreamer()),
  mic_(true),
  camera_(true)
{}

MediaManager::~MediaManager()
{
  fg_->running(false);
  fg_->uninit();
}

void MediaManager::init(std::shared_ptr<VideoviewFactory> viewfactory, StatisticsInterface *stats)
{
  qDebug() << "Iniating media manager";
  viewfactory_ = viewfactory;
  streamer_->init(stats);
  streamer_->start();
  fg_->init(viewfactory_->getVideo(0), stats); // 0 is the selfview index. The view should be created by GUI
}

void MediaManager::uninit()
{
  qDebug() << "Destroying media manager";
  // first filter graph, then streamer because of the rtpfilters
  fg_->running(false);
  fg_->uninit();

  streamer_->stop();
  streamer_->uninit();
}

void MediaManager::updateSettings()
{
  fg_->updateSettings();
  fg_->camera(camera_); // kind of a hack to make sure the camera/mic state is preserved
  fg_->mic(mic_);
}

void MediaManager::addParticipant(uint32_t sessionID, std::shared_ptr<SDPMessageInfo> peerInfo,
                    const std::shared_ptr<SDPMessageInfo> localInfo)
{
  // TODO: support stop-time and start-time as recommended by RFC 4566 section 5.9

  if(peerInfo->startTime != 0 || localInfo->startTime != 0)
  {
    qWarning() << "ERROR: Non zero start-time not supported!";
  }

  if(peerInfo->stopTime != 0 || localInfo->stopTime != 0)
  {
    qWarning() << "ERROR: Non zero stop-time not supported!";
  }

  if(peerInfo->connection_nettype == "IN")
  {
    QHostAddress address;
    address.setAddress(peerInfo->connection_address);

    if(peerInfo->connection_addrtype == "IP4")
    {
      in_addr ip;
      ip.S_un.S_addr = qToBigEndian(address.toIPv4Address());

      // TODO: Make it possible to have a separate ip address for each mediastream by fixing this.
      if(!streamer_->addPeer(ip, sessionID))
      {
        qCritical() << "Error creating RTP peer. Simultaneous destruction?";
        return;
      }
    }
    else if(peerInfo->connection_addrtype == "IP6")
    {
      qDebug() << "ERROR: IPv6 not supported in media creation";
      return;
    }
  }
  else
  {
    qWarning() << "ERROR: What are we using if not the internet!?";
    return;
  }

  // create each agreed media stream
  for(auto media : peerInfo->media)
  {
    createOutgoingMedia(sessionID, media);
  }

  for(auto media : localInfo->media)
  {
    createIncomingMedia(sessionID, media);
  }

  // crashes at the moment.
  //fg_->print();
}

void MediaManager::createOutgoingMedia(uint32_t sessionID, const MediaInfo& remoteMedia)
{
  if(remoteMedia.activity == A_RECVONLY || remoteMedia.activity == A_SENDRECV)
  {
    Q_ASSERT(remoteMedia.receivePort);
    Q_ASSERT(!remoteMedia.rtpNums.empty());

    QString codec = rtpNumberToCodec(remoteMedia);

    if(remoteMedia.proto == "RTP/AVP")
    {
      std::shared_ptr<Filter> framedSource = streamer_->addSendStream(sessionID, remoteMedia.receivePort,
                                                                      codec, remoteMedia.rtpNums.at(0));
      if(remoteMedia.type == "audio")
      {
        fg_->sendAudioTo(sessionID, std::shared_ptr<Filter>(framedSource));
      }
      else if(remoteMedia.type == "video")
      {
        fg_->sendVideoto(sessionID, std::shared_ptr<Filter>(framedSource));
      }
      else
      {
        qDebug() << "ERROR: Unsupported media type in :" << remoteMedia.type;
      }
    }
    else
    {
      qDebug() << "ERROR: SDP transport protocol not supported.";
    }
  }
  else
  {
    qDebug() << "Not creating media because they don't seem to want any according to attribute";
  }
}

void MediaManager::createIncomingMedia(uint32_t sessionID, const MediaInfo &localMedia)
{
  if(localMedia.activity == A_RECVONLY || localMedia.activity == A_SENDRECV)
  {
    Q_ASSERT(localMedia.receivePort);
    Q_ASSERT(!localMedia.rtpNums.empty());

    QString codec = rtpNumberToCodec(localMedia);

    qDebug() << "Creating incoming media with codec:" << codec;

    if(localMedia.proto == "RTP/AVP")
    {
      std::shared_ptr<Filter> rtpSink = streamer_->addReceiveStream(sessionID, localMedia.receivePort,
                                                                    localMedia.codecs.at(0).codec, localMedia.rtpNums.at(0));
      if(localMedia.type == "audio")
      {
        fg_->receiveAudioFrom(sessionID, std::shared_ptr<Filter>(rtpSink));
      }
      else if(localMedia.type == "video")
      {
        fg_->receiveVideoFrom(sessionID, std::shared_ptr<Filter>(rtpSink), viewfactory_->getVideo(sessionID));
      }
      else
      {
        qDebug() << "ERROR: Unsupported media type in :" << localMedia.type;
      }
    }
    else
    {
      qDebug() << "ERROR: SDP transport protocol not supported.";
    }
  }
  else
  {
    qDebug() << "Not creating media because they don't seem to want any according to attribute";
  }
}

void MediaManager::removeParticipant(uint32_t sessionID)
{
  fg_->removeParticipant(sessionID);
  fg_->camera(camera_); // if the last participant was destroyed, restore camera state
  fg_->mic(mic_);
  streamer_->removePeer(sessionID);
  qDebug() << "Session " << sessionID << " media removed.";
}

void MediaManager::endAllCalls()
{
  fg_->removeAllParticipants();
  streamer_->removeAllPeers();

  fg_->camera(camera_); // if the last participant was destroyed, restore camera state
  fg_->mic(mic_);
}

bool MediaManager::toggleMic()
{
  mic_ = !mic_;
  fg_->mic(mic_);
  return mic_;
}

bool MediaManager::toggleCamera()
{
  camera_ = !camera_;
  fg_->camera(camera_);
  return camera_;
}

QString MediaManager::rtpNumberToCodec(const MediaInfo& info)
{
  // If we are not using raw.
  // This is the place where all other preset audio video codec numbers should be set
  // but its unlikely that we will support any besides raw pcmu.
  if(info.rtpNums.at(0) != 0)
  {
    Q_ASSERT(!info.codecs.empty());
    if(!info.codecs.empty())
    {
      return info.codecs.at(0).codec;
    }
  }
  return "pcmu";
}
<|endoftext|>


<commit_before>#ifndef DIGGLER_PLATFORM_FOURCC_HPP
#define DIGGLER_PLATFORM_FOURCC_HPP

#include "Types.hpp"

namespace Diggler {

using FourCC = uint32;

constexpr inline FourCC MakeFourCC(char a, char b, char c, char d) {
#if defined(BUILDINFO_LITTLE_ENDIAN)
  return d | c >> 8 | b >> 16 | a >> 24;
#else
  return a | b >> 8 | c >> 16 | d >> 24;
#endif
}
constexpr inline FourCC MakeFourCC(const char *s) {
  return MakeFourCC(s[0], s[1], s[2], s[3]);
}

}

#endif /* DIGGLER_PLATFORM_FOURCC_HPP */
<commit_msg>platform/FourCC: properly cast computed values<commit_after>#ifndef DIGGLER_PLATFORM_FOURCC_HPP
#define DIGGLER_PLATFORM_FOURCC_HPP

#include "Types.hpp"

namespace Diggler {

using FourCC = uint32;

constexpr inline FourCC MakeFourCC(char a, char b, char c, char d) {
#if defined(BUILDINFO_LITTLE_ENDIAN)
  return static_cast<FourCC>(d | c >> 8 | b >> 16 | a >> 24);
#else
  return static_cast<FourCC>(a | b >> 8 | c >> 16 | d >> 24);
#endif
}

constexpr inline FourCC MakeFourCC(const char *s) {
  return MakeFourCC(s[0], s[1], s[2], s[3]);
}

}

#endif /* DIGGLER_PLATFORM_FOURCC_HPP */
<|endoftext|>


<commit_before>/*
 * Copyright 2011 Intel Corporation.
 *
 * This program is licensed under the terms and conditions of the
 * Apache License, version 2.0.  The full text of the Apache License is at
 * http://www.apache.org/licenses/LICENSE-2.0
 */

#include "EmailAccount.hpp"
#include <QDir>

// ------------------------------------------------------------------

namespace {
  QString get_evolution_folder_uri(QString folder)
  {
    QString home = QDir::home().absolutePath();

    // Assumes Unix path convention!
    return
      QString("mbox:%1/.local/share/evolution/mail/local#%2").arg(home).arg(folder);
  }
}

// ------------------------------------------------------------------

MeeGo::ActiveSync::EmailAccount::EmailAccount(QString email,
					      EAccountList * accountList)
  : m_account(0)
  , m_email(email)
{
  EAccount const * const found =
    e_account_list_find(accountList,
			E_ACCOUNT_FIND_ID_ADDRESS,
			email.toUtf8());

  // @todo What's the proper way to copy the const EAccount?
  m_account = (found == 0 ? e_account_new() : const_cast<EAccount *>(found));
}

MeeGo::ActiveSync::EmailAccount::~EmailAccount()
{
  g_object_unref(m_account);
}

bool
MeeGo::ActiveSync::EmailAccount::writeConfig(QString username,
					     EAccountList * accountList)
{
  if (accountList == 0 || username.isEmpty() || m_email.isEmpty())
    return false;

  // -------------------------
  // Name
  // -------------------------
  e_account_set_string(m_account,
		       E_ACCOUNT_NAME,
		       username.toUtf8());

  // -------------------------
  // Identity
  // -------------------------
  e_account_set_string(m_account,
		       E_ACCOUNT_ID_NAME,
		       username.toUtf8());

  e_account_set_string(m_account,
		       E_ACCOUNT_ID_ADDRESS,
		       m_email.toUtf8());

  // E_ACCOUNT_ID_REPLY_TO
  // E_ACCOUNT_ID_ORGANIZATION,

  e_account_set_string(m_account,
		       E_ACCOUNT_ID_SIGNATURE,
		       "");

  // -------------------------
  // Source
  // -------------------------
  QString const source_url =
    QString("eas://%1/;sync_offline=1;account_uid=%2").arg(m_email).arg(m_email);
  e_account_set_string(m_account,
		       E_ACCOUNT_SOURCE_URL,
		       source_url.toUtf8());

  e_account_set_bool(m_account,
		     E_ACCOUNT_SOURCE_KEEP_ON_SERVER,
		     FALSE);  // gboolean, not C++ bool.

  e_account_set_bool(m_account,
		     E_ACCOUNT_SOURCE_AUTO_CHECK,
		     FALSE);

  e_account_set_int(m_account,
		    E_ACCOUNT_SOURCE_AUTO_CHECK_TIME,
		    0);

  e_account_set_bool(m_account,
		     E_ACCOUNT_SOURCE_SAVE_PASSWD,
		     FALSE);

  // -------------------------
  // Transport
  // -------------------------
  QString const transport_url =
    QString("eas://%1/;account_uid=%2").arg(m_email).arg(m_email);
  e_account_set_string(m_account,
		       E_ACCOUNT_TRANSPORT_URL,
		       transport_url.toUtf8());

  e_account_set_bool(m_account,
		     E_ACCOUNT_TRANSPORT_SAVE_PASSWD,
		     FALSE);  // gboolean, not C++ bool.

  // -------------------------
  // Folder URIs
  // -------------------------
  QString const drafts_uri = get_evolution_folder_uri("Drafts");
  e_account_set_string(m_account,
		       E_ACCOUNT_DRAFTS_FOLDER_URI,
		       drafts_uri.toUtf8());

  QString const sent_uri = get_evolution_folder_uri("Sent");
  e_account_set_string(m_account,
		       E_ACCOUNT_SENT_FOLDER_URI,
		       sent_uri.toUtf8());

  // -------------------------
  // Enable or disable auto Cc/Bcc
  // -------------------------
  e_account_set_bool(m_account,
		     E_ACCOUNT_CC_ALWAYS,
		     FALSE);  // gboolean, not C++ bool.

  e_account_set_string(m_account,
		       E_ACCOUNT_CC_ADDRS,
		       "");

  e_account_set_bool(m_account,
		     E_ACCOUNT_BCC_ALWAYS,
		     FALSE);

  e_account_set_string(m_account,
		       E_ACCOUNT_BCC_ADDRS,
		       "");

  // -------------------------
  // Receipt policy
  // -------------------------
  e_account_set_int(m_account,
		    E_ACCOUNT_RECEIPT_POLICY,
		    E_ACCOUNT_RECEIPT_NEVER);

  // -------------------------
  // PGP config
  // -------------------------
  // E_ACCOUNT_PGP_KEY
  // E_ACCOUNT_PGP_HASH_ALGORITHM

  e_account_set_bool(m_account,
		     E_ACCOUNT_PGP_ENCRYPT_TO_SELF,
		     FALSE);  // gboolean, not C++ bool.

  e_account_set_bool(m_account,
		     E_ACCOUNT_PGP_ALWAYS_SIGN,
		     FALSE);

  e_account_set_bool(m_account,
		     E_ACCOUNT_PGP_NO_IMIP_SIGN,
		     FALSE);

  e_account_set_bool(m_account,
		     E_ACCOUNT_PGP_ALWAYS_TRUST,
		     FALSE);

  // -------------------------
  // SMIME config
  // -------------------------
  // E_ACCOUNT_SMIME_SIGN_KEY
  // E_ACCOUNT_SMIME_ENCRYPT_KEY
  // E_ACCOUNT_SMIME_HASH_ALGORITHM

  e_account_set_bool(m_account,
		     E_ACCOUNT_SMIME_SIGN_DEFAULT,
		     FALSE);
  e_account_set_bool(m_account,
		     E_ACCOUNT_SMIME_ENCRYPT_TO_SELF,
		     FALSE);
  e_account_set_bool(m_account,
		     E_ACCOUNT_SMIME_ENCRYPT_DEFAULT,
		     FALSE);

  // ----------------------------------------
  // Write the account to GConf.
  // ----------------------------------------
  e_account_list_add(accountList, m_account);
  e_account_list_save(accountList);

  return true;
}

void
MeeGo::ActiveSync::EmailAccount::removeConfig(EAccountList * accountList)
{
  if (accountList != 0)
    e_account_list_remove(accountList, m_account);
}
<commit_msg>Enable account by default<commit_after>/*
 * Copyright 2011 Intel Corporation.
 *
 * This program is licensed under the terms and conditions of the
 * Apache License, version 2.0.  The full text of the Apache License is at
 * http://www.apache.org/licenses/LICENSE-2.0
 */

#include "EmailAccount.hpp"
#include <QDir>

// ------------------------------------------------------------------

namespace {
  QString get_evolution_folder_uri(QString folder)
  {
    QString home = QDir::home().absolutePath();

    // Assumes Unix path convention!
    return
      QString("mbox:%1/.local/share/evolution/mail/local#%2").arg(home).arg(folder);
  }
}

// ------------------------------------------------------------------

MeeGo::ActiveSync::EmailAccount::EmailAccount(QString email,
					      EAccountList * accountList)
  : m_account(0)
  , m_email(email)
{
  EAccount const * const found =
    e_account_list_find(accountList,
			E_ACCOUNT_FIND_ID_ADDRESS,
			email.toUtf8());

  // @todo What's the proper way to copy the const EAccount?
  m_account = (found == 0 ? e_account_new() : const_cast<EAccount *>(found));
}

MeeGo::ActiveSync::EmailAccount::~EmailAccount()
{
  g_object_unref(m_account);
}

bool
MeeGo::ActiveSync::EmailAccount::writeConfig(QString username,
					     EAccountList * accountList)
{
  if (accountList == 0 || username.isEmpty() || m_email.isEmpty())
    return false;

  // -------------------------
  // Name
  // -------------------------
  e_account_set_string(m_account,
		       E_ACCOUNT_NAME,
		       username.toUtf8());

  // -------------------------
  // Identity
  // -------------------------
  e_account_set_string(m_account,
		       E_ACCOUNT_ID_NAME,
		       username.toUtf8());

  e_account_set_string(m_account,
		       E_ACCOUNT_ID_ADDRESS,
		       m_email.toUtf8());

  // E_ACCOUNT_ID_REPLY_TO
  // E_ACCOUNT_ID_ORGANIZATION,

  e_account_set_string(m_account,
		       E_ACCOUNT_ID_SIGNATURE,
		       "");

  // -------------------------
  // Source
  // -------------------------
  QString const source_url =
    QString("eas://%1/;sync_offline=1;account_uid=%2").arg(m_email).arg(m_email);
  e_account_set_string(m_account,
		       E_ACCOUNT_SOURCE_URL,
		       source_url.toUtf8());

  e_account_set_bool(m_account,
		     E_ACCOUNT_SOURCE_KEEP_ON_SERVER,
		     FALSE);  // gboolean, not C++ bool.

  e_account_set_bool(m_account,
		     E_ACCOUNT_SOURCE_AUTO_CHECK,
		     FALSE);

  e_account_set_int(m_account,
		    E_ACCOUNT_SOURCE_AUTO_CHECK_TIME,
		    0);

  e_account_set_bool(m_account,
		     E_ACCOUNT_SOURCE_SAVE_PASSWD,
		     FALSE);

  m_account->enabled = TRUE;

  // -------------------------
  // Transport
  // -------------------------
  QString const transport_url =
    QString("eas://%1/;account_uid=%2").arg(m_email).arg(m_email);
  e_account_set_string(m_account,
		       E_ACCOUNT_TRANSPORT_URL,
		       transport_url.toUtf8());

  e_account_set_bool(m_account,
		     E_ACCOUNT_TRANSPORT_SAVE_PASSWD,
		     FALSE);  // gboolean, not C++ bool.

  // -------------------------
  // Folder URIs
  // -------------------------
  QString const drafts_uri = get_evolution_folder_uri("Drafts");
  e_account_set_string(m_account,
		       E_ACCOUNT_DRAFTS_FOLDER_URI,
		       drafts_uri.toUtf8());

  QString const sent_uri = get_evolution_folder_uri("Sent");
  e_account_set_string(m_account,
		       E_ACCOUNT_SENT_FOLDER_URI,
		       sent_uri.toUtf8());

  // -------------------------
  // Enable or disable auto Cc/Bcc
  // -------------------------
  e_account_set_bool(m_account,
		     E_ACCOUNT_CC_ALWAYS,
		     FALSE);  // gboolean, not C++ bool.

  e_account_set_string(m_account,
		       E_ACCOUNT_CC_ADDRS,
		       "");

  e_account_set_bool(m_account,
		     E_ACCOUNT_BCC_ALWAYS,
		     FALSE);

  e_account_set_string(m_account,
		       E_ACCOUNT_BCC_ADDRS,
		       "");

  // -------------------------
  // Receipt policy
  // -------------------------
  e_account_set_int(m_account,
		    E_ACCOUNT_RECEIPT_POLICY,
		    E_ACCOUNT_RECEIPT_NEVER);

  // -------------------------
  // PGP config
  // -------------------------
  // E_ACCOUNT_PGP_KEY
  // E_ACCOUNT_PGP_HASH_ALGORITHM

  e_account_set_bool(m_account,
		     E_ACCOUNT_PGP_ENCRYPT_TO_SELF,
		     FALSE);  // gboolean, not C++ bool.

  e_account_set_bool(m_account,
		     E_ACCOUNT_PGP_ALWAYS_SIGN,
		     FALSE);

  e_account_set_bool(m_account,
		     E_ACCOUNT_PGP_NO_IMIP_SIGN,
		     FALSE);

  e_account_set_bool(m_account,
		     E_ACCOUNT_PGP_ALWAYS_TRUST,
		     FALSE);

  // -------------------------
  // SMIME config
  // -------------------------
  // E_ACCOUNT_SMIME_SIGN_KEY
  // E_ACCOUNT_SMIME_ENCRYPT_KEY
  // E_ACCOUNT_SMIME_HASH_ALGORITHM

  e_account_set_bool(m_account,
		     E_ACCOUNT_SMIME_SIGN_DEFAULT,
		     FALSE);
  e_account_set_bool(m_account,
		     E_ACCOUNT_SMIME_ENCRYPT_TO_SELF,
		     FALSE);
  e_account_set_bool(m_account,
		     E_ACCOUNT_SMIME_ENCRYPT_DEFAULT,
		     FALSE);

  // ----------------------------------------
  // Write the account to GConf.
  // ----------------------------------------
  e_account_list_add(accountList, m_account);
  e_account_list_save(accountList);

  return true;
}

void
MeeGo::ActiveSync::EmailAccount::removeConfig(EAccountList * accountList)
{
  if (accountList != 0)
    e_account_list_remove(accountList, m_account);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014, Matias Fontanini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above
 *   copyright notice, this list of conditions and the following disclaimer
 *   in the documentation and/or other materials provided with the
 *   distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#ifdef _WIN32
    #define NOMINMAX
#endif // _WIN32

#include <iostream>
#include <chrono>
#include <thread>
#include <cstdint>
#include <random>
#include <map>
#include <algorithm>
#include <atomic>
#include <limits>
#include <mutex>
#include <tins/tins.h>

using std::cout;
using std::endl;
using std::move;
using std::map;
using std::min;
using std::setw;
using std::atomic;
using std::runtime_error;
using std::string;
using std::to_string;
using std::thread;
using std::this_thread::sleep_for;
using std::lock_guard;
using std::mutex;
using std::random_device;
using std::numeric_limits;
using std::bind;
using std::chrono::milliseconds;

using namespace Tins;

class Traceroute {
public:
    typedef std::map<uint16_t, IPv4Address> result_type;

    Traceroute(NetworkInterface interface, IPv4Address address)
    : iface(interface), addr(address), lowest_dest_ttl(numeric_limits<int>::max()) {
        sequence = random_device()();
    }

    result_type trace() {
        SnifferConfiguration config;
        config.set_promisc_mode(false);
        // ICMPs that aren't sent from us.
        config.set_filter(
            "ip proto \\icmp and not src host " + iface.addresses().ip_addr.to_string());
        Sniffer sniffer(iface.name(), config);

        PacketSender sender;
        // Create our handler
        auto handler = bind(
            &Traceroute::sniff_callback,
            this,
            std::placeholders::_1
        );
        // We're running
        running = true;
        // Start the sniff thread
        thread sniff_thread(
            [&]() {
                sniffer.sniff_loop(handler);
            }
        );
        send_packets(sender);
        sniff_thread.join();
        // If the final hop responded, add its address at the appropriate ttl
        if (lowest_dest_ttl != numeric_limits<int>::max()) {
            results[lowest_dest_ttl] = addr;
        }
        // Clear our results and return what we've found
        return move(results);
    }
private:
    typedef map<uint16_t, size_t> ttl_map;

    void send_packets(PacketSender& sender) {
        // ICMPs are icmp-requests by default
        IP ip = IP(addr, iface.addresses().ip_addr) / ICMP();
        ICMP& icmp = ip.rfind_pdu<ICMP>();
        icmp.sequence(sequence);
        // We'll find at most 20 hops.

        for (auto i = 1; i <= 20; ++i) {
            // Set this ICMP id
            icmp.id(i);
            // Set the time-to-live option
            ip.ttl(i);

            // Critical section
            {
                lock_guard<mutex> _(lock);
                ttls[i] = i;
            }

            sender.send(ip);
            // Give him a little time
            sleep_for(milliseconds(100));
        }
        running = false;
        sender.send(ip);
    }

    bool sniff_callback(PDU& pdu) {
        // Find IP and ICMP PDUs
        const IP& ip = pdu.rfind_pdu<IP>();
        const ICMP& icmp = pdu.rfind_pdu<ICMP>();
        // Check if this is an ICMP TTL exceeded error response
        if (icmp.type() == ICMP::TIME_EXCEEDED) {
            // Fetch the IP PDU attached to the ICMP response
            const IP inner_ip = pdu.rfind_pdu<RawPDU>().to<IP>();
            // Now get the ICMP layer
            const ICMP& inner_icmp = inner_ip.rfind_pdu<ICMP>();
            // Make sure this is one of our packets.
            if (inner_icmp.sequence() == sequence) {
                ttl_map::const_iterator iter;

                // Critical section
                {
                    std::lock_guard<std::mutex> _(lock);
                    iter = ttls.find(inner_icmp.id());
                }

                // It's an actual response
                if(iter != ttls.end()) {
                    // Store it
                    results[inner_icmp.id()] = ip.src_addr();
                }
            }
        }
        // Otherwise, this could be the final hop making an echo response
        else if (icmp.type() == ICMP::ECHO_REPLY && icmp.sequence() == sequence &&
                ip.src_addr() == addr) {
            // Keep the lowest ttl seen for the destination.
            lowest_dest_ttl = min(lowest_dest_ttl, static_cast<int>(icmp.id()));
        }
        return running;
    }

    NetworkInterface iface;
    IPv4Address addr;
    atomic<bool> running;
    ttl_map ttls;
    result_type results;
    mutex lock;
    uint16_t sequence;
    int lowest_dest_ttl;
};

int main(int argc, char* argv[]) {
    if (argc <= 1) {
        cout << "Usage: " <<* argv << " <ip_address>" << endl;
        return 1;
    }
    try {
        IPv4Address addr = string(argv[1]);
        Traceroute tracer(addr, addr);
        auto results = tracer.trace();
        if (results.empty()) {
            cout << "No hops found" << endl;
        }
        else {
            cout << "Results: " << endl;
            for(const auto& entry : results) {
                cout << setw(2) << entry.first << " - " << entry.second << endl;
            }
        }
    }
    catch (runtime_error& ex) {
        cout << "Error - " << ex.what() << endl;
        return 2;
    }
}
<commit_msg>Mask 16 bits on random number generated on traceroute example<commit_after>/*
 * Copyright (c) 2014, Matias Fontanini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above
 *   copyright notice, this list of conditions and the following disclaimer
 *   in the documentation and/or other materials provided with the
 *   distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#ifdef _WIN32
    #define NOMINMAX
#endif // _WIN32

#include <iostream>
#include <chrono>
#include <thread>
#include <cstdint>
#include <random>
#include <map>
#include <algorithm>
#include <atomic>
#include <limits>
#include <mutex>
#include <tins/tins.h>

using std::cout;
using std::endl;
using std::move;
using std::map;
using std::min;
using std::setw;
using std::atomic;
using std::runtime_error;
using std::string;
using std::to_string;
using std::thread;
using std::this_thread::sleep_for;
using std::lock_guard;
using std::mutex;
using std::random_device;
using std::numeric_limits;
using std::bind;
using std::chrono::milliseconds;

using namespace Tins;

class Traceroute {
public:
    typedef std::map<uint16_t, IPv4Address> result_type;

    Traceroute(NetworkInterface interface, IPv4Address address)
    : iface(interface), addr(address), lowest_dest_ttl(numeric_limits<int>::max()) {
        sequence = random_device()() & 0xffff;
    }

    result_type trace() {
        SnifferConfiguration config;
        config.set_promisc_mode(false);
        // ICMPs that aren't sent from us.
        config.set_filter(
            "ip proto \\icmp and not src host " + iface.addresses().ip_addr.to_string());
        Sniffer sniffer(iface.name(), config);

        PacketSender sender;
        // Create our handler
        auto handler = bind(
            &Traceroute::sniff_callback,
            this,
            std::placeholders::_1
        );
        // We're running
        running = true;
        // Start the sniff thread
        thread sniff_thread(
            [&]() {
                sniffer.sniff_loop(handler);
            }
        );
        send_packets(sender);
        sniff_thread.join();
        // If the final hop responded, add its address at the appropriate ttl
        if (lowest_dest_ttl != numeric_limits<int>::max()) {
            results[lowest_dest_ttl] = addr;
        }
        // Clear our results and return what we've found
        return move(results);
    }
private:
    typedef map<uint16_t, size_t> ttl_map;

    void send_packets(PacketSender& sender) {
        // ICMPs are icmp-requests by default
        IP ip = IP(addr, iface.addresses().ip_addr) / ICMP();
        ICMP& icmp = ip.rfind_pdu<ICMP>();
        icmp.sequence(sequence);
        // We'll find at most 20 hops.

        for (auto i = 1; i <= 20; ++i) {
            // Set this ICMP id
            icmp.id(i);
            // Set the time-to-live option
            ip.ttl(i);

            // Critical section
            {
                lock_guard<mutex> _(lock);
                ttls[i] = i;
            }

            sender.send(ip);
            // Give him a little time
            sleep_for(milliseconds(100));
        }
        running = false;
        sender.send(ip);
    }

    bool sniff_callback(PDU& pdu) {
        // Find IP and ICMP PDUs
        const IP& ip = pdu.rfind_pdu<IP>();
        const ICMP& icmp = pdu.rfind_pdu<ICMP>();
        // Check if this is an ICMP TTL exceeded error response
        if (icmp.type() == ICMP::TIME_EXCEEDED) {
            // Fetch the IP PDU attached to the ICMP response
            const IP inner_ip = pdu.rfind_pdu<RawPDU>().to<IP>();
            // Now get the ICMP layer
            const ICMP& inner_icmp = inner_ip.rfind_pdu<ICMP>();
            // Make sure this is one of our packets.
            if (inner_icmp.sequence() == sequence) {
                ttl_map::const_iterator iter;

                // Critical section
                {
                    std::lock_guard<std::mutex> _(lock);
                    iter = ttls.find(inner_icmp.id());
                }

                // It's an actual response
                if(iter != ttls.end()) {
                    // Store it
                    results[inner_icmp.id()] = ip.src_addr();
                }
            }
        }
        // Otherwise, this could be the final hop making an echo response
        else if (icmp.type() == ICMP::ECHO_REPLY && icmp.sequence() == sequence &&
                ip.src_addr() == addr) {
            // Keep the lowest ttl seen for the destination.
            lowest_dest_ttl = min(lowest_dest_ttl, static_cast<int>(icmp.id()));
        }
        return running;
    }

    NetworkInterface iface;
    IPv4Address addr;
    atomic<bool> running;
    ttl_map ttls;
    result_type results;
    mutex lock;
    uint16_t sequence;
    int lowest_dest_ttl;
};

int main(int argc, char* argv[]) {
    if (argc <= 1) {
        cout << "Usage: " <<* argv << " <ip_address>" << endl;
        return 1;
    }
    try {
        IPv4Address addr = string(argv[1]);
        Traceroute tracer(addr, addr);
        auto results = tracer.trace();
        if (results.empty()) {
            cout << "No hops found" << endl;
        }
        else {
            cout << "Results: " << endl;
            for(const auto& entry : results) {
                cout << setw(2) << entry.first << " - " << entry.second << endl;
            }
        }
    }
    catch (runtime_error& ex) {
        cout << "Error - " << ex.what() << endl;
        return 2;
    }
}
<|endoftext|>


<commit_before>#if _WIN32
#pragma warning(disable : 4267 4996)
#endif
#include "./labeller.h"
#include <Eigen/Geometry>
#include <QLoggingCategory>
#include <vector>
#include <map>
#include <chrono>
#include "../math/eigen.h"
#include "../utils/cuda_array_provider.h"
#include "../utils/logging.h"
#include "./summed_area_table.h"
#include "./constraint_updater.h"
#include "./persistent_constraint_updater.h"
#include "./labels_arranger.h"
#include "../utils/memory.h"

namespace Placement
{

QLoggingCategory plChan("Placement.Labeller");

Labeller::Labeller(std::shared_ptr<LabelsContainer> labels) : labels(labels)
{
}

void Labeller::initialize(
    std::shared_ptr<CudaArrayProvider> integralCostsTextureMapper,
    std::shared_ptr<CudaArrayProvider> constraintTextureMapper,
    std::shared_ptr<PersistentConstraintUpdater> constraintUpdater)
{
  qCInfo(plChan) << "Initialize";
  if (!integralCosts.get())
    integralCosts =
        std::make_shared<SummedAreaTable>(integralCostsTextureMapper);

  this->constraintUpdater = constraintUpdater;

  bufferSize = Eigen::Vector2i(integralCostsTextureMapper->getWidth(),
                               integralCostsTextureMapper->getHeight());

  costFunctionCalculator =
      std::make_unique<CostFunctionCalculator>(constraintTextureMapper);
  costFunctionCalculator->resize(size.x(), size.y());
  costFunctionCalculator->setTextureSize(bufferSize.x(), bufferSize.y());
}

void Labeller::cleanup()
{
  integralCosts.reset();
  costFunctionCalculator.reset();
}

std::map<int, Eigen::Vector2f>
Labeller::update(const LabellerFrameData &frameData, bool ignoreOldPosition,
                 const LabelPositions &oldLabelPositions)
{
  if (labels->count() == 0)
    return std::map<int, Eigen::Vector2f>();

  oldPositions.clear();
  for (auto &pair : newPositions)
  {
    if (oldLabelPositions.count(pair.first))
      oldPositions[pair.first] =
          frameData.project2d(oldLabelPositions.get3dFor(pair.first));
  }

  newPositions.clear();
  if (!integralCosts.get())
    return newPositions;

  auto startTime = std::chrono::high_resolution_clock::now();
  integralCosts->runKernel();
  qCDebug(plChan) << "SAT took" << calculateDurationSince(startTime) << "ms";

  costSum = 0.0f;
  auto labelsInLayer = labelsArranger->getArrangement(frameData, labels);

  for (auto &label : labelsInLayer)
  {
    auto anchor2D = frameData.project(label.anchorPosition).head<2>();

    Eigen::Vector2i labelSizeForBuffer =
        label.size.cast<int>().cwiseProduct(bufferSize).cwiseQuotient(size);

    Eigen::Vector2f anchorPixels = toPixel(anchor2D, size);
    Eigen::Vector2i anchorForBuffer = toPixel(anchor2D, bufferSize).cast<int>();

    constraintUpdater->updateConstraints(label.id, anchorForBuffer,
                                         labelSizeForBuffer);

    bool ignoreOldLabel = ignoreOldPosition || !oldPositions.count(label.id);
    Eigen::Vector2f oldPositionPixel =
        ignoreOldLabel ? Eigen::Vector2f(0, 0)
                       : toPixel(oldPositions.at(label.id), size);

    auto result = costFunctionCalculator->calculateForLabel(
        integralCosts->getResults(), label.id, anchorPixels.x(),
        anchorPixels.y(), label.size.x(), label.size.y(), ignoreOldLabel,
        oldPositionPixel.x(), oldPositionPixel.y());

    constraintUpdater->setPosition(label.id, result.position);
    costSum += result.cost;

    qCDebug(plChan) << label.id << "\t" << result.position.x() << "|"
                    << result.position.y() << result.cost;

    auto relativeResult =
        result.position.cast<float>().cwiseQuotient(bufferSize.cast<float>());
    Eigen::Vector2f newNDC2d =
        2.0f * relativeResult - Eigen::Vector2f(1.0f, 1.0f);
    newPositions[label.id] = newNDC2d;
  }

  oldViewProjectionMatrix = frameData.viewProjection;

  return newPositions;
}

void Labeller::resize(int width, int height)
{
  size = Eigen::Vector2i(width, height);

  if (costFunctionCalculator.get())
    costFunctionCalculator->resize(width, height);
}

void Labeller::setCostFunctionWeights(CostFunctionWeights weights)
{
  costFunctionCalculator->weights = weights;
}

void Labeller::setLabelsArranger(std::shared_ptr<LabelsArranger> labelsArranger)
{
  this->labelsArranger = labelsArranger;
}

std::map<int, Eigen::Vector2f> Labeller::getLastPlacementResult()
{
  return newPositions;
}

float Labeller::getLastSumOfCosts()
{
  return costSum;
}

}  // namespace Placement
<commit_msg>Minor: improve logging.<commit_after>#if _WIN32
#pragma warning(disable : 4267 4996)
#endif
#include "./labeller.h"
#include <Eigen/Geometry>
#include <QLoggingCategory>
#include <vector>
#include <map>
#include <chrono>
#include "../math/eigen.h"
#include "../utils/cuda_array_provider.h"
#include "../utils/logging.h"
#include "./summed_area_table.h"
#include "./constraint_updater.h"
#include "./persistent_constraint_updater.h"
#include "./labels_arranger.h"
#include "../utils/memory.h"

namespace Placement
{

QLoggingCategory plChan("Placement.Labeller");

Labeller::Labeller(std::shared_ptr<LabelsContainer> labels) : labels(labels)
{
}

void Labeller::initialize(
    std::shared_ptr<CudaArrayProvider> integralCostsTextureMapper,
    std::shared_ptr<CudaArrayProvider> constraintTextureMapper,
    std::shared_ptr<PersistentConstraintUpdater> constraintUpdater)
{
  qCInfo(plChan) << "Initialize";
  if (!integralCosts.get())
    integralCosts =
        std::make_shared<SummedAreaTable>(integralCostsTextureMapper);

  this->constraintUpdater = constraintUpdater;

  bufferSize = Eigen::Vector2i(integralCostsTextureMapper->getWidth(),
                               integralCostsTextureMapper->getHeight());

  costFunctionCalculator =
      std::make_unique<CostFunctionCalculator>(constraintTextureMapper);
  costFunctionCalculator->resize(size.x(), size.y());
  costFunctionCalculator->setTextureSize(bufferSize.x(), bufferSize.y());
}

void Labeller::cleanup()
{
  integralCosts.reset();
  costFunctionCalculator.reset();
}

std::map<int, Eigen::Vector2f>
Labeller::update(const LabellerFrameData &frameData, bool ignoreOldPosition,
                 const LabelPositions &oldLabelPositions)
{
  if (labels->count() == 0)
    return std::map<int, Eigen::Vector2f>();

  oldPositions.clear();
  for (auto &pair : newPositions)
  {
    if (oldLabelPositions.count(pair.first))
      oldPositions[pair.first] =
          frameData.project2d(oldLabelPositions.get3dFor(pair.first));
  }

  newPositions.clear();
  if (!integralCosts.get())
    return newPositions;

  auto startTime = std::chrono::high_resolution_clock::now();
  integralCosts->runKernel();
  qCDebug(plChan) << "SAT took" << calculateDurationSince(startTime) << "ms";

  costSum = 0.0f;
  auto labelsInLayer = labelsArranger->getArrangement(frameData, labels);

  for (auto &label : labelsInLayer)
  {
    auto anchor2D = frameData.project(label.anchorPosition).head<2>();

    Eigen::Vector2i labelSizeForBuffer =
        label.size.cast<int>().cwiseProduct(bufferSize).cwiseQuotient(size);

    Eigen::Vector2f anchorPixels = toPixel(anchor2D, size);
    Eigen::Vector2i anchorForBuffer = toPixel(anchor2D, bufferSize).cast<int>();

    constraintUpdater->updateConstraints(label.id, anchorForBuffer,
                                         labelSizeForBuffer);

    bool ignoreOldLabel = ignoreOldPosition || !oldPositions.count(label.id);
    Eigen::Vector2f oldPositionPixel =
        ignoreOldLabel ? Eigen::Vector2f(0, 0)
                       : toPixel(oldPositions.at(label.id), size);

    auto result = costFunctionCalculator->calculateForLabel(
        integralCosts->getResults(), label.id, anchorPixels.x(),
        anchorPixels.y(), label.size.x(), label.size.y(), ignoreOldLabel,
        oldPositionPixel.x(), oldPositionPixel.y());

    constraintUpdater->setPosition(label.id, result.position);
    costSum += result.cost;

    qCDebug(plChan) << label.id << " :" << label.text.c_str() << "\t"
                    << result.position.x() << "|" << result.position.y()
                    << result.cost;

    auto relativeResult =
        result.position.cast<float>().cwiseQuotient(bufferSize.cast<float>());
    Eigen::Vector2f newNDC2d =
        2.0f * relativeResult - Eigen::Vector2f(1.0f, 1.0f);
    newPositions[label.id] = newNDC2d;
  }

  oldViewProjectionMatrix = frameData.viewProjection;

  return newPositions;
}

void Labeller::resize(int width, int height)
{
  size = Eigen::Vector2i(width, height);

  if (costFunctionCalculator.get())
    costFunctionCalculator->resize(width, height);
}

void Labeller::setCostFunctionWeights(CostFunctionWeights weights)
{
  costFunctionCalculator->weights = weights;
}

void Labeller::setLabelsArranger(std::shared_ptr<LabelsArranger> labelsArranger)
{
  this->labelsArranger = labelsArranger;
}

std::map<int, Eigen::Vector2f> Labeller::getLastPlacementResult()
{
  return newPositions;
}

float Labeller::getLastSumOfCosts()
{
  return costSum;
}

}  // namespace Placement
<|endoftext|>


<commit_before>#include <tamer/tamer.hh>
#include <sys/select.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

namespace tamer {
namespace {

class driver_tamer : public driver { public:

    driver_tamer();
    ~driver_tamer();

    virtual void at_fd(int fd, int action, const event<int> &e);
    virtual void at_time(const timeval &expiry, const event<> &e);
    virtual void at_asap(const event<> &e);
    virtual void kill_fd(int fd);

    virtual bool empty();
    virtual void once();
    virtual void loop();

  private:

    struct ttimer {
	union {
	    unsigned order;
	    ttimer *next;
	} u;
	timeval expiry;
	event<> trigger;
	ttimer(const timeval &expiry_, unsigned order_, const event<> &trigger_)
	    : expiry(expiry_), trigger(trigger_) {
	    u.order = order_;
	}
	bool operator>(const ttimer &o) const {
	    if (expiry.tv_sec != o.expiry.tv_sec)
		return expiry.tv_sec > o.expiry.tv_sec;
	    if (expiry.tv_usec != o.expiry.tv_usec)
		return expiry.tv_usec > o.expiry.tv_usec;
	    return (int) (u.order - o.u.order) > 0;
	}
    };

    struct ttimer_group {
	ttimer_group *next;
	ttimer t[1];
    };

    struct tfd {
	int fd : 30;
	unsigned action : 2;
	event<int> e;
	tfd *next;
    };

    struct tfd_group {
	tfd_group *next;
	tfd t[1];
    };

    ttimer **_t;
    int _nt;
    unsigned _torder;

    tfd *_fd;
    int _nfds;
    fd_set _fdset[2];

    tamerpriv::debuffer<event<> > _asap;

    int _tcap;
    ttimer_group *_tgroup;
    int _tgroup_cap;
    ttimer *_tfree;

    int _fdcap;
    tfd_group *_fdgroup;
    tfd *_fdfree;
    rendezvous<> _fdcancelr;

    void expand_timers();
    void check_timers() const;
    void timer_reheapify_from(int pos, ttimer *t, bool will_delete);
    void expand_fds();

};

driver_tamer::driver_tamer()
    : _t(0), _nt(0), _torder(0),
      _fd(0), _nfds(0),
      _tcap(0), _tgroup(0), _tgroup_cap(7), _tfree(0),
      _fdcap(0), _fdgroup(0), _fdfree(0)
{
    expand_timers();
    FD_ZERO(&_fdset[fdread]);
    FD_ZERO(&_fdset[fdwrite]);
    set_now();
}

driver_tamer::~driver_tamer()
{
    // destroy all active timers
    for (int i = 0; i < _nt; i++)
	_t[i]->~ttimer();

    // free timer groups
    while (_tgroup) {
	ttimer_group *next = _tgroup->next;
	delete[] reinterpret_cast<unsigned char *>(_tgroup);
	_tgroup = next;
    }
    delete[] _t;

    // destroy all active file descriptors
    while (_fd) {
	_fd->e.~event();
	_fd = _fd->next;
    }

    // free file descriptor groups
    while (_fdgroup) {
	tfd_group *next = _fdgroup->next;
	delete[] reinterpret_cast<unsigned char *>(_fdgroup);
	_fdgroup = next;
    }
}

void driver_tamer::expand_timers()
{
    if (_tgroup_cap <= 511)
	_tgroup_cap = (_tgroup_cap * 2) + 1;

    ttimer_group *ngroup = reinterpret_cast<ttimer_group *>(new unsigned char[sizeof(ttimer_group) + sizeof(ttimer) * (_tgroup_cap - 1)]);
    ngroup->next = _tgroup;
    _tgroup = ngroup;
    for (int i = 0; i < _tgroup_cap; i++) {
	ngroup->t[i].u.next = _tfree;
	_tfree = &ngroup->t[i];
    }

    ttimer **t = new ttimer *[_tcap + _tgroup_cap];
    memcpy(t, _t, sizeof(ttimer *) * _nt);
    delete[] _t;
    _t = t;
    _tcap = _tcap + _tgroup_cap;
}

void driver_tamer::timer_reheapify_from(int pos, ttimer *t, bool /*will_delete*/)
{
    int npos;
    while (pos > 0
	   && (npos = (pos-1) >> 1, *_t[npos] > *t)) {
	_t[pos] = _t[npos];
	pos = npos;
    }

    while (1) {
	ttimer *smallest = t;
	npos = 2*pos + 1;
	if (npos < _nt && *smallest > *_t[npos])
	    smallest = _t[npos];
	if (npos+1 < _nt && *smallest > *_t[npos+1])
	    smallest = _t[npos+1], npos++;

	_t[pos] = smallest;

	if (smallest == t)
	    break;

	pos = npos;
    }
#if 0
    if (_t + 1 < tend || !will_delete)
	_timer_expiry = tbegin[0]->expiry;
    else
	_timer_expiry = Timestamp();
#endif
}

#if 0
void driver_tamer::check_timers() const
{
    fprintf(stderr, "---");
    for (int k = 0; k < _nt; k++)
	fprintf(stderr, " %p/%d.%06d", _t[k], _t[k]->expiry.tv_sec, _t[k]->expiry.tv_usec);
    fprintf(stderr, "\n");

    for (int i = 0; i < _nt / 2; i++)
	for (int j = 2*i + 1; j < 2*i + 3; j++)
	    if (j < _nt && *_t[i] > *_t[j]) {
		fprintf(stderr, "***");
		for (int k = 0; k < _nt; k++)
		    fprintf(stderr, (k == i || k == j ? " **%d.%06d**" : " %d.%06d"), _t[k]->expiry.tv_sec, _t[k]->expiry.tv_usec);
		fprintf(stderr, "\n");
		assert(0);
	    }
}
#endif

void driver_tamer::expand_fds()
{
    int ncap = (_fdcap ? _fdcap * 2 : 16);

    tfd_group *ngroup = reinterpret_cast<tfd_group *>(new unsigned char[sizeof(tfd_group) + sizeof(tfd) * (ncap - 1)]);
    ngroup->next = _fdgroup;
    _fdgroup = ngroup;
    for (int i = 0; i < ncap; i++) {
	ngroup->t[i].next = _fdfree;
	_fdfree = &ngroup->t[i];
    }
}

void driver_tamer::at_fd(int fd, int action, const event<int> &trigger)
{
    if (!_fdfree)
	expand_fds();
    if (fd >= FD_SETSIZE)
	throw tamer::tamer_error("file descriptor too large");
    if (trigger) {
	tfd *t = _fdfree;
	_fdfree = t->next;
	t->next = _fd;
	_fd = t;

	t->fd = fd;
	t->action = action;
	(void) new(static_cast<void *>(&t->e)) event<int>(trigger);

	FD_SET(fd, &_fdset[action]);
	if (fd >= _nfds)
	    _nfds = fd + 1;
	if (action <= fdwrite)
	    t->e.at_trigger(make_event(_fdcancelr));
    }
}

void driver_tamer::kill_fd(int fd)
{
    assert(fd >= 0);
    if (fd < _nfds && (FD_ISSET(fd, &_fdset[fdread]) || FD_ISSET(fd, &_fdset[fdwrite]))) {
	FD_CLR(fd, &_fdset[fdread]);
	FD_CLR(fd, &_fdset[fdwrite]);
	tfd **pprev = &_fd, *t;
	while ((t = *pprev))
	    if (t->fd == fd) {
		t->e.trigger(-ECANCELED);
		t->e.~event();
		*pprev = t->next;
		t->next = _fdfree;
		_fdfree = t;
	    } else
		pprev = &t->next;
    }
}

void driver_tamer::at_time(const timeval &expiry, const event<> &e)
{
    if (!_tfree)
	expand_timers();
    ttimer *t = _tfree;
    _tfree = t->u.next;
    (void) new(static_cast<void *>(t)) ttimer(expiry, ++_torder, e);
    _t[_nt++] = 0;
    timer_reheapify_from(_nt-1, t, false);
}

void driver_tamer::at_asap(const event<> &e)
{
    _asap.push_back(e);
}

bool driver_tamer::empty()
{
    if (_nt != 0 || _nfds != 0 || _asap.size() != 0
	|| sig_any_active || tamerpriv::abstract_rendezvous::unblocked)
	return false;
    return true;
}

void driver_tamer::once()
{
    // get rid of initial cancelled timers
    ttimer *t;
    while (_nt > 0 && (t = _t[0], !t->trigger)) {
	timer_reheapify_from(0, _t[_nt - 1], true);
	_nt--;
	t->~ttimer();
	t->u.next = _tfree;
	_tfree = t;
    }

    // determine timeout
    struct timeval to, *toptr;
    if (_asap.size()
	|| (_nt > 0 && !timercmp(&_t[0]->expiry, &now, >))
	|| sig_any_active) {
	timerclear(&to);
	toptr = &to;
    } else if (_nt == 0)
	toptr = 0;
    else {
	timersub(&_t[0]->expiry, &now, &to);
	toptr = &to;
    }

    // get rid of canceled descriptors, if any
    if (_fdcancelr.nready()) {
	while (_fdcancelr.join())
	    /* nada */;
	FD_ZERO(&_fdset[fdread]);
	FD_ZERO(&_fdset[fdwrite]);
	_nfds = 0;
	tfd **pprev = &_fd, *t;
	while ((t = *pprev))
	    if (!t->e) {
		t->e.~event();
		*pprev = t->next;
		t->next = _fdfree;
		_fdfree = t;
	    } else {
		FD_SET(t->fd, &_fdset[t->action]);
		if (t->fd >= _nfds)
		    _nfds = t->fd + 1;
		pprev = &t->next;
	    }
    }

    // select!
    fd_set fds[2];
    fds[fdread] = _fdset[fdread];
    fds[fdwrite] = _fdset[fdwrite];
    int nfds = _nfds;
    if (sig_pipe[0] >= 0) {
	FD_SET(sig_pipe[0], &fds[fdread]);
	if (sig_pipe[0] > nfds)
	    nfds = sig_pipe[0] + 1;
    }
    nfds = select(nfds, &fds[fdread], &fds[fdwrite], 0, toptr);

    // run signals
    if (sig_any_active)
	dispatch_signals();

    // run asaps
    while (event<> *e = _asap.front()) {
	e->trigger();
	_asap.pop_front();
    }

    // run file descriptors
    if (nfds > 0) {
	tfd **pprev = &_fd, *t;
	while ((t = *pprev))
	    if (t->action <= fdwrite && FD_ISSET(t->fd, &fds[t->action])) {
		FD_CLR(t->fd, &_fdset[t->action]);
		t->e.trigger(0);
		t->e.~event();
		*pprev = t->next;
		t->next = _fdfree;
		_fdfree = t;
	    } else if (!t->e) {
		t->e.~event();
		*pprev = t->next;
		t->next = _fdfree;
		_fdfree = t;
	    } else
		pprev = &t->next;
    }

    // run the timers that worked
    set_now();
    while (_nt > 0 && (t = _t[0], !timercmp(&t->expiry, &now, >))) {
	timer_reheapify_from(0, _t[_nt - 1], true);
	_nt--;
	t->trigger.trigger();
	t->~ttimer();
	t->u.next = _tfree;
	_tfree = t;
    }

    // run active closures
    while (tamerpriv::abstract_rendezvous *r = tamerpriv::abstract_rendezvous::unblocked)
	r->run();
}

#if 0
void driver_tamer::print_fds()
{
    tfd *t = _fd;
    while (t) {
	fprintf(stderr, "%d.%d ", t->fd, t->action);
	t = t->next;
    }
    if (_fd)
	fprintf(stderr, "\n");
}
#endif

void driver_tamer::loop()
{
    while (1)
	once();
}

}

driver *driver::make_tamer()
{
    return new driver_tamer;
}

}
<commit_msg>reap a cancel notifier to avoid unnecessary reconstructions of the select set<commit_after>#include <tamer/tamer.hh>
#include <sys/select.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

namespace tamer {
namespace {

class driver_tamer : public driver { public:

    driver_tamer();
    ~driver_tamer();

    virtual void at_fd(int fd, int action, const event<int> &e);
    virtual void at_time(const timeval &expiry, const event<> &e);
    virtual void at_asap(const event<> &e);
    virtual void kill_fd(int fd);

    virtual bool empty();
    virtual void once();
    virtual void loop();

  private:

    struct ttimer {
	union {
	    unsigned order;
	    ttimer *next;
	} u;
	timeval expiry;
	event<> trigger;
	ttimer(const timeval &expiry_, unsigned order_, const event<> &trigger_)
	    : expiry(expiry_), trigger(trigger_) {
	    u.order = order_;
	}
	bool operator>(const ttimer &o) const {
	    if (expiry.tv_sec != o.expiry.tv_sec)
		return expiry.tv_sec > o.expiry.tv_sec;
	    if (expiry.tv_usec != o.expiry.tv_usec)
		return expiry.tv_usec > o.expiry.tv_usec;
	    return (int) (u.order - o.u.order) > 0;
	}
    };

    struct ttimer_group {
	ttimer_group *next;
	ttimer t[1];
    };

    struct tfd {
	int fd : 30;
	unsigned action : 2;
	event<int> e;
	tfd *next;
    };

    struct tfd_group {
	tfd_group *next;
	tfd t[1];
    };

    ttimer **_t;
    int _nt;
    unsigned _torder;

    tfd *_fd;
    int _nfds;
    fd_set _fdset[2];

    tamerpriv::debuffer<event<> > _asap;

    int _tcap;
    ttimer_group *_tgroup;
    int _tgroup_cap;
    ttimer *_tfree;

    int _fdcap;
    tfd_group *_fdgroup;
    tfd *_fdfree;
    rendezvous<> _fdcancelr;

    void expand_timers();
    void check_timers() const;
    void timer_reheapify_from(int pos, ttimer *t, bool will_delete);
    void expand_fds();

};

driver_tamer::driver_tamer()
    : _t(0), _nt(0), _torder(0),
      _fd(0), _nfds(0),
      _tcap(0), _tgroup(0), _tgroup_cap(7), _tfree(0),
      _fdcap(0), _fdgroup(0), _fdfree(0)
{
    expand_timers();
    FD_ZERO(&_fdset[fdread]);
    FD_ZERO(&_fdset[fdwrite]);
    set_now();
}

driver_tamer::~driver_tamer()
{
    // destroy all active timers
    for (int i = 0; i < _nt; i++)
	_t[i]->~ttimer();

    // free timer groups
    while (_tgroup) {
	ttimer_group *next = _tgroup->next;
	delete[] reinterpret_cast<unsigned char *>(_tgroup);
	_tgroup = next;
    }
    delete[] _t;

    // destroy all active file descriptors
    while (_fd) {
	_fd->e.~event();
	_fd = _fd->next;
    }

    // free file descriptor groups
    while (_fdgroup) {
	tfd_group *next = _fdgroup->next;
	delete[] reinterpret_cast<unsigned char *>(_fdgroup);
	_fdgroup = next;
    }
}

void driver_tamer::expand_timers()
{
    if (_tgroup_cap <= 511)
	_tgroup_cap = (_tgroup_cap * 2) + 1;

    ttimer_group *ngroup = reinterpret_cast<ttimer_group *>(new unsigned char[sizeof(ttimer_group) + sizeof(ttimer) * (_tgroup_cap - 1)]);
    ngroup->next = _tgroup;
    _tgroup = ngroup;
    for (int i = 0; i < _tgroup_cap; i++) {
	ngroup->t[i].u.next = _tfree;
	_tfree = &ngroup->t[i];
    }

    ttimer **t = new ttimer *[_tcap + _tgroup_cap];
    memcpy(t, _t, sizeof(ttimer *) * _nt);
    delete[] _t;
    _t = t;
    _tcap = _tcap + _tgroup_cap;
}

void driver_tamer::timer_reheapify_from(int pos, ttimer *t, bool /*will_delete*/)
{
    int npos;
    while (pos > 0
	   && (npos = (pos-1) >> 1, *_t[npos] > *t)) {
	_t[pos] = _t[npos];
	pos = npos;
    }

    while (1) {
	ttimer *smallest = t;
	npos = 2*pos + 1;
	if (npos < _nt && *smallest > *_t[npos])
	    smallest = _t[npos];
	if (npos+1 < _nt && *smallest > *_t[npos+1])
	    smallest = _t[npos+1], npos++;

	_t[pos] = smallest;

	if (smallest == t)
	    break;

	pos = npos;
    }
#if 0
    if (_t + 1 < tend || !will_delete)
	_timer_expiry = tbegin[0]->expiry;
    else
	_timer_expiry = Timestamp();
#endif
}

#if 0
void driver_tamer::check_timers() const
{
    fprintf(stderr, "---");
    for (int k = 0; k < _nt; k++)
	fprintf(stderr, " %p/%d.%06d", _t[k], _t[k]->expiry.tv_sec, _t[k]->expiry.tv_usec);
    fprintf(stderr, "\n");

    for (int i = 0; i < _nt / 2; i++)
	for (int j = 2*i + 1; j < 2*i + 3; j++)
	    if (j < _nt && *_t[i] > *_t[j]) {
		fprintf(stderr, "***");
		for (int k = 0; k < _nt; k++)
		    fprintf(stderr, (k == i || k == j ? " **%d.%06d**" : " %d.%06d"), _t[k]->expiry.tv_sec, _t[k]->expiry.tv_usec);
		fprintf(stderr, "\n");
		assert(0);
	    }
}
#endif

void driver_tamer::expand_fds()
{
    int ncap = (_fdcap ? _fdcap * 2 : 16);

    tfd_group *ngroup = reinterpret_cast<tfd_group *>(new unsigned char[sizeof(tfd_group) + sizeof(tfd) * (ncap - 1)]);
    ngroup->next = _fdgroup;
    _fdgroup = ngroup;
    for (int i = 0; i < ncap; i++) {
	ngroup->t[i].next = _fdfree;
	_fdfree = &ngroup->t[i];
    }
}

void driver_tamer::at_fd(int fd, int action, const event<int> &trigger)
{
    if (!_fdfree)
	expand_fds();
    if (fd >= FD_SETSIZE)
	throw tamer::tamer_error("file descriptor too large");
    if (trigger) {
	tfd *t = _fdfree;
	_fdfree = t->next;
	t->next = _fd;
	_fd = t;

	t->fd = fd;
	t->action = action;
	(void) new(static_cast<void *>(&t->e)) event<int>(trigger);

	FD_SET(fd, &_fdset[action]);
	if (fd >= _nfds)
	    _nfds = fd + 1;
	if (action <= fdwrite)
	    t->e.at_trigger(make_event(_fdcancelr));
    }
}

void driver_tamer::kill_fd(int fd)
{
    assert(fd >= 0);
    if (fd < _nfds && (FD_ISSET(fd, &_fdset[fdread]) || FD_ISSET(fd, &_fdset[fdwrite]))) {
	FD_CLR(fd, &_fdset[fdread]);
	FD_CLR(fd, &_fdset[fdwrite]);
	tfd **pprev = &_fd, *t;
	while ((t = *pprev))
	    if (t->fd == fd) {
		t->e.trigger(-ECANCELED);
		t->e.~event();
		*pprev = t->next;
		t->next = _fdfree;
		_fdfree = t;
	    } else
		pprev = &t->next;
    }
}

void driver_tamer::at_time(const timeval &expiry, const event<> &e)
{
    if (!_tfree)
	expand_timers();
    ttimer *t = _tfree;
    _tfree = t->u.next;
    (void) new(static_cast<void *>(t)) ttimer(expiry, ++_torder, e);
    _t[_nt++] = 0;
    timer_reheapify_from(_nt-1, t, false);
}

void driver_tamer::at_asap(const event<> &e)
{
    _asap.push_back(e);
}

bool driver_tamer::empty()
{
    if (_nt != 0 || _nfds != 0 || _asap.size() != 0
	|| sig_any_active || tamerpriv::abstract_rendezvous::unblocked)
	return false;
    return true;
}

void driver_tamer::once()
{
    // get rid of initial cancelled timers
    ttimer *t;
    while (_nt > 0 && (t = _t[0], !t->trigger)) {
	timer_reheapify_from(0, _t[_nt - 1], true);
	_nt--;
	t->~ttimer();
	t->u.next = _tfree;
	_tfree = t;
    }

    // determine timeout
    struct timeval to, *toptr;
    if (_asap.size()
	|| (_nt > 0 && !timercmp(&_t[0]->expiry, &now, >))
	|| sig_any_active) {
	timerclear(&to);
	toptr = &to;
    } else if (_nt == 0)
	toptr = 0;
    else {
	timersub(&_t[0]->expiry, &now, &to);
	toptr = &to;
    }

    // get rid of canceled descriptors, if any
    if (_fdcancelr.nready()) {
	while (_fdcancelr.join())
	    /* nada */;
	FD_ZERO(&_fdset[fdread]);
	FD_ZERO(&_fdset[fdwrite]);
	_nfds = 0;
	tfd **pprev = &_fd, *t;
	while ((t = *pprev))
	    if (!t->e) {
		t->e.~event();
		*pprev = t->next;
		t->next = _fdfree;
		_fdfree = t;
	    } else {
		FD_SET(t->fd, &_fdset[t->action]);
		if (t->fd >= _nfds)
		    _nfds = t->fd + 1;
		pprev = &t->next;
	    }
    }

    // select!
    fd_set fds[2];
    fds[fdread] = _fdset[fdread];
    fds[fdwrite] = _fdset[fdwrite];
    int nfds = _nfds;
    if (sig_pipe[0] >= 0) {
	FD_SET(sig_pipe[0], &fds[fdread]);
	if (sig_pipe[0] > nfds)
	    nfds = sig_pipe[0] + 1;
    }
    nfds = select(nfds, &fds[fdread], &fds[fdwrite], 0, toptr);

    // run signals
    if (sig_any_active)
	dispatch_signals();

    // run asaps
    while (event<> *e = _asap.front()) {
	e->trigger();
	_asap.pop_front();
    }

    // run file descriptors
    if (nfds > 0) {
	tfd **pprev = &_fd, *t;
	while ((t = *pprev))
	    if (t->action <= fdwrite && FD_ISSET(t->fd, &fds[t->action])) {
		FD_CLR(t->fd, &_fdset[t->action]);
		t->e.trigger(0);
		t->e.~event();
		_fdcancelr.join(); // reap the notifier we just triggered
		*pprev = t->next;
		t->next = _fdfree;
		_fdfree = t;
	    } else if (!t->e) {
		t->e.~event();
		*pprev = t->next;
		t->next = _fdfree;
		_fdfree = t;
	    } else
		pprev = &t->next;
    }

    // run the timers that worked
    set_now();
    while (_nt > 0 && (t = _t[0], !timercmp(&t->expiry, &now, >))) {
	timer_reheapify_from(0, _t[_nt - 1], true);
	_nt--;
	t->trigger.trigger();
	t->~ttimer();
	t->u.next = _tfree;
	_tfree = t;
    }

    // run active closures
    while (tamerpriv::abstract_rendezvous *r = tamerpriv::abstract_rendezvous::unblocked)
	r->run();
}

#if 0
void driver_tamer::print_fds()
{
    tfd *t = _fd;
    while (t) {
	fprintf(stderr, "%d.%d ", t->fd, t->action);
	t = t->next;
    }
    if (_fd)
	fprintf(stderr, "\n");
}
#endif

void driver_tamer::loop()
{
    while (1)
	once();
}

}

driver *driver::make_tamer()
{
    return new driver_tamer;
}

}
<|endoftext|>


<commit_before>#include "transformLetExprs.h"
#include "expr.h"
#include "stmt.h"
#include "symbol.h"
#include "type.h"
#include "symtab.h"
#include "stringutil.h"
#include "insertFunctionTemps.h"

TransformLetExprs::TransformLetExprs() {
  lets.clear();
}

void TransformLetExprs::postProcessExpr(Expr* expr) {
  if (LetExpr* letExpr = dynamic_cast<LetExpr*>(expr)) {
    lets.add(letExpr);
  }
}

void TransformLetExprs::run(ModuleList* moduleList) {
  Traversal::run(moduleList);
  doTransformation();
}

void TransformLetExprs::doTransformation(void) {
  static int uid = 1;
  forv_Vec(BaseAST, ast, lets) {
    LetExpr* letExpr = dynamic_cast<LetExpr*>(ast);
    if (!letExpr) {
      INT_FATAL(ast, "LetExpr expected");
    }
    Stmt* letStmt = letExpr->getStmt();
    BlockStmt* blockStmt = Symboltable::startCompoundStmt();
    Expr* innerCopy = letExpr->innerExpr->copy(false, NULL, &lets);
    letExpr->replace(innerCopy);
    Map<BaseAST*,BaseAST*>* map = new Map<BaseAST*,BaseAST*>();
    AList<Stmt>* defStmts = new AList<Stmt>();
    for_alist(DefExpr, defExpr, letExpr->symDefs) {
      DefExpr* defExprCopy = defExpr->copy(true, map, &lets);
      defExprCopy->sym->cname =
        glomstrings(3, defExprCopy->sym->cname, "_let_", intstring(uid++));
      defStmts->insertAtTail(new ExprStmt(defExprCopy));
    }
    Stmt* letStmtCopy = letStmt->copy(false, map, &lets);
    defStmts->insertAtTail(letStmtCopy);
    blockStmt = Symboltable::finishCompoundStmt(blockStmt, defStmts);
    letStmt->replace(blockStmt);
    TRAVERSE(blockStmt, new InsertFunctionTemps(), true);
  }
}
<commit_msg>Fixed a small bug in the let transformation in which the old let scope was accidentally left in the AST.<commit_after>#include "transformLetExprs.h"
#include "expr.h"
#include "stmt.h"
#include "symbol.h"
#include "type.h"
#include "symtab.h"
#include "stringutil.h"
#include "insertFunctionTemps.h"

TransformLetExprs::TransformLetExprs() {
  lets.clear();
}

void TransformLetExprs::postProcessExpr(Expr* expr) {
  if (LetExpr* letExpr = dynamic_cast<LetExpr*>(expr)) {
    lets.add(letExpr);
  }
}

void TransformLetExprs::run(ModuleList* moduleList) {
  Traversal::run(moduleList);
  doTransformation();
}

void TransformLetExprs::doTransformation(void) {
  static int uid = 1;
  forv_Vec(BaseAST, ast, lets) {
    LetExpr* letExpr = dynamic_cast<LetExpr*>(ast);
    if (!letExpr) {
      INT_FATAL(ast, "LetExpr expected");
    }
    Stmt* letStmt = letExpr->getStmt();
    BlockStmt* blockStmt = Symboltable::startCompoundStmt();
    Expr* innerCopy = letExpr->innerExpr->copy(false, NULL, &lets);
    letExpr->replace(innerCopy);
    Symboltable::removeScope(letExpr->letScope);
    Map<BaseAST*,BaseAST*>* map = new Map<BaseAST*,BaseAST*>();
    AList<Stmt>* defStmts = new AList<Stmt>();
    for_alist(DefExpr, defExpr, letExpr->symDefs) {
      DefExpr* defExprCopy = defExpr->copy(true, map, &lets);
      defExprCopy->sym->cname =
        glomstrings(3, defExprCopy->sym->cname, "_let_", intstring(uid++));
      defStmts->insertAtTail(new ExprStmt(defExprCopy));
    }
    Stmt* letStmtCopy = letStmt->copy(false, map, &lets);
    defStmts->insertAtTail(letStmtCopy);
    blockStmt = Symboltable::finishCompoundStmt(blockStmt, defStmts);
    letStmt->replace(blockStmt);
    TRAVERSE(blockStmt, new InsertFunctionTemps(), true);
  }
}
<|endoftext|>