<commit_before>#include "CppUnitLite/TestHarness.h"
#include "types.h"
#include "query.h"

void mock_set_speed(unsigned int newspeed); // From snmp-mock.cpp

int main()
{
    TestResult tr;
    TestRegistry::runAllTests(tr);

  return 0;
}

TEST(RTGConf, parse_example)
{
	RTGConf conf = read_rtg_conf("example-rtg.conf");
	LONGS_EQUAL(30, conf.interval);
	LONGS_EQUAL(2, conf.threads);
	STRINGS_EQUAL("rtguser", conf.dbuser.c_str());
	STRINGS_EQUAL("password", conf.dbpass.c_str());
	STRINGS_EQUAL("sql-server", conf.dbhost.c_str());
	STRINGS_EQUAL("rtgdb", conf.database.c_str());
}

TEST(Targets, parse_example_1)
{
	RTGConf conf = read_rtg_conf("example-rtg.conf");
	std::vector<QueryHost> hosts = read_rtg_targets("example-targets.cfg", conf);
	LONGS_EQUAL(2, hosts.size()); // Two hosts
	LONGS_EQUAL(2, hosts[0].rows.size()); // Two rows for host one
	LONGS_EQUAL(2, hosts[1].rows.size()); // Two rows for host two
}

TEST(Targets, parse_example_2)
{
	RTGConf conf = read_rtg_conf("example-rtg.conf");
	std::vector<QueryHost> hosts = read_rtg_targets("example-targets.cfg", conf);
	STRINGS_EQUAL("172.16.1.1", hosts[0].host.c_str());
	STRINGS_EQUAL("172.16.1.2", hosts[1].host.c_str());
	STRINGS_EQUAL("c0mmun1ty", hosts[0].community.c_str());
	STRINGS_EQUAL("f00barbaz", hosts[1].community.c_str());
	LONGS_EQUAL(1, hosts[0].snmpver);
	LONGS_EQUAL(2, hosts[1].snmpver);
}

TEST(Targets, parse_example_3)
{
	RTGConf conf = read_rtg_conf("example-rtg.conf");
	std::vector<QueryHost> hosts = read_rtg_targets("example-targets.cfg", conf);
	STRINGS_EQUAL(".1.3.6.1.2.1.2.2.1.16.1001002", hosts[0].rows[0].oid.c_str());
	STRINGS_EQUAL("ifOutOctets_362", hosts[0].rows[0].table.c_str());
	LONGS_EQUAL(4309, hosts[0].rows[0].id);
	UINT64_EQUAL(285600000, hosts[0].rows[0].speed);
	LONGS_EQUAL(32, hosts[0].rows[0].bits);
}

TEST(CalculateRate, zero_rate_with_32_bits)
{
	time_t cur_time = time(NULL);
	time_t prev_time = cur_time - 60;
	uint64_t prev_counter = 1e6;
	uint64_t cur_counter = prev_counter;
	std::pair<uint64_t, uint64_t> rate = calculate_rate(prev_time, prev_counter, cur_time, cur_counter, 32);
	UINT64_EQUAL(0, rate.first);
	UINT64_EQUAL(0, rate.second);
}

TEST(CalculateRate, one_kbps_rate_with_32_bits)
{
	time_t cur_time = time(NULL);
	time_t prev_time = cur_time - 60;
	uint64_t prev_counter = 1e6;
	uint64_t cur_counter = 1e6 + 60 * 1000 / 8;
	std::pair<uint64_t, uint64_t> rate = calculate_rate(prev_time, prev_counter, cur_time, cur_counter, 32);
	UINT64_EQUAL(60 * 1000/8, rate.first);
	UINT64_EQUAL(1000/8, rate.second);
}

TEST(CalculateRate, one_kbps_counter_wrap_32_bits)
{
	time_t cur_time = time(NULL);
	time_t prev_time = cur_time - 60;
	uint32_t prev_counter = 4294967000ul;
	uint32_t cur_counter = prev_counter + 60 * 1000 / 8;
	std::pair<uint64_t, uint64_t> rate = calculate_rate(prev_time, prev_counter, cur_time, cur_counter, 32);
	UINT64_EQUAL(60 * 1000/8, rate.first);
	UINT64_EQUAL(1000/8, rate.second);
}

TEST(CalculateRate, one_kbps_counter_wrap_64_bits)
{
	time_t cur_time = time(NULL);
	time_t prev_time = cur_time - 60;
	uint64_t prev_counter = 18446744073709551000ull;
	uint64_t cur_counter = prev_counter + 60 * 1000 / 8;
	std::pair<uint64_t, uint64_t> rate = calculate_rate(prev_time, prev_counter, cur_time, cur_counter, 64);
	UINT64_EQUAL(60 * 1000/8, rate.first);
	UINT64_EQUAL(1000/8, rate.second);
}

TEST(CalculateRate, gauge)
{
	time_t cur_time = time(NULL);
	time_t prev_time = cur_time - 60;
	uint64_t prev_counter = 1e6;
	uint64_t cur_counter = 1e6 + 1000;
	std::pair<uint64_t, uint64_t> rate = calculate_rate(prev_time, prev_counter, cur_time, cur_counter, 0);
	UINT64_EQUAL(1e6 + 1000, rate.first);
	UINT64_EQUAL(1e6 + 1000, rate.second);
}

TEST(Query, one_host)
{
	RTGConf conf = read_rtg_conf("example-rtg.conf");
	std::vector<QueryHost> hosts = read_rtg_targets("example-targets.cfg", conf);
	std::map<std::string, ResultSet> rs = query(hosts[0]);
	LONGS_EQUAL(1, rs.size()); // One table
	ResultSet set = rs["ifOutOctets_362"];
	LONGS_EQUAL(2, set.rows.size()); // Two rows
	LONGS_EQUAL(4309, set.rows[0].id);
	LONGS_EQUAL(4310, set.rows[1].id);
}

#ifdef LONGTESTS
TEST(ProcessHost, one_host_one_Mbps_10_secs)
{
	mock_set_speed(1e6 / 8);
	RTGConf conf = read_rtg_conf("example-rtg.conf");
	std::vector<QueryHost> hosts = read_rtg_targets("example-targets.cfg", conf);
	ResultCache cache;
	std::vector<std::string> queries = process_host(hosts[0], cache);
	LONGS_EQUAL(0, queries.size()); // No inserts first iteration
	sleep(10);
	queries = process_host(hosts[0], cache);
	LONGS_EQUAL(1, queries.size()); // One insert next iteration
	// std::cerr << queries[0] << std::endl;
	size_t pos = queries[0].find(", 1250000, 125000)");
	CHECK(pos != std::string::npos);
	pos = queries[0].find(", 1250000, 125000)", pos+1);
	CHECK(pos != std::string::npos);
}

TEST(ProcessHost, one_host_hundred_Mbps_one_interval)
{
	mock_set_speed(100e6 / 8);
	RTGConf conf = read_rtg_conf("example-rtg.conf");
	std::vector<QueryHost> hosts = read_rtg_targets("example-targets.cfg", conf);
	ResultCache cache;
	std::vector<std::string> queries = process_host(hosts[0], cache);
	LONGS_EQUAL(0, queries.size()); // No inserts first iteration
	sleep(conf.interval);
	queries = process_host(hosts[0], cache);
	LONGS_EQUAL(0, queries.size()); // No inserts next iteration due to too high speed
}
#endif
<commit_msg>Add test for unchanged gauge<commit_after>#include "CppUnitLite/TestHarness.h"
#include "types.h"
#include "query.h"

void mock_set_speed(unsigned int newspeed); // From snmp-mock.cpp

int main()
{
    TestResult tr;
    TestRegistry::runAllTests(tr);

  return 0;
}

TEST(RTGConf, parse_example)
{
	RTGConf conf = read_rtg_conf("example-rtg.conf");
	LONGS_EQUAL(30, conf.interval);
	LONGS_EQUAL(2, conf.threads);
	STRINGS_EQUAL("rtguser", conf.dbuser.c_str());
	STRINGS_EQUAL("password", conf.dbpass.c_str());
	STRINGS_EQUAL("sql-server", conf.dbhost.c_str());
	STRINGS_EQUAL("rtgdb", conf.database.c_str());
}

TEST(Targets, parse_example_1)
{
	RTGConf conf = read_rtg_conf("example-rtg.conf");
	std::vector<QueryHost> hosts = read_rtg_targets("example-targets.cfg", conf);
	LONGS_EQUAL(2, hosts.size()); // Two hosts
	LONGS_EQUAL(2, hosts[0].rows.size()); // Two rows for host one
	LONGS_EQUAL(2, hosts[1].rows.size()); // Two rows for host two
}

TEST(Targets, parse_example_2)
{
	RTGConf conf = read_rtg_conf("example-rtg.conf");
	std::vector<QueryHost> hosts = read_rtg_targets("example-targets.cfg", conf);
	STRINGS_EQUAL("172.16.1.1", hosts[0].host.c_str());
	STRINGS_EQUAL("172.16.1.2", hosts[1].host.c_str());
	STRINGS_EQUAL("c0mmun1ty", hosts[0].community.c_str());
	STRINGS_EQUAL("f00barbaz", hosts[1].community.c_str());
	LONGS_EQUAL(1, hosts[0].snmpver);
	LONGS_EQUAL(2, hosts[1].snmpver);
}

TEST(Targets, parse_example_3)
{
	RTGConf conf = read_rtg_conf("example-rtg.conf");
	std::vector<QueryHost> hosts = read_rtg_targets("example-targets.cfg", conf);
	STRINGS_EQUAL(".1.3.6.1.2.1.2.2.1.16.1001002", hosts[0].rows[0].oid.c_str());
	STRINGS_EQUAL("ifOutOctets_362", hosts[0].rows[0].table.c_str());
	LONGS_EQUAL(4309, hosts[0].rows[0].id);
	UINT64_EQUAL(285600000, hosts[0].rows[0].speed);
	LONGS_EQUAL(32, hosts[0].rows[0].bits);
}

TEST(CalculateRate, zero_rate_with_32_bits)
{
	time_t cur_time = time(NULL);
	time_t prev_time = cur_time - 60;
	uint64_t prev_counter = 1e6;
	uint64_t cur_counter = prev_counter;
	std::pair<uint64_t, uint64_t> rate = calculate_rate(prev_time, prev_counter, cur_time, cur_counter, 32);
	UINT64_EQUAL(0, rate.first);
	UINT64_EQUAL(0, rate.second);
}

TEST(CalculateRate, one_kbps_rate_with_32_bits)
{
	time_t cur_time = time(NULL);
	time_t prev_time = cur_time - 60;
	uint64_t prev_counter = 1e6;
	uint64_t cur_counter = 1e6 + 60 * 1000 / 8;
	std::pair<uint64_t, uint64_t> rate = calculate_rate(prev_time, prev_counter, cur_time, cur_counter, 32);
	UINT64_EQUAL(60 * 1000/8, rate.first);
	UINT64_EQUAL(1000/8, rate.second);
}

TEST(CalculateRate, one_kbps_counter_wrap_32_bits)
{
	time_t cur_time = time(NULL);
	time_t prev_time = cur_time - 60;
	uint32_t prev_counter = 4294967000ul;
	uint32_t cur_counter = prev_counter + 60 * 1000 / 8;
	std::pair<uint64_t, uint64_t> rate = calculate_rate(prev_time, prev_counter, cur_time, cur_counter, 32);
	UINT64_EQUAL(60 * 1000/8, rate.first);
	UINT64_EQUAL(1000/8, rate.second);
}

TEST(CalculateRate, one_kbps_counter_wrap_64_bits)
{
	time_t cur_time = time(NULL);
	time_t prev_time = cur_time - 60;
	uint64_t prev_counter = 18446744073709551000ull;
	uint64_t cur_counter = prev_counter + 60 * 1000 / 8;
	std::pair<uint64_t, uint64_t> rate = calculate_rate(prev_time, prev_counter, cur_time, cur_counter, 64);
	UINT64_EQUAL(60 * 1000/8, rate.first);
	UINT64_EQUAL(1000/8, rate.second);
}

TEST(CalculateRate, gauge_unchanged)
{
	time_t cur_time = time(NULL);
	time_t prev_time = cur_time - 60;
	uint64_t prev_counter = 1e6;
	uint64_t cur_counter = 1e6;
	std::pair<uint64_t, uint64_t> rate = calculate_rate(prev_time, prev_counter, cur_time, cur_counter, 0);
	UINT64_EQUAL(1e6, rate.first);
	UINT64_EQUAL(1e6, rate.second);
}

TEST(CalculateRate, gauge_changed)
{
	time_t cur_time = time(NULL);
	time_t prev_time = cur_time - 60;
	uint64_t prev_counter = 1e6;
	uint64_t cur_counter = 1e6 + 1000;
	std::pair<uint64_t, uint64_t> rate = calculate_rate(prev_time, prev_counter, cur_time, cur_counter, 0);
	UINT64_EQUAL(1e6 + 1000, rate.first);
	UINT64_EQUAL(1e6 + 1000, rate.second);
}

TEST(Query, one_host)
{
	RTGConf conf = read_rtg_conf("example-rtg.conf");
	std::vector<QueryHost> hosts = read_rtg_targets("example-targets.cfg", conf);
	std::map<std::string, ResultSet> rs = query(hosts[0]);
	LONGS_EQUAL(1, rs.size()); // One table
	ResultSet set = rs["ifOutOctets_362"];
	LONGS_EQUAL(2, set.rows.size()); // Two rows
	LONGS_EQUAL(4309, set.rows[0].id);
	LONGS_EQUAL(4310, set.rows[1].id);
}

#ifdef LONGTESTS
TEST(ProcessHost, one_host_one_Mbps_10_secs)
{
	mock_set_speed(1e6 / 8);
	RTGConf conf = read_rtg_conf("example-rtg.conf");
	std::vector<QueryHost> hosts = read_rtg_targets("example-targets.cfg", conf);
	ResultCache cache;
	std::vector<std::string> queries = process_host(hosts[0], cache);
	LONGS_EQUAL(0, queries.size()); // No inserts first iteration
	sleep(10);
	queries = process_host(hosts[0], cache);
	LONGS_EQUAL(1, queries.size()); // One insert next iteration
	// std::cerr << queries[0] << std::endl;
	size_t pos = queries[0].find(", 1250000, 125000)");
	CHECK(pos != std::string::npos);
	pos = queries[0].find(", 1250000, 125000)", pos+1);
	CHECK(pos != std::string::npos);
}

TEST(ProcessHost, one_host_hundred_Mbps_one_interval)
{
	mock_set_speed(100e6 / 8);
	RTGConf conf = read_rtg_conf("example-rtg.conf");
	std::vector<QueryHost> hosts = read_rtg_targets("example-targets.cfg", conf);
	ResultCache cache;
	std::vector<std::string> queries = process_host(hosts[0], cache);
	LONGS_EQUAL(0, queries.size()); // No inserts first iteration
	sleep(conf.interval);
	queries = process_host(hosts[0], cache);
	LONGS_EQUAL(0, queries.size()); // No inserts next iteration due to too high speed
}
#endif
<|endoftext|>


<commit_before>
#include <q/promise.hpp>
#include <q/lib.hpp>
#include <q/blocking_dispatcher.hpp>
#include <q/threadpool.hpp>
#include <q/execution_context.hpp>
#include <q/scheduler.hpp>
#include <q/timer.hpp>

#include <iomanip>
#include <numeric>

void print_timer( std::ostream& os, q::timer::duration_type dur, std::size_t denominator )
{
	auto ns = std::chrono::duration_cast< std::chrono::nanoseconds >( dur );
	auto float_ns = static_cast< double >( ns.count( ) );
	double partdur = float_ns / denominator;

	os
		<< std::fixed << std::setprecision( 0 )
		<< partdur << "ns (i.e. "
		<< ( 1000.0 * 1000.0 * 1000.0 ) / partdur << "/s)"
		<< std::endl;
}

void benchmark_title( const std::string& title )
{
	std::string msg = "Benchmarking: " + title;
	std::string lines( msg.size( ), '=' );

	std::cout << lines << std::endl;
	std::cout << msg << std::endl;
	std::cout << lines << std::endl;
}

q::scoped_timer make_benchmark_timer(
	q::timer::duration_type& total_dur,
	std::size_t iterations,
	std::string title
)
{
	auto fn = [ &total_dur, iterations, title ]( q::timer::duration_type dur )
	{
		total_dur += dur;

		std::cout << title << ": ";
		print_timer( std::cout, dur, iterations );
	};

	return q::scoped_timer( std::move( fn ) );
}

static inline void empty_fn( ) { }

template< template< typename > class Fn >
void benchmark_q_function( std::size_t iterations, std::string impl )
{
	benchmark_title( impl );

	q::timer::duration_type total_dur( 0 );

	{
		auto timer_scope = make_benchmark_timer(
			total_dur, iterations, "void()" );

		for ( std::size_t i = 0; i < iterations; ++i )
		{
			Fn< void( ) > fn( empty_fn );
			fn( );
		}
	}

	{
		auto timer_scope = make_benchmark_timer(
			total_dur, iterations, "Non-capturing lambda< void() >" );

		auto l = [ ]( ) { };

		for ( std::size_t i = 0; i < iterations; ++i )
		{
			Fn< void( ) > fn( l );
			fn( );
		}
	}

	{
		auto timer_scope = make_benchmark_timer(
			total_dur, iterations, "Small (16 bytes) capturing lambda< void() >" );

		typedef char cap_type[ 16 ];

		cap_type cap;
		auto l = [ cap ]( ) { };

		for ( std::size_t i = 0; i < iterations; ++i )
		{
			Fn< void( ) > fn( l );
			fn( );
		}
	}

	{
		auto timer_scope = make_benchmark_timer(
			total_dur, iterations, "Medium size (64 bytes) capturing lambda< void() >" );

		typedef char cap_type[ 64 ];

		cap_type cap;
		auto l = [ cap ]( ) { };

		for ( std::size_t i = 0; i < iterations; ++i )
		{
			Fn< void( ) > fn( l );
			fn( );
		}
	}

	{
		auto timer_scope = make_benchmark_timer(
			total_dur, iterations, "Large size (128 bytes) capturing lambda< void() >" );

		typedef char cap_type[ 128 ];

		int i = 0;

		cap_type cap;
		auto l = [ cap, &i ]( ) {
			++i;
		};

		for ( std::size_t i = 0; i < iterations; ++i )
		{
			Fn< void( ) > fn( l );
			fn( );
		}
	}

	{
		auto timer_scope = make_benchmark_timer(
			total_dur, iterations, "Large size (128 bytes) capturing lambda< void() >, copied twice" );

		typedef char cap_type[ 128 ];

		int i = 0;

		cap_type cap;
		auto l = [ cap, &i ]( ) {
			++i;
		};

		for ( std::size_t i = 0; i < iterations; ++i )
		{
			Fn< void( ) > fn( l );
			Fn< void( ) > fn2 = fn;
			Fn< void( ) > fn3 = fn2;
			fn3( );
		}
	}

	std::cout << std::endl;
}

template< typename Start, typename Stop >
void benchmark_queueing_and_scheduling( Start&& start, Stop&& stop, bool parallel, q::queue_ptr queue, std::size_t iterations )
{
	q::shared_promise< int > promise = q::with( queue, 0 ).share( );
	std::vector< q::promise< int > > waitable;
	q::promise< int > serial_promise = q::with( queue, 0 );
	waitable.reserve( iterations );

	q::timer::duration_type total_dur( 0 );

	{
		q::scoped_timer::function_type fn = [ &total_dur, iterations ]( q::timer::duration_type dur )
		{
			total_dur += dur;

			std::cout << "Queueing a task takes ";
			print_timer( std::cout, dur, iterations );
		};
		q::scoped_timer timer( std::move( fn ) );

		if ( parallel )
			for ( std::size_t i = 0; i < iterations; ++i )
				waitable.push_back(
					promise.then( [ ]( int value )
					{
						return value + 1;
					}, queue )
				);
		else
			for ( std::size_t i = 0; i < iterations; ++i )
				serial_promise = serial_promise
				.then( [ ]( int value )
				{
					return value + 1;
				}, queue );
	}

	std::size_t final = 0;
	if ( parallel )
	{
		q::scoped_timer::function_type fn = [ &total_dur, iterations ]( q::timer::duration_type dur )
		{
			total_dur += dur;

			std::cout << "Scheduling completions for " << iterations << " tasks using q::all() takes per task ";
			print_timer( std::cout, dur, iterations );
		};

		q::scoped_timer timer( std::move( fn ) );

		q::all( std::move( waitable ), queue )
		.then( [ &final, stop ]( std::vector< int >&& values )
		{
			int sum = std::accumulate( values.begin( ), values.end( ), 0 );
			final += sum;
			stop( );
		} );
	}
	else
	{
		serial_promise
		.then( [ &final, stop ]( int val )
		{
			final = val;
			stop( );
		} );
	}

	{
		q::scoped_timer::function_type fn = [ &total_dur, iterations ]( q::timer::duration_type dur )
		{
			total_dur += dur;

			std::cout << "Scheduling and running a task takes ";
			print_timer( std::cout, dur, iterations );
		};

		q::scoped_timer timer( std::move( fn ) );

		start( );
	}

	if ( final != iterations )
	{
		std::cerr
			<< "Error running benchmark, wrong amount iterations: "
			<< final << " != " << iterations << "!" << std::endl;
		return;
	}

	std::cout << "Queueing, scheduling and running takes ";
	print_timer( std::cout, total_dur, iterations );
}

void benchmark_tasks_on_main_queue( std::size_t iterations, bool parallel )
{
	auto bd2 = q::make_shared< q::blocking_dispatcher >( "test" );
	auto s2 = q::make_shared< q::direct_scheduler >( bd2 );
	auto ctx2 = q::make_shared< q::execution_context >( bd2, s2 );
	auto queue = ctx2->queue( );

	auto start = [ bd2 ]( )
	{
		bd2->start( );
	};
	auto stop = [ bd2 ]( )
	{
		bd2->terminate( q::termination::linger );
	};

	std::string in_parallel;
	if ( parallel )
		in_parallel = " in parallel";

	benchmark_title( "queueing, scheduling and running trivial tasks" + in_parallel );
	benchmark_queueing_and_scheduling( start, stop, parallel, queue, iterations );
	std::cout << std::endl;
}

void benchmark_tasks_on_threadpool( std::size_t iterations, bool parallel )
{
	auto bd2 = q::make_shared< q::blocking_dispatcher >( "test" );
	auto s2 = q::make_shared< q::direct_scheduler >( bd2 );
	auto ctx2 = q::make_shared< q::execution_context >( bd2, s2 );
	auto queue = ctx2->queue( );

	auto tp = q::make_shared< q::threadpool >( "threadpool", queue );
	auto bg_queue = q::make_shared< q::queue >( 0 );
	auto bg_sched = q::make_shared< q::direct_scheduler >( tp );

	auto start = [ tp, bd2, bg_sched, bg_queue ]( )
	{
		bg_sched->add_queue( bg_queue );
		tp->start( );
		bd2->start( );
	};
	auto stop = [ bd2, tp ]( )
	{
		bd2->terminate( q::termination::linger );
		tp->terminate( q::termination::linger );
		tp->await_termination( );
	};

	std::string in_parallel;
	if ( parallel )
		in_parallel = " in parallel";

	benchmark_title( "queueing, scheduling and running trivial tasks" + in_parallel + " on thread pool" );
	benchmark_queueing_and_scheduling( start, stop, parallel, bg_queue, iterations );
	std::cout << std::endl;
}

int main( int argc, char** argv )
{
	q::settings settings;
	settings.set_long_stack_support( true );

	auto scope = q::scoped_initialize( settings );

	auto bd = q::make_shared< q::blocking_dispatcher >( "main" );
	auto s = q::make_shared< q::direct_scheduler >( bd );
	auto ctx = q::make_shared< q::execution_context >( bd, s );
	auto qu = ctx->queue( );

	std::size_t iterations = 500 * 1000;

	auto fn_iterations = iterations * 10;

	benchmark_q_function< std::function >( fn_iterations, "std::function" );
	benchmark_q_function< q::function >( fn_iterations, "q::function" );

	benchmark_tasks_on_main_queue( iterations, true );
	benchmark_tasks_on_threadpool( iterations, true );

	benchmark_tasks_on_main_queue( iterations, false );
	benchmark_tasks_on_threadpool( iterations, false );
}
<commit_msg>[MSVC] Fixed compilation issue<commit_after>
#include <q/promise.hpp>
#include <q/lib.hpp>
#include <q/blocking_dispatcher.hpp>
#include <q/threadpool.hpp>
#include <q/execution_context.hpp>
#include <q/scheduler.hpp>
#include <q/timer.hpp>

#include <iomanip>
#include <numeric>

void print_timer( std::ostream& os, q::timer::duration_type dur, std::size_t denominator )
{
	auto ns = std::chrono::duration_cast< std::chrono::nanoseconds >( dur );
	auto float_ns = static_cast< double >( ns.count( ) );
	double partdur = float_ns / denominator;

	os
		<< std::fixed << std::setprecision( 0 )
		<< partdur << "ns (i.e. "
		<< ( 1000.0 * 1000.0 * 1000.0 ) / partdur << "/s)"
		<< std::endl;
}

void benchmark_title( const std::string& title )
{
	std::string msg = "Benchmarking: " + title;
	std::string lines( msg.size( ), '=' );

	std::cout << lines << std::endl;
	std::cout << msg << std::endl;
	std::cout << lines << std::endl;
}

q::scoped_timer make_benchmark_timer(
	q::timer::duration_type& total_dur,
	std::size_t iterations,
	std::string title
)
{
	auto fn = [ &total_dur, iterations, title ]( q::timer::duration_type dur )
	{
		total_dur += dur;

		std::cout << title << ": ";
		print_timer( std::cout, dur, iterations );
	};

	return q::scoped_timer( std::move( fn ) );
}

static inline void empty_fn( ) { }

#ifdef LIBQ_ON_WINDOWS
#	define BRACE_INIT( value ) { value }
#else
#	define BRACE_INIT( value )
#endif

template< template< typename > class Fn >
void benchmark_q_function( std::size_t iterations, std::string impl )
{
	benchmark_title( impl );

	q::timer::duration_type total_dur( 0 );

	{
		auto timer_scope = make_benchmark_timer(
			total_dur, iterations, "void()" );

		for ( std::size_t i = 0; i < iterations; ++i )
		{
			Fn< void( ) > fn( empty_fn );
			fn( );
		}
	}

	{
		auto timer_scope = make_benchmark_timer(
			total_dur, iterations, "Non-capturing lambda< void() >" );

		auto l = [ ]( ) { };

		for ( std::size_t i = 0; i < iterations; ++i )
		{
			Fn< void( ) > fn( l );
			fn( );
		}
	}

	{
		auto timer_scope = make_benchmark_timer(
			total_dur, iterations, "Small (16 bytes) capturing lambda< void() >" );

		typedef char cap_type[ 16 ];

		cap_type cap;
		auto l = [ cap BRACE_INIT( cap ) ]( ) { };

		for ( std::size_t i = 0; i < iterations; ++i )
		{
			Fn< void( ) > fn( l );
			fn( );
		}
	}

	{
		auto timer_scope = make_benchmark_timer(
			total_dur, iterations, "Medium size (64 bytes) capturing lambda< void() >" );

		typedef char cap_type[ 64 ];

		cap_type cap;
		auto l = [ cap BRACE_INIT( cap ) ]( ) { };

		for ( std::size_t i = 0; i < iterations; ++i )
		{
			Fn< void( ) > fn( l );
			fn( );
		}
	}

	{
		auto timer_scope = make_benchmark_timer(
			total_dur, iterations, "Large size (128 bytes) capturing lambda< void() >" );

		typedef char cap_type[ 128 ];

		int i = 0;

		cap_type cap;
		auto l = [ cap BRACE_INIT( cap ), &i ]( ) {
			++i;
		};

		for ( std::size_t i = 0; i < iterations; ++i )
		{
			Fn< void( ) > fn( l );
			fn( );
		}
	}

	{
		auto timer_scope = make_benchmark_timer(
			total_dur, iterations, "Large size (128 bytes) capturing lambda< void() >, copied twice" );

		typedef char cap_type[ 128 ];

		int i = 0;

		cap_type cap;
		auto l = [ cap BRACE_INIT( cap ), &i ]( ) {
			++i;
		};

		for ( std::size_t i = 0; i < iterations; ++i )
		{
			Fn< void( ) > fn( l );
			Fn< void( ) > fn2 = fn;
			Fn< void( ) > fn3 = fn2;
			fn3( );
		}
	}

	std::cout << std::endl;
}

template< typename Start, typename Stop >
void benchmark_queueing_and_scheduling( Start&& start, Stop&& stop, bool parallel, q::queue_ptr queue, std::size_t iterations )
{
	q::shared_promise< int > promise = q::with( queue, 0 ).share( );
	std::vector< q::promise< int > > waitable;
	q::promise< int > serial_promise = q::with( queue, 0 );
	waitable.reserve( iterations );

	q::timer::duration_type total_dur( 0 );

	{
		q::scoped_timer::function_type fn = [ &total_dur, iterations ]( q::timer::duration_type dur )
		{
			total_dur += dur;

			std::cout << "Queueing a task takes ";
			print_timer( std::cout, dur, iterations );
		};
		q::scoped_timer timer( std::move( fn ) );

		if ( parallel )
			for ( std::size_t i = 0; i < iterations; ++i )
				waitable.push_back(
					promise.then( [ ]( int value )
					{
						return value + 1;
					}, queue )
				);
		else
			for ( std::size_t i = 0; i < iterations; ++i )
				serial_promise = serial_promise
				.then( [ ]( int value )
				{
					return value + 1;
				}, queue );
	}

	std::size_t final = 0;
	if ( parallel )
	{
		q::scoped_timer::function_type fn = [ &total_dur, iterations ]( q::timer::duration_type dur )
		{
			total_dur += dur;

			std::cout << "Scheduling completions for " << iterations << " tasks using q::all() takes per task ";
			print_timer( std::cout, dur, iterations );
		};

		q::scoped_timer timer( std::move( fn ) );

		q::all( std::move( waitable ), queue )
		.then( [ &final, stop ]( std::vector< int >&& values )
		{
			int sum = std::accumulate( values.begin( ), values.end( ), 0 );
			final += sum;
			stop( );
		} );
	}
	else
	{
		serial_promise
		.then( [ &final, stop ]( int val )
		{
			final = val;
			stop( );
		} );
	}

	{
		q::scoped_timer::function_type fn = [ &total_dur, iterations ]( q::timer::duration_type dur )
		{
			total_dur += dur;

			std::cout << "Scheduling and running a task takes ";
			print_timer( std::cout, dur, iterations );
		};

		q::scoped_timer timer( std::move( fn ) );

		start( );
	}

	if ( final != iterations )
	{
		std::cerr
			<< "Error running benchmark, wrong amount iterations: "
			<< final << " != " << iterations << "!" << std::endl;
		return;
	}

	std::cout << "Queueing, scheduling and running takes ";
	print_timer( std::cout, total_dur, iterations );
}

void benchmark_tasks_on_main_queue( std::size_t iterations, bool parallel )
{
	auto bd2 = q::make_shared< q::blocking_dispatcher >( "test" );
	auto s2 = q::make_shared< q::direct_scheduler >( bd2 );
	auto ctx2 = q::make_shared< q::execution_context >( bd2, s2 );
	auto queue = ctx2->queue( );

	auto start = [ bd2 ]( )
	{
		bd2->start( );
	};
	auto stop = [ bd2 ]( )
	{
		bd2->terminate( q::termination::linger );
	};

	std::string in_parallel;
	if ( parallel )
		in_parallel = " in parallel";

	benchmark_title( "queueing, scheduling and running trivial tasks" + in_parallel );
	benchmark_queueing_and_scheduling( start, stop, parallel, queue, iterations );
	std::cout << std::endl;
}

void benchmark_tasks_on_threadpool( std::size_t iterations, bool parallel )
{
	auto bd2 = q::make_shared< q::blocking_dispatcher >( "test" );
	auto s2 = q::make_shared< q::direct_scheduler >( bd2 );
	auto ctx2 = q::make_shared< q::execution_context >( bd2, s2 );
	auto queue = ctx2->queue( );

	auto tp = q::make_shared< q::threadpool >( "threadpool", queue );
	auto bg_queue = q::make_shared< q::queue >( 0 );
	auto bg_sched = q::make_shared< q::direct_scheduler >( tp );

	auto start = [ tp, bd2, bg_sched, bg_queue ]( )
	{
		bg_sched->add_queue( bg_queue );
		tp->start( );
		bd2->start( );
	};
	auto stop = [ bd2, tp ]( )
	{
		bd2->terminate( q::termination::linger );
		tp->terminate( q::termination::linger );
		tp->await_termination( );
	};

	std::string in_parallel;
	if ( parallel )
		in_parallel = " in parallel";

	benchmark_title( "queueing, scheduling and running trivial tasks" + in_parallel + " on thread pool" );
	benchmark_queueing_and_scheduling( start, stop, parallel, bg_queue, iterations );
	std::cout << std::endl;
}

int main( int argc, char** argv )
{
	q::settings settings;
	settings.set_long_stack_support( true );

	auto scope = q::scoped_initialize( settings );

	auto bd = q::make_shared< q::blocking_dispatcher >( "main" );
	auto s = q::make_shared< q::direct_scheduler >( bd );
	auto ctx = q::make_shared< q::execution_context >( bd, s );
	auto qu = ctx->queue( );

	std::size_t iterations = 500 * 1000;

	auto fn_iterations = iterations * 10;

	benchmark_q_function< std::function >( fn_iterations, "std::function" );
	benchmark_q_function< q::function >( fn_iterations, "q::function" );

	benchmark_tasks_on_main_queue( iterations, true );
	benchmark_tasks_on_threadpool( iterations, true );

	benchmark_tasks_on_main_queue( iterations, false );
	benchmark_tasks_on_threadpool( iterations, false );
}
<|endoftext|>


<commit_before>#include <config.h>
#include "grid_creation.hh"

#include <dune/grid/common/gridenums.hh>

#include <dune/stuff/common/ranges.hh>
#include <dune/stuff/grid/structuredgridfactory.hh>
#include <dune/stuff/grid/information.hh>
#include <dune/multiscale/problems/selector.hh>
#include <dune/common/parallel/mpihelper.hh>

// Helper struct to make overlap for SPGrid possible
// Declared in unnamed namespace to avoid naming conflicts
namespace {
template <class GridType>
class MyGridFactory {
  typedef typename GridType::ctype ctype;
  static const int dimworld = GridType::dimensionworld;
  static const int dim = GridType::dimension;

public:
  static std::shared_ptr<GridType> createCubeGrid(const Dune::FieldVector<ctype, dimworld>& lowerLeft,
                                                  const Dune::FieldVector<ctype, dimworld>& upperRight,
                                                  const Dune::array<unsigned int, dim>& elements,
                                                  const Dune::array<unsigned int, dim>& /*overlap*/) {
    // structured grid factory allows overlap only for SPGrid at the moment, hence the following check
    BOOST_ASSERT_MSG((DSC_CONFIG_GET("msfem.oversampling_layers", 0) == 0),
                     "Oversampling may only be used in combination with SPGrid!");
    return Dune::StructuredGridFactory<GridType>::createCubeGrid(lowerLeft, upperRight, elements);
  }
};

template <class ct, int dim, Dune::SPRefinementStrategy strategy, class Comm>
class MyGridFactory<Dune::SPGrid<ct, dim, strategy, Comm>> {
  typedef Dune::SPGrid<ct, dim, strategy, Comm> GridType;
  typedef typename GridType::ctype ctype;
  static const int dimworld = GridType::dimensionworld;

public:
  static std::shared_ptr<GridType> createCubeGrid(const Dune::FieldVector<ctype, dimworld>& lowerLeft,
                                                  const Dune::FieldVector<ctype, dimworld>& upperRight,
                                                  const Dune::array<unsigned int, dim>& elements,
                                                  const Dune::array<unsigned int, dim>& overlap) {
    return Dune::StructuredGridFactory<GridType>::createCubeGrid(lowerLeft, upperRight, elements, overlap);
  }
};
}

std::pair<std::shared_ptr<Dune::Multiscale::CommonTraits::GridType>,
          std::shared_ptr<Dune::Multiscale::CommonTraits::GridType>>
Dune::Multiscale::make_grids(const bool check_partitioning) {
  BOOST_ASSERT_MSG(DSC_CONFIG.has_sub("grids"), "Parameter tree needs to have 'grids' subtree!");

  const auto gridParameterTree = DSC_CONFIG.sub("grids");
  const int dim_world = CommonTraits::GridType::dimensionworld;
  typedef CommonTraits::DomainType CoordType;
  const auto& gridCorners = Problem::getModelData()->gridCorners();
  CoordType lowerLeft = gridCorners.first;
  CoordType upperRight = gridCorners.second;

  const auto oversamplingLayers = DSC_CONFIG_GET("msfem.oversampling_layers", 0);
  const auto microPerMacro = gridParameterTree.get<CoordType>("micro_cells_per_macrocell_dim", CoordType(8), dim_world);

  const auto coarse_cells = gridParameterTree.get<CoordType>("macro_cells_per_dim", CoordType(8), dim_world);
  array<unsigned int, dim_world> elements;
  array<unsigned int, dim_world> overCoarse;
  array<unsigned int, dim_world> overFine;
  for (const auto i : DSC::valueRange(dim_world)) {
    elements[i] = coarse_cells[i];
    overCoarse[i] = std::ceil(double(oversamplingLayers) / double(microPerMacro[i]));
    overFine[i] = DSC_CONFIG_GET("grids.overlap", 1);
  }
  auto coarse_gridptr =
      MyGridFactory<CommonTraits::GridType>::createCubeGrid(lowerLeft, upperRight, elements, overCoarse);
  const auto expected_elements = std::accumulate(elements.begin(), elements.end(), 1u, std::multiplies<unsigned int>());
  auto actual_elements = coarse_gridptr->size(0);
  if (int(expected_elements) != coarse_gridptr->comm().sum(actual_elements))
    DUNE_THROW(InvalidStateException, "Wonky grid distribution");

  for (const auto i : DSC::valueRange(dim_world)) {
    elements[i] = coarse_cells[i] * microPerMacro[i];
  }
  auto fine_gridptr =
      StructuredGridFactory<CommonTraits::GridType>::createCubeGrid(lowerLeft, upperRight, elements, overFine);

  // check whether grids match (may not match after load balancing if different refinements in different
  // spatial directions are used)
  if (check_partitioning && Dune::MPIHelper::getCollectiveCommunication().size() > 1) {
    const auto coarse_dimensions =
        DSG::dimensions(coarse_gridptr->leafGridView<PartitionIteratorType::Interior_Partition>());
    const auto fine_dimensions =
        DSG::dimensions(fine_gridptr->leafGridView<PartitionIteratorType::Interior_Partition>());
    for (const auto i : DSC::valueRange(dim_world)) {
      const bool match =
          DSC::FloatCmp::eq(coarse_dimensions.coord_limits[i].min(), fine_dimensions.coord_limits[i].min()) &&
          DSC::FloatCmp::eq(coarse_dimensions.coord_limits[i].max(), fine_dimensions.coord_limits[i].max());
      if (!match)
        DUNE_THROW(InvalidStateException, "Coarse and fine mesh do not match after load balancing, do \
                       you use different refinements in different spatial dimensions?");
    }
  }

  return {coarse_gridptr, fine_gridptr};
}
<commit_msg>partion size dbg output<commit_after>#include <config.h>
#include "grid_creation.hh"

#include <dune/grid/common/gridenums.hh>

#include <dune/stuff/common/ranges.hh>
#include <dune/stuff/grid/structuredgridfactory.hh>
#include <dune/stuff/grid/information.hh>
#include <dune/multiscale/problems/selector.hh>
#include <dune/common/parallel/mpihelper.hh>

// Helper struct to make overlap for SPGrid possible
// Declared in unnamed namespace to avoid naming conflicts
namespace {
template <class GridType>
class MyGridFactory {
  typedef typename GridType::ctype ctype;
  static const int dimworld = GridType::dimensionworld;
  static const int dim = GridType::dimension;

public:
  static std::shared_ptr<GridType> createCubeGrid(const Dune::FieldVector<ctype, dimworld>& lowerLeft,
                                                  const Dune::FieldVector<ctype, dimworld>& upperRight,
                                                  const Dune::array<unsigned int, dim>& elements,
                                                  const Dune::array<unsigned int, dim>& /*overlap*/) {
    // structured grid factory allows overlap only for SPGrid at the moment, hence the following check
    BOOST_ASSERT_MSG((DSC_CONFIG_GET("msfem.oversampling_layers", 0) == 0),
                     "Oversampling may only be used in combination with SPGrid!");
    return Dune::StructuredGridFactory<GridType>::createCubeGrid(lowerLeft, upperRight, elements);
  }
};

template <class ct, int dim, Dune::SPRefinementStrategy strategy, class Comm>
class MyGridFactory<Dune::SPGrid<ct, dim, strategy, Comm>> {
  typedef Dune::SPGrid<ct, dim, strategy, Comm> GridType;
  typedef typename GridType::ctype ctype;
  static const int dimworld = GridType::dimensionworld;

public:
  static std::shared_ptr<GridType> createCubeGrid(const Dune::FieldVector<ctype, dimworld>& lowerLeft,
                                                  const Dune::FieldVector<ctype, dimworld>& upperRight,
                                                  const Dune::array<unsigned int, dim>& elements,
                                                  const Dune::array<unsigned int, dim>& overlap) {
    return Dune::StructuredGridFactory<GridType>::createCubeGrid(lowerLeft, upperRight, elements, overlap);
  }
};
}

std::pair<std::shared_ptr<Dune::Multiscale::CommonTraits::GridType>,
          std::shared_ptr<Dune::Multiscale::CommonTraits::GridType>>
Dune::Multiscale::make_grids(const bool check_partitioning) {
  BOOST_ASSERT_MSG(DSC_CONFIG.has_sub("grids"), "Parameter tree needs to have 'grids' subtree!");

  const auto gridParameterTree = DSC_CONFIG.sub("grids");
  const int dim_world = CommonTraits::GridType::dimensionworld;
  typedef CommonTraits::DomainType CoordType;
  const auto& gridCorners = Problem::getModelData()->gridCorners();
  CoordType lowerLeft = gridCorners.first;
  CoordType upperRight = gridCorners.second;

  const auto oversamplingLayers = DSC_CONFIG_GET("msfem.oversampling_layers", 0);
  const auto microPerMacro = gridParameterTree.get<CoordType>("micro_cells_per_macrocell_dim", CoordType(8), dim_world);

  const auto coarse_cells = gridParameterTree.get<CoordType>("macro_cells_per_dim", CoordType(8), dim_world);
  array<unsigned int, dim_world> elements;
  array<unsigned int, dim_world> overCoarse;
  array<unsigned int, dim_world> overFine;
  for (const auto i : DSC::valueRange(dim_world)) {
    elements[i] = coarse_cells[i];
    overCoarse[i] = std::ceil(double(oversamplingLayers) / double(microPerMacro[i]));
    overFine[i] = DSC_CONFIG_GET("grids.overlap", 1);
  }
  auto coarse_gridptr =
      MyGridFactory<CommonTraits::GridType>::createCubeGrid(lowerLeft, upperRight, elements, overCoarse);
  const auto expected_elements = std::accumulate(elements.begin(), elements.end(), 1u, std::multiplies<unsigned int>());
  auto actual_elements = coarse_gridptr->size(0);
  if (int(expected_elements) != coarse_gridptr->comm().sum(actual_elements))
    DUNE_THROW(InvalidStateException, "Wonky grid distribution");

  for (const auto i : DSC::valueRange(dim_world)) {
    elements[i] = coarse_cells[i] * microPerMacro[i];
  }
  auto fine_gridptr =
      StructuredGridFactory<CommonTraits::GridType>::createCubeGrid(lowerLeft, upperRight, elements, overFine);

  // check whether grids match (may not match after load balancing if different refinements in different
  // spatial directions are used)
  DSC_LOG_DEBUG << boost::format("Rank %d has %d coarse codim-0 elements and %d fine ones\n")
                   % coarse_gridptr->comm().rank()
                   % coarse_gridptr->size(0)
                   % fine_gridptr->size(0)
                << std::endl;
  if (check_partitioning && Dune::MPIHelper::getCollectiveCommunication().size() > 1) {
    const auto coarse_dimensions =
        DSG::dimensions(coarse_gridptr->leafGridView<PartitionIteratorType::Interior_Partition>());
    const auto fine_dimensions =
        DSG::dimensions(fine_gridptr->leafGridView<PartitionIteratorType::Interior_Partition>());
    for (const auto i : DSC::valueRange(dim_world)) {
      const bool match =
          DSC::FloatCmp::eq(coarse_dimensions.coord_limits[i].min(), fine_dimensions.coord_limits[i].min()) &&
          DSC::FloatCmp::eq(coarse_dimensions.coord_limits[i].max(), fine_dimensions.coord_limits[i].max());
      if (!match)
        DUNE_THROW(InvalidStateException, "Coarse and fine mesh do not match after load balancing, do \
                       you use different refinements in different spatial dimensions?");
    }
  }

  return {coarse_gridptr, fine_gridptr};
}
<|endoftext|>


<commit_before>// -*- coding: us-ascii-unix -*-
#include "test-sys/test.hh"
#include "geo/tri.hh"

void verify_tri(const faint::Tri& t, const faint::Point& p0, const faint::Point& p1, const faint::Point& p2){
  const auto eps = 0.001_eps;
  NEAR(t.P0().x, p0.x, eps);
  NEAR(t.P1().x, p1.x, eps);
  NEAR(t.P0().y, p0.y, eps);
  NEAR(t.P2().y, p2.y, eps);
  NEAR(t.P2().y, p2.y, eps);
}

#define VERIFY_TRI FWY(verify_tri)

void test_tri_offset_aligned(){
  using namespace faint;

  // <../../doc/test-tri-legend.png>

  {
    // <../../doc/test-tri-a-1.png>
    const Tri t({0,0}, {10,0}, {0,8});

    FWD(verify_tri(offset_aligned(t, 3.0, 2.0),
        {3.0, 2.0}, {13.0, 2.0}, {3.0, 10.0}));

    FWD(verify_tri(offset_aligned(t, -3, -2.0),
        {-3.0, -2.0}, {7.0, -2.0}, {-3.0, 6.0}));
  }

  {
    // <../../doc/test-tri-a-2.png>
    const Tri t(Point(0,0), Point(0,10), Point(-10,0));

    FWD(verify_tri(offset_aligned(t, 3.0, 2.0),
        {-2.0, 3.0}, {-2.0, 13.0}, {-12.0, 3.0}));

    FWD(verify_tri(offset_aligned(t, -3, -2.0),
        {2.0,-3.0}, {2.0,7.0}, {-8.0,-3.0}));
  }

  {
    // <../../doc/test-tri-a-3.png>
    const Tri t(Point(0,0), Point(-10,0), Point(0,-8));

    FWD(verify_tri(offset_aligned(t, 3.0, 2.0),
        {-3,-2}, {-13,-2}, {-3,-10}));

    FWD(verify_tri(offset_aligned(t, -3, -2.0),
        {3,2}, {-7,2}, {3,-6}));
  }

  {
    // <../../doc/test-tri-a-4.png>
    const Tri t(Point(0,0), Point(0,-10), Point(8,0));

    FWD(verify_tri(offset_aligned(t, 3.0, 2.0),
        {2.0, -3.0}, {2.0, -13.0}, {10.0,-3.0}));

    FWD(verify_tri(offset_aligned(t, -3, -2.0),
        {-2.0, 3.0}, {-2.0,-7.0}, {6.0,3.0}));
  }

  {
    // <../../doc/test-tri-b-1.png>
    const Tri t(Point(0,0), Point(-10,0), Point(0,8));

    FWD(verify_tri(offset_aligned(t, 3.0, 2.0),
        {-3.0, 2.0}, {-13.0, 2.0}, {-3.0, 10.0}));

    FWD(verify_tri(offset_aligned(t, -3, -2.0),
        {3.0, -2.0}, {-7.0, -2.0}, {3.0, 6.0}));
  }

  {
    // <../../doc/test-tri-b-2.png>
    const Tri t(Point(0,0), Point(0,-10), Point(-8,0));

    FWD(verify_tri(offset_aligned(t, 3.0, 2.0),
        {-2.0,-3.0}, {-2.0, -13.0}, {-10.0,-3.0}));

    FWD(verify_tri(offset_aligned(t, -3, -2.0),
        {2.0, 3.0}, {2.0, -7.0}, {-6.0, 3.0}));
  }

  {
    // <../../doc/test-tri-b-3.png>
    const Tri t(Point(0,0), Point(10,0), Point(0,-8));

    FWD(verify_tri(offset_aligned(t, 3.0, 2.0),
        {3.0, -2.0}, {13.0, -2.0}, {3.0, -10.0}));

    FWD(verify_tri(offset_aligned(t, -3, -2.0),
        {-3.0, 2.0}, {7.0, 2.0}, {-3.0, -6.0}));
  }

  {
    // <../../doc/test-tri-b-4.png>
    const Tri t(Point(0, 0), Point(0, 10), Point(8, 0));

    FWD(verify_tri(offset_aligned(t, 3.0, 2.0),
        {2.0, 3.0}, {2.0, 13.0}, {10.0, 3.0}));

    FWD(verify_tri(offset_aligned(t, -3, -2.0),
        {-2.0, -3.0}, {-2.0, 7.0}, {6.0, -3.0}));
  }
}
<commit_msg>Cleaned up a test a little.<commit_after>// -*- coding: us-ascii-unix -*-
#include "test-sys/test.hh"
#include "geo/tri.hh"

static void verify_tri(const faint::Tri& t,
  const faint::Point& p0,
  const faint::Point& p1,
  const faint::Point& p2)
{
  const auto eps = 0.001_eps;
  NEAR(t.P0().x, p0.x, eps);
  NEAR(t.P1().x, p1.x, eps);
  NEAR(t.P0().y, p0.y, eps);
  NEAR(t.P2().y, p2.y, eps);
  NEAR(t.P2().y, p2.y, eps);
}

void test_tri_offset_aligned(){
  using namespace faint;

  // <../../doc/test-tri-legend.png>

  {
    // <../../doc/test-tri-a-1.png>
    const Tri t({0,0}, {10,0}, {0,8});

    FWD(verify_tri(offset_aligned(t, 3.0, 2.0),
        {3.0, 2.0}, {13.0, 2.0}, {3.0, 10.0}));

    FWD(verify_tri(offset_aligned(t, -3, -2.0),
        {-3.0, -2.0}, {7.0, -2.0}, {-3.0, 6.0}));
  }

  {
    // <../../doc/test-tri-a-2.png>
    const Tri t(Point(0,0), Point(0,10), Point(-10,0));

    FWD(verify_tri(offset_aligned(t, 3.0, 2.0),
        {-2.0, 3.0}, {-2.0, 13.0}, {-12.0, 3.0}));

    FWD(verify_tri(offset_aligned(t, -3, -2.0),
        {2.0,-3.0}, {2.0,7.0}, {-8.0,-3.0}));
  }

  {
    // <../../doc/test-tri-a-3.png>
    const Tri t(Point(0,0), Point(-10,0), Point(0,-8));

    FWD(verify_tri(offset_aligned(t, 3.0, 2.0),
        {-3,-2}, {-13,-2}, {-3,-10}));

    FWD(verify_tri(offset_aligned(t, -3, -2.0),
        {3,2}, {-7,2}, {3,-6}));
  }

  {
    // <../../doc/test-tri-a-4.png>
    const Tri t(Point(0,0), Point(0,-10), Point(8,0));

    FWD(verify_tri(offset_aligned(t, 3.0, 2.0),
        {2.0, -3.0}, {2.0, -13.0}, {10.0,-3.0}));

    FWD(verify_tri(offset_aligned(t, -3, -2.0),
        {-2.0, 3.0}, {-2.0,-7.0}, {6.0,3.0}));
  }

  {
    // <../../doc/test-tri-b-1.png>
    const Tri t(Point(0,0), Point(-10,0), Point(0,8));

    FWD(verify_tri(offset_aligned(t, 3.0, 2.0),
        {-3.0, 2.0}, {-13.0, 2.0}, {-3.0, 10.0}));

    FWD(verify_tri(offset_aligned(t, -3, -2.0),
        {3.0, -2.0}, {-7.0, -2.0}, {3.0, 6.0}));
  }

  {
    // <../../doc/test-tri-b-2.png>
    const Tri t(Point(0,0), Point(0,-10), Point(-8,0));

    FWD(verify_tri(offset_aligned(t, 3.0, 2.0),
        {-2.0,-3.0}, {-2.0, -13.0}, {-10.0,-3.0}));

    FWD(verify_tri(offset_aligned(t, -3, -2.0),
        {2.0, 3.0}, {2.0, -7.0}, {-6.0, 3.0}));
  }

  {
    // <../../doc/test-tri-b-3.png>
    const Tri t(Point(0,0), Point(10,0), Point(0,-8));

    FWD(verify_tri(offset_aligned(t, 3.0, 2.0),
        {3.0, -2.0}, {13.0, -2.0}, {3.0, -10.0}));

    FWD(verify_tri(offset_aligned(t, -3, -2.0),
        {-3.0, 2.0}, {7.0, 2.0}, {-3.0, -6.0}));
  }

  {
    // <../../doc/test-tri-b-4.png>
    const Tri t(Point(0, 0), Point(0, 10), Point(8, 0));

    FWD(verify_tri(offset_aligned(t, 3.0, 2.0),
        {2.0, 3.0}, {2.0, 13.0}, {10.0, 3.0}));

    FWD(verify_tri(offset_aligned(t, -3, -2.0),
        {-2.0, -3.0}, {-2.0, 7.0}, {6.0, -3.0}));
  }
}
<|endoftext|>


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

#include "MacroExpander.h"

#include <algorithm>
#include <sstream>

#include "Diagnostics.h"
#include "Token.h"

namespace pp
{

class TokenLexer : public Lexer
{
 public:
	typedef std::vector<Token> TokenVector;

	TokenLexer(TokenVector* tokens)
	{
		tokens->swap(mTokens);
		mIter = mTokens.begin();
	}

	virtual void lex(Token* token)
	{
		if (mIter == mTokens.end())
		{
			token->reset();
			token->type = Token::LAST;
		}
		else
		{
			*token = *mIter++;
		}
	}

 private:
	PP_DISALLOW_COPY_AND_ASSIGN(TokenLexer);

	TokenVector mTokens;
	TokenVector::const_iterator mIter;
};

MacroExpander::MacroExpander(Lexer* lexer,
                             MacroSet* macroSet,
                             Diagnostics* diagnostics,
                             bool parseDefined) :
	mLexer(lexer), mMacroSet(macroSet), mDiagnostics(diagnostics), mParseDefined(parseDefined)
{
	mReserveToken = nullptr;
}

MacroExpander::~MacroExpander()
{
	for (size_t i = 0; i < mContextStack.size(); ++i)
	{
		delete mContextStack[i];
	}

	delete mReserveToken;
}

void MacroExpander::lex(Token* token)
{
	while (true)
	{
		getToken(token);

		if (token->type != Token::IDENTIFIER)
			break;

		// Defined operator is parsed here since it may be generated by macro expansion.
		// Defined operator produced by macro expansion has undefined behavior according to C++
		// spec, which the GLSL spec references (see C++14 draft spec section 16.1.4), but this
		// behavior is needed for passing dEQP tests, which enforce stricter compatibility between
		// implementations.
		if (mParseDefined && token->text == "defined")
		{
			bool paren = false;
			getToken(token);
			if (token->type == '(')
			{
				paren = true;
				getToken(token);
			}
			if (token->type != Token::IDENTIFIER)
			{
				mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, token->location,
				                     token->text);
				break;
			}
			auto iter = mMacroSet->find(token->text);
			std::string expression = iter != mMacroSet->end() ? "1" : "0";

			if (paren)
			{
				getToken(token);
				if (token->type != ')')
				{
					mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, token->location,
					                     token->text);
					break;
				}
			}

			// We have a valid defined operator.
			// Convert the current token into a CONST_INT token.
			token->type = Token::CONST_INT;
			token->text = expression;
			break;
		}

		if (token->expansionDisabled())
			break;

		MacroSet::const_iterator iter = mMacroSet->find(token->text);
		if (iter == mMacroSet->end())
			break;

		const Macro& macro = iter->second;
		if (macro.disabled)
		{
			// If a particular token is not expanded, it is never expanded.
			token->setExpansionDisabled(true);
			break;
		}
		if ((macro.type == Macro::kTypeFunc) && !isNextTokenLeftParen())
		{
			// If the token immediately after the macro name is not a '(',
			// this macro should not be expanded.
			break;
		}

		pushMacro(macro, *token);
	}
}

void MacroExpander::getToken(Token* token)
{
	if (mReserveToken)
	{
		*token = *mReserveToken;
		delete mReserveToken;
		return;
	}

	// First pop all empty macro contexts.
	while (!mContextStack.empty() && mContextStack.back()->empty())
	{
		popMacro();
	}

	if (!mContextStack.empty())
	{
		*token = mContextStack.back()->get();
	}
	else
	{
		mLexer->lex(token);
	}
}

void MacroExpander::ungetToken(const Token& token)
{
	if (!mContextStack.empty())
	{
		MacroContext* context = mContextStack.back();
		context->unget();
		assert(context->replacements[context->index] == token);
	}
	else
	{
		assert(!mReserveToken);
		mReserveToken = new Token(token);
	}
}

bool MacroExpander::isNextTokenLeftParen()
{
	Token token;
	getToken(&token);

	bool lparen = token.type == '(';
	ungetToken(token);

	return lparen;
}

bool MacroExpander::pushMacro(const Macro& macro, const Token& identifier)
{
	assert(!macro.disabled);
	assert(!identifier.expansionDisabled());
	assert(identifier.type == Token::IDENTIFIER);
	assert(identifier.text == macro.name);

	std::vector<Token> replacements;
	if (!expandMacro(macro, identifier, &replacements))
		return false;

	// Macro is disabled for expansion until it is popped off the stack.
	macro.disabled = true;

	MacroContext* context = new MacroContext;
	context->macro = &macro;
	context->replacements.swap(replacements);
	mContextStack.push_back(context);
	return true;
}

void MacroExpander::popMacro()
{
	assert(!mContextStack.empty());

	MacroContext* context = mContextStack.back();
	mContextStack.pop_back();

	assert(context->empty());
	assert(context->macro->disabled);
	context->macro->disabled = false;
	delete context;
}

bool MacroExpander::expandMacro(const Macro& macro,
                                const Token& identifier,
                                std::vector<Token>* replacements)
{
	replacements->clear();
	if (macro.type == Macro::kTypeObj)
	{
		replacements->assign(macro.replacements.begin(),
		                     macro.replacements.end());

		if (macro.predefined)
		{
			static const std::string kLine = "__LINE__";
			static const std::string kFile = "__FILE__";

			assert(replacements->size() == 1);
			Token& repl = replacements->front();
			if (macro.name == kLine)
			{
				std::ostringstream stream;
				stream << identifier.location.line;
				repl.text = stream.str();
			}
			else if (macro.name == kFile)
			{
				std::ostringstream stream;
				stream << identifier.location.file;
				repl.text = stream.str();
			}
		}
	}
	else
	{
		assert(macro.type == Macro::kTypeFunc);
		std::vector<MacroArg> args;
		args.reserve(macro.parameters.size());
		if (!collectMacroArgs(macro, identifier, &args))
			return false;

		replaceMacroParams(macro, args, replacements);
	}

	for (size_t i = 0; i < replacements->size(); ++i)
	{
		Token& repl = replacements->at(i);
		if (i == 0)
		{
			// The first token in the replacement list inherits the padding
			// properties of the identifier token.
			repl.setAtStartOfLine(identifier.atStartOfLine());
			repl.setHasLeadingSpace(identifier.hasLeadingSpace());
		}
		repl.location = identifier.location;
	}
	return true;
}

bool MacroExpander::collectMacroArgs(const Macro& macro,
                                     const Token& identifier,
                                     std::vector<MacroArg>* args)
{
	Token token;
	getToken(&token);
	assert(token.type == '(');

	args->push_back(MacroArg());
	for (int openParens = 1; openParens != 0; )
	{
		getToken(&token);

		if (token.type == Token::LAST)
		{
			mDiagnostics->report(Diagnostics::MACRO_UNTERMINATED_INVOCATION,
			                     identifier.location, identifier.text);
			// Do not lose EOF token.
			ungetToken(token);
			return false;
		}

		bool isArg = false; // True if token is part of the current argument.
		switch (token.type)
		{
		case '(':
			++openParens;
			isArg = true;
			break;
		case ')':
			--openParens;
			isArg = openParens != 0;
			break;
		case ',':
			// The individual arguments are separated by comma tokens, but
			// the comma tokens between matching inner parentheses do not
			// seperate arguments.
			if (openParens == 1) args->push_back(MacroArg());
			isArg = openParens != 1;
			break;
		default:
			isArg = true;
			break;
		}
		if (isArg)
		{
			MacroArg& arg = args->back();
			// Initial whitespace is not part of the argument.
			if (arg.empty()) token.setHasLeadingSpace(false);
			arg.push_back(token);
		}
	}

	const Macro::Parameters& params = macro.parameters;
	// If there is only one empty argument, it is equivalent to no argument.
	if (params.empty() && (args->size() == 1) && args->front().empty())
	{
		args->clear();
	}
	// Validate the number of arguments.
	if (args->size() != params.size())
	{
		Diagnostics::ID id = args->size() < macro.parameters.size() ?
			Diagnostics::MACRO_TOO_FEW_ARGS :
			Diagnostics::MACRO_TOO_MANY_ARGS;
		mDiagnostics->report(id, identifier.location, identifier.text);
		return false;
	}

	// Pre-expand each argument before substitution.
	// This step expands each argument individually before they are
	// inserted into the macro body.
	for (size_t i = 0; i < args->size(); ++i)
	{
		MacroArg& arg = args->at(i);
		TokenLexer lexer(&arg);
		MacroExpander expander(&lexer, mMacroSet, mDiagnostics, mParseDefined);

		arg.clear();
		expander.lex(&token);
		while (token.type != Token::LAST)
		{
			arg.push_back(token);
			expander.lex(&token);
		}
	}
	return true;
}

void MacroExpander::replaceMacroParams(const Macro& macro,
                                       const std::vector<MacroArg>& args,
                                       std::vector<Token>* replacements)
{
	for (size_t i = 0; i < macro.replacements.size(); ++i)
	{
		const Token& repl = macro.replacements[i];
		if (repl.type != Token::IDENTIFIER)
		{
			replacements->push_back(repl);
			continue;
		}

		// TODO(alokp): Optimize this.
		// There is no need to search for macro params every time.
		// The param index can be cached with the replacement token.
		Macro::Parameters::const_iterator iter = std::find(
			macro.parameters.begin(), macro.parameters.end(), repl.text);
		if (iter == macro.parameters.end())
		{
			replacements->push_back(repl);
			continue;
		}

		size_t iArg = std::distance(macro.parameters.begin(), iter);
		const MacroArg& arg = args[iArg];
		if (arg.empty())
		{
			continue;
		}
		size_t iRepl = replacements->size();
		replacements->insert(replacements->end(), arg.begin(), arg.end());
		// The replacement token inherits padding properties from
		// macro replacement token.
		replacements->at(iRepl).setHasLeadingSpace(repl.hasLeadingSpace());
	}
}

}  // namespace pp

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

#include "MacroExpander.h"

#include <algorithm>
#include <sstream>

#include "Diagnostics.h"
#include "Token.h"

namespace pp
{

class TokenLexer : public Lexer
{
 public:
	typedef std::vector<Token> TokenVector;

	TokenLexer(TokenVector* tokens)
	{
		tokens->swap(mTokens);
		mIter = mTokens.begin();
	}

	virtual void lex(Token* token)
	{
		if (mIter == mTokens.end())
		{
			token->reset();
			token->type = Token::LAST;
		}
		else
		{
			*token = *mIter++;
		}
	}

 private:
	PP_DISALLOW_COPY_AND_ASSIGN(TokenLexer);

	TokenVector mTokens;
	TokenVector::const_iterator mIter;
};

MacroExpander::MacroExpander(Lexer* lexer,
                             MacroSet* macroSet,
                             Diagnostics* diagnostics,
                             bool parseDefined) :
	mLexer(lexer), mMacroSet(macroSet), mDiagnostics(diagnostics), mParseDefined(parseDefined)
{
	mReserveToken = nullptr;
}

MacroExpander::~MacroExpander()
{
	for (size_t i = 0; i < mContextStack.size(); ++i)
	{
		delete mContextStack[i];
	}

	delete mReserveToken;
}

void MacroExpander::lex(Token* token)
{
	while (true)
	{
		getToken(token);

		if (token->type != Token::IDENTIFIER)
			break;

		// Defined operator is parsed here since it may be generated by macro expansion.
		// Defined operator produced by macro expansion has undefined behavior according to C++
		// spec, which the GLSL spec references (see C++14 draft spec section 16.1.4), but this
		// behavior is needed for passing dEQP tests, which enforce stricter compatibility between
		// implementations.
		if (mParseDefined && token->text == "defined")
		{
			bool paren = false;
			getToken(token);
			if (token->type == '(')
			{
				paren = true;
				getToken(token);
			}
			if (token->type != Token::IDENTIFIER)
			{
				mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, token->location,
				                     token->text);
				break;
			}
			auto iter = mMacroSet->find(token->text);
			std::string expression = iter != mMacroSet->end() ? "1" : "0";

			if (paren)
			{
				getToken(token);
				if (token->type != ')')
				{
					mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, token->location,
					                     token->text);
					break;
				}
			}

			// We have a valid defined operator.
			// Convert the current token into a CONST_INT token.
			token->type = Token::CONST_INT;
			token->text = expression;
			break;
		}

		if (token->expansionDisabled())
			break;

		MacroSet::const_iterator iter = mMacroSet->find(token->text);
		if (iter == mMacroSet->end())
			break;

		const Macro& macro = iter->second;
		if (macro.disabled)
		{
			// If a particular token is not expanded, it is never expanded.
			token->setExpansionDisabled(true);
			break;
		}
		if ((macro.type == Macro::kTypeFunc) && !isNextTokenLeftParen())
		{
			// If the token immediately after the macro name is not a '(',
			// this macro should not be expanded.
			break;
		}

		pushMacro(macro, *token);
	}
}

void MacroExpander::getToken(Token* token)
{
	if (mReserveToken)
	{
		*token = *mReserveToken;
		delete mReserveToken;
		mReserveToken = nullptr;
		return;
	}

	// First pop all empty macro contexts.
	while (!mContextStack.empty() && mContextStack.back()->empty())
	{
		popMacro();
	}

	if (!mContextStack.empty())
	{
		*token = mContextStack.back()->get();
	}
	else
	{
		mLexer->lex(token);
	}
}

void MacroExpander::ungetToken(const Token& token)
{
	if (!mContextStack.empty())
	{
		MacroContext* context = mContextStack.back();
		context->unget();
		assert(context->replacements[context->index] == token);
	}
	else
	{
		assert(!mReserveToken);
		mReserveToken = new Token(token);
	}
}

bool MacroExpander::isNextTokenLeftParen()
{
	Token token;
	getToken(&token);

	bool lparen = token.type == '(';
	ungetToken(token);

	return lparen;
}

bool MacroExpander::pushMacro(const Macro& macro, const Token& identifier)
{
	assert(!macro.disabled);
	assert(!identifier.expansionDisabled());
	assert(identifier.type == Token::IDENTIFIER);
	assert(identifier.text == macro.name);

	std::vector<Token> replacements;
	if (!expandMacro(macro, identifier, &replacements))
		return false;

	// Macro is disabled for expansion until it is popped off the stack.
	macro.disabled = true;

	MacroContext* context = new MacroContext;
	context->macro = &macro;
	context->replacements.swap(replacements);
	mContextStack.push_back(context);
	return true;
}

void MacroExpander::popMacro()
{
	assert(!mContextStack.empty());

	MacroContext* context = mContextStack.back();
	mContextStack.pop_back();

	assert(context->empty());
	assert(context->macro->disabled);
	context->macro->disabled = false;
	delete context;
}

bool MacroExpander::expandMacro(const Macro& macro,
                                const Token& identifier,
                                std::vector<Token>* replacements)
{
	replacements->clear();
	if (macro.type == Macro::kTypeObj)
	{
		replacements->assign(macro.replacements.begin(),
		                     macro.replacements.end());

		if (macro.predefined)
		{
			static const std::string kLine = "__LINE__";
			static const std::string kFile = "__FILE__";

			assert(replacements->size() == 1);
			Token& repl = replacements->front();
			if (macro.name == kLine)
			{
				std::ostringstream stream;
				stream << identifier.location.line;
				repl.text = stream.str();
			}
			else if (macro.name == kFile)
			{
				std::ostringstream stream;
				stream << identifier.location.file;
				repl.text = stream.str();
			}
		}
	}
	else
	{
		assert(macro.type == Macro::kTypeFunc);
		std::vector<MacroArg> args;
		args.reserve(macro.parameters.size());
		if (!collectMacroArgs(macro, identifier, &args))
			return false;

		replaceMacroParams(macro, args, replacements);
	}

	for (size_t i = 0; i < replacements->size(); ++i)
	{
		Token& repl = replacements->at(i);
		if (i == 0)
		{
			// The first token in the replacement list inherits the padding
			// properties of the identifier token.
			repl.setAtStartOfLine(identifier.atStartOfLine());
			repl.setHasLeadingSpace(identifier.hasLeadingSpace());
		}
		repl.location = identifier.location;
	}
	return true;
}

bool MacroExpander::collectMacroArgs(const Macro& macro,
                                     const Token& identifier,
                                     std::vector<MacroArg>* args)
{
	Token token;
	getToken(&token);
	assert(token.type == '(');

	args->push_back(MacroArg());
	for (int openParens = 1; openParens != 0; )
	{
		getToken(&token);

		if (token.type == Token::LAST)
		{
			mDiagnostics->report(Diagnostics::MACRO_UNTERMINATED_INVOCATION,
			                     identifier.location, identifier.text);
			// Do not lose EOF token.
			ungetToken(token);
			return false;
		}

		bool isArg = false; // True if token is part of the current argument.
		switch (token.type)
		{
		case '(':
			++openParens;
			isArg = true;
			break;
		case ')':
			--openParens;
			isArg = openParens != 0;
			break;
		case ',':
			// The individual arguments are separated by comma tokens, but
			// the comma tokens between matching inner parentheses do not
			// seperate arguments.
			if (openParens == 1) args->push_back(MacroArg());
			isArg = openParens != 1;
			break;
		default:
			isArg = true;
			break;
		}
		if (isArg)
		{
			MacroArg& arg = args->back();
			// Initial whitespace is not part of the argument.
			if (arg.empty()) token.setHasLeadingSpace(false);
			arg.push_back(token);
		}
	}

	const Macro::Parameters& params = macro.parameters;
	// If there is only one empty argument, it is equivalent to no argument.
	if (params.empty() && (args->size() == 1) && args->front().empty())
	{
		args->clear();
	}
	// Validate the number of arguments.
	if (args->size() != params.size())
	{
		Diagnostics::ID id = args->size() < macro.parameters.size() ?
			Diagnostics::MACRO_TOO_FEW_ARGS :
			Diagnostics::MACRO_TOO_MANY_ARGS;
		mDiagnostics->report(id, identifier.location, identifier.text);
		return false;
	}

	// Pre-expand each argument before substitution.
	// This step expands each argument individually before they are
	// inserted into the macro body.
	for (size_t i = 0; i < args->size(); ++i)
	{
		MacroArg& arg = args->at(i);
		TokenLexer lexer(&arg);
		MacroExpander expander(&lexer, mMacroSet, mDiagnostics, mParseDefined);

		arg.clear();
		expander.lex(&token);
		while (token.type != Token::LAST)
		{
			arg.push_back(token);
			expander.lex(&token);
		}
	}
	return true;
}

void MacroExpander::replaceMacroParams(const Macro& macro,
                                       const std::vector<MacroArg>& args,
                                       std::vector<Token>* replacements)
{
	for (size_t i = 0; i < macro.replacements.size(); ++i)
	{
		const Token& repl = macro.replacements[i];
		if (repl.type != Token::IDENTIFIER)
		{
			replacements->push_back(repl);
			continue;
		}

		// TODO(alokp): Optimize this.
		// There is no need to search for macro params every time.
		// The param index can be cached with the replacement token.
		Macro::Parameters::const_iterator iter = std::find(
			macro.parameters.begin(), macro.parameters.end(), repl.text);
		if (iter == macro.parameters.end())
		{
			replacements->push_back(repl);
			continue;
		}

		size_t iArg = std::distance(macro.parameters.begin(), iter);
		const MacroArg& arg = args[iArg];
		if (arg.empty())
		{
			continue;
		}
		size_t iRepl = replacements->size();
		replacements->insert(replacements->end(), arg.begin(), arg.end());
		// The replacement token inherits padding properties from
		// macro replacement token.
		replacements->at(iRepl).setHasLeadingSpace(repl.hasLeadingSpace());
	}
}

}  // namespace pp

<|endoftext|>


<commit_before>#include "stdafx.h"

#include "P23.MetaTrader4.Manager.ClrWrapper.h"

IList<P23::MetaTrader4::Manager::Contracts::BackupInfo^>^ P23::MetaTrader4::Manager::ClrWrapper::BackupInfoUsers(int mode)
{
	IList<P23::MetaTrader4::Manager::Contracts::BackupInfo^>^ output = gcnew List<P23::MetaTrader4::Manager::Contracts::BackupInfo^>();
	int total = 0;
	BackupInfo* result = _manager->Manager->BackupInfoUsers(mode, &total);
	for (int i = 0; i < total; i++)
		output->Add(Convert(&result[i]));

	_manager->Manager->MemFree(result);

	return output;
}

IList<P23::MetaTrader4::Manager::Contracts::BackupInfo^>^  P23::MetaTrader4::Manager::ClrWrapper::BackupInfoOrders(int mode)
{

	IList<P23::MetaTrader4::Manager::Contracts::BackupInfo^>^ output = gcnew List<P23::MetaTrader4::Manager::Contracts::BackupInfo^>();
	int total = 0;
	BackupInfo* result = _manager->Manager->BackupInfoOrders(mode, &total);
	for (int i = 0; i < total; i++)
		output->Add(Convert(&result[i]));

	_manager->Manager->MemFree(result);

	return output;
}

IList<P23::MetaTrader4::Manager::Contracts::UserRecord^>^  P23::MetaTrader4::Manager::ClrWrapper::BackupRequestUsers(String^ file, String^ request)
{
	IList<P23::MetaTrader4::Manager::Contracts::UserRecord^>^ output = gcnew List<P23::MetaTrader4::Manager::Contracts::UserRecord^>();
	int total = 0;

	char* f = Convert(file);
	char* r = Convert(request);
	if (f == NULL || r == NULL)
		throw gcnew ArgumentException("File and request mandatory parameters");

	UserRecord* result = _manager->Manager->BackupRequestUsers(f, r, &total);
	for (int i = 0; i < total; i++)
		output->Add(Convert(&result[i]));

	_manager->Manager->MemFree(result);

	return output;
}

IList<P23::MetaTrader4::Manager::Contracts::TradeRecord^>^ P23::MetaTrader4::Manager::ClrWrapper::BackupRequestOrders(String^ file, String^ request)
{
	IList<P23::MetaTrader4::Manager::Contracts::TradeRecord^>^ output = gcnew List<P23::MetaTrader4::Manager::Contracts::TradeRecord^>();
	int total = 0;

	char* f = Convert(file);
	char* r = Convert(request);
	if (f == NULL || r == NULL)
		throw gcnew ArgumentException("File and request mandatory parameters");

	TradeRecord* result = _manager->Manager->BackupRequestOrders(f, r, &total);
	for (int i = 0; i < total; i++)
		output->Add(Convert(&result[i]));

	_manager->Manager->MemFree(result);

	return output;
}

int P23::MetaTrader4::Manager::ClrWrapper::BackupRestoreUsers(IList<P23::MetaTrader4::Manager::Contracts::UserRecord^>^ users)
{
	int total = 0;

	UserRecord* u = new UserRecord[users->Count];
	for (int i = 0; i < users->Count; i++)
		u[i] = *Convert(users[i]);

	return _manager->Manager->BackupRestoreUsers(u, total);
}

IList<P23::MetaTrader4::Manager::Contracts::TradeRestoreResult^>^ P23::MetaTrader4::Manager::ClrWrapper::BackupRestoreOrders(IList<P23::MetaTrader4::Manager::Contracts::TradeRecord^>^ trades)
{
	int total = trades->Count;

	TradeRecord* t = new TradeRecord[total];
	for (int i = 0; i < total; i++)
		t[i] = *Convert(trades[i]);

	TradeRestoreResult* result = _manager->Manager->BackupRestoreOrders(t, &total);

	IList<P23::MetaTrader4::Manager::Contracts::TradeRestoreResult^>^ output = gcnew List<P23::MetaTrader4::Manager::Contracts::TradeRestoreResult^>();
	for (int i = 0; i < total; i++)
		output->Add(Convert(&result[i]));

	_manager->Manager->MemFree(result);

	return output;
}<commit_msg>File Backups<commit_after>#include "stdafx.h"

#include "P23.MetaTrader4.Manager.ClrWrapper.h"

IList<P23::MetaTrader4::Manager::Contracts::BackupInfo^>^ P23::MetaTrader4::Manager::ClrWrapper::BackupInfoUsers(int mode)
{
	IList<P23::MetaTrader4::Manager::Contracts::BackupInfo^>^ output = gcnew List<P23::MetaTrader4::Manager::Contracts::BackupInfo^>();
	int total = 0;
	BackupInfo* result = _manager->Manager->BackupInfoUsers(mode, &total);
	for (int i = 0; i < total; i++)
		output->Add(Convert(&result[i]));

	_manager->Manager->MemFree(result);

	return output;
}

IList<P23::MetaTrader4::Manager::Contracts::BackupInfo^>^  P23::MetaTrader4::Manager::ClrWrapper::BackupInfoOrders(int mode)
{

	IList<P23::MetaTrader4::Manager::Contracts::BackupInfo^>^ output = gcnew List<P23::MetaTrader4::Manager::Contracts::BackupInfo^>();
	int total = 0;
	BackupInfo* result = _manager->Manager->BackupInfoOrders(mode, &total);
	for (int i = 0; i < total; i++)
		output->Add(Convert(&result[i]));

	_manager->Manager->MemFree(result);

	return output;
}

IList<P23::MetaTrader4::Manager::Contracts::UserRecord^>^  P23::MetaTrader4::Manager::ClrWrapper::BackupRequestUsers(String^ file, String^ request)
{
	IList<P23::MetaTrader4::Manager::Contracts::UserRecord^>^ output = gcnew List<P23::MetaTrader4::Manager::Contracts::UserRecord^>();
	int total = 0;

	char* f = Convert(file);
	char* r = Convert(request);
	if (f == NULL || r == NULL)
		throw gcnew ArgumentException("File and request mandatory parameters");

	UserRecord* result = _manager->Manager->BackupRequestUsers(f, r, &total);
	for (int i = 0; i < total; i++)
		output->Add(Convert(&result[i]));

	_manager->Manager->MemFree(result);
	Marshal::FreeHGlobal(IntPtr(f));
	Marshal::FreeHGlobal(IntPtr(r));

	return output;
}

IList<P23::MetaTrader4::Manager::Contracts::TradeRecord^>^ P23::MetaTrader4::Manager::ClrWrapper::BackupRequestOrders(String^ file, String^ request)
{
	IList<P23::MetaTrader4::Manager::Contracts::TradeRecord^>^ output = gcnew List<P23::MetaTrader4::Manager::Contracts::TradeRecord^>();
	int total = 0;

	char* f = Convert(file);
	char* r = Convert(request);
	if (f == NULL || r == NULL)
		throw gcnew ArgumentException("File and request mandatory parameters");

	TradeRecord* result = _manager->Manager->BackupRequestOrders(f, r, &total);
	for (int i = 0; i < total; i++)
		output->Add(Convert(&result[i]));

	_manager->Manager->MemFree(result);
	Marshal::FreeHGlobal(IntPtr(f));
	Marshal::FreeHGlobal(IntPtr(r));

	return output;
}

int P23::MetaTrader4::Manager::ClrWrapper::BackupRestoreUsers(IList<P23::MetaTrader4::Manager::Contracts::UserRecord^>^ users)
{
	int total = 0;

	UserRecord* u = new UserRecord[users->Count];
	for (int i = 0; i < users->Count; i++)
		u[i] = *Convert(users[i]);

	int result = _manager->Manager->BackupRestoreUsers(u, total);

	delete[] u;

	return result
}

IList<P23::MetaTrader4::Manager::Contracts::TradeRestoreResult^>^ P23::MetaTrader4::Manager::ClrWrapper::BackupRestoreOrders(IList<P23::MetaTrader4::Manager::Contracts::TradeRecord^>^ trades)
{
	int total = trades->Count;

	TradeRecord* t = new TradeRecord[total];
	for (int i = 0; i < total; i++)
		t[i] = *Convert(trades[i]);

	TradeRestoreResult* result = _manager->Manager->BackupRestoreOrders(t, &total);

	IList<P23::MetaTrader4::Manager::Contracts::TradeRestoreResult^>^ output = gcnew List<P23::MetaTrader4::Manager::Contracts::TradeRestoreResult^>();
	for (int i = 0; i < total; i++)
		output->Add(Convert(&result[i]));

	_manager->Manager->MemFree(result);
	delete[] t;

	return output;
}<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: bmkmenu.cxx,v $
 *
 *  $Revision: 1.15 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-16 13:44:42 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_framework.hxx"

//_________________________________________________________________________________________________________________
//  my own includes
//_________________________________________________________________________________________________________________

#include <limits.h>

#include "classes/bmkmenu.hxx"

#ifndef __FRAMEWORK_GENERAL_H_
#include <general.h>
#endif

#ifndef __FRAMEWORK_MACROS_DEBUG_ASSERTION_HXX_
#include <macros/debug/assertion.hxx>
#endif

#ifndef __FRAMEWORK_HELPER_IMAGEPRODUCER_HXX_
#include <helper/imageproducer.hxx>
#endif

#ifndef __FRAMEWORK_CLASSES_MENUCONFIGURATION_HXX_
#include <classes/menuconfiguration.hxx>
#endif

//_________________________________________________________________________________________________________________
//  interface includes
//_________________________________________________________________________________________________________________

#ifndef _COM_SUN_STAR_UNO_REFERENCE_H_
#include <com/sun/star/uno/Reference.h>
#endif
#ifndef _COM_SUN_STAR_UTIL_URL_HPP_
#include <com/sun/star/util/URL.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_PROPERTYVALUE_HPP_
#include <com/sun/star/beans/PropertyValue.hpp>
#endif
#ifndef _UNOTOOLS_PROCESSFACTORY_HXX
#include <comphelper/processfactory.hxx>
#endif
#ifndef _COM_SUN_STAR_UTIL_XURLTRANSFORMER_HPP_
#include <com/sun/star/util/XURLTransformer.hpp>
#endif

#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif
#ifndef _COM_SUN_STAR_UTIL_DATETIME_HPP_
#include <com/sun/star/util/DateTime.hpp>
#endif

//_________________________________________________________________________________________________________________
//  includes of other projects
//_________________________________________________________________________________________________________________

#ifndef _CONFIG_HXX
#include <tools/config.hxx>
#endif
#include <vcl/svapp.hxx>
#include <svtools/dynamicmenuoptions.hxx>
#ifndef INCLUDED_SVTOOLS_MENUOPTIONS_HXX
#include <svtools/menuoptions.hxx>
#endif
#ifndef _RTL_LOGFILE_HXX_
#include <rtl/logfile.hxx>
#endif

//_________________________________________________________________________________________________________________
//  namespace
//_________________________________________________________________________________________________________________

using namespace ::rtl;
using namespace ::comphelper;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::util;
using namespace ::com::sun::star::frame;
using namespace ::com::sun::star::beans;

namespace framework
{

void GetMenuEntry(
    Sequence< PropertyValue >&  aDynamicMenuEntry,
    ::rtl::OUString&            rTitle,
    ::rtl::OUString&            rURL,
    ::rtl::OUString&            rFrame,
    ::rtl::OUString&            rImageId );

class BmkMenu_Impl
{
    private:
        static USHORT        m_nMID;

    public:
        BmkMenu*             m_pRoot;
        BOOL                 m_bInitialized;

        BmkMenu_Impl( BmkMenu* pRoot );
        BmkMenu_Impl();
        ~BmkMenu_Impl();

        static USHORT       GetMID();
};

USHORT BmkMenu_Impl::m_nMID = BMKMENU_ITEMID_START;

BmkMenu_Impl::BmkMenu_Impl( BmkMenu* pRoot ) :
    m_pRoot(pRoot),
    m_bInitialized(FALSE)
{
}

BmkMenu_Impl::BmkMenu_Impl() :
    m_pRoot(0),
    m_bInitialized(FALSE)
{
}

BmkMenu_Impl::~BmkMenu_Impl()
{
}

USHORT BmkMenu_Impl::GetMID()
{
    m_nMID++;
    if( !m_nMID )
        m_nMID = BMKMENU_ITEMID_START;
    return m_nMID;
}

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

BmkMenu::BmkMenu( Reference< XFrame >& xFrame, BmkMenu::BmkMenuType nType, BmkMenu* pRoot ) :
    m_nType( nType ), m_xFrame( xFrame )
{
    _pImp = new BmkMenu_Impl( pRoot );
    Initialize();
}

BmkMenu::BmkMenu( Reference< XFrame >& xFrame, BmkMenu::BmkMenuType nType ) :
    m_nType( nType ), m_xFrame( xFrame )
{
    _pImp = new BmkMenu_Impl();
    Initialize();
}

BmkMenu::~BmkMenu()
{
    delete _pImp;

    for ( int i = 0; i < GetItemCount(); i++ )
    {
        if ( GetItemType( i ) != MENUITEM_SEPARATOR )
        {
            // delete user attributes created with new!
            USHORT nId = GetItemId( i );
            MenuConfiguration::Attributes* pUserAttributes = (MenuConfiguration::Attributes*)GetUserValue( nId );
            delete pUserAttributes;
        }
    }
}

void BmkMenu::Initialize()
{
    RTL_LOGFILE_CONTEXT( aLog, "framework (cd100003) ::BmkMenu::Initialize" );

    if( _pImp->m_bInitialized )
        return;

    _pImp->m_bInitialized = TRUE;

    Sequence< Sequence< PropertyValue > > aDynamicMenuEntries;

    if ( m_nType == BmkMenu::BMK_NEWMENU )
        aDynamicMenuEntries = SvtDynamicMenuOptions().GetMenu( E_NEWMENU );
    else if ( m_nType == BmkMenu::BMK_WIZARDMENU )
        aDynamicMenuEntries = SvtDynamicMenuOptions().GetMenu( E_WIZARDMENU );
    BOOL bShowMenuImages = SvtMenuOptions().IsMenuIconsEnabled();

    ::rtl::OUString aTitle;
    ::rtl::OUString aURL;
    ::rtl::OUString aTargetFrame;
    ::rtl::OUString aImageId;

    const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
    BOOL bIsHiContrastMode = rSettings.GetMenuColor().IsDark();

    UINT32 i, nCount = aDynamicMenuEntries.getLength();
    for ( i = 0; i < nCount; ++i )
    {
        GetMenuEntry( aDynamicMenuEntries[i], aTitle, aURL, aTargetFrame, aImageId );

        if ( !aTitle.getLength() && !aURL.getLength() )
            continue;

        if ( aURL == ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "private:separator" )))
            InsertSeparator();
        else
        {
            sal_Bool    bImageSet = sal_False;
            USHORT      nId = CreateMenuId();

            if ( bShowMenuImages )
            {
                if ( aImageId.getLength() > 0 )
                {
                    Image aImage = GetImageFromURL( m_xFrame, aImageId, FALSE, bIsHiContrastMode );
                    if ( !!aImage )
                    {
                        bImageSet = sal_True;
                        InsertItem( nId, aTitle, aImage );
                    }
                }

                if ( !bImageSet )
                {
                    Image aImage = GetImageFromURL( m_xFrame, aURL, FALSE, bIsHiContrastMode );
                    if ( !aImage )
                        InsertItem( nId, aTitle );
                    else
                        InsertItem( nId, aTitle, aImage );
                }
            }
            else
                InsertItem( nId, aTitle );

            // Store values from configuration to the New and Wizard menu entries to enable
            // sfx2 based code to support high contrast mode correctly!
            MenuConfiguration::Attributes* pUserAttributes = new MenuConfiguration::Attributes( aTargetFrame, aImageId );
            SetUserValue( nId, (ULONG)pUserAttributes );

            SetItemCommand( nId, aURL );
        }
    }
}

USHORT BmkMenu::CreateMenuId()
{
    return BmkMenu_Impl::GetMID();
}

void GetMenuEntry
(
    Sequence< PropertyValue >& aDynamicMenuEntry,
    ::rtl::OUString& rTitle,
    ::rtl::OUString& rURL,
    ::rtl::OUString& rFrame,
    ::rtl::OUString& rImageId
)
{
    for ( int i = 0; i < aDynamicMenuEntry.getLength(); i++ )
    {
        if ( aDynamicMenuEntry[i].Name == DYNAMICMENU_PROPERTYNAME_URL )
            aDynamicMenuEntry[i].Value >>= rURL;
        else if ( aDynamicMenuEntry[i].Name == DYNAMICMENU_PROPERTYNAME_TITLE )
            aDynamicMenuEntry[i].Value >>= rTitle;
        else if ( aDynamicMenuEntry[i].Name == DYNAMICMENU_PROPERTYNAME_IMAGEIDENTIFIER )
            aDynamicMenuEntry[i].Value >>= rImageId;
        else if ( aDynamicMenuEntry[i].Name == DYNAMICMENU_PROPERTYNAME_TARGETNAME )
            aDynamicMenuEntry[i].Value >>= rFrame;
    }
}

}
<commit_msg>INTEGRATION: CWS sb59 (1.14.46); FILE MERGED 2006/08/10 08:16:20 sb 1.14.46.1: #i67487# Made code warning-free (wntmsci10).<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: bmkmenu.cxx,v $
 *
 *  $Revision: 1.16 $
 *
 *  last change: $Author: obo $ $Date: 2006-10-12 10:39:42 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_framework.hxx"

//_________________________________________________________________________________________________________________
//  my own includes
//_________________________________________________________________________________________________________________

#include <limits.h>

#include "classes/bmkmenu.hxx"

#ifndef __FRAMEWORK_GENERAL_H_
#include <general.h>
#endif

#ifndef __FRAMEWORK_MACROS_DEBUG_ASSERTION_HXX_
#include <macros/debug/assertion.hxx>
#endif

#ifndef __FRAMEWORK_HELPER_IMAGEPRODUCER_HXX_
#include <helper/imageproducer.hxx>
#endif

#ifndef __FRAMEWORK_CLASSES_MENUCONFIGURATION_HXX_
#include <classes/menuconfiguration.hxx>
#endif

//_________________________________________________________________________________________________________________
//  interface includes
//_________________________________________________________________________________________________________________

#ifndef _COM_SUN_STAR_UNO_REFERENCE_H_
#include <com/sun/star/uno/Reference.h>
#endif
#ifndef _COM_SUN_STAR_UTIL_URL_HPP_
#include <com/sun/star/util/URL.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_PROPERTYVALUE_HPP_
#include <com/sun/star/beans/PropertyValue.hpp>
#endif
#ifndef _UNOTOOLS_PROCESSFACTORY_HXX
#include <comphelper/processfactory.hxx>
#endif
#ifndef _COM_SUN_STAR_UTIL_XURLTRANSFORMER_HPP_
#include <com/sun/star/util/XURLTransformer.hpp>
#endif

#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif
#ifndef _COM_SUN_STAR_UTIL_DATETIME_HPP_
#include <com/sun/star/util/DateTime.hpp>
#endif

//_________________________________________________________________________________________________________________
//  includes of other projects
//_________________________________________________________________________________________________________________

#ifndef _CONFIG_HXX
#include <tools/config.hxx>
#endif
#include <vcl/svapp.hxx>
#include <svtools/dynamicmenuoptions.hxx>
#ifndef INCLUDED_SVTOOLS_MENUOPTIONS_HXX
#include <svtools/menuoptions.hxx>
#endif
#ifndef _RTL_LOGFILE_HXX_
#include <rtl/logfile.hxx>
#endif

//_________________________________________________________________________________________________________________
//  namespace
//_________________________________________________________________________________________________________________

using namespace ::rtl;
using namespace ::comphelper;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::util;
using namespace ::com::sun::star::frame;
using namespace ::com::sun::star::beans;

namespace framework
{

void GetMenuEntry(
    Sequence< PropertyValue >&  aDynamicMenuEntry,
    ::rtl::OUString&            rTitle,
    ::rtl::OUString&            rURL,
    ::rtl::OUString&            rFrame,
    ::rtl::OUString&            rImageId );

class BmkMenu_Impl
{
    private:
        static USHORT        m_nMID;

    public:
        BmkMenu*             m_pRoot;
        BOOL                 m_bInitialized;

        BmkMenu_Impl( BmkMenu* pRoot );
        BmkMenu_Impl();
        ~BmkMenu_Impl();

        static USHORT       GetMID();
};

USHORT BmkMenu_Impl::m_nMID = BMKMENU_ITEMID_START;

BmkMenu_Impl::BmkMenu_Impl( BmkMenu* pRoot ) :
    m_pRoot(pRoot),
    m_bInitialized(FALSE)
{
}

BmkMenu_Impl::BmkMenu_Impl() :
    m_pRoot(0),
    m_bInitialized(FALSE)
{
}

BmkMenu_Impl::~BmkMenu_Impl()
{
}

USHORT BmkMenu_Impl::GetMID()
{
    m_nMID++;
    if( !m_nMID )
        m_nMID = BMKMENU_ITEMID_START;
    return m_nMID;
}

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

BmkMenu::BmkMenu( Reference< XFrame >& xFrame, BmkMenu::BmkMenuType nType, BmkMenu* pRoot ) :
    m_nType( nType ), m_xFrame( xFrame )
{
    _pImp = new BmkMenu_Impl( pRoot );
    Initialize();
}

BmkMenu::BmkMenu( Reference< XFrame >& xFrame, BmkMenu::BmkMenuType nType ) :
    m_nType( nType ), m_xFrame( xFrame )
{
    _pImp = new BmkMenu_Impl();
    Initialize();
}

BmkMenu::~BmkMenu()
{
    delete _pImp;

    for ( USHORT i = 0; i < GetItemCount(); i++ )
    {
        if ( GetItemType( i ) != MENUITEM_SEPARATOR )
        {
            // delete user attributes created with new!
            USHORT nId = GetItemId( i );
            MenuConfiguration::Attributes* pUserAttributes = (MenuConfiguration::Attributes*)GetUserValue( nId );
            delete pUserAttributes;
        }
    }
}

void BmkMenu::Initialize()
{
    RTL_LOGFILE_CONTEXT( aLog, "framework (cd100003) ::BmkMenu::Initialize" );

    if( _pImp->m_bInitialized )
        return;

    _pImp->m_bInitialized = TRUE;

    Sequence< Sequence< PropertyValue > > aDynamicMenuEntries;

    if ( m_nType == BmkMenu::BMK_NEWMENU )
        aDynamicMenuEntries = SvtDynamicMenuOptions().GetMenu( E_NEWMENU );
    else if ( m_nType == BmkMenu::BMK_WIZARDMENU )
        aDynamicMenuEntries = SvtDynamicMenuOptions().GetMenu( E_WIZARDMENU );
    BOOL bShowMenuImages = SvtMenuOptions().IsMenuIconsEnabled();

    ::rtl::OUString aTitle;
    ::rtl::OUString aURL;
    ::rtl::OUString aTargetFrame;
    ::rtl::OUString aImageId;

    const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
    BOOL bIsHiContrastMode = rSettings.GetMenuColor().IsDark();

    UINT32 i, nCount = aDynamicMenuEntries.getLength();
    for ( i = 0; i < nCount; ++i )
    {
        GetMenuEntry( aDynamicMenuEntries[i], aTitle, aURL, aTargetFrame, aImageId );

        if ( !aTitle.getLength() && !aURL.getLength() )
            continue;

        if ( aURL == ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "private:separator" )))
            InsertSeparator();
        else
        {
            sal_Bool    bImageSet = sal_False;
            USHORT      nId = CreateMenuId();

            if ( bShowMenuImages )
            {
                if ( aImageId.getLength() > 0 )
                {
                    Image aImage = GetImageFromURL( m_xFrame, aImageId, FALSE, bIsHiContrastMode );
                    if ( !!aImage )
                    {
                        bImageSet = sal_True;
                        InsertItem( nId, aTitle, aImage );
                    }
                }

                if ( !bImageSet )
                {
                    Image aImage = GetImageFromURL( m_xFrame, aURL, FALSE, bIsHiContrastMode );
                    if ( !aImage )
                        InsertItem( nId, aTitle );
                    else
                        InsertItem( nId, aTitle, aImage );
                }
            }
            else
                InsertItem( nId, aTitle );

            // Store values from configuration to the New and Wizard menu entries to enable
            // sfx2 based code to support high contrast mode correctly!
            MenuConfiguration::Attributes* pUserAttributes = new MenuConfiguration::Attributes( aTargetFrame, aImageId );
            SetUserValue( nId, (ULONG)pUserAttributes );

            SetItemCommand( nId, aURL );
        }
    }
}

USHORT BmkMenu::CreateMenuId()
{
    return BmkMenu_Impl::GetMID();
}

void GetMenuEntry
(
    Sequence< PropertyValue >& aDynamicMenuEntry,
    ::rtl::OUString& rTitle,
    ::rtl::OUString& rURL,
    ::rtl::OUString& rFrame,
    ::rtl::OUString& rImageId
)
{
    for ( int i = 0; i < aDynamicMenuEntry.getLength(); i++ )
    {
        if ( aDynamicMenuEntry[i].Name == DYNAMICMENU_PROPERTYNAME_URL )
            aDynamicMenuEntry[i].Value >>= rURL;
        else if ( aDynamicMenuEntry[i].Name == DYNAMICMENU_PROPERTYNAME_TITLE )
            aDynamicMenuEntry[i].Value >>= rTitle;
        else if ( aDynamicMenuEntry[i].Name == DYNAMICMENU_PROPERTYNAME_IMAGEIDENTIFIER )
            aDynamicMenuEntry[i].Value >>= rImageId;
        else if ( aDynamicMenuEntry[i].Name == DYNAMICMENU_PROPERTYNAME_TARGETNAME )
            aDynamicMenuEntry[i].Value >>= rFrame;
    }
}

}
<|endoftext|>


<commit_before>#include "NormalPack.h"
#include "MaxRectsBinaryPack2.h"

#include <easyimage.h>

namespace libpacker
{

NormalPack::NormalPack(const std::vector<wxString>& files)
	: m_files(files)
{
}

void NormalPack::Pack()
{
	for (int i = 0, n = m_files.size(); i < n; ++i) {
		const wxString& path = m_files[i];
		RectSize sz;
		eimage::ImageIO::ReadHeader(path.mb_str(), sz.width, sz.height);
		m_src_sizes.push_back(sz);
	}

	MaxRectsBinaryPack2 packer;
	packer.Pack(m_src_sizes, m_output);
	m_size = packer.GetSize();
}

void NormalPack::OutputInfo(const wxString& src_folder, const wxString& dst_file) const
{
	assert(m_files.size() == m_src_sizes.size() && m_files.size() == m_output.size());

	Json::Value value;
	for (int i = 0, n = m_files.size(); i < n; ++i)
	{
		Json::Value frame_val;

		wxString filename = d2d::FilenameTools::getRelativePath(src_folder, m_files[i]);
		frame_val["filename"] = filename.ToStdString();

		const RectSize& src_sz = m_src_sizes[i];

		const Rect& pos = m_output[i];
		frame_val["frame"]["x"] = pos.x;
		frame_val["frame"]["y"] = pos.y;
		frame_val["frame"]["w"] = pos.width;
		frame_val["frame"]["h"] = pos.height;

		assert(src_sz.width == pos.width && src_sz.height == pos.height
			|| src_sz.width == pos.height && src_sz.height == pos.width);
		frame_val["rotated"] = src_sz.width == pos.width && src_sz.height == pos.height;

		frame_val["trimmed"] = false;
		frame_val["spriteSourceSize"]["x"] = 0;
		frame_val["spriteSourceSize"]["y"] = 0;
		frame_val["spriteSourceSize"]["w"] = pos.width;
		frame_val["spriteSourceSize"]["h"] = pos.height;

		frame_val["sourceSize"]["w"] = pos.width;
		frame_val["sourceSize"]["h"] = pos.height;

		value["frames"][i] = frame_val;
	}

	Json::Value meta_val;
	meta_val["size"]["w"] = m_size.width;
	meta_val["size"]["h"] = m_size.height;
	meta_val["scale"] = "1";

	value["meta"] = meta_val;

	Json::StyledStreamWriter writer;
	std::locale::global(std::locale(""));
	std::ofstream fout(dst_file.fn_str());
	std::locale::global(std::locale("C"));
	writer.write(fout, value);
	fout.close();
}

void NormalPack::OutputImage(const wxString& filepath) const
{
	assert(m_files.size() == m_src_sizes.size() && m_files.size() == m_output.size());

	eimage::ImagePack pack(m_size.width, m_size.height);
	for (int i = 0, n = m_files.size(); i < n; ++i)
	{
		const Rect& pos = m_output[i];
		d2d::Image* img = d2d::ImageMgr::Instance()->getItem(m_files[i]);
		pack.AddImage(img, pos.x, pos.y, pos.width, pos.height);
		img->Release();
	}

	pack.OutputToFile(filepath);
}

}<commit_msg>[FIXED] normal pack rotate<commit_after>#include "NormalPack.h"
#include "MaxRectsBinaryPack2.h"

#include <easyimage.h>

namespace libpacker
{

NormalPack::NormalPack(const std::vector<wxString>& files)
	: m_files(files)
{
}

void NormalPack::Pack()
{
	for (int i = 0, n = m_files.size(); i < n; ++i) {
		const wxString& path = m_files[i];
		RectSize sz;
		eimage::ImageIO::ReadHeader(path.mb_str(), sz.width, sz.height);
		m_src_sizes.push_back(sz);
	}

	MaxRectsBinaryPack2 packer;
	packer.Pack(m_src_sizes, m_output);
	m_size = packer.GetSize();
}

void NormalPack::OutputInfo(const wxString& src_folder, const wxString& dst_file) const
{
	assert(m_files.size() == m_src_sizes.size() && m_files.size() == m_output.size());

	Json::Value value;
	for (int i = 0, n = m_files.size(); i < n; ++i)
	{
		Json::Value frame_val;

		wxString filename = d2d::FilenameTools::getRelativePath(src_folder, m_files[i]);
		frame_val["filename"] = filename.ToStdString();

		const RectSize& src_sz = m_src_sizes[i];

		const Rect& pos = m_output[i];
		frame_val["frame"]["x"] = pos.x;
		frame_val["frame"]["y"] = pos.y;
		frame_val["frame"]["w"] = pos.width;
		frame_val["frame"]["h"] = pos.height;

		assert(src_sz.width == pos.width && src_sz.height == pos.height
			|| src_sz.width == pos.height && src_sz.height == pos.width);
		if (src_sz.width == pos.width && src_sz.height == pos.height) {
			frame_val["rotated"] = false;
		} else {
			frame_val["rotated"] = true;
		}

		frame_val["trimmed"] = false;
		frame_val["spriteSourceSize"]["x"] = 0;
		frame_val["spriteSourceSize"]["y"] = 0;
		frame_val["spriteSourceSize"]["w"] = pos.width;
		frame_val["spriteSourceSize"]["h"] = pos.height;

		frame_val["sourceSize"]["w"] = pos.width;
		frame_val["sourceSize"]["h"] = pos.height;

		value["frames"][i] = frame_val;
	}

	Json::Value meta_val;
	meta_val["size"]["w"] = m_size.width;
	meta_val["size"]["h"] = m_size.height;
	meta_val["scale"] = "1";

	value["meta"] = meta_val;

	Json::StyledStreamWriter writer;
	std::locale::global(std::locale(""));
	std::ofstream fout(dst_file.fn_str());
	std::locale::global(std::locale("C"));
	writer.write(fout, value);
	fout.close();
}

void NormalPack::OutputImage(const wxString& filepath) const
{
	assert(m_files.size() == m_src_sizes.size() && m_files.size() == m_output.size());

	eimage::ImagePack pack(m_size.width, m_size.height);
	for (int i = 0, n = m_files.size(); i < n; ++i)
	{
		const Rect& pos = m_output[i];
		d2d::Image* img = d2d::ImageMgr::Instance()->getItem(m_files[i]);
		pack.AddImage(img, pos.x, pos.y, pos.width, pos.height);
		img->Release();
	}

	pack.OutputToFile(filepath);
}

}<|endoftext|>