<commit_before>///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Lewis Baker
// Licenced under MIT license. See LICENSE.txt for details.
///////////////////////////////////////////////////////////////////////////////
#include <cppcoro/task.hpp>
#include <cppcoro/lazy_task.hpp>
#include <cppcoro/single_consumer_event.hpp>
#include <cppcoro/async_mutex.hpp>

#include <memory>

#include <cassert>

struct counter
{
	static int default_construction_count;
	static int copy_construction_count;
	static int move_construction_count;
	static int destruction_count;

	int id;

	static void reset_counts()
	{
		default_construction_count = 0;
		copy_construction_count = 0;
		move_construction_count = 0;
		destruction_count = 0;
	}

	static int construction_count()
	{
		return default_construction_count + copy_construction_count + move_construction_count;
	}

	static int active_count()
	{
		return construction_count() - destruction_count;
	}

	counter() : id(default_construction_count++) {}
	counter(const counter& other) : id(other.id) { ++copy_construction_count; }
	counter(counter&& other) : id(other.id) { ++move_construction_count; other.id = -1; }
	~counter() { ++destruction_count; }

};

int counter::default_construction_count;
int counter::copy_construction_count;
int counter::move_construction_count;
int counter::destruction_count;

void testAwaitSynchronouslyCompletingVoidFunction()
{
	auto doNothingAsync = []() -> cppcoro::task<>
	{
		co_return;
	};

	auto task = doNothingAsync();

	assert(task.is_ready());

	bool ok = false;
	auto test = [&]() -> cppcoro::task<>
	{
		co_await task;
		ok = true;
	};

	test();

	assert(ok);
}

void testAwaitTaskReturningMoveOnlyType()
{
	auto getIntPtrAsync = []() -> cppcoro::task<std::unique_ptr<int>>
	{
		co_return std::make_unique<int>(123);
	};

	auto test = [&]() -> cppcoro::task<>
	{
		auto intPtr = co_await getIntPtrAsync();
		assert(*intPtr == 123);

		auto intPtrTask = getIntPtrAsync();
		{
			// co_await yields l-value reference if task is l-value
			auto& intPtr2 = co_await intPtrTask;
			assert(*intPtr2 == 123);
		}

		{
			// Returns r-value reference if task is r-value
			auto intPtr3 = co_await std::move(intPtrTask);
			assert(*intPtr3 == 123);
		}
	};

	auto task = test();

	assert(task.is_ready());
}

void testAwaitTaskReturningReference()
{
	int value = 0;
	auto getRefAsync = [&]() -> cppcoro::task<int&>
	{
		co_return value;
	};

	auto test = [&]() -> cppcoro::task<>
	{
		// Await r-value task results in l-value reference
		decltype(auto) result = co_await getRefAsync();
		assert(&result == &value);

		// Await l-value task results in l-value reference
		auto getRefTask = getRefAsync();
		decltype(auto) result2 = co_await getRefTask;
		assert(&result2 == &value);
	};

	auto task = test();
	assert(task.is_ready());
}

void testAwaitTaskReturningValueMovesIntoPromiseIfPassedRValue()
{
	counter::reset_counts();

	auto f = []() -> cppcoro::task<counter>
	{
		co_return counter{};
	};

	assert(counter::active_count() == 0);

	{
		auto t = f();
		assert(counter::default_construction_count == 1);
		assert(counter::copy_construction_count == 0);
		assert(counter::move_construction_count == 1);
		assert(counter::destruction_count == 1);
		assert(counter::active_count() == 1);

		// Moving task doesn't move/copy result.
		auto t2 = std::move(t);
		assert(counter::default_construction_count == 1);
		assert(counter::copy_construction_count == 0);
		assert(counter::move_construction_count == 1);
		assert(counter::destruction_count == 1);
		assert(counter::active_count() == 1);
	}

	assert(counter::active_count() == 0);
}

void testAwaitTaskReturningValueCopiesIntoPromiseIfPassedLValue()
{
	counter::reset_counts();

	auto f = []() -> cppcoro::task<counter>
	{
		counter temp;

		// Should be calling copy-constructor here since <promise>.return_value()
		// is being passed an l-value reference.
		co_return temp;
	};

	assert(counter::active_count() == 0);

	{
		auto t = f();
		assert(counter::default_construction_count == 1);
		assert(counter::copy_construction_count == 1);
		assert(counter::move_construction_count == 0);
		assert(counter::destruction_count == 1);
		assert(counter::active_count() == 1);

		// Moving the task doesn't move/copy the result
		auto t2 = std::move(t);
		assert(counter::default_construction_count == 1);
		assert(counter::copy_construction_count == 1);
		assert(counter::move_construction_count == 0);
		assert(counter::destruction_count == 1);
		assert(counter::active_count() == 1);
	}

	assert(counter::active_count() == 0);
}

void testAwaitDelayedCompletionChain()
{
	cppcoro::single_consumer_event event;
	bool reachedPointA = false;
	bool reachedPointB = false;
	auto async1 = [&]() -> cppcoro::task<int>
	{
		reachedPointA = true;
		co_await event;
		reachedPointB = true;
		co_return 1;
	};

	bool reachedPointC = false;
	bool reachedPointD = false;
	auto async2 = [&]() -> cppcoro::task<int>
	{
		reachedPointC = true;
		int result = co_await async1();
		reachedPointD = true;
		co_return result;
	};

	auto task = async2();

	assert(!task.is_ready());
	assert(reachedPointA);
	assert(!reachedPointB);
	assert(reachedPointC);
	assert(!reachedPointD);

	event.set();

	assert(task.is_ready());
	assert(reachedPointB);
	assert(reachedPointD);

	[](cppcoro::task<int> t) -> cppcoro::task<>
	{
		int value = co_await t;
		assert(value == 1);
	}(std::move(task));
}

void testAwaitingBrokenPromiseThrows()
{
	bool ok = false;
	auto test = [&]() -> cppcoro::task<>
	{
		cppcoro::task<> broken;
		try
		{
			co_await broken;
		}
		catch (cppcoro::broken_promise)
		{
			ok = true;
		}
	};

	auto t = test();
	assert(t.is_ready());
	assert(ok);
}

void testAwaitRethrowsException()
{
	class X {};

	auto run = [](bool doThrow) -> cppcoro::task<>
	{
		if (doThrow) throw X{};
		co_return;
	};

	auto t = run(true);

	bool ok = false;
	auto consumeT = [&]() -> cppcoro::task<>
	{
		try
		{
			co_await t;
		}
		catch (X)
		{
			ok = true;
		}
	};

	auto consumer = consumeT();

	assert(t.is_ready());
	assert(consumer.is_ready());
	assert(ok);
}

void testAwaitWhenReadyDoesntThrowException()
{
	class X {};

	auto run = [](bool doThrow) -> cppcoro::task<>
	{
		if (doThrow) throw X{};
		co_return;
	};

	auto t = run(true);

	bool ok = false;
	auto consumeT = [&]() -> cppcoro::task<>
	{
		try
		{
			co_await t.when_ready();
			ok = true;
		}
		catch (...)
		{
		}
	};

	auto consumer = consumeT();

	assert(t.is_ready());
	assert(consumer.is_ready());
	assert(ok);
}

void testLazyTaskDoesntStartUntilAwaited()
{
	bool started = false;
	auto func = [&]() -> cppcoro::lazy_task<>
	{
		started = true;
		co_return;
	};

	auto t = func();
	assert(!started);

	[&]() -> cppcoro::task<>
	{
		co_await t;
	}();

	assert(started);
}

void testAwaitingDefaultConstructedLazyTaskThrowsBrokenPromise()
{
	bool ok = false;
	[&]() -> cppcoro::task<>
	{
		cppcoro::lazy_task<> t;
		try
		{
			co_await t;
			assert(false);
		}
		catch (const cppcoro::broken_promise&)
		{
			ok = true;
		}
		catch (...)
		{
			assert(false);
		}
	}();

	assert(ok);
}

void testAwaitingLazyTaskThatCompletesAsynchronously()
{
	bool reachedBeforeEvent = false;
	bool reachedAfterEvent = false;
	cppcoro::single_consumer_event event;
	auto f = [&]() -> cppcoro::lazy_task<>
	{
		reachedBeforeEvent = true;
		co_await event;
		reachedAfterEvent = true;
	};

	auto t = f();

	assert(!t.is_ready());
	assert(!reachedBeforeEvent);

	auto t2 = [](cppcoro::lazy_task<>& t) -> cppcoro::task<>
	{
		co_await t;
	}(t);

	assert(!t2.is_ready());

	event.set();

	assert(t.is_ready());
	assert(t2.is_ready());
	assert(reachedAfterEvent);
}

void testLazyTaskNeverAwaitedDestroysCapturedArgs()
{
	counter::reset_counts();

	auto f = [](counter c) -> cppcoro::lazy_task<counter>
	{
		co_return c;
	};

	assert(counter::active_count() == 0);

	{
		auto t = f(counter{});
		assert(counter::active_count() == 1);
	}

	assert(counter::active_count() == 0);
}

void testLazyTaskResultLifetime()
{
	counter::reset_counts();

	auto f = []() -> cppcoro::lazy_task<counter>
	{
		co_return counter{};
	};

	{
		auto t = f();
		assert(counter::active_count() == 0);

		[](cppcoro::lazy_task<counter>& t) -> cppcoro::task<>
		{
			co_await t;
			assert(t.is_ready());
			assert(counter::active_count() == 1);
		}(t);

		assert(counter::active_count() == 1);
	}

	assert(counter::active_count() == 0);
}

void testLazyTaskReturnByReference()
{
	int value = 3;
	auto f = [&]() -> cppcoro::lazy_task<int&>
	{
		co_return value;
	};

	auto g = [&]() -> cppcoro::task<>
	{
		{
			decltype(auto) result = co_await f();
			static_assert(
				std::is_same<decltype(result), int&>::value,
				"co_await r-value reference of lazy_task<int&> should result in an int&");
			assert(&result == &value);
		}
		{
			auto t = f();
			decltype(auto) result = co_await t;
			static_assert(
				std::is_same<decltype(result), int&>::value,
				"co_await l-value reference of lazy_task<int&> should result in an int&");
			assert(&result == &value);
		}
	};

	auto t = g();
	assert(t.is_ready());
}

void testAsyncMutex()
{
	int value = 0;
	cppcoro::async_mutex mutex;
	cppcoro::single_consumer_event a;
	cppcoro::single_consumer_event b;
	cppcoro::single_consumer_event c;
	cppcoro::single_consumer_event d;

	auto f = [&](cppcoro::single_consumer_event& e) -> cppcoro::task<>
	{
		cppcoro::async_mutex_lock lock = co_await mutex.lock_async();
		co_await e;
		++value;
	};

	auto t1 = f(a);
	assert(!t1.is_ready());
	assert(value == 0);

	auto t2 = f(b);
	auto t3 = f(c);

	a.set();

	assert(value == 1);

	auto t4 = f(d);

	b.set();

	assert(value == 2);

	c.set();

	assert(value == 3);

	d.set();

	assert(value == 4);

	assert(t1.is_ready());
	assert(t2.is_ready());
	assert(t3.is_ready());
	assert(t4.is_ready());
}

int main(int argc, char** argv)
{
	testAwaitSynchronouslyCompletingVoidFunction();
	testAwaitTaskReturningMoveOnlyType();
	testAwaitTaskReturningReference();
	testAwaitDelayedCompletionChain();
	testAwaitTaskReturningValueMovesIntoPromiseIfPassedRValue();
	testAwaitTaskReturningValueCopiesIntoPromiseIfPassedLValue();
	testAwaitingBrokenPromiseThrows();
	testAwaitRethrowsException();
	testAwaitWhenReadyDoesntThrowException();

	testLazyTaskDoesntStartUntilAwaited();
	testAwaitingDefaultConstructedLazyTaskThrowsBrokenPromise();
	testAwaitingLazyTaskThatCompletesAsynchronously();
	testLazyTaskResultLifetime();
	testLazyTaskNeverAwaitedDestroysCapturedArgs();
	testLazyTaskReturnByReference();

	testAsyncMutex();

	return 0;
}
<commit_msg>Undefine NDEBUG in test/main.cpp so asserts are always enabled.<commit_after>///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Lewis Baker
// Licenced under MIT license. See LICENSE.txt for details.
///////////////////////////////////////////////////////////////////////////////
#ifdef NDEBUG
# undef NDEBUG
#endif

#include <cppcoro/task.hpp>
#include <cppcoro/lazy_task.hpp>
#include <cppcoro/single_consumer_event.hpp>
#include <cppcoro/async_mutex.hpp>

#include <memory>

#include <cassert>

struct counter
{
	static int default_construction_count;
	static int copy_construction_count;
	static int move_construction_count;
	static int destruction_count;

	int id;

	static void reset_counts()
	{
		default_construction_count = 0;
		copy_construction_count = 0;
		move_construction_count = 0;
		destruction_count = 0;
	}

	static int construction_count()
	{
		return default_construction_count + copy_construction_count + move_construction_count;
	}

	static int active_count()
	{
		return construction_count() - destruction_count;
	}

	counter() : id(default_construction_count++) {}
	counter(const counter& other) : id(other.id) { ++copy_construction_count; }
	counter(counter&& other) : id(other.id) { ++move_construction_count; other.id = -1; }
	~counter() { ++destruction_count; }

};

int counter::default_construction_count;
int counter::copy_construction_count;
int counter::move_construction_count;
int counter::destruction_count;

void testAwaitSynchronouslyCompletingVoidFunction()
{
	auto doNothingAsync = []() -> cppcoro::task<>
	{
		co_return;
	};

	auto task = doNothingAsync();

	assert(task.is_ready());

	bool ok = false;
	auto test = [&]() -> cppcoro::task<>
	{
		co_await task;
		ok = true;
	};

	test();

	assert(ok);
}

void testAwaitTaskReturningMoveOnlyType()
{
	auto getIntPtrAsync = []() -> cppcoro::task<std::unique_ptr<int>>
	{
		co_return std::make_unique<int>(123);
	};

	auto test = [&]() -> cppcoro::task<>
	{
		auto intPtr = co_await getIntPtrAsync();
		assert(*intPtr == 123);

		auto intPtrTask = getIntPtrAsync();
		{
			// co_await yields l-value reference if task is l-value
			auto& intPtr2 = co_await intPtrTask;
			assert(*intPtr2 == 123);
		}

		{
			// Returns r-value reference if task is r-value
			auto intPtr3 = co_await std::move(intPtrTask);
			assert(*intPtr3 == 123);
		}
	};

	auto task = test();

	assert(task.is_ready());
}

void testAwaitTaskReturningReference()
{
	int value = 0;
	auto getRefAsync = [&]() -> cppcoro::task<int&>
	{
		co_return value;
	};

	auto test = [&]() -> cppcoro::task<>
	{
		// Await r-value task results in l-value reference
		decltype(auto) result = co_await getRefAsync();
		assert(&result == &value);

		// Await l-value task results in l-value reference
		auto getRefTask = getRefAsync();
		decltype(auto) result2 = co_await getRefTask;
		assert(&result2 == &value);
	};

	auto task = test();
	assert(task.is_ready());
}

void testAwaitTaskReturningValueMovesIntoPromiseIfPassedRValue()
{
	counter::reset_counts();

	auto f = []() -> cppcoro::task<counter>
	{
		co_return counter{};
	};

	assert(counter::active_count() == 0);

	{
		auto t = f();
		assert(counter::default_construction_count == 1);
		assert(counter::copy_construction_count == 0);
		assert(counter::move_construction_count == 1);
		assert(counter::destruction_count == 1);
		assert(counter::active_count() == 1);

		// Moving task doesn't move/copy result.
		auto t2 = std::move(t);
		assert(counter::default_construction_count == 1);
		assert(counter::copy_construction_count == 0);
		assert(counter::move_construction_count == 1);
		assert(counter::destruction_count == 1);
		assert(counter::active_count() == 1);
	}

	assert(counter::active_count() == 0);
}

void testAwaitTaskReturningValueCopiesIntoPromiseIfPassedLValue()
{
	counter::reset_counts();

	auto f = []() -> cppcoro::task<counter>
	{
		counter temp;

		// Should be calling copy-constructor here since <promise>.return_value()
		// is being passed an l-value reference.
		co_return temp;
	};

	assert(counter::active_count() == 0);

	{
		auto t = f();
		assert(counter::default_construction_count == 1);
		assert(counter::copy_construction_count == 1);
		assert(counter::move_construction_count == 0);
		assert(counter::destruction_count == 1);
		assert(counter::active_count() == 1);

		// Moving the task doesn't move/copy the result
		auto t2 = std::move(t);
		assert(counter::default_construction_count == 1);
		assert(counter::copy_construction_count == 1);
		assert(counter::move_construction_count == 0);
		assert(counter::destruction_count == 1);
		assert(counter::active_count() == 1);
	}

	assert(counter::active_count() == 0);
}

void testAwaitDelayedCompletionChain()
{
	cppcoro::single_consumer_event event;
	bool reachedPointA = false;
	bool reachedPointB = false;
	auto async1 = [&]() -> cppcoro::task<int>
	{
		reachedPointA = true;
		co_await event;
		reachedPointB = true;
		co_return 1;
	};

	bool reachedPointC = false;
	bool reachedPointD = false;
	auto async2 = [&]() -> cppcoro::task<int>
	{
		reachedPointC = true;
		int result = co_await async1();
		reachedPointD = true;
		co_return result;
	};

	auto task = async2();

	assert(!task.is_ready());
	assert(reachedPointA);
	assert(!reachedPointB);
	assert(reachedPointC);
	assert(!reachedPointD);

	event.set();

	assert(task.is_ready());
	assert(reachedPointB);
	assert(reachedPointD);

	[](cppcoro::task<int> t) -> cppcoro::task<>
	{
		int value = co_await t;
		assert(value == 1);
	}(std::move(task));
}

void testAwaitingBrokenPromiseThrows()
{
	bool ok = false;
	auto test = [&]() -> cppcoro::task<>
	{
		cppcoro::task<> broken;
		try
		{
			co_await broken;
		}
		catch (cppcoro::broken_promise)
		{
			ok = true;
		}
	};

	auto t = test();
	assert(t.is_ready());
	assert(ok);
}

void testAwaitRethrowsException()
{
	class X {};

	auto run = [](bool doThrow) -> cppcoro::task<>
	{
		if (doThrow) throw X{};
		co_return;
	};

	auto t = run(true);

	bool ok = false;
	auto consumeT = [&]() -> cppcoro::task<>
	{
		try
		{
			co_await t;
		}
		catch (X)
		{
			ok = true;
		}
	};

	auto consumer = consumeT();

	assert(t.is_ready());
	assert(consumer.is_ready());
	assert(ok);
}

void testAwaitWhenReadyDoesntThrowException()
{
	class X {};

	auto run = [](bool doThrow) -> cppcoro::task<>
	{
		if (doThrow) throw X{};
		co_return;
	};

	auto t = run(true);

	bool ok = false;
	auto consumeT = [&]() -> cppcoro::task<>
	{
		try
		{
			co_await t.when_ready();
			ok = true;
		}
		catch (...)
		{
		}
	};

	auto consumer = consumeT();

	assert(t.is_ready());
	assert(consumer.is_ready());
	assert(ok);
}

void testLazyTaskDoesntStartUntilAwaited()
{
	bool started = false;
	auto func = [&]() -> cppcoro::lazy_task<>
	{
		started = true;
		co_return;
	};

	auto t = func();
	assert(!started);

	[&]() -> cppcoro::task<>
	{
		co_await t;
	}();

	assert(started);
}

void testAwaitingDefaultConstructedLazyTaskThrowsBrokenPromise()
{
	bool ok = false;
	[&]() -> cppcoro::task<>
	{
		cppcoro::lazy_task<> t;
		try
		{
			co_await t;
			assert(false);
		}
		catch (const cppcoro::broken_promise&)
		{
			ok = true;
		}
		catch (...)
		{
			assert(false);
		}
	}();

	assert(ok);
}

void testAwaitingLazyTaskThatCompletesAsynchronously()
{
	bool reachedBeforeEvent = false;
	bool reachedAfterEvent = false;
	cppcoro::single_consumer_event event;
	auto f = [&]() -> cppcoro::lazy_task<>
	{
		reachedBeforeEvent = true;
		co_await event;
		reachedAfterEvent = true;
	};

	auto t = f();

	assert(!t.is_ready());
	assert(!reachedBeforeEvent);

	auto t2 = [](cppcoro::lazy_task<>& t) -> cppcoro::task<>
	{
		co_await t;
	}(t);

	assert(!t2.is_ready());

	event.set();

	assert(t.is_ready());
	assert(t2.is_ready());
	assert(reachedAfterEvent);
}

void testLazyTaskNeverAwaitedDestroysCapturedArgs()
{
	counter::reset_counts();

	auto f = [](counter c) -> cppcoro::lazy_task<counter>
	{
		co_return c;
	};

	assert(counter::active_count() == 0);

	{
		auto t = f(counter{});
		assert(counter::active_count() == 1);
	}

	assert(counter::active_count() == 0);
}

void testLazyTaskResultLifetime()
{
	counter::reset_counts();

	auto f = []() -> cppcoro::lazy_task<counter>
	{
		co_return counter{};
	};

	{
		auto t = f();
		assert(counter::active_count() == 0);

		[](cppcoro::lazy_task<counter>& t) -> cppcoro::task<>
		{
			co_await t;
			assert(t.is_ready());
			assert(counter::active_count() == 1);
		}(t);

		assert(counter::active_count() == 1);
	}

	assert(counter::active_count() == 0);
}

void testLazyTaskReturnByReference()
{
	int value = 3;
	auto f = [&]() -> cppcoro::lazy_task<int&>
	{
		co_return value;
	};

	auto g = [&]() -> cppcoro::task<>
	{
		{
			decltype(auto) result = co_await f();
			static_assert(
				std::is_same<decltype(result), int&>::value,
				"co_await r-value reference of lazy_task<int&> should result in an int&");
			assert(&result == &value);
		}
		{
			auto t = f();
			decltype(auto) result = co_await t;
			static_assert(
				std::is_same<decltype(result), int&>::value,
				"co_await l-value reference of lazy_task<int&> should result in an int&");
			assert(&result == &value);
		}
	};

	auto t = g();
	assert(t.is_ready());
}

void testAsyncMutex()
{
	int value = 0;
	cppcoro::async_mutex mutex;
	cppcoro::single_consumer_event a;
	cppcoro::single_consumer_event b;
	cppcoro::single_consumer_event c;
	cppcoro::single_consumer_event d;

	auto f = [&](cppcoro::single_consumer_event& e) -> cppcoro::task<>
	{
		cppcoro::async_mutex_lock lock = co_await mutex.lock_async();
		co_await e;
		++value;
	};

	auto t1 = f(a);
	assert(!t1.is_ready());
	assert(value == 0);

	auto t2 = f(b);
	auto t3 = f(c);

	a.set();

	assert(value == 1);

	auto t4 = f(d);

	b.set();

	assert(value == 2);

	c.set();

	assert(value == 3);

	d.set();

	assert(value == 4);

	assert(t1.is_ready());
	assert(t2.is_ready());
	assert(t3.is_ready());
	assert(t4.is_ready());
}

int main(int argc, char** argv)
{
	testAwaitSynchronouslyCompletingVoidFunction();
	testAwaitTaskReturningMoveOnlyType();
	testAwaitTaskReturningReference();
	testAwaitDelayedCompletionChain();
	testAwaitTaskReturningValueMovesIntoPromiseIfPassedRValue();
	testAwaitTaskReturningValueCopiesIntoPromiseIfPassedLValue();
	testAwaitingBrokenPromiseThrows();
	testAwaitRethrowsException();
	testAwaitWhenReadyDoesntThrowException();

	testLazyTaskDoesntStartUntilAwaited();
	testAwaitingDefaultConstructedLazyTaskThrowsBrokenPromise();
	testAwaitingLazyTaskThatCompletesAsynchronously();
	testLazyTaskResultLifetime();
	testLazyTaskNeverAwaitedDestroysCapturedArgs();
	testLazyTaskReturnByReference();

	testAsyncMutex();

	return 0;
}
<|endoftext|>


<commit_before>// Copyright Hugh Perkins 2015 hughperkins at gmail
//
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.

#include <iostream>
#include <algorithm>

#include "LayerDimensions.h"
#include "test/GtestGlobals.h"
#include "test/TestArgsParser.h"

#include "DimFromArgs.h"

using namespace std;

void DimFromArgs::arg( LayerDimensions *p_dim ) {
    TestArgsParser::arg( "inputplanes", &(p_dim->inputPlanes) );
    TestArgsParser::arg( "inputboardsize", &(p_dim->inputBoardSize) );
    TestArgsParser::arg( "numfilters", &(p_dim->numFilters) );
    TestArgsParser::arg( "filtersize", &(p_dim->filterSize) );
    TestArgsParser::arg( "padzeros", &(p_dim->padZeros) );
    TestArgsParser::arg( "biased", &(p_dim->biased) );
//    cout << "DimFromArgs::arg() " << *p_dim << endl;
}

<commit_msg>add numinputplanes to DimFromArgs<commit_after>// Copyright Hugh Perkins 2015 hughperkins at gmail
//
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.

#include <iostream>
#include <algorithm>

#include "LayerDimensions.h"
#include "test/GtestGlobals.h"
#include "test/TestArgsParser.h"

#include "DimFromArgs.h"

using namespace std;

void DimFromArgs::arg( LayerDimensions *p_dim ) {
    TestArgsParser::arg( "inputplanes", &(p_dim->inputPlanes) );
    TestArgsParser::arg( "numinputplanes", &(p_dim->inputPlanes) );
    TestArgsParser::arg( "inputboardsize", &(p_dim->inputBoardSize) );
    TestArgsParser::arg( "numfilters", &(p_dim->numFilters) );
    TestArgsParser::arg( "filtersize", &(p_dim->filterSize) );
    TestArgsParser::arg( "padzeros", &(p_dim->padZeros) );
    TestArgsParser::arg( "biased", &(p_dim->biased) );
//    cout << "DimFromArgs::arg() " << *p_dim << endl;
}

<|endoftext|>


<commit_before>// ========================================================================== //
// This file is part of DO++, a basic set of libraries in C++ for computer
// vision.
//
// Copyright (C) 2013 David Ok <david.ok8@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at http://mozilla.org/MPL/2.0/.
// ========================================================================== //

#include <gtest/gtest.h>

#include <DO/KDTree.hpp>

using namespace DO;
using namespace std;

class TestKDTree : public testing::Test
{
protected:
  MatrixXd data;
  size_t num_points;
  size_t num_points_in_circle;

  TestKDTree()
  {
    // We construct two sets in points. The first one lives in the
    // zero-centered unit circle and the second in the zero-centered
    // circle with radius 10.
    num_points_in_circle = 5;
    num_points = 2*num_points_in_circle;
    data.resize(2, num_points);

    const size_t& N = num_points_in_circle;
    for (size_t i = 0; i < N; ++i)
    {
      double theta = i / (2*N*M_PI);
      data.col(i) << cos(theta), sin(theta);
    }

    for (size_t i = N; i < 2*N; ++i)
    {
      double theta = i / (2*N*M_PI);
      data.col(i) << 10*cos(theta), 10*sin(theta);
    }
  }
};

TEST_F(TestKDTree, test_simple_knn_search)
{
  KDTree tree(data);

  Vector2d query = Vector2d::Zero();
  size_t num_nearest_neighbors = num_points_in_circle;

  vector<int> indices;
  vector<double> squared_distances;

  tree.knn_search(query, num_nearest_neighbors, indices,
                  squared_distances);

  EXPECT_EQ(indices.size(), num_nearest_neighbors);
  for (size_t j = 0; j < indices.size(); ++j)
  {
    EXPECT_LE(indices[j], num_nearest_neighbors);
    EXPECT_NEAR(squared_distances[j], 1., 1e-10);
  }
}

TEST_F(TestKDTree, test_simple_radius_search)
{
  // Input data.
  KDTree tree(data);
  Vector2d query = Vector2d::Zero();
  size_t num_nearest_neighbors = num_points_in_circle;
  double squared_search_radius = 1.0001;

  // In-out data.
  vector<int> nn_indices;
  vector<double> nn_squared_distances;

  // Output data.
  int num_found_neighbors;

  // First use case: we want to examine the squared distances.
  num_found_neighbors = tree.radius_search(
    query,
    squared_search_radius,
    nn_indices,
    nn_squared_distances);

  EXPECT_EQ(nn_indices.size(), num_nearest_neighbors);
  EXPECT_EQ(num_found_neighbors, num_nearest_neighbors);
  for (size_t j = 0; j < nn_indices.size(); ++j)
  {
    EXPECT_LE(nn_indices[j], num_nearest_neighbors);
    EXPECT_NEAR(nn_squared_distances[j], 1., 1e-10);
  }

  // Second use case: we want to limit the number of neighbors to return.
  size_t max_num_nearest_neighbors = 2;
  num_found_neighbors = tree.radius_search(query,
                                           squared_search_radius,
                                           nn_indices,
                                           nn_squared_distances,
                                           max_num_nearest_neighbors);

  EXPECT_EQ(nn_indices.size(), max_num_nearest_neighbors);
  EXPECT_EQ(num_found_neighbors, max_num_nearest_neighbors);
  for (size_t j = 0; j < nn_indices.size(); ++j)
  {
    EXPECT_LE(nn_indices[j], num_nearest_neighbors);
    EXPECT_NEAR(nn_squared_distances[j], 1., 1e-10);
  }
}

TEST_F(TestKDTree, test_simple_knn_search_with_query_point_in_data)
{
  KDTree tree(data);

  size_t query_index = 0;
  size_t num_nearest_neighbors = num_points_in_circle-1;

  vector<int> indices;
  vector<double> squared_distances;

  tree.knn_search(query_index, num_nearest_neighbors, indices,
                  squared_distances);

  EXPECT_EQ(indices.size(), num_nearest_neighbors);
  for (size_t j = 0; j < indices.size(); ++j)
  {
    EXPECT_LE(indices[j], num_nearest_neighbors);
    EXPECT_LE(squared_distances[j], 2.);
  }
}

TEST_F(TestKDTree, test_simple_radius_search_with_query_point_in_data)
{
  // Input data.
  KDTree tree(data);
  size_t query = 0;
  size_t num_nearest_neighbors = num_points_in_circle-1;
  double squared_search_radius = 2.0001;

  // In-out data.
  vector<int> nn_indices;
  vector<double> nn_squared_distances;

  // Output data.
  int num_found_neighbors;

  // First use case: we want to examine the squared distances.
  num_found_neighbors = tree.radius_search(
    query,
    squared_search_radius,
    nn_indices,
    nn_squared_distances);

  EXPECT_EQ(nn_indices.size(), num_nearest_neighbors);
  EXPECT_EQ(num_found_neighbors, num_nearest_neighbors);
  for (size_t j = 0; j < nn_indices.size(); ++j)
  {
    EXPECT_LE(nn_indices[j], num_nearest_neighbors);
    EXPECT_LE(nn_squared_distances[j], 2.);
  }

  // Second use case: we want to limit the number of neighbors to return.
  size_t max_num_nearest_neighbors = 2;
  num_found_neighbors = tree.radius_search(query,
                                           squared_search_radius,
                                           nn_indices,
                                           nn_squared_distances,
                                           max_num_nearest_neighbors);

  EXPECT_EQ(nn_indices.size(), max_num_nearest_neighbors);
  EXPECT_EQ(num_found_neighbors, max_num_nearest_neighbors);
  for (size_t j = 0; j < nn_indices.size(); ++j)
  {
    EXPECT_LE(nn_indices[j], num_nearest_neighbors);
    EXPECT_LE(nn_squared_distances[j], 2.);
  }
}

TEST_F(TestKDTree, test_batch_knn_search)
{
  KDTree tree(data);
  const size_t& num_queries = num_points_in_circle;
  const size_t& num_nearest_neighbors = num_points_in_circle;
  MatrixXd queries(data.leftCols(num_queries));

  vector<vector<int> > indices;
  vector<vector<double> > squared_distances;

  tree.knn_search(queries, num_nearest_neighbors, indices, squared_distances);

  EXPECT_EQ(indices.size(), num_queries);
  for (size_t i = 0; i < num_queries; ++i)
  {
    EXPECT_EQ(indices[i].size(), num_queries);
    for (size_t j = 0; j < indices[i].size(); ++j)
    {
      EXPECT_LE(indices[i][j], num_queries);
      EXPECT_LE(squared_distances[i][j], 2.);
    }
  }
}

TEST_F(TestKDTree, test_batch_radius_search)
{
  // Input data.
  KDTree tree(data);
  const size_t& num_queries = num_points_in_circle;
  MatrixXd queries(data.leftCols(num_queries));
  double squared_search_radius = 2.0001;

  // In-out data.
  vector<vector<int> > nn_indices;
  vector<vector<double> > nn_squared_distances;

  // First use case: we want to examine the squared distances.
  tree.radius_search(
    queries,
    squared_search_radius,
    nn_indices,
    nn_squared_distances);

  EXPECT_EQ(nn_indices.size(), num_queries);
  for (size_t i = 0; i < num_queries; ++i)
  {
    EXPECT_EQ(nn_indices[i].size(), num_queries);
    for (size_t j = 0; j < nn_indices[i].size(); ++j)
    {
      EXPECT_LE(nn_indices[i][j], num_queries);
      EXPECT_LE(nn_squared_distances[i][j], 2.);
    }
  }

  // Second use case: we want to limit the number of neighbors to return.
  size_t max_num_nearest_neighbors = 2;
  tree.radius_search(queries, squared_search_radius, nn_indices,
                     nn_squared_distances, max_num_nearest_neighbors);

  EXPECT_EQ(nn_indices.size(), num_queries);
  for (size_t i = 0; i < num_queries; ++i)
  {
    EXPECT_EQ(nn_indices[i].size(), max_num_nearest_neighbors);
    for (size_t j = 0; j < nn_indices[i].size(); ++j)
    {
      EXPECT_LE(nn_indices[i][j], num_queries);
      EXPECT_LE(nn_squared_distances[i][j], 2.);
    }
  }
}

TEST_F(TestKDTree, test_batch_knn_search_with_query_point_in_data)
{
  KDTree tree(data);
  const size_t num_queries = num_points_in_circle;
  const size_t num_nearest_neighbors = num_points_in_circle-1;

  vector<size_t> queries(num_queries);
  for (size_t i = 0; i != queries.size(); ++i)
    queries[i] = i;

  vector<vector<int> > indices;
  vector<vector<double> > squared_distances;

  tree.knn_search(queries, num_nearest_neighbors, indices, squared_distances);

  EXPECT_EQ(indices.size(), num_queries);
  for (size_t i = 0; i != indices.size(); ++i)
  {
    EXPECT_EQ(indices[i].size(), num_nearest_neighbors);
    for (size_t j = 0; j < indices[i].size(); ++j)
    {
      EXPECT_LE(indices[i][j], num_nearest_neighbors);
      EXPECT_LE(squared_distances[i][j], 2.);
    }
  }
}

TEST_F(TestKDTree, test_batch_radius_search_with_query_point_in_data)
{
  // Input data.
  KDTree tree(data);
  const size_t& num_queries = num_points_in_circle;
  vector<size_t> queries;
  for (size_t i = 0; i < num_queries; ++i)
    queries.push_back(i);
  double squared_search_radius = 2.0001;

  // In-out data.
  vector<vector<int> > nn_indices;
  vector<vector<double> > nn_squared_distances;

  // First use case: we want to examine the squared distances.
  tree.radius_search(
    queries,
    squared_search_radius,
    nn_indices,
    nn_squared_distances);

  EXPECT_EQ(nn_indices.size(), num_queries);
  for (size_t i = 0; i < num_queries; ++i)
  {
    EXPECT_EQ(nn_indices[i].size(), num_queries-1);
    for (size_t j = 0; j < nn_indices[i].size(); ++j)
    {
      EXPECT_LE(nn_indices[i][j], num_queries);
      EXPECT_LE(nn_squared_distances[i][j], 2.);
    }
  }

  // Second use case: we want to limit the number of neighbors to return.
  size_t max_num_nearest_neighbors = 2;
  tree.radius_search(queries, squared_search_radius, nn_indices,
    nn_squared_distances, max_num_nearest_neighbors);

  EXPECT_EQ(nn_indices.size(), num_queries);
  for (size_t i = 0; i < num_queries; ++i)
  {
    EXPECT_EQ(nn_indices[i].size(), max_num_nearest_neighbors);
    for (size_t j = 0; j < nn_indices[i].size(); ++j)
    {
      EXPECT_LE(nn_indices[i][j], num_queries);
      EXPECT_LE(nn_squared_distances[i][j], 2.);
    }
  }
}

int main(int argc, char **argv)
{
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}<commit_msg>Clean up unit tests.<commit_after>// ========================================================================== //
// This file is part of DO++, a basic set of libraries in C++ for computer
// vision.
//
// Copyright (C) 2013 David Ok <david.ok8@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at http://mozilla.org/MPL/2.0/.
// ========================================================================== //

//! TODO: this is a messy set of unit tests. It maybe worth reinstating Google
//! mock in the library. We can compare easily vectors.

#include <set>

#include <gtest/gtest.h>

#include <DO/KDTree.hpp>

using namespace DO;
using namespace std;

inline vector<int> range(int begin, int end)
{
  vector<int> _range(end-begin);
  for (int i = begin; i < end; ++i)
    _range[i-begin] = i;
  return _range;
}

inline vector<int> range(int end)
{
  return range(0, end);
}

template <typename T>
inline set<T> to_set(const vector<T>& v)
{
  return set<T>(v.begin(), v.end());
}

// Define a macro that does something 'self.assertItemsEqual' in Python.
#define EXPECT_ITEMS_EQ(vector1, vector2) \
EXPECT_EQ(to_set(vector1), to_set(vector2))

class TestKDTree : public testing::Test
{
protected:
  MatrixXd data;
  size_t num_points;
  size_t num_points_in_circle;

  TestKDTree()
  {
    // We construct two sets in points. The first one lives in the
    // zero-centered unit circle and the second in the zero-centered
    // circle with radius 10.
    num_points_in_circle = 5;
    num_points = 2*num_points_in_circle;
    data.resize(2, num_points);

    const size_t& N = num_points_in_circle;
    for (size_t i = 0; i < N; ++i)
    {
      double theta = i / (2*N*M_PI);
      data.col(i) << cos(theta), sin(theta);
    }

    for (size_t i = N; i < 2*N; ++i)
    {
      double theta = i / (2*N*M_PI);
      data.col(i) << 10*cos(theta), 10*sin(theta);
    }
  }
};

TEST_F(TestKDTree, test_simple_knn_search)
{
  KDTree tree(data);

  Vector2d query = Vector2d::Zero();
  size_t num_nearest_neighbors = num_points_in_circle;

  vector<int> nn_indices;
  vector<double> nn_squared_distances;

  tree.knn_search(query, num_nearest_neighbors, nn_indices,
                  nn_squared_distances);

  // Check equality of items.
  EXPECT_ITEMS_EQ(nn_indices, range(num_points_in_circle));

  // Check the squared distances.
  for (size_t j = 0; j < nn_indices.size(); ++j)
    EXPECT_NEAR(nn_squared_distances[j], 1., 1e-10);
}

TEST_F(TestKDTree, test_simple_radius_search)
{
  // Input data.
  KDTree tree(data);
  Vector2d query = Vector2d::Zero();
  size_t num_nearest_neighbors = num_points_in_circle;
  double squared_search_radius = 1.0001;

  // In-out data.
  vector<int> nn_indices;
  vector<double> nn_squared_distances;

  // Output data.
  int num_found_neighbors;

  // First use case: we want to examine the squared distances.
  num_found_neighbors = tree.radius_search(
    query,
    squared_search_radius,
    nn_indices,
    nn_squared_distances);

  EXPECT_EQ(nn_indices.size(), num_nearest_neighbors);
  EXPECT_EQ(num_found_neighbors, num_nearest_neighbors);
  EXPECT_ITEMS_EQ(nn_indices, range(num_points_in_circle));
  for (size_t j = 0; j < nn_indices.size(); ++j)
    EXPECT_NEAR(nn_squared_distances[j], 1., 1e-10);

  // Second use case: we want to limit the number of neighbors to return.
  size_t max_num_nearest_neighbors = 2;
  num_found_neighbors = tree.radius_search(query,
                                           squared_search_radius,
                                           nn_indices,
                                           nn_squared_distances,
                                           max_num_nearest_neighbors);
  EXPECT_EQ(nn_indices.size(), max_num_nearest_neighbors);
  EXPECT_EQ(num_found_neighbors, max_num_nearest_neighbors);
  EXPECT_ITEMS_EQ(nn_indices, range(num_points_in_circle));
  for (size_t j = 0; j < nn_indices.size(); ++j)
    EXPECT_NEAR(nn_squared_distances[j], 1., 1e-10);
}

TEST_F(TestKDTree, test_simple_knn_search_with_query_point_in_data)
{
  KDTree tree(data);

  size_t query_index = 0;
  size_t num_nearest_neighbors = num_points_in_circle-1;

  vector<int> indices;
  vector<double> squared_distances;

  tree.knn_search(query_index, num_nearest_neighbors, indices,
                  squared_distances);

  EXPECT_EQ(indices.size(), num_nearest_neighbors);
  for (size_t j = 0; j < indices.size(); ++j)
  {
    EXPECT_LE(indices[j], num_nearest_neighbors);
    EXPECT_LE(squared_distances[j], 2.);
  }
}

TEST_F(TestKDTree, test_simple_radius_search_with_query_point_in_data)
{
  // Input data.
  KDTree tree(data);
  size_t query = 0;
  size_t num_nearest_neighbors = num_points_in_circle-1;
  double squared_search_radius = 2.0001;

  // In-out data.
  vector<int> nn_indices;
  vector<double> nn_squared_distances;

  // Output data.
  int num_found_neighbors;

  // First use case: we want to examine the squared distances.
  num_found_neighbors = tree.radius_search(
    query,
    squared_search_radius,
    nn_indices,
    nn_squared_distances);

  EXPECT_EQ(nn_indices.size(), num_nearest_neighbors);
  EXPECT_EQ(num_found_neighbors, num_nearest_neighbors);
  for (size_t j = 0; j < nn_indices.size(); ++j)
  {
    EXPECT_LE(nn_indices[j], num_nearest_neighbors);
    EXPECT_LE(nn_squared_distances[j], 2.);
  }

  // Second use case: we want to limit the number of neighbors to return.
  size_t max_num_nearest_neighbors = 2;
  num_found_neighbors = tree.radius_search(query,
                                           squared_search_radius,
                                           nn_indices,
                                           nn_squared_distances,
                                           max_num_nearest_neighbors);

  EXPECT_EQ(nn_indices.size(), max_num_nearest_neighbors);
  EXPECT_EQ(num_found_neighbors, max_num_nearest_neighbors);
  for (size_t j = 0; j < nn_indices.size(); ++j)
  {
    EXPECT_LE(nn_indices[j], num_nearest_neighbors);
    EXPECT_LE(nn_squared_distances[j], 2.);
  }
}

TEST_F(TestKDTree, test_batch_knn_search)
{
  KDTree tree(data);
  const size_t& num_queries = num_points_in_circle;
  const size_t& num_nearest_neighbors = num_points_in_circle;
  MatrixXd queries(data.leftCols(num_queries));

  vector<vector<int> > indices;
  vector<vector<double> > squared_distances;

  tree.knn_search(queries, num_nearest_neighbors, indices, squared_distances);

  EXPECT_EQ(indices.size(), num_queries);
  for (size_t i = 0; i < num_queries; ++i)
  {
    EXPECT_EQ(indices[i].size(), num_queries);
    for (size_t j = 0; j < indices[i].size(); ++j)
    {
      EXPECT_LE(indices[i][j], num_queries);
      EXPECT_LE(squared_distances[i][j], 2.);
    }
  }
}

TEST_F(TestKDTree, test_batch_radius_search)
{
  // Input data.
  KDTree tree(data);
  const size_t& num_queries = num_points_in_circle;
  MatrixXd queries(data.leftCols(num_queries));
  double squared_search_radius = 2.0001;

  // In-out data.
  vector<vector<int> > nn_indices;
  vector<vector<double> > nn_squared_distances;

  // First use case: we want to examine the squared distances.
  tree.radius_search(
    queries,
    squared_search_radius,
    nn_indices,
    nn_squared_distances);

  EXPECT_EQ(nn_indices.size(), num_queries);
  for (size_t i = 0; i < num_queries; ++i)
  {
    EXPECT_EQ(nn_indices[i].size(), num_queries);
    for (size_t j = 0; j < nn_indices[i].size(); ++j)
    {
      EXPECT_LE(nn_indices[i][j], num_queries);
      EXPECT_LE(nn_squared_distances[i][j], 2.);
    }
  }

  // Second use case: we want to limit the number of neighbors to return.
  size_t max_num_nearest_neighbors = 2;
  tree.radius_search(queries, squared_search_radius, nn_indices,
                     nn_squared_distances, max_num_nearest_neighbors);

  EXPECT_EQ(nn_indices.size(), num_queries);
  for (size_t i = 0; i < num_queries; ++i)
  {
    EXPECT_EQ(nn_indices[i].size(), max_num_nearest_neighbors);
    for (size_t j = 0; j < nn_indices[i].size(); ++j)
    {
      EXPECT_LE(nn_indices[i][j], num_queries);
      EXPECT_LE(nn_squared_distances[i][j], 2.);
    }
  }
}

TEST_F(TestKDTree, test_batch_knn_search_with_query_point_in_data)
{
  KDTree tree(data);
  const size_t num_queries = num_points_in_circle;
  const size_t num_nearest_neighbors = num_points_in_circle-1;

  vector<size_t> queries(num_queries);
  for (size_t i = 0; i != queries.size(); ++i)
    queries[i] = i;

  vector<vector<int> > indices;
  vector<vector<double> > squared_distances;

  tree.knn_search(queries, num_nearest_neighbors, indices, squared_distances);

  EXPECT_EQ(indices.size(), num_queries);
  for (size_t i = 0; i != indices.size(); ++i)
  {
    EXPECT_EQ(indices[i].size(), num_nearest_neighbors);
    for (size_t j = 0; j < indices[i].size(); ++j)
    {
      EXPECT_LE(indices[i][j], num_nearest_neighbors);
      EXPECT_LE(squared_distances[i][j], 2.);
    }
  }
}

TEST_F(TestKDTree, test_batch_radius_search_with_query_point_in_data)
{
  // Input data.
  KDTree tree(data);
  const size_t& num_queries = num_points_in_circle;
  vector<size_t> queries;
  for (size_t i = 0; i < num_queries; ++i)
    queries.push_back(i);
  double squared_search_radius = 2.0001;

  // In-out data.
  vector<vector<int> > nn_indices;
  vector<vector<double> > nn_squared_distances;

  // First use case: we want to examine the squared distances.
  tree.radius_search(
    queries,
    squared_search_radius,
    nn_indices,
    nn_squared_distances);

  EXPECT_EQ(nn_indices.size(), num_queries);
  for (size_t i = 0; i < num_queries; ++i)
  {
    EXPECT_EQ(nn_indices[i].size(), num_queries-1);
    for (size_t j = 0; j < nn_indices[i].size(); ++j)
    {
      EXPECT_LE(nn_indices[i][j], num_queries);
      EXPECT_LE(nn_squared_distances[i][j], 2.);
    }
  }

  // Second use case: we want to limit the number of neighbors to return.
  size_t max_num_nearest_neighbors = 2;
  tree.radius_search(queries, squared_search_radius, nn_indices,
    nn_squared_distances, max_num_nearest_neighbors);

  EXPECT_EQ(nn_indices.size(), num_queries);
  for (size_t i = 0; i < num_queries; ++i)
  {
    EXPECT_EQ(nn_indices[i].size(), max_num_nearest_neighbors);
    for (size_t j = 0; j < nn_indices[i].size(); ++j)
    {
      EXPECT_LE(nn_indices[i][j], num_queries);
      EXPECT_LE(nn_squared_distances[i][j], 2.);
    }
  }
}

int main(int argc, char **argv)
{
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}<|endoftext|>


<commit_before>#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){
    ofBackground(0);
    ofSetLogLevel(OF_LOG_VERBOSE);
    // basic connection:
    // client.connect("echo.websocket.org");
    // OR optionally use SSL
    // client.connect("echo.websocket.org", true);

    // advanced: set keep-alive timeouts for events like
    // loss of internet

    // 1 - get default options
    ofxLibwebsockets::ClientOptions options = ofxLibwebsockets::defaultClientOptions();

    // 2 - set basic params
    options.host = "echo.websocket.org";

    // 3 - set keep alive params
    // BIG GOTCHA: on BSD systems, e.g. Mac OS X, these time params are system-wide
    // ...so ka_time just says "check if alive when you want" instead of "check if
    // alive after X seconds"
    options.ka_time     = 1;
//    options.ka_probes   = 1;
//    options.ka_interval = 1;

    // 4 - connect
    client.connect(options);

    ofSetLogLevel(OF_LOG_ERROR);

    client.addListener(this);
    ofSetFrameRate(60);
}

//--------------------------------------------------------------
void ofApp::update(){
}

//--------------------------------------------------------------
void ofApp::draw(){
    ofDrawBitmapString("Type anywhere to send 'hello' to your server\nCheck the console for output!", 10,20);
    ofDrawBitmapString(client.isConnected() ? "Client is connected" : "Client disconnected :(", 10,50);
}

//--------------------------------------------------------------
void ofApp::onConnect( ofxLibwebsockets::Event& args ){
    cout<<"on connected"<<endl;
}

//--------------------------------------------------------------
void ofApp::onOpen( ofxLibwebsockets::Event& args ){
    cout<<"on open"<<endl;
}

//--------------------------------------------------------------
void ofApp::onClose( ofxLibwebsockets::Event& args ){
    cout<<"on close"<<endl;
}

//--------------------------------------------------------------
void ofApp::onIdle( ofxLibwebsockets::Event& args ){
    cout<<"on idle"<<endl;
}

//--------------------------------------------------------------
void ofApp::onMessage( ofxLibwebsockets::Event& args ){
    cout<<"got message "<<args.message<<endl;
}

//--------------------------------------------------------------
void ofApp::onBroadcast( ofxLibwebsockets::Event& args ){
    cout<<"got broadcast "<<args.message<<endl;
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){

    client.send("Hello");
    cout << "sending hello" <<endl;
}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){
}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){

}<commit_msg>Update ofApp.cpp<commit_after>#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){
    ofBackground(0);
    ofSetLogLevel(OF_LOG_VERBOSE);
    // basic connection:
    // client.connect("echo.websocket.org");
    // OR optionally use SSL
    // client.connect("echo.websocket.org", true);

    // advanced: set keep-alive timeouts for events like
    // loss of internet

    // 1 - get default options
    ofxLibwebsockets::ClientOptions options = ofxLibwebsockets::defaultClientOptions();

    // 2 - set basic params
    options.host = "echo.websocket.org";

    // 3 - set keep alive params
    // BIG GOTCHA: on BSD systems, e.g. Mac OS X, these time params are system-wide
    // ...so ka_time just says "check if alive when you want" instead of "check if
    // alive after X seconds"
    // Note: some have had issues with only setting one of these; may be an
    // all-or-nothing type option!
    options.ka_time     = 1;
    options.ka_probes   = 1;
    options.ka_interval = 1;

    // 4 - connect
    client.connect(options);

    ofSetLogLevel(OF_LOG_ERROR);

    client.addListener(this);
    ofSetFrameRate(60);
}

//--------------------------------------------------------------
void ofApp::update(){
}

//--------------------------------------------------------------
void ofApp::draw(){
    ofDrawBitmapString("Type anywhere to send 'hello' to your server\nCheck the console for output!", 10,20);
    ofDrawBitmapString(client.isConnected() ? "Client is connected" : "Client disconnected :(", 10,50);
}

//--------------------------------------------------------------
void ofApp::onConnect( ofxLibwebsockets::Event& args ){
    cout<<"on connected"<<endl;
}

//--------------------------------------------------------------
void ofApp::onOpen( ofxLibwebsockets::Event& args ){
    cout<<"on open"<<endl;
}

//--------------------------------------------------------------
void ofApp::onClose( ofxLibwebsockets::Event& args ){
    cout<<"on close"<<endl;
}

//--------------------------------------------------------------
void ofApp::onIdle( ofxLibwebsockets::Event& args ){
    cout<<"on idle"<<endl;
}

//--------------------------------------------------------------
void ofApp::onMessage( ofxLibwebsockets::Event& args ){
    cout<<"got message "<<args.message<<endl;
}

//--------------------------------------------------------------
void ofApp::onBroadcast( ofxLibwebsockets::Event& args ){
    cout<<"got broadcast "<<args.message<<endl;
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){

    client.send("Hello");
    cout << "sending hello" <<endl;
}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){
}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){

}
<|endoftext|>


<commit_before>#pragma once
#ifndef SCOPEEXIT_HPP
# define SCOPEEXIT_HPP

#include <utility>

/* This counts the number of args */
#define NARGS_SEQ(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
#define NARGS(...) NARGS_SEQ(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)

/* This will let macros expand before concating them */
#define PRIMITIVE_CAT(x, y) x ## y
#define CAT(x, y) PRIMITIVE_CAT(x, y)

/* This will pop the last argument off */
#define POP_LAST(...) CAT(POP_LAST_, NARGS(__VA_ARGS__))(__VA_ARGS__)
#define POP_LAST_1(x1)
#define POP_LAST_2(x1, x2) x1
#define POP_LAST_3(x1, x2, x3) x1, x2
#define POP_LAST_4(x1, x2, x3, x4) x1, x2, x3
#define POP_LAST_5(x1, x2, x3, x4, x5) x1, x2, x3, x4
#define POP_LAST_6(x1, x2, x3, x4, x5, x6) x1, x2, x3, x4, x5
#define POP_LAST_7(x1, x2, x3, x4, x5, x6, x7) x1, x2, x3, x4, x5, x6
#define POP_LAST_8(x1, x2, x3, x4, x5, x6, x7, x8) x1, x2, x3, x4, x5, x6, x7
#define POP_LAST_9(x1, x2, x3, x4, x5, x6, x7, x8, x9) x1, x2, x3, x4, x5, x6, x7, x8
#define POP_LAST_10(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10) x1, x2, x3, x4, x5, x6, x7, x8, x9

/* This will return the last argument */
#define LAST(...) CAT(LAST_, NARGS(__VA_ARGS__))(__VA_ARGS__)
#define LAST_1(x1) x1
#define LAST_2(x1, x2) x2
#define LAST_3(x1, x2, x3) x3
#define LAST_4(x1, x2, x3, x4) x4
#define LAST_5(x1, x2, x3, x4, x5) x5
#define LAST_6(x1, x2, x3, x4, x5, x6) x6
#define LAST_7(x1, x2, x3, x4, x5, x6, x7) x7
#define LAST_8(x1, x2, x3, x4, x5, x6, x7, x8) x8
#define LAST_9(x1, x2, x3, x4, x5, x6, x7, x8, x9) x9
#define LAST_10(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10) x10

namespace detail
{

template <typename T>
class scope_exit
{
public:
  explicit scope_exit(T&& f) noexcept : f_(::std::forward<T>(f))
  {
    static_assert(noexcept(f_()), "throwing functors are unsupported");
  }

  ~scope_exit() noexcept { f_(); }

private:
  T f_;
};

class scope_exit_helper { };

template<typename T>
inline scope_exit<T> make_scope_exit(T&& f)
{
  return scope_exit<T>(::std::forward<T>(f));
}

template<typename T>
inline scope_exit<T> operator+(scope_exit_helper&&, T&& f)
{
  return scope_exit<T>(::std::forward<T>(f));
}

}

#define SCOPE_EXIT(...) auto const CAT(scope_exit_, __LINE__)          \
  (::detail::make_scope_exit([POP_LAST(__VA_ARGS__)]() noexcept\
    { LAST(__VA_ARGS__); }))
#define SCOPE_EXIT_ auto const CAT(scope_exit_, __LINE__) =            \
  ::detail::scope_exit_helper()+[&]() noexcept
#define SCOPE_EXIT__(...) auto const CAT(scope_exit_, __LINE__) =      \
  ::detail::scope_exit_helper()+[__VA_ARGS__]() noexcept

#endif // SCOPEEXIT_HPP
<commit_msg>some fixes<commit_after>#pragma once
#ifndef SCOPEEXIT_HPP
# define SCOPEEXIT_HPP

#include <utility>

/* This counts the number of args */
#define NARGS_SEQ(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
#define NARGS(...) NARGS_SEQ(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)

/* This will let macros expand before concating them */
#define PRIMITIVE_CAT(x, y) x ## y
#define CAT(x, y) PRIMITIVE_CAT(x, y)

/* This will pop the last argument off */
#define POP_LAST(...) CAT(POP_LAST_, NARGS(__VA_ARGS__))(__VA_ARGS__)
#define POP_LAST_1(x1)
#define POP_LAST_2(x1, x2) x1
#define POP_LAST_3(x1, x2, x3) x1, x2
#define POP_LAST_4(x1, x2, x3, x4) x1, x2, x3
#define POP_LAST_5(x1, x2, x3, x4, x5) x1, x2, x3, x4
#define POP_LAST_6(x1, x2, x3, x4, x5, x6) x1, x2, x3, x4, x5
#define POP_LAST_7(x1, x2, x3, x4, x5, x6, x7) x1, x2, x3, x4, x5, x6
#define POP_LAST_8(x1, x2, x3, x4, x5, x6, x7, x8) x1, x2, x3, x4, x5, x6, x7
#define POP_LAST_9(x1, x2, x3, x4, x5, x6, x7, x8, x9) x1, x2, x3, x4, x5, x6, x7, x8
#define POP_LAST_10(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10) x1, x2, x3, x4, x5, x6, x7, x8, x9

/* This will return the last argument */
#define LAST(...) CAT(LAST_, NARGS(__VA_ARGS__))(__VA_ARGS__)
#define LAST_1(x1) x1
#define LAST_2(x1, x2) x2
#define LAST_3(x1, x2, x3) x3
#define LAST_4(x1, x2, x3, x4) x4
#define LAST_5(x1, x2, x3, x4, x5) x5
#define LAST_6(x1, x2, x3, x4, x5, x6) x6
#define LAST_7(x1, x2, x3, x4, x5, x6, x7) x7
#define LAST_8(x1, x2, x3, x4, x5, x6, x7, x8) x8
#define LAST_9(x1, x2, x3, x4, x5, x6, x7, x8, x9) x9
#define LAST_10(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10) x10

namespace detail
{

template <typename T>
class scope_exit
{
public:
  explicit scope_exit(T&& f) noexcept : f_(::std::forward<T>(f))
  {
    static_assert(noexcept(f_()), "throwing functors are unsupported");
  }

  ~scope_exit() noexcept { f_(); }

private:
  T f_;
};

class scope_exit_helper { };

template<typename T>
inline scope_exit<T> make_scope_exit(T&& f) noexcept
{
  return scope_exit<T>(::std::forward<T>(f));
}

template<typename T>
inline scope_exit<T> operator+(scope_exit_helper&&, T&& f) noexcept
{
  return scope_exit<T>(::std::forward<T>(f));
}

}

#define SCOPE_EXIT(...) auto const CAT(scope_exit_, __LINE__)          \
  (::detail::make_scope_exit([POP_LAST(__VA_ARGS__)]() noexcept\
    { LAST(__VA_ARGS__); }))
#define SCOPE_EXIT_ auto const CAT(scope_exit_, __LINE__) =            \
  ::detail::scope_exit_helper()+[&]() noexcept
#define SCOPE_EXIT__(...) auto const CAT(scope_exit_, __LINE__) =      \
  ::detail::scope_exit_helper()+[__VA_ARGS__]() noexcept

#endif // SCOPEEXIT_HPP
<|endoftext|>


<commit_before>/*
**
** Author(s):
**  - Pierre ROULLON <proullon@aldebaran-robotics.com>
**
** Copyright (C) 2012, 2013 Aldebaran Robotics
** See COPYING for the license
*/

#include <qi/anyobject.hpp>
#include <qi/jsoncodec.hpp>

#include <jnitools.hpp>
#include <object.hpp>
#include <callbridge.hpp>
#include <jobjectconverter.hpp>

qiLogCategory("qimessaging.jni");

extern MethodInfoHandler gInfoHandler;

JNIEXPORT jlong JNICALL Java_com_aldebaran_qi_AnyObject_property(JNIEnv* env, jobject QI_UNUSED(jobj), jlong pObj, jstring name)
{
  qi::AnyObject&     obj = *(reinterpret_cast<qi::AnyObject*>(pObj));
  std::string        propName = qi::jni::toString(name);

  qi::Future<qi::AnyValue>* ret = new qi::Future<qi::AnyValue>();

  qi::jni::JNIAttach attach(env);

  try
  {
    *ret = obj.property<qi::AnyValue>(propName);
  } catch (qi::FutureUserException& e)
  {
    delete ret;
    throwNewException(env, e.what());
    return 0;
  }

  return (jlong) ret;
}

JNIEXPORT jlong JNICALL Java_com_aldebaran_qi_AnyObject_setProperty(JNIEnv* env, jobject QI_UNUSED(jobj), jlong pObj, jstring name, jobject property)
{
  qi::AnyObject *obj = reinterpret_cast<qi::AnyObject*>(pObj);
  std::string propName = qi::jni::toString(name);

  qi::jni::JNIAttach attach(env);

  auto value = qi::AnyValue::from<jobject>(property);
  try
  {
    qi::Future<void> propertyFuture = obj->setProperty(propName, std::move(value));
    qi::Future<qi::AnyValue> future = qi::toAnyValueFuture(std::move(propertyFuture));
    auto futurePtr = new qi::Future<qi::AnyValue>(std::move(future));
    return reinterpret_cast<jlong>(futurePtr);
  }
  catch (std::runtime_error &e)
  {
    throwNewDynamicCallException(env, e.what());
    return 0;
  }
}

JNIEXPORT jlong JNICALL Java_com_aldebaran_qi_AnyObject_asyncCall(JNIEnv* env, jobject QI_UNUSED(jobj), jlong pObject, jstring jmethod, jobjectArray args)
{
  qi::AnyObject&    obj = *(reinterpret_cast<qi::AnyObject*>(pObject));
  std::string       method;
  qi::Future<qi::AnyValue>* fut = 0;

  qi::jni::JNIAttach attach(env);

  // Get method name and parameters C style.
  method = qi::jni::toString(jmethod);
  try {
    fut = call_from_java(env, obj, method, args);
  } catch (std::exception& e)
  {
    throwNewDynamicCallException(env, e.what());
    return 0;
  }

  return (jlong) fut;
}

JNIEXPORT jstring JNICALL Java_com_aldebaran_qi_AnyObject_printMetaObject(JNIEnv* QI_UNUSED(env), jobject QI_UNUSED(jobj), jlong pObject)
{
  qi::AnyObject&    obj = *(reinterpret_cast<qi::AnyObject*>(pObject));
  std::stringstream ss;

  qi::detail::printMetaObject(ss, obj.metaObject());
  return qi::jni::toJstring(ss.str());
}

JNIEXPORT void JNICALL Java_com_aldebaran_qi_AnyObject_destroy(JNIEnv* QI_UNUSED(env), jobject QI_UNUSED(jobj), jlong pObject)
{
  qi::AnyObject*    obj = reinterpret_cast<qi::AnyObject*>(pObject);

  delete obj;
}

JNIEXPORT jlong JNICALL Java_com_aldebaran_qi_AnyObject_disconnect(JNIEnv *env, jobject QI_UNUSED(jobj), jlong pObject, jlong subscriberId)
{
  qi::AnyObject&             obj = *(reinterpret_cast<qi::AnyObject *>(pObject));
  try {
    obj.disconnect(subscriberId);
  } catch (std::exception& e)
  {
    throwNewException(env, e.what());
  }
  return 0;
}

JNIEXPORT jlong JNICALL Java_com_aldebaran_qi_AnyObject_connect(JNIEnv *env, jobject jobj, jlong pObject, jstring method, jobject instance, jstring service, jstring eventName)
{
  qi::AnyObject&             obj = *(reinterpret_cast<qi::AnyObject *>(pObject));
  std::string                signature = qi::jni::toString(method);
  std::string                event = qi::jni::toString(eventName);
  qi_method_info*            data;
  std::vector<std::string>  sigInfo;

  // Keep a pointer on JavaVM singleton if not already set.
  JVM(env);

  // Create a new global reference on object instance.
  // jobject structure are local reference and are destroyed when returning to JVM
  instance = env->NewGlobalRef(instance);

  // Remove return value
  sigInfo = qi::signatureSplit(signature);
  signature = sigInfo[1];
  signature.append("::");
  signature.append(sigInfo[2]);

  // Create a struct holding a jobject instance, jmethodId id and other needed thing for callback
  // Pass it to void * data to register_method
  // FIXME jobj is not a global ref, it may be invalid when it will be used
  data = new qi_method_info(instance, signature, jobj);
  gInfoHandler.push(data);

  try {
    qi::SignalLink link =obj.connect(event,
                        qi::SignalSubscriber(
                          qi::AnyFunction::fromDynamicFunction(
                            boost::bind(&event_callback_to_java, (void*) data, _1))));
    return link;
  } catch (std::exception& e)
  {
    throwNewException(env, e.what());
    return 0;
  }
}

JNIEXPORT jlong JNICALL Java_com_aldebaran_qi_AnyObject_connectSignal(JNIEnv *env, jobject QI_UNUSED(obj), jlong pObject, jstring jSignalName, jobject listener)
{
  qi::AnyObject *anyObject = reinterpret_cast<qi::AnyObject *>(pObject);
  std::string signalName = qi::jni::toString(jSignalName);
  auto gListener = qi::jni::makeSharedGlobalRef(env, listener);

  qi::SignalSubscriber subscriber {
    qi::AnyFunction::fromDynamicFunction(
      [gListener](const std::vector<qi::AnyReference> &params) -> qi::AnyReference {
        jobject listener = gListener.get();

        qi::jni::JNIAttach attach;
        JNIEnv *env = attach.get();

        const char *method = "onSignalReceived";
        const char *methodSig = "([Ljava/lang/Object;)V";
        jobjectArray jparams = qi::jni::toJobjectArray(params);
        qi::jni::Call<void>::invoke(env, listener, method, methodSig, jparams);
        jthrowable exception = env->ExceptionOccurred();
        if (exception)
        {
          env->ExceptionDescribe();
          // an exception occurred in a listener, report and ignore
          env->ExceptionClear();
        }
        return {}; // a void AnyReference
      }
    )
  };

  qi::Future<qi::SignalLink> signalLinkFuture = anyObject->connect(signalName, subscriber);

  qi::Future<qi::AnyValue> future = qi::toAnyValueFuture(std::move(signalLinkFuture));
  auto futurePtr = new qi::Future<qi::AnyValue>(std::move(future));
  return reinterpret_cast<jlong>(futurePtr);
}

JNIEXPORT jlong JNICALL Java_com_aldebaran_qi_AnyObject_disconnectSignal(JNIEnv *env, jobject QI_UNUSED(obj), jlong pObject, jlong subscriberId)
{
  qi::AnyObject *anyObject = reinterpret_cast<qi::AnyObject *>(pObject);
  qi::Future<void> disconnectFuture = anyObject->disconnect(subscriberId);

  qi::Future<qi::AnyValue> future = qi::toAnyValueFuture(std::move(disconnectFuture));
  auto futurePtr = new qi::Future<qi::AnyValue>(std::move(future));
  return reinterpret_cast<jlong>(futurePtr);
}

JNIEXPORT void JNICALL Java_com_aldebaran_qi_AnyObject_post(JNIEnv *env, jobject QI_UNUSED(jobj), jlong pObject, jstring eventName, jobjectArray jargs)
{
  qi::AnyObject obj = *(reinterpret_cast<qi::AnyObject *>(pObject));
  std::string   event = qi::jni::toString(eventName);
  qi::GenericFunctionParameters params;
  std::string signature;
  jsize size;
  jsize i = 0;

  qi::jni::JNIAttach attach(env);

  size = env->GetArrayLength(jargs);
  i = 0;
  while (i < size)
  {
    jobject current = env->GetObjectArrayElement(jargs, i);
    qi::AnyReference val = qi::AnyReference(AnyValue_from_JObject(current).first);
    params.push_back(val);
    i++;
  }

  // Signature construction
  signature = event + "::(";
  for (unsigned i=0; i< params.size(); ++i)
    signature += params[i].signature(true).toString();
  signature += ")";

  try {
    obj.metaPost(event, params);
  } catch (std::exception& e)
  {
    throwNewException(env, e.what());
  }

  // Destroy arguments
  i = 0;
  for(qi::GenericFunctionParameters::iterator it = params.begin(); it != params.end(); ++it)
    (*it).destroy();
  return;
}

JNIEXPORT jobject JNICALL Java_com_aldebaran_qi_AnyObject_decodeJSON(JNIEnv *QI_UNUSED(env), jclass QI_UNUSED(cls), jstring what)
{
  std::string str = qi::jni::toString(what);
  qi::AnyValue val = qi::decodeJSON(str);
  return JObject_from_AnyValue(val.asReference());
}

JNIEXPORT jstring JNICALL Java_com_aldebaran_qi_AnyObject_encodeJSON(JNIEnv *QI_UNUSED(env), jclass QI_UNUSED(cls), jobject what)
{
  std::string res = qi::encodeJSON(what);
  return qi::jni::toJstring(res);
}
<commit_msg>Delete signal parameter local reference<commit_after>/*
**
** Author(s):
**  - Pierre ROULLON <proullon@aldebaran-robotics.com>
**
** Copyright (C) 2012, 2013 Aldebaran Robotics
** See COPYING for the license
*/

#include <qi/anyobject.hpp>
#include <qi/jsoncodec.hpp>

#include <jnitools.hpp>
#include <object.hpp>
#include <callbridge.hpp>
#include <jobjectconverter.hpp>

qiLogCategory("qimessaging.jni");

extern MethodInfoHandler gInfoHandler;

JNIEXPORT jlong JNICALL Java_com_aldebaran_qi_AnyObject_property(JNIEnv* env, jobject QI_UNUSED(jobj), jlong pObj, jstring name)
{
  qi::AnyObject&     obj = *(reinterpret_cast<qi::AnyObject*>(pObj));
  std::string        propName = qi::jni::toString(name);

  qi::Future<qi::AnyValue>* ret = new qi::Future<qi::AnyValue>();

  qi::jni::JNIAttach attach(env);

  try
  {
    *ret = obj.property<qi::AnyValue>(propName);
  } catch (qi::FutureUserException& e)
  {
    delete ret;
    throwNewException(env, e.what());
    return 0;
  }

  return (jlong) ret;
}

JNIEXPORT jlong JNICALL Java_com_aldebaran_qi_AnyObject_setProperty(JNIEnv* env, jobject QI_UNUSED(jobj), jlong pObj, jstring name, jobject property)
{
  qi::AnyObject *obj = reinterpret_cast<qi::AnyObject*>(pObj);
  std::string propName = qi::jni::toString(name);

  qi::jni::JNIAttach attach(env);

  auto value = qi::AnyValue::from<jobject>(property);
  try
  {
    qi::Future<void> propertyFuture = obj->setProperty(propName, std::move(value));
    qi::Future<qi::AnyValue> future = qi::toAnyValueFuture(std::move(propertyFuture));
    auto futurePtr = new qi::Future<qi::AnyValue>(std::move(future));
    return reinterpret_cast<jlong>(futurePtr);
  }
  catch (std::runtime_error &e)
  {
    throwNewDynamicCallException(env, e.what());
    return 0;
  }
}

JNIEXPORT jlong JNICALL Java_com_aldebaran_qi_AnyObject_asyncCall(JNIEnv* env, jobject QI_UNUSED(jobj), jlong pObject, jstring jmethod, jobjectArray args)
{
  qi::AnyObject&    obj = *(reinterpret_cast<qi::AnyObject*>(pObject));
  std::string       method;
  qi::Future<qi::AnyValue>* fut = 0;

  qi::jni::JNIAttach attach(env);

  // Get method name and parameters C style.
  method = qi::jni::toString(jmethod);
  try {
    fut = call_from_java(env, obj, method, args);
  } catch (std::exception& e)
  {
    throwNewDynamicCallException(env, e.what());
    return 0;
  }

  return (jlong) fut;
}

JNIEXPORT jstring JNICALL Java_com_aldebaran_qi_AnyObject_printMetaObject(JNIEnv* QI_UNUSED(env), jobject QI_UNUSED(jobj), jlong pObject)
{
  qi::AnyObject&    obj = *(reinterpret_cast<qi::AnyObject*>(pObject));
  std::stringstream ss;

  qi::detail::printMetaObject(ss, obj.metaObject());
  return qi::jni::toJstring(ss.str());
}

JNIEXPORT void JNICALL Java_com_aldebaran_qi_AnyObject_destroy(JNIEnv* QI_UNUSED(env), jobject QI_UNUSED(jobj), jlong pObject)
{
  qi::AnyObject*    obj = reinterpret_cast<qi::AnyObject*>(pObject);

  delete obj;
}

JNIEXPORT jlong JNICALL Java_com_aldebaran_qi_AnyObject_disconnect(JNIEnv *env, jobject QI_UNUSED(jobj), jlong pObject, jlong subscriberId)
{
  qi::AnyObject&             obj = *(reinterpret_cast<qi::AnyObject *>(pObject));
  try {
    obj.disconnect(subscriberId);
  } catch (std::exception& e)
  {
    throwNewException(env, e.what());
  }
  return 0;
}

JNIEXPORT jlong JNICALL Java_com_aldebaran_qi_AnyObject_connect(JNIEnv *env, jobject jobj, jlong pObject, jstring method, jobject instance, jstring service, jstring eventName)
{
  qi::AnyObject&             obj = *(reinterpret_cast<qi::AnyObject *>(pObject));
  std::string                signature = qi::jni::toString(method);
  std::string                event = qi::jni::toString(eventName);
  qi_method_info*            data;
  std::vector<std::string>  sigInfo;

  // Keep a pointer on JavaVM singleton if not already set.
  JVM(env);

  // Create a new global reference on object instance.
  // jobject structure are local reference and are destroyed when returning to JVM
  instance = env->NewGlobalRef(instance);

  // Remove return value
  sigInfo = qi::signatureSplit(signature);
  signature = sigInfo[1];
  signature.append("::");
  signature.append(sigInfo[2]);

  // Create a struct holding a jobject instance, jmethodId id and other needed thing for callback
  // Pass it to void * data to register_method
  // FIXME jobj is not a global ref, it may be invalid when it will be used
  data = new qi_method_info(instance, signature, jobj);
  gInfoHandler.push(data);

  try {
    qi::SignalLink link =obj.connect(event,
                        qi::SignalSubscriber(
                          qi::AnyFunction::fromDynamicFunction(
                            boost::bind(&event_callback_to_java, (void*) data, _1))));
    return link;
  } catch (std::exception& e)
  {
    throwNewException(env, e.what());
    return 0;
  }
}

JNIEXPORT jlong JNICALL Java_com_aldebaran_qi_AnyObject_connectSignal(JNIEnv *env, jobject QI_UNUSED(obj), jlong pObject, jstring jSignalName, jobject listener)
{
  qi::AnyObject *anyObject = reinterpret_cast<qi::AnyObject *>(pObject);
  std::string signalName = qi::jni::toString(jSignalName);
  auto gListener = qi::jni::makeSharedGlobalRef(env, listener);

  qi::SignalSubscriber subscriber {
    qi::AnyFunction::fromDynamicFunction(
      [gListener](const std::vector<qi::AnyReference> &params) -> qi::AnyReference {
        jobject listener = gListener.get();

        qi::jni::JNIAttach attach;
        JNIEnv *env = attach.get();

        const char *method = "onSignalReceived";
        const char *methodSig = "([Ljava/lang/Object;)V";
        jobjectArray jparams = qi::jni::toJobjectArray(params);
        qi::jni::Call<void>::invoke(env, listener, method, methodSig, jparams);
        env->DeleteLocalRef(jparams);
        jthrowable exception = env->ExceptionOccurred();
        if (exception)
        {
          env->ExceptionDescribe();
          // an exception occurred in a listener, report and ignore
          env->ExceptionClear();
        }
        return {}; // a void AnyReference
      }
    )
  };

  qi::Future<qi::SignalLink> signalLinkFuture = anyObject->connect(signalName, subscriber);

  qi::Future<qi::AnyValue> future = qi::toAnyValueFuture(std::move(signalLinkFuture));
  auto futurePtr = new qi::Future<qi::AnyValue>(std::move(future));
  return reinterpret_cast<jlong>(futurePtr);
}

JNIEXPORT jlong JNICALL Java_com_aldebaran_qi_AnyObject_disconnectSignal(JNIEnv *env, jobject QI_UNUSED(obj), jlong pObject, jlong subscriberId)
{
  qi::AnyObject *anyObject = reinterpret_cast<qi::AnyObject *>(pObject);
  qi::Future<void> disconnectFuture = anyObject->disconnect(subscriberId);

  qi::Future<qi::AnyValue> future = qi::toAnyValueFuture(std::move(disconnectFuture));
  auto futurePtr = new qi::Future<qi::AnyValue>(std::move(future));
  return reinterpret_cast<jlong>(futurePtr);
}

JNIEXPORT void JNICALL Java_com_aldebaran_qi_AnyObject_post(JNIEnv *env, jobject QI_UNUSED(jobj), jlong pObject, jstring eventName, jobjectArray jargs)
{
  qi::AnyObject obj = *(reinterpret_cast<qi::AnyObject *>(pObject));
  std::string   event = qi::jni::toString(eventName);
  qi::GenericFunctionParameters params;
  std::string signature;
  jsize size;
  jsize i = 0;

  qi::jni::JNIAttach attach(env);

  size = env->GetArrayLength(jargs);
  i = 0;
  while (i < size)
  {
    jobject current = env->GetObjectArrayElement(jargs, i);
    qi::AnyReference val = qi::AnyReference(AnyValue_from_JObject(current).first);
    params.push_back(val);
    i++;
  }

  // Signature construction
  signature = event + "::(";
  for (unsigned i=0; i< params.size(); ++i)
    signature += params[i].signature(true).toString();
  signature += ")";

  try {
    obj.metaPost(event, params);
  } catch (std::exception& e)
  {
    throwNewException(env, e.what());
  }

  // Destroy arguments
  i = 0;
  for(qi::GenericFunctionParameters::iterator it = params.begin(); it != params.end(); ++it)
    (*it).destroy();
  return;
}

JNIEXPORT jobject JNICALL Java_com_aldebaran_qi_AnyObject_decodeJSON(JNIEnv *QI_UNUSED(env), jclass QI_UNUSED(cls), jstring what)
{
  std::string str = qi::jni::toString(what);
  qi::AnyValue val = qi::decodeJSON(str);
  return JObject_from_AnyValue(val.asReference());
}

JNIEXPORT jstring JNICALL Java_com_aldebaran_qi_AnyObject_encodeJSON(JNIEnv *QI_UNUSED(env), jclass QI_UNUSED(cls), jobject what)
{
  std::string res = qi::encodeJSON(what);
  return qi::jni::toJstring(res);
}
<|endoftext|>


<commit_before>#include <stingray/toolkit/string/regex.h>

#ifdef PLATFORM_POSIX
#	include <regex.h>
#else
#	warning No regex support on nonposix systems!
#endif

#include <stingray/toolkit/string/StringUtils.h>
#include <stingray/toolkit/exception.h>
#include <stingray/toolkit/variant.h>

namespace stingray
{

	struct RegexMatch
	{
		int	Begin;
		int	End;

		RegexMatch() : Begin(0), End(0) { }

		int GetLength() const
		{
			int len = End - Begin;
			STINGRAYKIT_CHECK(len > 0, "Submatch length is negative!");
			return len;
		}

		std::string ToString() const { return StringBuilder() % "(" % Begin % ", " % End % ")"; }
	};

	typedef std::vector<RegexMatch>						RegexMatchVec;

	typedef variant<TypeList<std::string, int>::type>	ReplacementEntry;
	typedef std::vector<ReplacementEntry>				ReplacementEntryVec;

	class ReplacementEntryVisitor : public static_visitor<std::string>
	{
	private:
		const char*				_srcString;
		const RegexMatchVec&	_matches;

	public:
		ReplacementEntryVisitor(const char* srcString, const RegexMatchVec& matches)
			: _srcString(srcString), _matches(matches)
		{ }

		std::string operator () (int matchNumber) const
		{
			int i = matchNumber;
			STINGRAYKIT_CHECK(i >= 0 && i < (int)_matches.size(), IndexOutOfRangeException(i, _matches.size()));
			std::string res = std::string(_srcString + _matches[i].Begin, _matches[i].GetLength());
			return res;
		}

		std::string operator () (const std::string& str) const
		{ return str; }
	};

	template < typename PlatformRegex >
	class BasicRegexImpl : public PlatformRegex
	{
	public:
		BasicRegexImpl(const std::string& str)
			: PlatformRegex(str)
		{ }

		bool Search(const std::string& str, smatch& m, regex_constants::match_flag_type flags)
		{
			m._results.clear();
			m._positions.clear();

			STINGRAYKIT_CHECK(flags == regex_constants::match_default, NotImplementedException());

			RegexMatchVec matches;
			if (!this->DoMatch(str.c_str(), matches))
				return false;

			for (size_t i = 0; i < matches.size(); ++i)
			{
				RegexMatch& submatch = matches[i];
				m._results.push_back(str.substr(submatch.Begin, submatch.GetLength()));
				m._positions.push_back(submatch.Begin);
			}
			return true;
		}

		std::string Replace(const std::string& str, const regex& re, const std::string& replacement, regex_constants::match_flag_type flags)
		{
			STINGRAYKIT_CHECK((flags & ~regex_constants::format_first_only) == 0, NotImplementedException());

			ReplacementEntryVec replacement_entries;
			PlatformRegex group_regex("\\\\(\\d+)"); // TODO: cache this somewhere
			RegexMatchVec group_matches;

			size_t replacement_begin = 0;
			do
			{
				if (!group_regex.DoMatch(replacement.c_str() + replacement_begin, group_matches))
				{
					if (replacement_begin < replacement.size())
						replacement_entries.push_back(replacement.substr(replacement_begin));
					break;
				}

				if (group_matches.at(0).Begin > 0)
					replacement_entries.push_back(replacement.substr(replacement_begin, group_matches.at(0).Begin));
				replacement_entries.push_back(FromString<int>(replacement.substr(group_matches.at(1).Begin, group_matches.at(1).GetLength())));
				replacement_begin += group_matches.at(0).End;
			} while (true);

			int begin = 0;
			std::string result;

			RegexMatchVec matches;
			do
			{
				if (!this->DoMatch(str.c_str() + begin, matches))
				{
					result += str.substr(begin);
					break;
				}

				ReplacementEntryVisitor visitor(str.c_str() + begin, matches);

				result += str.substr(begin, matches.at(0).Begin);
				for (ReplacementEntryVec::const_iterator it = replacement_entries.begin(); it != replacement_entries.end(); ++it)
					result += apply_visitor(visitor, *it);
				begin += matches.at(0).End;
			} while (true);

			return result;
		}
	};

#ifdef PLATFORM_POSIX
	class PosixRegexImpl
	{
	private:
		std::string	_str;
		regex_t		_regex;

	public:
		PosixRegexImpl(const std::string& str)
			: _str(str)
		{
			ReplaceAll(_str, "\\d", "[0-9]");

			int ret = regcomp(&_regex, _str.c_str(), REG_EXTENDED);
			STINGRAYKIT_CHECK(ret == 0, StringBuilder() % "Could not compile regex '" % _str % "', ret = " % ret % "\n" % GetRegexError(_regex, ret));
		}

		~PosixRegexImpl()
		{ regfree(&_regex); }

		bool DoMatch(const char* str, RegexMatchVec& matches) const
		{
			std::vector<regmatch_t> posix_matches(32);
			int ret = regexec(&_regex, str, posix_matches.size(), posix_matches.data(), 0);

			if (ret == REG_NOMATCH)
				return false;

			if (ret != 0)
				STINGRAYKIT_THROW(StringBuilder() % "Could not execute regex '" % _str % "' for string '" % str % "', ret = " % ret % "\n" % GetRegexError(_regex, ret));

			int count = 0;
			while (posix_matches[count].rm_so >= 0)
				++count;

			matches.resize(count);
			for (int i = 0; i < count; ++i)
			{
				matches[i].Begin = posix_matches[i].rm_so;
				matches[i].End = posix_matches[i].rm_eo;
			}
			return true;
		}

	private:
		static std::string GetRegexError(const regex_t& regex, int errCode)
		{
			std::string result(256, '~');
			result.resize(regerror(errCode, &regex, &result[0], result.size()));
			return result;
		}
	};

	typedef PosixRegexImpl	PlatformRegexImpl;
#endif

	class regex::Impl : public BasicRegexImpl<PlatformRegexImpl>
	{
	public:
		Impl(const std::string& str) : BasicRegexImpl<PlatformRegexImpl>(str) { }
	};

	regex::regex(const std::string& str)
		: _impl(new Impl(str))
	{ }

	regex::regex(const regex& other)
		: _impl(other._impl)
	{ }

	regex::~regex()
	{ }

	regex& regex::operator = (const regex& other)
	{
		_impl = other._impl;
		return *this;
	}

	bool regex_search(const std::string& str, smatch& m, const regex& re, regex_constants::match_flag_type flags)
	{
		return re._impl->Search(str, m, flags);
	}

	std::string regex_replace(const std::string& str, const regex& re, const std::string& replacement, regex_constants::match_flag_type flags)
	{
		return re._impl->Replace(str, re, replacement, flags);
	}

}
<commit_msg>add \w regex metacharacter support<commit_after>#include <stingray/toolkit/string/regex.h>

#ifdef PLATFORM_POSIX
#	include <regex.h>
#else
#	warning No regex support on nonposix systems!
#endif

#include <stingray/toolkit/string/StringUtils.h>
#include <stingray/toolkit/exception.h>
#include <stingray/toolkit/variant.h>

namespace stingray
{

	struct RegexMatch
	{
		int	Begin;
		int	End;

		RegexMatch() : Begin(0), End(0) { }

		int GetLength() const
		{
			int len = End - Begin;
			STINGRAYKIT_CHECK(len > 0, "Submatch length is negative!");
			return len;
		}

		std::string ToString() const { return StringBuilder() % "(" % Begin % ", " % End % ")"; }
	};

	typedef std::vector<RegexMatch>						RegexMatchVec;

	typedef variant<TypeList<std::string, int>::type>	ReplacementEntry;
	typedef std::vector<ReplacementEntry>				ReplacementEntryVec;

	class ReplacementEntryVisitor : public static_visitor<std::string>
	{
	private:
		const char*				_srcString;
		const RegexMatchVec&	_matches;

	public:
		ReplacementEntryVisitor(const char* srcString, const RegexMatchVec& matches)
			: _srcString(srcString), _matches(matches)
		{ }

		std::string operator () (int matchNumber) const
		{
			int i = matchNumber;
			STINGRAYKIT_CHECK(i >= 0 && i < (int)_matches.size(), IndexOutOfRangeException(i, _matches.size()));
			std::string res = std::string(_srcString + _matches[i].Begin, _matches[i].GetLength());
			return res;
		}

		std::string operator () (const std::string& str) const
		{ return str; }
	};

	template < typename PlatformRegex >
	class BasicRegexImpl : public PlatformRegex
	{
	public:
		BasicRegexImpl(const std::string& str)
			: PlatformRegex(str)
		{ }

		bool Search(const std::string& str, smatch& m, regex_constants::match_flag_type flags)
		{
			m._results.clear();
			m._positions.clear();

			STINGRAYKIT_CHECK(flags == regex_constants::match_default, NotImplementedException());

			RegexMatchVec matches;
			if (!this->DoMatch(str.c_str(), matches))
				return false;

			for (size_t i = 0; i < matches.size(); ++i)
			{
				RegexMatch& submatch = matches[i];
				m._results.push_back(str.substr(submatch.Begin, submatch.GetLength()));
				m._positions.push_back(submatch.Begin);
			}
			return true;
		}

		std::string Replace(const std::string& str, const regex& re, const std::string& replacement, regex_constants::match_flag_type flags)
		{
			STINGRAYKIT_CHECK((flags & ~regex_constants::format_first_only) == 0, NotImplementedException());

			ReplacementEntryVec replacement_entries;
			PlatformRegex group_regex("\\\\(\\d+)"); // TODO: cache this somewhere
			RegexMatchVec group_matches;

			size_t replacement_begin = 0;
			do
			{
				if (!group_regex.DoMatch(replacement.c_str() + replacement_begin, group_matches))
				{
					if (replacement_begin < replacement.size())
						replacement_entries.push_back(replacement.substr(replacement_begin));
					break;
				}

				if (group_matches.at(0).Begin > 0)
					replacement_entries.push_back(replacement.substr(replacement_begin, group_matches.at(0).Begin));
				replacement_entries.push_back(FromString<int>(replacement.substr(group_matches.at(1).Begin, group_matches.at(1).GetLength())));
				replacement_begin += group_matches.at(0).End;
			} while (true);

			int begin = 0;
			std::string result;

			RegexMatchVec matches;
			do
			{
				if (!this->DoMatch(str.c_str() + begin, matches))
				{
					result += str.substr(begin);
					break;
				}

				ReplacementEntryVisitor visitor(str.c_str() + begin, matches);

				result += str.substr(begin, matches.at(0).Begin);
				for (ReplacementEntryVec::const_iterator it = replacement_entries.begin(); it != replacement_entries.end(); ++it)
					result += apply_visitor(visitor, *it);
				begin += matches.at(0).End;
			} while (true);

			return result;
		}
	};

#ifdef PLATFORM_POSIX
	class PosixRegexImpl
	{
	private:
		std::string	_str;
		regex_t		_regex;

	public:
		PosixRegexImpl(const std::string& str)
			: _str(str)
		{
			ReplaceAll(_str, "\\d", "[0-9]");
			ReplaceAll(_str, "\\w", "[a-zA-Z0-9_]");

			int ret = regcomp(&_regex, _str.c_str(), REG_EXTENDED);
			STINGRAYKIT_CHECK(ret == 0, StringBuilder() % "Could not compile regex '" % _str % "', ret = " % ret % "\n" % GetRegexError(_regex, ret));
		}

		~PosixRegexImpl()
		{ regfree(&_regex); }

		bool DoMatch(const char* str, RegexMatchVec& matches) const
		{
			std::vector<regmatch_t> posix_matches(32);
			int ret = regexec(&_regex, str, posix_matches.size(), posix_matches.data(), 0);

			if (ret == REG_NOMATCH)
				return false;

			if (ret != 0)
				STINGRAYKIT_THROW(StringBuilder() % "Could not execute regex '" % _str % "' for string '" % str % "', ret = " % ret % "\n" % GetRegexError(_regex, ret));

			int count = 0;
			while (posix_matches[count].rm_so >= 0)
				++count;

			matches.resize(count);
			for (int i = 0; i < count; ++i)
			{
				matches[i].Begin = posix_matches[i].rm_so;
				matches[i].End = posix_matches[i].rm_eo;
			}
			return true;
		}

	private:
		static std::string GetRegexError(const regex_t& regex, int errCode)
		{
			std::string result(256, '~');
			result.resize(regerror(errCode, &regex, &result[0], result.size()));
			return result;
		}
	};

	typedef PosixRegexImpl	PlatformRegexImpl;
#endif

	class regex::Impl : public BasicRegexImpl<PlatformRegexImpl>
	{
	public:
		Impl(const std::string& str) : BasicRegexImpl<PlatformRegexImpl>(str) { }
	};

	regex::regex(const std::string& str)
		: _impl(new Impl(str))
	{ }

	regex::regex(const regex& other)
		: _impl(other._impl)
	{ }

	regex::~regex()
	{ }

	regex& regex::operator = (const regex& other)
	{
		_impl = other._impl;
		return *this;
	}

	bool regex_search(const std::string& str, smatch& m, const regex& re, regex_constants::match_flag_type flags)
	{
		return re._impl->Search(str, m, flags);
	}

	std::string regex_replace(const std::string& str, const regex& re, const std::string& replacement, regex_constants::match_flag_type flags)
	{
		return re._impl->Replace(str, re, replacement, flags);
	}

}
<|endoftext|>


<commit_before>// Copyright 2010-2014 RethinkDB, all rights reserved.
#include "btree/node.hpp"

#include "btree/leaf_node.hpp"
#include "btree/internal_node.hpp"

const block_magic_t btree_superblock_t::expected_magic = { { 's', 'u', 'p', 'e' } };
const block_magic_t internal_node_t::expected_magic = { { 'i', 'n', 't', 'e' } };
const block_magic_t btree_sindex_block_t::expected_magic = { { 's', 'i', 'n', 'd' } };

void btree_superblock_ct_asserts() {
    // Just some place to put the CT_ASSERTs
    CT_ASSERT(btree_superblock_t::METAINFO_BLOB_MAXREFLEN > 0);
    CT_ASSERT(from_cache_block_size_t<sizeof(btree_superblock_t)>::ser_size \
              == DEVICE_BLOCK_SIZE);
}

namespace node {

bool is_underfull(value_sizer_t *sizer, const node_t *node) {
    if (node->magic == sizer->btree_leaf_magic()) {
        return leaf::is_underfull(sizer, reinterpret_cast<const leaf_node_t *>(node));
    } else {
        rassert(is_internal(node));
        return internal_node::is_underfull(sizer->block_size(), reinterpret_cast<const internal_node_t *>(node));
    }
}

bool is_mergable(value_sizer_t *sizer, const node_t *node, const node_t *sibling, const internal_node_t *parent) {
    if (sizer->btree_leaf_magic() == node->magic) {
        return leaf::is_mergable(sizer, reinterpret_cast<const leaf_node_t *>(node), reinterpret_cast<const leaf_node_t *>(sibling));
    } else {
        rassert(is_internal(node));
        return internal_node::is_mergable(sizer->block_size(), reinterpret_cast<const internal_node_t *>(node), reinterpret_cast<const internal_node_t *>(sibling), parent);
    }
}

void split(value_sizer_t *sizer, node_t *node, node_t *rnode, btree_key_t *median) {
    if (is_leaf(node)) {
        leaf::split(sizer, reinterpret_cast<leaf_node_t *>(node),
                    reinterpret_cast<leaf_node_t *>(rnode), median);
    } else {
        internal_node::split(sizer->block_size(), reinterpret_cast<internal_node_t *>(node),
                             reinterpret_cast<internal_node_t *>(rnode), median);
    }
}

void merge(value_sizer_t *sizer, node_t *node, node_t *rnode, const internal_node_t *parent) {
    if (is_leaf(node)) {
        leaf::merge(sizer, reinterpret_cast<leaf_node_t *>(node), reinterpret_cast<leaf_node_t *>(rnode));
    } else {
        internal_node::merge(sizer->block_size(), reinterpret_cast<internal_node_t *>(node), reinterpret_cast<internal_node_t *>(rnode), parent);
    }
}

void validate(DEBUG_VAR value_sizer_t *sizer, DEBUG_VAR const node_t *node) {
#ifndef NDEBUG
    if (node->magic == sizer->btree_leaf_magic()) {
        leaf::validate(sizer, reinterpret_cast<const leaf_node_t *>(node));
    } else if (node->magic == internal_node_t::expected_magic) {
        internal_node::validate(sizer->block_size(), reinterpret_cast<const internal_node_t *>(node));
    } else {
        unreachable("Invalid leaf node type.");
    }
#endif
}

}  // namespace node
<commit_msg>Removed superfluous backslash<commit_after>// Copyright 2010-2014 RethinkDB, all rights reserved.
#include "btree/node.hpp"

#include "btree/leaf_node.hpp"
#include "btree/internal_node.hpp"

const block_magic_t btree_superblock_t::expected_magic = { { 's', 'u', 'p', 'e' } };
const block_magic_t internal_node_t::expected_magic = { { 'i', 'n', 't', 'e' } };
const block_magic_t btree_sindex_block_t::expected_magic = { { 's', 'i', 'n', 'd' } };

void btree_superblock_ct_asserts() {
    // Just some place to put the CT_ASSERTs
    CT_ASSERT(btree_superblock_t::METAINFO_BLOB_MAXREFLEN > 0);
    CT_ASSERT(from_cache_block_size_t<sizeof(btree_superblock_t)>::ser_size
              == DEVICE_BLOCK_SIZE);
}

namespace node {

bool is_underfull(value_sizer_t *sizer, const node_t *node) {
    if (node->magic == sizer->btree_leaf_magic()) {
        return leaf::is_underfull(sizer, reinterpret_cast<const leaf_node_t *>(node));
    } else {
        rassert(is_internal(node));
        return internal_node::is_underfull(sizer->block_size(), reinterpret_cast<const internal_node_t *>(node));
    }
}

bool is_mergable(value_sizer_t *sizer, const node_t *node, const node_t *sibling, const internal_node_t *parent) {
    if (sizer->btree_leaf_magic() == node->magic) {
        return leaf::is_mergable(sizer, reinterpret_cast<const leaf_node_t *>(node), reinterpret_cast<const leaf_node_t *>(sibling));
    } else {
        rassert(is_internal(node));
        return internal_node::is_mergable(sizer->block_size(), reinterpret_cast<const internal_node_t *>(node), reinterpret_cast<const internal_node_t *>(sibling), parent);
    }
}

void split(value_sizer_t *sizer, node_t *node, node_t *rnode, btree_key_t *median) {
    if (is_leaf(node)) {
        leaf::split(sizer, reinterpret_cast<leaf_node_t *>(node),
                    reinterpret_cast<leaf_node_t *>(rnode), median);
    } else {
        internal_node::split(sizer->block_size(), reinterpret_cast<internal_node_t *>(node),
                             reinterpret_cast<internal_node_t *>(rnode), median);
    }
}

void merge(value_sizer_t *sizer, node_t *node, node_t *rnode, const internal_node_t *parent) {
    if (is_leaf(node)) {
        leaf::merge(sizer, reinterpret_cast<leaf_node_t *>(node), reinterpret_cast<leaf_node_t *>(rnode));
    } else {
        internal_node::merge(sizer->block_size(), reinterpret_cast<internal_node_t *>(node), reinterpret_cast<internal_node_t *>(rnode), parent);
    }
}

void validate(DEBUG_VAR value_sizer_t *sizer, DEBUG_VAR const node_t *node) {
#ifndef NDEBUG
    if (node->magic == sizer->btree_leaf_magic()) {
        leaf::validate(sizer, reinterpret_cast<const leaf_node_t *>(node));
    } else if (node->magic == internal_node_t::expected_magic) {
        internal_node::validate(sizer->block_size(), reinterpret_cast<const internal_node_t *>(node));
    } else {
        unreachable("Invalid leaf node type.");
    }
#endif
}

}  // namespace node
<|endoftext|>