<commit_before>/*
 * WIN32 Events for POSIX
 * Author: Mahmoud Al-Qudsi <mqudsi@neosmart.net>
 * Copyright (C) 2011 by NeoSmart Technologies
 * This code is released under the terms of the MIT License
 */

#include "pevents.h"
#include <assert.h>
#include <sys/time.h>
#ifdef WFMO
#include <vector>
#endif

namespace neosmart
{
#ifdef WFMO
	struct neosmart_wfmo_t_
	{
		pthread_mutex_t Mutex;
		pthread_cond_t CVariable;
		std::vector<bool> EventStatus;
		bool StillWaiting;
		int RefCount;
		bool WaitAll;

		void Destroy()
		{
			pthread_mutex_destroy(&Mutex);
			pthread_cond_destroy(&CVariable);
		}
	};
	typedef neosmart_wfmo_t_ *neosmart_wfmo_t;

	struct neosmart_wfmo_info_t_
	{
		neosmart_wfmo_t Waiter;
		int WaitIndex;
	};
	typedef neosmart_wfmo_info_t_ *neosmart_wfmo_info_t;
#endif

	struct neosmart_event_t_
	{
		bool AutoReset;
		pthread_cond_t CVariable;
		pthread_mutex_t Mutex;
		bool State;
#ifdef WFMO
		std::vector<neosmart_wfmo_info_t_> RegisteredWaits;
#endif
	};

	neosmart_event_t CreateEvent(bool manualReset, bool initialState)
	{
		neosmart_event_t event = new neosmart_event_t_;

		pthread_mutexattr_t mutexattr;
		pthread_mutexattr_init(&mutexattr);
		pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE);

		int result = pthread_cond_init(&event->CVariable, 0);
		if(result != 0)
			return NULL;

		result = pthread_mutex_init(&event->Mutex, 0);
		if(result != 0)
			return NULL;

		event->State = false;
		event->AutoReset = !manualReset;

		if(initialState && SetEvent(event) != 0)
			return NULL; //Shouldn't ever happen

		return event;
	}

	int WaitForEvent(neosmart_event_t event, uint64_t milliseconds)
	{
		int result = pthread_mutex_lock(&event->Mutex);
		if(result != 0)
			return result;

		if(!event->State)
		{
			timespec ts;
			if(milliseconds != -1)
			{
				timeval tv;
				gettimeofday(&tv, NULL);

				uint64_t nanoseconds = tv.tv_sec * 1000 * 1000 * 1000 + milliseconds * 1000 * 1000 + tv.tv_usec * 1000;

				ts.tv_sec = nanoseconds / 1000 / 1000 / 1000;
				ts.tv_nsec = (nanoseconds - ts.tv_sec * 1000 * 1000 * 1000);
			}

			do
			{
				//Regardless of whether it's an auto-reset or manual-reset event:
				//wait to obtain the event, then lock anyone else out
				if(milliseconds != -1)
				{
					result = pthread_cond_timedwait(&event->CVariable, &event->Mutex, &ts);
				}
				else
				{
					result = pthread_cond_wait(&event->CVariable, &event->Mutex);
				}
			} while(result == 0 && !event->State);

			if(result == 0)
			{
				//We've only accquired the event if the wait succeeded
				event->State = false;
			}
		}
		else if(event->AutoReset)
		{
			//It's an auto-reset event that's currently available;
			//we need to stop anyone else from using it
			result = 0;
			event->State = false;
		}
		//Else we're trying to obtain a manual reset event with a signalled state;
		//don't do anything

		pthread_mutex_unlock(&event->Mutex);

		return result;
	}

#ifdef WFMO
	int WaitForMultipleEvents(neosmart_event_t *events, int count, bool waitAll, uint64_t milliseconds, int &waitIndex)
	{
		neosmart_wfmo_t wfmo = new neosmart_wfmo_t_;

		int result = pthread_mutex_init(&wfmo->Mutex, 0);
		if(result != 0)
			return result;

		result = pthread_cond_init(&wfmo->CVariable, 0);
		if(result != 0)
			return result;

		neosmart_wfmo_info_t_ waitInfo;
		waitInfo.Waiter = wfmo;
		waitInfo.WaitIndex = -1;

		wfmo->WaitAll = waitAll;
		wfmo->StillWaiting = true;
		wfmo->RefCount = 1;
		wfmo->EventStatus.resize(count, false);

		pthread_mutex_lock(&wfmo->Mutex);

		bool done = false;
		waitIndex = -1;

		for(int i = 0; i < count; ++i)
		{
			waitInfo.WaitIndex = i;

			if(WaitForEvent(events[i], 0) == 0)
			{
				wfmo->EventStatus[i] = true;
				if(!waitAll)
				{
					waitIndex = i;
					done = true;
					break;
				}
			}
			else
			{
				int result = pthread_mutex_lock(&events[i]->Mutex);
				if(result != 0)
					return result;

				events[i]->RegisteredWaits.push_back(waitInfo);
				++wfmo->RefCount;

				pthread_mutex_unlock(&events[i]->Mutex);
			}
		}

		timespec ts;
		if(!done && milliseconds != -1)
		{
			timeval tv;
			gettimeofday(&tv, NULL);

			uint64_t nanoseconds = tv.tv_sec * 1000 * 1000 * 1000 + milliseconds * 1000 * 1000 + tv.tv_usec * 1000;

			ts.tv_sec = nanoseconds / 1000 / 1000 / 1000;
			ts.tv_nsec = (nanoseconds - ts.tv_sec * 1000 * 1000 * 1000);
		}

		while(!done)
		{
			//One (or more) of the events we're monitoring has been triggered?

			//If we're waiting for all events, assume we're done and check if there's an event that hasn't fired
			//But if we're waiting for just one event, assume we're not done until we find a fired event
			done = waitAll;
			for(int i = 0; i < count; ++i)
			{
				if(!waitAll && wfmo->EventStatus[i])
				{
					done = true;
					waitIndex = i;
					break;
				}
				if(waitAll && !wfmo->EventStatus[i])
				{
					done = false;
					break;
				}
			}

			if(!done)
			{
				if(milliseconds != -1)
				{
					result = pthread_cond_timedwait(&wfmo->CVariable, &wfmo->Mutex, &ts);
				}
				else
				{
					result = pthread_cond_wait(&wfmo->CVariable, &wfmo->Mutex);
				}

				if(result != 0)
					break;
			}
		}

		wfmo->StillWaiting = false;

		--wfmo->RefCount;
		if(wfmo->RefCount == 0)
		{
			wfmo->Destroy();
			delete wfmo;
		}
		else
		{
			pthread_mutex_unlock(&wfmo->Mutex);
		}

		return result;
	}
#endif

	int DestroyEvent(neosmart_event_t event)
	{
		int result = pthread_cond_destroy(&event->CVariable);
		if(result != 0)
			return result;

		result = pthread_mutex_destroy(&event->Mutex);
		if(result != 0)
			return result;

		delete event;

		return 0;
	}

	int SetEvent(neosmart_event_t event)
	{
		int result = pthread_mutex_lock(&event->Mutex);
		if(result != 0)
			return result;

		event->State = true;

		//Depending on the event type, we either trigger everyone or only one
		if(event->AutoReset)
		{
#ifdef WFMO
			bool skipCV = false;
			while(!event->RegisteredWaits.empty())
			{
				neosmart_wfmo_info_t i = &event->RegisteredWaits.back();
				pthread_mutex_lock(&i->Waiter->Mutex);
				--i->Waiter->RefCount;
				if(!i->Waiter->StillWaiting)
				{
					if(i->Waiter->RefCount == 0)
					{
						i->Waiter->Destroy();
						delete i->Waiter;
					}
					else
					{
						pthread_mutex_unlock(&i->Waiter->Mutex);
					}
					event->RegisteredWaits.pop_back();
					continue;
				}

				skipCV = true;
				event->State = false;
				i->Waiter->EventStatus[i->WaitIndex] = true;
				if(!i->Waiter->WaitAll)
					i->Waiter->StillWaiting = false;
				result = pthread_cond_signal(&i->Waiter->CVariable);
				pthread_mutex_unlock(&i->Waiter->Mutex);
				event->RegisteredWaits.pop_back();
				break;
			}
			if(!skipCV)
#endif
			result = pthread_cond_signal(&event->CVariable);
		}
		else
		{
#ifdef WFMO
			for(int i = 0; i < event->RegisteredWaits.size(); ++i)
			{
				neosmart_wfmo_info_t info = &event->RegisteredWaits[i];
				pthread_mutex_lock(&info->Waiter->Mutex);
				--info->Waiter->RefCount;
				if(!info->Waiter->StillWaiting)
				{
					if(info->Waiter->RefCount == 0)
					{
						info->Waiter->Destroy();
						delete info->Waiter;
					}
					else
					{
						pthread_mutex_unlock(&info->Waiter->Mutex);
					}
					continue;
				}
				info->Waiter->EventStatus[info->WaitIndex] = true;
				pthread_cond_signal(&info->Waiter->CVariable);
				pthread_mutex_unlock(&info->Waiter->Mutex);
			}
			event->RegisteredWaits.clear();
#endif
			result = pthread_cond_broadcast(&event->CVariable);
		}

		pthread_mutex_unlock(&event->Mutex);

		return result;
	}

	int ResetEvent(neosmart_event_t event)
	{
		int result = pthread_mutex_lock(&event->Mutex);
		if(result != 0)
			return result;

		event->State = false;

		pthread_mutex_unlock(&event->Mutex);

		return result;
	}
}
<commit_msg>Cleaned up ugly conditional across #ifdef borders<commit_after>/*
 * WIN32 Events for POSIX
 * Author: Mahmoud Al-Qudsi <mqudsi@neosmart.net>
 * Copyright (C) 2011 by NeoSmart Technologies
 * This code is released under the terms of the MIT License
 */

#include "pevents.h"
#include <assert.h>
#include <sys/time.h>
#ifdef WFMO
#include <vector>
#endif

namespace neosmart
{
#ifdef WFMO
	struct neosmart_wfmo_t_
	{
		pthread_mutex_t Mutex;
		pthread_cond_t CVariable;
		std::vector<bool> EventStatus;
		bool StillWaiting;
		int RefCount;
		bool WaitAll;

		void Destroy()
		{
			pthread_mutex_destroy(&Mutex);
			pthread_cond_destroy(&CVariable);
		}
	};
	typedef neosmart_wfmo_t_ *neosmart_wfmo_t;

	struct neosmart_wfmo_info_t_
	{
		neosmart_wfmo_t Waiter;
		int WaitIndex;
	};
	typedef neosmart_wfmo_info_t_ *neosmart_wfmo_info_t;
#endif

	struct neosmart_event_t_
	{
		bool AutoReset;
		pthread_cond_t CVariable;
		pthread_mutex_t Mutex;
		bool State;
#ifdef WFMO
		std::vector<neosmart_wfmo_info_t_> RegisteredWaits;
#endif
	};

	neosmart_event_t CreateEvent(bool manualReset, bool initialState)
	{
		neosmart_event_t event = new neosmart_event_t_;

		pthread_mutexattr_t mutexattr;
		pthread_mutexattr_init(&mutexattr);
		pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE);

		int result = pthread_cond_init(&event->CVariable, 0);
		if(result != 0)
			return NULL;

		result = pthread_mutex_init(&event->Mutex, 0);
		if(result != 0)
			return NULL;

		event->State = false;
		event->AutoReset = !manualReset;

		if(initialState && SetEvent(event) != 0)
			return NULL; //Shouldn't ever happen

		return event;
	}

	int WaitForEvent(neosmart_event_t event, uint64_t milliseconds)
	{
		int result = pthread_mutex_lock(&event->Mutex);
		if(result != 0)
			return result;

		if(!event->State)
		{
			timespec ts;
			if(milliseconds != -1)
			{
				timeval tv;
				gettimeofday(&tv, NULL);

				uint64_t nanoseconds = tv.tv_sec * 1000 * 1000 * 1000 + milliseconds * 1000 * 1000 + tv.tv_usec * 1000;

				ts.tv_sec = nanoseconds / 1000 / 1000 / 1000;
				ts.tv_nsec = (nanoseconds - ts.tv_sec * 1000 * 1000 * 1000);
			}

			do
			{
				//Regardless of whether it's an auto-reset or manual-reset event:
				//wait to obtain the event, then lock anyone else out
				if(milliseconds != -1)
				{
					result = pthread_cond_timedwait(&event->CVariable, &event->Mutex, &ts);
				}
				else
				{
					result = pthread_cond_wait(&event->CVariable, &event->Mutex);
				}
			} while(result == 0 && !event->State);

			if(result == 0)
			{
				//We've only accquired the event if the wait succeeded
				event->State = false;
			}
		}
		else if(event->AutoReset)
		{
			//It's an auto-reset event that's currently available;
			//we need to stop anyone else from using it
			result = 0;
			event->State = false;
		}
		//Else we're trying to obtain a manual reset event with a signalled state;
		//don't do anything

		pthread_mutex_unlock(&event->Mutex);

		return result;
	}

#ifdef WFMO
	int WaitForMultipleEvents(neosmart_event_t *events, int count, bool waitAll, uint64_t milliseconds, int &waitIndex)
	{
		neosmart_wfmo_t wfmo = new neosmart_wfmo_t_;

		int result = pthread_mutex_init(&wfmo->Mutex, 0);
		if(result != 0)
			return result;

		result = pthread_cond_init(&wfmo->CVariable, 0);
		if(result != 0)
			return result;

		neosmart_wfmo_info_t_ waitInfo;
		waitInfo.Waiter = wfmo;
		waitInfo.WaitIndex = -1;

		wfmo->WaitAll = waitAll;
		wfmo->StillWaiting = true;
		wfmo->RefCount = 1;
		wfmo->EventStatus.resize(count, false);

		pthread_mutex_lock(&wfmo->Mutex);

		bool done = false;
		waitIndex = -1;

		for(int i = 0; i < count; ++i)
		{
			waitInfo.WaitIndex = i;

			if(WaitForEvent(events[i], 0) == 0)
			{
				wfmo->EventStatus[i] = true;
				if(!waitAll)
				{
					waitIndex = i;
					done = true;
					break;
				}
			}
			else
			{
				int result = pthread_mutex_lock(&events[i]->Mutex);
				if(result != 0)
					return result;

				events[i]->RegisteredWaits.push_back(waitInfo);
				++wfmo->RefCount;

				pthread_mutex_unlock(&events[i]->Mutex);
			}
		}

		timespec ts;
		if(!done && milliseconds != -1)
		{
			timeval tv;
			gettimeofday(&tv, NULL);

			uint64_t nanoseconds = tv.tv_sec * 1000 * 1000 * 1000 + milliseconds * 1000 * 1000 + tv.tv_usec * 1000;

			ts.tv_sec = nanoseconds / 1000 / 1000 / 1000;
			ts.tv_nsec = (nanoseconds - ts.tv_sec * 1000 * 1000 * 1000);
		}

		while(!done)
		{
			//One (or more) of the events we're monitoring has been triggered?

			//If we're waiting for all events, assume we're done and check if there's an event that hasn't fired
			//But if we're waiting for just one event, assume we're not done until we find a fired event
			done = waitAll;
			for(int i = 0; i < count; ++i)
			{
				if(!waitAll && wfmo->EventStatus[i])
				{
					done = true;
					waitIndex = i;
					break;
				}
				if(waitAll && !wfmo->EventStatus[i])
				{
					done = false;
					break;
				}
			}

			if(!done)
			{
				if(milliseconds != -1)
				{
					result = pthread_cond_timedwait(&wfmo->CVariable, &wfmo->Mutex, &ts);
				}
				else
				{
					result = pthread_cond_wait(&wfmo->CVariable, &wfmo->Mutex);
				}

				if(result != 0)
					break;
			}
		}

		wfmo->StillWaiting = false;

		--wfmo->RefCount;
		if(wfmo->RefCount == 0)
		{
			wfmo->Destroy();
			delete wfmo;
		}
		else
		{
			pthread_mutex_unlock(&wfmo->Mutex);
		}

		return result;
	}
#endif

	int DestroyEvent(neosmart_event_t event)
	{
		int result = pthread_cond_destroy(&event->CVariable);
		if(result != 0)
			return result;

		result = pthread_mutex_destroy(&event->Mutex);
		if(result != 0)
			return result;

		delete event;

		return 0;
	}

	int SetEvent(neosmart_event_t event)
	{
		int result = pthread_mutex_lock(&event->Mutex);
		if(result != 0)
			return result;

		event->State = true;

		//Depending on the event type, we either trigger everyone or only one
		if(event->AutoReset)
		{
#ifdef WFMO
			while(!event->RegisteredWaits.empty())
			{
				neosmart_wfmo_info_t i = &event->RegisteredWaits.back();
				pthread_mutex_lock(&i->Waiter->Mutex);
				--i->Waiter->RefCount;
				if(!i->Waiter->StillWaiting)
				{
					if(i->Waiter->RefCount == 0)
					{
						i->Waiter->Destroy();
						delete i->Waiter;
					}
					else
					{
						pthread_mutex_unlock(&i->Waiter->Mutex);
					}
					event->RegisteredWaits.pop_back();
					continue;
				}

				event->State = false;
				i->Waiter->EventStatus[i->WaitIndex] = true;
				if(!i->Waiter->WaitAll)
					i->Waiter->StillWaiting = false;
				result = pthread_cond_signal(&i->Waiter->CVariable);
				pthread_mutex_unlock(&i->Waiter->Mutex);
				event->RegisteredWaits.pop_back();
				break;
			}
#endif
			//event->State can be false if compiled with WFMO support
			if(event->State)
			{
				result = pthread_cond_signal(&event->CVariable);
			}
		}
		else
		{
#ifdef WFMO
			for(int i = 0; i < event->RegisteredWaits.size(); ++i)
			{
				neosmart_wfmo_info_t info = &event->RegisteredWaits[i];
				pthread_mutex_lock(&info->Waiter->Mutex);
				--info->Waiter->RefCount;
				if(!info->Waiter->StillWaiting)
				{
					if(info->Waiter->RefCount == 0)
					{
						info->Waiter->Destroy();
						delete info->Waiter;
					}
					else
					{
						pthread_mutex_unlock(&info->Waiter->Mutex);
					}
					continue;
				}
				info->Waiter->EventStatus[info->WaitIndex] = true;
				pthread_cond_signal(&info->Waiter->CVariable);
				pthread_mutex_unlock(&info->Waiter->Mutex);
			}
			event->RegisteredWaits.clear();
#endif
			result = pthread_cond_broadcast(&event->CVariable);
		}

		pthread_mutex_unlock(&event->Mutex);

		return result;
	}

	int ResetEvent(neosmart_event_t event)
	{
		int result = pthread_mutex_lock(&event->Mutex);
		if(result != 0)
			return result;

		event->State = false;

		pthread_mutex_unlock(&event->Mutex);

		return result;
	}
}
<|endoftext|>


<commit_before>#include <const_string/const_string.h>
#include <iostream>
#include <string>
#include <thread>

#include <catch2/catch.hpp>

using namespace std::literals;

void requireZero(std::string_view view) {
	REQUIRE(view.data()[view.size()] == '\0');
}

TEST_CASE("Provides standard container type defs", "[const_string]")
{
	using T = const_string;
	T::traits_type 	traits{};
	T::value_type 	v{};
	T::pointer		p{};
	T::const_pointer cp{};
	T::reference 	r = v;
	T::const_reference 	cr = v;
	T::const_iterator  cit{};
	T::iterator 	it{};
	T::reverse_iterator 	rit{};
	T::const_reverse_iterator 	crit{};
	T::size_type 	s{};
	T::difference_type 	d{};
	REQUIRE(true);
}

TEST_CASE("Provides standard container type defs 2", "[const_zstring]")
{
	using T = const_zstring;
	T::traits_type 	traits{};
	T::value_type 	v{};
	T::pointer		p{};
	T::const_pointer cp{};
	T::reference 	r = v;
	T::const_reference 	cr = v;
	T::const_iterator  cit{};
	T::iterator 	it{};
	T::reverse_iterator 	rit{};
	T::const_reverse_iterator 	crit{};
	T::size_type 	s{};
	T::difference_type 	d{};
	REQUIRE(true);
}

TEST_CASE("Construction from literal", "[const_string]")
{
	const_string str1 = "Hello World";
	REQUIRE(str1 == "Hello World");

	const_string str2{ "Hello World" };
	REQUIRE(str2 == "Hello World");

	const_string str3 = { "Hello World" };
	REQUIRE(str3 == "Hello World");
}

TEST_CASE("Construction empty", "[const_string]")
{
	const_string str1 = "";
	const_string str2{};
	REQUIRE(str1 == str2);
}

TEST_CASE("Construction from std::string", "[const_string]")
{
	const_string str1("Hello World");
	REQUIRE(str1 == "Hello World");

	const_string str2{ "Hello World"s };
	REQUIRE(str2 == "Hello World");

	auto stdstr = "Hello World"s;
	const_string str3{ stdstr };
	REQUIRE(str3 == "Hello World");
}

TEST_CASE("Construction from temporary std::string", "[const_string]")
{
	const_string cs = []
	{
		auto stdstr = "Hello World"s;
		const_string cs{ stdstr };
		stdstr[0] = 'M'; // modify original string to make sure we really have an independent copy
		REQUIRE(cs != stdstr);
		return cs;
	}();
	REQUIRE(cs == "Hello World");
}

TEST_CASE("Copy", "[const_string]")
{
	const_string str1;
	{
		//no heap allocation
		const_string tcs = "Hello World";
		str1 = tcs;
	}
	REQUIRE(str1 == "Hello World");

	const_string str2;
	{
		//heap allocated
		const_string tcs{ "Hello World"s };
		str2 = tcs;
	}
	REQUIRE(str2 == "Hello World");

}

TEST_CASE("concat", "[const_string]")
{
	const_string cs = "How are you?";
	auto combined = concat("Hello", " World! "s, cs);
	REQUIRE(combined == "Hello World! How are you?");
	REQUIRE(combined.isZeroTerminated());
	requireZero(combined);
}

TEST_CASE("thread")
{
	constexpr int iterations = 1'000'000;
	using namespace std::literals;
	const std::string	cpps1 = "Good";
	const std::string	cpps2 = "Bad";
	const_string s1{ "Hello"s };
	const_string s2{ "World!"s };
	std::atomic_uint64_t total = 0;

	std::atomic_int total_cpps1_fail_cnt = 0;
	std::atomic_int total_cpps2_fail_cnt = 0;
	std::atomic_int total_s1_fail_cnt = 0;
	std::atomic_int total_s2_fail_cnt = 0;

	auto f = [&, s1,s2] {
		int sum = 0;
		int cpps1_fail_cnt = 0;
		int cpps2_fail_cnt = 0;
		int s1_fail_cnt = 0;
		int s2_fail_cnt = 0;
		for (int i = 0; i < iterations; i++) {
			{
				const_string cs{ cpps1 };
				sum += cs.size();
				cpps1_fail_cnt += cs[0] != 'G';
			}
			{
				const_string cs{ cpps2 };
				sum += cs.size();
				cpps2_fail_cnt += cs[0] != 'B';
			}
			{
				auto s = s1;
				sum += s.size();
				s1_fail_cnt += s[0] != 'H';
				s = s2;
				s2_fail_cnt += s[0] != 'W';
				sum += s.size();
			}
		}
		total += sum;
		total_cpps1_fail_cnt += cpps1_fail_cnt;
		total_cpps2_fail_cnt += cpps2_fail_cnt;
		total_s1_fail_cnt += s1_fail_cnt;
		total_s2_fail_cnt += s2_fail_cnt;
	};
	std::thread th1(f);
	std::thread th2(f);
	th1.join();
	th2.join();
	REQUIRE(total == (s1.size() + s2.size() + cpps1.size() + cpps2.size()) * 2 * iterations);
	REQUIRE(total_cpps1_fail_cnt == 0);
	REQUIRE(total_cpps2_fail_cnt == 0);
	REQUIRE(total_s1_fail_cnt == 0);
	REQUIRE(total_s2_fail_cnt == 0);

}

//TEST_CASE("Split Position") {
//	const_string s("Hello World");
//	{
//		auto[h, w] = s.split(5);
//		REQUIRE(h == "Hello");
//		REQUIRE(w == " World");
//	}
//	{
//		auto[h, w] = s.split(5, const_string::Separator::KeepFront);
//		REQUIRE(h == "Hello");
//		REQUIRE(w == " World");
//	}
//	{
//		auto[h, w] = s.split(5, const_string::Separator::KeepBack);
//		REQUIRE(h == "Hello ");
//		REQUIRE(w == "World");
//	}
//	{
//		auto[h, w] = s.split(5, const_string::Separator::Drop);
//		REQUIRE(h == "Hello");
//		REQUIRE(w == "World");
//	}
//}
//
//TEST_CASE("Split Separator Single") {
//	const_string s("Hello World");
//	{
//		auto[h, w] = s.split_first(' ');
//		REQUIRE(h == "Hello");
//		REQUIRE(w == "World");
//	}
//	{
//		auto[h, w] = s.split_first(' ', const_string::Separator::KeepFront);
//		REQUIRE(h == "Hello");
//		REQUIRE(w == " World");
//	}
//	{
//		auto[h, w] = s.split_first(' ', const_string::Separator::KeepBack);
//		REQUIRE(h == "Hello ");
//		REQUIRE(w == "World");
//	}
//	{
//		auto[h, w] = s.split_first(' ', const_string::Separator::Drop);
//		REQUIRE(h == "Hello");
//		REQUIRE(w == "World");
//	}
//
//	{
//		auto[h, w] = s.split_last(' ');
//		REQUIRE(h == "Hello");
//		REQUIRE(w == "World");
//	}
//	{
//		auto[h, w] = s.split_last(' ', const_string::Separator::KeepFront);
//		REQUIRE(h == "Hello");
//		REQUIRE(w == " World");
//	}
//	{
//		auto[h, w] = s.split_last(' ', const_string::Separator::KeepBack);
//		REQUIRE(h == "Hello ");
//		REQUIRE(w == "World");
//	}
//	{
//		auto[h, w] = s.split_last(' ', const_string::Separator::Drop);
//		REQUIRE(h == "Hello");
//		REQUIRE(w == "World");
//	}
//}
//
//TEST_CASE("Split Separator multi") {
//	const_string s("Hello My World");
//	{
//		auto[h, w] = s.split_first(' ');
//		REQUIRE(h == "Hello");
//		REQUIRE(w == "My World");
//	}
//	{
//		auto[h, w] = s.split_first(' ', const_string::Separator::KeepFront);
//		REQUIRE(h == "Hello");
//		REQUIRE(w == " My World");
//	}
//	{
//		auto[h, w] = s.split_first(' ', const_string::Separator::KeepBack);
//		REQUIRE(h == "Hello ");
//		REQUIRE(w == "My World");
//	}
//	{
//		auto[h, w] = s.split_first(' ', const_string::Separator::Drop);
//		REQUIRE(h == "Hello");
//		REQUIRE(w == "My World");
//	}
//
//	{
//		auto[h, w] = s.split_last(' ');
//		REQUIRE(h == "Hello My");
//		REQUIRE(w == "World");
//	}
//	{
//		auto[h, w] = s.split_last(' ', const_string::Separator::KeepFront);
//		REQUIRE(h == "Hello My");
//		REQUIRE(w == " World");
//	}
//	{
//		auto[h, w] = s.split_last(' ', const_string::Separator::KeepBack);
//		REQUIRE(h == "Hello My ");
//		REQUIRE(w == "World");
//	}
//	{
//		auto[h, w] = s.split_last(' ', const_string::Separator::Drop);
//		REQUIRE(h == "Hello My");
//		REQUIRE(w == "World");
//	}
//}
//
//TEST_CASE("Split full") {
//	const_string s("Hello my dear! How are you?");
//	std::vector<const_string> rev{ "Hello", "my", "dear!", "How", "are", "you?" };
//	auto words = s.split_full(' ');
//	//for (auto w : words) {
//	//	std::cout << "[" << w << "]\n";
//	//}
//
//	REQUIRE(words.size() == 6);
//	REQUIRE(words == rev);
//
//}

//int main() {
//	std::cout << "Hello World\n";
//}<commit_msg>[Tests] Supress warnings about unused variables<commit_after>#include <const_string/const_string.h>
#include <iostream>
#include <string>
#include <thread>

#include <catch2/catch.hpp>

using namespace std::literals;

void requireZero(std::string_view view) {
	REQUIRE(view.data()[view.size()] == '\0');
}

TEST_CASE("Provides standard container type defs", "[const_string]")
{
	using T = const_string;
	[[maybe_unused]] T::traits_type			   traits {};
	[[maybe_unused]] T::value_type			   v {};
	[[maybe_unused]] T::pointer				   p {};
	[[maybe_unused]] T::const_pointer		   cp {};
	[[maybe_unused]] T::reference			   r  = v;
	[[maybe_unused]] T::const_reference		   cr = v;
	[[maybe_unused]] T::const_iterator		   cit {};
	[[maybe_unused]] T::iterator	           it {};
	[[maybe_unused]] T::reverse_iterator       rit {};
	[[maybe_unused]] T::const_reverse_iterator crit {};
	[[maybe_unused]] T::size_type			   s {};
	[[maybe_unused]] T::difference_type		   d {};
	REQUIRE(true);
}

TEST_CASE("Provides standard container type defs 2", "[const_zstring]")
{
	using T = const_zstring;
	[[maybe_unused]] T::traits_type traits {};
	[[maybe_unused]] T::value_type  v {};
	[[maybe_unused]] T::pointer		p {};
	[[maybe_unused]] T::const_pointer cp {};
	[[maybe_unused]] T::reference	 r  = v;
	[[maybe_unused]] T::const_reference cr = v;
	[[maybe_unused]] T::const_iterator  cit {};
	[[maybe_unused]] T::iterator		it {};
	[[maybe_unused]] T::reverse_iterator rit {};
	[[maybe_unused]] T::const_reverse_iterator crit {};
	[[maybe_unused]] T::size_type			   s {};
	[[maybe_unused]] T::difference_type		   d {};
	REQUIRE(true);
}

TEST_CASE("Construction from literal", "[const_string]")
{
	const_string str1 = "Hello World";
	REQUIRE(str1 == "Hello World");

	const_string str2{ "Hello World" };
	REQUIRE(str2 == "Hello World");

	const_string str3 = { "Hello World" };
	REQUIRE(str3 == "Hello World");
}

TEST_CASE("Construction empty", "[const_string]")
{
	const_string str1 = "";
	const_string str2{};
	REQUIRE(str1 == str2);
}

TEST_CASE("Construction from std::string", "[const_string]")
{
	const_string str1("Hello World");
	REQUIRE(str1 == "Hello World");

	const_string str2{ "Hello World"s };
	REQUIRE(str2 == "Hello World");

	auto stdstr = "Hello World"s;
	const_string str3{ stdstr };
	REQUIRE(str3 == "Hello World");
}

TEST_CASE("Construction from temporary std::string", "[const_string]")
{
	const_string cs = []
	{
		auto stdstr = "Hello World"s;
		const_string cs{ stdstr };
		stdstr[0] = 'M'; // modify original string to make sure we really have an independent copy
		REQUIRE(cs != stdstr);
		return cs;
	}();
	REQUIRE(cs == "Hello World");
}

TEST_CASE("Copy", "[const_string]")
{
	const_string str1;
	{
		//no heap allocation
		const_string tcs = "Hello World";
		str1 = tcs;
	}
	REQUIRE(str1 == "Hello World");

	const_string str2;
	{
		//heap allocated
		const_string tcs{ "Hello World"s };
		str2 = tcs;
	}
	REQUIRE(str2 == "Hello World");

}

TEST_CASE("concat", "[const_string]")
{
	const_string cs = "How are you?";
	auto combined = concat("Hello", " World! "s, cs);
	REQUIRE(combined == "Hello World! How are you?");
	REQUIRE(combined.isZeroTerminated());
	requireZero(combined);
}

TEST_CASE("thread")
{
	constexpr int iterations = 1'000'000;
	using namespace std::literals;
	const std::string	cpps1 = "Good";
	const std::string	cpps2 = "Bad";
	const_string s1{ "Hello"s };
	const_string s2{ "World!"s };
	std::atomic_uint64_t total = 0;

	std::atomic_int total_cpps1_fail_cnt = 0;
	std::atomic_int total_cpps2_fail_cnt = 0;
	std::atomic_int total_s1_fail_cnt = 0;
	std::atomic_int total_s2_fail_cnt = 0;

	auto f = [&, s1,s2] {
		int sum = 0;
		int cpps1_fail_cnt = 0;
		int cpps2_fail_cnt = 0;
		int s1_fail_cnt = 0;
		int s2_fail_cnt = 0;
		for (int i = 0; i < iterations; i++) {
			{
				const_string cs{ cpps1 };
				sum += cs.size();
				cpps1_fail_cnt += cs[0] != 'G';
			}
			{
				const_string cs{ cpps2 };
				sum += cs.size();
				cpps2_fail_cnt += cs[0] != 'B';
			}
			{
				auto s = s1;
				sum += s.size();
				s1_fail_cnt += s[0] != 'H';
				s = s2;
				s2_fail_cnt += s[0] != 'W';
				sum += s.size();
			}
		}
		total += sum;
		total_cpps1_fail_cnt += cpps1_fail_cnt;
		total_cpps2_fail_cnt += cpps2_fail_cnt;
		total_s1_fail_cnt += s1_fail_cnt;
		total_s2_fail_cnt += s2_fail_cnt;
	};
	std::thread th1(f);
	std::thread th2(f);
	th1.join();
	th2.join();
	REQUIRE(total == (s1.size() + s2.size() + cpps1.size() + cpps2.size()) * 2 * iterations);
	REQUIRE(total_cpps1_fail_cnt == 0);
	REQUIRE(total_cpps2_fail_cnt == 0);
	REQUIRE(total_s1_fail_cnt == 0);
	REQUIRE(total_s2_fail_cnt == 0);

}

//TEST_CASE("Split Position") {
//	const_string s("Hello World");
//	{
//		auto[h, w] = s.split(5);
//		REQUIRE(h == "Hello");
//		REQUIRE(w == " World");
//	}
//	{
//		auto[h, w] = s.split(5, const_string::Separator::KeepFront);
//		REQUIRE(h == "Hello");
//		REQUIRE(w == " World");
//	}
//	{
//		auto[h, w] = s.split(5, const_string::Separator::KeepBack);
//		REQUIRE(h == "Hello ");
//		REQUIRE(w == "World");
//	}
//	{
//		auto[h, w] = s.split(5, const_string::Separator::Drop);
//		REQUIRE(h == "Hello");
//		REQUIRE(w == "World");
//	}
//}
//
//TEST_CASE("Split Separator Single") {
//	const_string s("Hello World");
//	{
//		auto[h, w] = s.split_first(' ');
//		REQUIRE(h == "Hello");
//		REQUIRE(w == "World");
//	}
//	{
//		auto[h, w] = s.split_first(' ', const_string::Separator::KeepFront);
//		REQUIRE(h == "Hello");
//		REQUIRE(w == " World");
//	}
//	{
//		auto[h, w] = s.split_first(' ', const_string::Separator::KeepBack);
//		REQUIRE(h == "Hello ");
//		REQUIRE(w == "World");
//	}
//	{
//		auto[h, w] = s.split_first(' ', const_string::Separator::Drop);
//		REQUIRE(h == "Hello");
//		REQUIRE(w == "World");
//	}
//
//	{
//		auto[h, w] = s.split_last(' ');
//		REQUIRE(h == "Hello");
//		REQUIRE(w == "World");
//	}
//	{
//		auto[h, w] = s.split_last(' ', const_string::Separator::KeepFront);
//		REQUIRE(h == "Hello");
//		REQUIRE(w == " World");
//	}
//	{
//		auto[h, w] = s.split_last(' ', const_string::Separator::KeepBack);
//		REQUIRE(h == "Hello ");
//		REQUIRE(w == "World");
//	}
//	{
//		auto[h, w] = s.split_last(' ', const_string::Separator::Drop);
//		REQUIRE(h == "Hello");
//		REQUIRE(w == "World");
//	}
//}
//
//TEST_CASE("Split Separator multi") {
//	const_string s("Hello My World");
//	{
//		auto[h, w] = s.split_first(' ');
//		REQUIRE(h == "Hello");
//		REQUIRE(w == "My World");
//	}
//	{
//		auto[h, w] = s.split_first(' ', const_string::Separator::KeepFront);
//		REQUIRE(h == "Hello");
//		REQUIRE(w == " My World");
//	}
//	{
//		auto[h, w] = s.split_first(' ', const_string::Separator::KeepBack);
//		REQUIRE(h == "Hello ");
//		REQUIRE(w == "My World");
//	}
//	{
//		auto[h, w] = s.split_first(' ', const_string::Separator::Drop);
//		REQUIRE(h == "Hello");
//		REQUIRE(w == "My World");
//	}
//
//	{
//		auto[h, w] = s.split_last(' ');
//		REQUIRE(h == "Hello My");
//		REQUIRE(w == "World");
//	}
//	{
//		auto[h, w] = s.split_last(' ', const_string::Separator::KeepFront);
//		REQUIRE(h == "Hello My");
//		REQUIRE(w == " World");
//	}
//	{
//		auto[h, w] = s.split_last(' ', const_string::Separator::KeepBack);
//		REQUIRE(h == "Hello My ");
//		REQUIRE(w == "World");
//	}
//	{
//		auto[h, w] = s.split_last(' ', const_string::Separator::Drop);
//		REQUIRE(h == "Hello My");
//		REQUIRE(w == "World");
//	}
//}
//
//TEST_CASE("Split full") {
//	const_string s("Hello my dear! How are you?");
//	std::vector<const_string> rev{ "Hello", "my", "dear!", "How", "are", "you?" };
//	auto words = s.split_full(' ');
//	//for (auto w : words) {
//	//	std::cout << "[" << w << "]\n";
//	//}
//
//	REQUIRE(words.size() == 6);
//	REQUIRE(words == rev);
//
//}

//int main() {
//	std::cout << "Hello World\n";
//}<|endoftext|>


<commit_before>/*=========================================================================

  Program:   KWSys - Kitware System Library
  Module:    ProcessWin32Kill.cxx

  Copyright (c) Kitware, Inc., Insight Consortium.  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#define KWSYS_IN_PROCESS_C
#include "kwsysPrivate.h"
#include KWSYS_HEADER(ProcessWin32Kill.h)

/* The following process tree kill implementation is taken from
   http://www.alexfedotov.com/articles/killproc.asp
   It will work only on some versions of windows.  Hopefully
   I will eventually get some time to do a real implementation of this
   for all windows versions.  */

#include <windows.h>
#include <tchar.h>
#include <crtdbg.h>
#include <stdio.h>
#include <stdarg.h>
#include <tlhelp32.h>

//---------------------------------------------------------------------------
// KillProcess
//
//  Terminates the specified process.
//
//  Parameters:
//        dwProcessId - identifier of the process to terminate
//
//  Returns:
//        TRUE, if successful, FALSE - otherwise.
//
static BOOL
WINAPI
KillProcess(
        IN DWORD dwProcessId
        )
{
        HANDLE hProcess;
        DWORD dwError;

        // first try to obtain handle to the process without the use of any
        // additional privileges
        hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, dwProcessId);
        if (hProcess == NULL)
        {
                if (GetLastError() != ERROR_ACCESS_DENIED)
                        return FALSE;

                OSVERSIONINFO osvi;

                // determine operating system version
                osvi.dwOSVersionInfoSize = sizeof(osvi);
                GetVersionEx(&osvi);

                // we cannot do anything else if this is not Windows NT
                if (osvi.dwPlatformId != VER_PLATFORM_WIN32_NT)
                        return SetLastError(ERROR_ACCESS_DENIED), FALSE;

                // enable SE_DEBUG_NAME privilege and try again

                TOKEN_PRIVILEGES Priv, PrivOld;
                DWORD cbPriv = sizeof(PrivOld);
                HANDLE hToken;

                // obtain the token of the current thread
                if (!OpenThreadToken(GetCurrentThread(),
                                                         TOKEN_QUERY|TOKEN_ADJUST_PRIVILEGES,
                                                         FALSE, &hToken))
                {
                        if (GetLastError() != ERROR_NO_TOKEN)
                                return FALSE;

                        // revert to the process token
                        if (!OpenProcessToken(GetCurrentProcess(),
                                                                  TOKEN_QUERY|TOKEN_ADJUST_PRIVILEGES,
                                                                  &hToken))
                                return FALSE;
                }

                if(!(ANYSIZE_ARRAY > 0))
                  {
                  return 0;
                  }

                Priv.PrivilegeCount = 1;
                Priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
                LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &Priv.Privileges[0].Luid);

                // try to enable the privilege
                if (!AdjustTokenPrivileges(hToken, FALSE, &Priv, sizeof(Priv),
                                                                   &PrivOld, &cbPriv))
                {
                        dwError = GetLastError();
                        CloseHandle(hToken);
                        return SetLastError(dwError), FALSE;
                }

                if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
                {
                        // the SE_DEBUG_NAME privilege is not present in the caller's
                        // token
                        CloseHandle(hToken);
                        return SetLastError(ERROR_ACCESS_DENIED), FALSE;
                }

                // try to open process handle again
                hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, dwProcessId);
                dwError = GetLastError();

                // restore the original state of the privilege
                AdjustTokenPrivileges(hToken, FALSE, &PrivOld, sizeof(PrivOld),
                                                          NULL, NULL);
                CloseHandle(hToken);

                if (hProcess == NULL)
                        return SetLastError(FALSE), NULL;
        }

        // terminate the process
        if (!TerminateProcess(hProcess, (UINT)-1))
        {
                dwError = GetLastError();
                CloseHandle(hProcess);
                return SetLastError(dwError), FALSE;
        }

        CloseHandle(hProcess);

        // completed successfully
        return TRUE;
}

typedef LONG    NTSTATUS;
typedef LONG    KPRIORITY;

#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)

#define STATUS_INFO_LENGTH_MISMATCH      ((NTSTATUS)0xC0000004L)

#define SystemProcessesAndThreadsInformation    5

typedef struct _CLIENT_ID {
    DWORD           UniqueProcess;
    DWORD           UniqueThread;
} CLIENT_ID;

typedef struct _UNICODE_STRING {
    USHORT          Length;
    USHORT          MaximumLength;
    PWSTR           Buffer;
} UNICODE_STRING;

typedef struct _VM_COUNTERS {
    SIZE_T          PeakVirtualSize;
    SIZE_T          VirtualSize;
    ULONG           PageFaultCount;
    SIZE_T          PeakWorkingSetSize;
    SIZE_T          WorkingSetSize;
    SIZE_T          QuotaPeakPagedPoolUsage;
    SIZE_T          QuotaPagedPoolUsage;
    SIZE_T          QuotaPeakNonPagedPoolUsage;
    SIZE_T          QuotaNonPagedPoolUsage;
    SIZE_T          PagefileUsage;
    SIZE_T          PeakPagefileUsage;
} VM_COUNTERS;

typedef struct _SYSTEM_THREADS {
    LARGE_INTEGER   KernelTime;
    LARGE_INTEGER   UserTime;
    LARGE_INTEGER   CreateTime;
    ULONG                       WaitTime;
    PVOID                       StartAddress;
    CLIENT_ID       ClientId;
    KPRIORITY       Priority;
    KPRIORITY       BasePriority;
    ULONG                       ContextSwitchCount;
    LONG                        State;
    LONG                        WaitReason;
} SYSTEM_THREADS, * PSYSTEM_THREADS;

// Note that the size of the SYSTEM_PROCESSES structure is different on
// NT 4 and Win2K, but we don't care about it, since we don't access neither
// IoCounters member nor Threads array

typedef struct _SYSTEM_PROCESSES {
    ULONG                       NextEntryDelta;
    ULONG                       ThreadCount;
    ULONG                       Reserved1[6];
    LARGE_INTEGER   CreateTime;
    LARGE_INTEGER   UserTime;
    LARGE_INTEGER   KernelTime;
    UNICODE_STRING  ProcessName;
    KPRIORITY       BasePriority;
    ULONG                       ProcessId;
    ULONG                       InheritedFromProcessId;
    ULONG                       HandleCount;
    ULONG                       Reserved2[2];
    VM_COUNTERS     VmCounters;
#if _WIN32_WINNT >= 0x500
    IO_COUNTERS     IoCounters;
#endif
    SYSTEM_THREADS  Threads[1];
} SYSTEM_PROCESSES, * PSYSTEM_PROCESSES;

//---------------------------------------------------------------------------
// KillProcessTreeNtHelper
//
//  This is a recursive helper function that terminates all the processes
//  started by the specified process and them terminates the process itself
//
//  Parameters:
//        pInfo       - processes information
//        dwProcessId - identifier of the process to terminate
//
//  Returns:
//        Win32 error code.
//
static
BOOL
WINAPI
KillProcessTreeNtHelper(
        IN PSYSTEM_PROCESSES pInfo,
        IN DWORD dwProcessId
        )
{
  if(!pInfo)
    {
    return 0;
    }

    PSYSTEM_PROCESSES p = pInfo;

    // kill all children first
    for (;;)
    {
                if (p->InheritedFromProcessId == dwProcessId)
                        KillProcessTreeNtHelper(pInfo, p->ProcessId);

                if (p->NextEntryDelta == 0)
                        break;

                // find the address of the next process structure
                p = (PSYSTEM_PROCESSES)(((LPBYTE)p) + p->NextEntryDelta);
    }

        // kill the process itself
    if (!KillProcess(dwProcessId))
                return GetLastError();

        return ERROR_SUCCESS;
}

//---------------------------------------------------------------------------
// KillProcessTreeWinHelper
//
//  This is a recursive helper function that terminates all the processes
//  started by the specified process and them terminates the process itself
//
//  Parameters:
//        dwProcessId - identifier of the process to terminate
//
//  Returns:
//        Win32 error code.
//
static
BOOL
WINAPI
KillProcessTreeWinHelper(
        IN DWORD dwProcessId
        )
{
        HINSTANCE hKernel;
        HANDLE (WINAPI * _CreateToolhelp32Snapshot)(DWORD, DWORD);
        BOOL (WINAPI * _Process32First)(HANDLE, PROCESSENTRY32 *);
        BOOL (WINAPI * _Process32Next)(HANDLE, PROCESSENTRY32 *);

        // get handle to KERNEL32.DLL
        hKernel = GetModuleHandle(_T("kernel32.dll"));
        if(!hKernel)
          {
          return 0;
          }

        // locate necessary functions in KERNEL32.DLL
        *(FARPROC *)&_CreateToolhelp32Snapshot =
                GetProcAddress(hKernel, "CreateToolhelp32Snapshot");
        *(FARPROC *)&_Process32First =
                GetProcAddress(hKernel, "Process32First");
        *(FARPROC *)&_Process32Next =
                GetProcAddress(hKernel, "Process32Next");

        if (_CreateToolhelp32Snapshot == NULL ||
                _Process32First == NULL ||
                _Process32Next == NULL)
                return ERROR_PROC_NOT_FOUND;

        HANDLE hSnapshot;
        PROCESSENTRY32 Entry;

        // create a snapshot
        hSnapshot = _CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
        if (hSnapshot == INVALID_HANDLE_VALUE)
                return GetLastError();

        Entry.dwSize = sizeof(Entry);
        if (!_Process32First(hSnapshot, &Entry))
        {
                DWORD dwError = GetLastError();
                CloseHandle(hSnapshot);
                return dwError;
        }

        // kill all children first
        do
        {
                if (Entry.th32ParentProcessID == dwProcessId)
                        KillProcessTreeWinHelper(Entry.th32ProcessID);

                Entry.dwSize = sizeof(Entry);
        }
        while (_Process32Next(hSnapshot, &Entry));

        CloseHandle(hSnapshot);

        // kill the process itself
    if (!KillProcess(dwProcessId))
                return GetLastError();

        return ERROR_SUCCESS;
}

//---------------------------------------------------------------------------
// KillProcessEx
//
//  Terminates the specified process and, optionally, all processes started
//      from the specified process (the so-called process tree).
//
//  Parameters:
//        dwProcessId - identifier of the process to terminate
//        bTree           - specifies whether the entire process tree should be
//                                      terminated
//
//  Returns:
//        TRUE, if successful, FALSE - otherwise.
//
static BOOL
WINAPI
KillProcessEx(
        IN DWORD dwProcessId,
        IN BOOL bTree
        )
{
        if (!bTree)
                return KillProcess(dwProcessId);

        OSVERSIONINFO osvi;
        DWORD dwError;

        // determine operating system version
        osvi.dwOSVersionInfoSize = sizeof(osvi);
        GetVersionEx(&osvi);

        if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT &&
                osvi.dwMajorVersion < 5)
        {
                HINSTANCE hNtDll;
                NTSTATUS (WINAPI * _ZwQuerySystemInformation)(UINT, PVOID, ULONG, PULONG);

                // get handle to NTDLL.DLL
                hNtDll = GetModuleHandle(_T("ntdll.dll"));
                if(!hNtDll)
                  {
                  return 0;
                  }

                // find the address of ZwQuerySystemInformation
                *(FARPROC *)&_ZwQuerySystemInformation =
                        GetProcAddress(hNtDll, "ZwQuerySystemInformation");
                if (_ZwQuerySystemInformation == NULL)
                        return SetLastError(ERROR_PROC_NOT_FOUND), NULL;

                // obtain a handle to the default process heap
                HANDLE hHeap = GetProcessHeap();

                NTSTATUS Status;
                ULONG cbBuffer = 0x8000;
                PVOID pBuffer = NULL;

                // it is difficult to say a priory which size of the buffer
                // will be enough to retrieve all information, so we start
                // with 32K buffer and increase its size until we get the
                // information successfully
                do
                {
                        pBuffer = HeapAlloc(hHeap, 0, cbBuffer);
                        if (pBuffer == NULL)
                                return SetLastError(ERROR_NOT_ENOUGH_MEMORY), FALSE;

                        Status = _ZwQuerySystemInformation(
                                                        SystemProcessesAndThreadsInformation,
                                                        pBuffer, cbBuffer, NULL);

                        if (Status == STATUS_INFO_LENGTH_MISMATCH)
                        {
                                HeapFree(hHeap, 0, pBuffer);
                                cbBuffer *= 2;
                        }
                        else if (!NT_SUCCESS(Status))
                        {
                                HeapFree(hHeap, 0, pBuffer);
                                return SetLastError(Status), NULL;
                        }
                }
                while (Status == STATUS_INFO_LENGTH_MISMATCH);

                // call the helper function
                dwError = KillProcessTreeNtHelper((PSYSTEM_PROCESSES)pBuffer,
                                                                                dwProcessId);

                HeapFree(hHeap, 0, pBuffer);
        }
        else
        {
                // call the helper function
                dwError = KillProcessTreeWinHelper(dwProcessId);
        }

        SetLastError(dwError);
        return dwError == ERROR_SUCCESS;
}

extern "C" {
int kwsysProcessWin32Kill(int pid)
{
  return KillProcessEx(pid, 1)? 1:0;
}
}
<commit_msg>ENH: remove unused include file so it will build with mingw<commit_after>/*=========================================================================

  Program:   KWSys - Kitware System Library
  Module:    ProcessWin32Kill.cxx

  Copyright (c) Kitware, Inc., Insight Consortium.  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#define KWSYS_IN_PROCESS_C
#include "kwsysPrivate.h"
#include KWSYS_HEADER(ProcessWin32Kill.h)

/* The following process tree kill implementation is taken from
   http://www.alexfedotov.com/articles/killproc.asp
   It will work only on some versions of windows.  Hopefully
   I will eventually get some time to do a real implementation of this
   for all windows versions.  */

#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <stdarg.h>
#include <tlhelp32.h>

//---------------------------------------------------------------------------
// KillProcess
//
//  Terminates the specified process.
//
//  Parameters:
//        dwProcessId - identifier of the process to terminate
//
//  Returns:
//        TRUE, if successful, FALSE - otherwise.
//
static BOOL
WINAPI
KillProcess(
        IN DWORD dwProcessId
        )
{
        HANDLE hProcess;
        DWORD dwError;

        // first try to obtain handle to the process without the use of any
        // additional privileges
        hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, dwProcessId);
        if (hProcess == NULL)
        {
                if (GetLastError() != ERROR_ACCESS_DENIED)
                        return FALSE;

                OSVERSIONINFO osvi;

                // determine operating system version
                osvi.dwOSVersionInfoSize = sizeof(osvi);
                GetVersionEx(&osvi);

                // we cannot do anything else if this is not Windows NT
                if (osvi.dwPlatformId != VER_PLATFORM_WIN32_NT)
                        return SetLastError(ERROR_ACCESS_DENIED), FALSE;

                // enable SE_DEBUG_NAME privilege and try again

                TOKEN_PRIVILEGES Priv, PrivOld;
                DWORD cbPriv = sizeof(PrivOld);
                HANDLE hToken;

                // obtain the token of the current thread
                if (!OpenThreadToken(GetCurrentThread(),
                                                         TOKEN_QUERY|TOKEN_ADJUST_PRIVILEGES,
                                                         FALSE, &hToken))
                {
                        if (GetLastError() != ERROR_NO_TOKEN)
                                return FALSE;

                        // revert to the process token
                        if (!OpenProcessToken(GetCurrentProcess(),
                                                                  TOKEN_QUERY|TOKEN_ADJUST_PRIVILEGES,
                                                                  &hToken))
                                return FALSE;
                }

                if(!(ANYSIZE_ARRAY > 0))
                  {
                  return 0;
                  }

                Priv.PrivilegeCount = 1;
                Priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
                LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &Priv.Privileges[0].Luid);

                // try to enable the privilege
                if (!AdjustTokenPrivileges(hToken, FALSE, &Priv, sizeof(Priv),
                                                                   &PrivOld, &cbPriv))
                {
                        dwError = GetLastError();
                        CloseHandle(hToken);
                        return SetLastError(dwError), FALSE;
                }

                if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
                {
                        // the SE_DEBUG_NAME privilege is not present in the caller's
                        // token
                        CloseHandle(hToken);
                        return SetLastError(ERROR_ACCESS_DENIED), FALSE;
                }

                // try to open process handle again
                hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, dwProcessId);
                dwError = GetLastError();

                // restore the original state of the privilege
                AdjustTokenPrivileges(hToken, FALSE, &PrivOld, sizeof(PrivOld),
                                                          NULL, NULL);
                CloseHandle(hToken);

                if (hProcess == NULL)
                        return SetLastError(FALSE), NULL;
        }

        // terminate the process
        if (!TerminateProcess(hProcess, (UINT)-1))
        {
                dwError = GetLastError();
                CloseHandle(hProcess);
                return SetLastError(dwError), FALSE;
        }

        CloseHandle(hProcess);

        // completed successfully
        return TRUE;
}

typedef LONG    NTSTATUS;
typedef LONG    KPRIORITY;

#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)

#define STATUS_INFO_LENGTH_MISMATCH      ((NTSTATUS)0xC0000004L)

#define SystemProcessesAndThreadsInformation    5

typedef struct _CLIENT_ID {
    DWORD           UniqueProcess;
    DWORD           UniqueThread;
} CLIENT_ID;

typedef struct _UNICODE_STRING {
    USHORT          Length;
    USHORT          MaximumLength;
    PWSTR           Buffer;
} UNICODE_STRING;

typedef struct _VM_COUNTERS {
    SIZE_T          PeakVirtualSize;
    SIZE_T          VirtualSize;
    ULONG           PageFaultCount;
    SIZE_T          PeakWorkingSetSize;
    SIZE_T          WorkingSetSize;
    SIZE_T          QuotaPeakPagedPoolUsage;
    SIZE_T          QuotaPagedPoolUsage;
    SIZE_T          QuotaPeakNonPagedPoolUsage;
    SIZE_T          QuotaNonPagedPoolUsage;
    SIZE_T          PagefileUsage;
    SIZE_T          PeakPagefileUsage;
} VM_COUNTERS;

typedef struct _SYSTEM_THREADS {
    LARGE_INTEGER   KernelTime;
    LARGE_INTEGER   UserTime;
    LARGE_INTEGER   CreateTime;
    ULONG                       WaitTime;
    PVOID                       StartAddress;
    CLIENT_ID       ClientId;
    KPRIORITY       Priority;
    KPRIORITY       BasePriority;
    ULONG                       ContextSwitchCount;
    LONG                        State;
    LONG                        WaitReason;
} SYSTEM_THREADS, * PSYSTEM_THREADS;

// Note that the size of the SYSTEM_PROCESSES structure is different on
// NT 4 and Win2K, but we don't care about it, since we don't access neither
// IoCounters member nor Threads array

typedef struct _SYSTEM_PROCESSES {
    ULONG                       NextEntryDelta;
    ULONG                       ThreadCount;
    ULONG                       Reserved1[6];
    LARGE_INTEGER   CreateTime;
    LARGE_INTEGER   UserTime;
    LARGE_INTEGER   KernelTime;
    UNICODE_STRING  ProcessName;
    KPRIORITY       BasePriority;
    ULONG                       ProcessId;
    ULONG                       InheritedFromProcessId;
    ULONG                       HandleCount;
    ULONG                       Reserved2[2];
    VM_COUNTERS     VmCounters;
#if _WIN32_WINNT >= 0x500
    IO_COUNTERS     IoCounters;
#endif
    SYSTEM_THREADS  Threads[1];
} SYSTEM_PROCESSES, * PSYSTEM_PROCESSES;

//---------------------------------------------------------------------------
// KillProcessTreeNtHelper
//
//  This is a recursive helper function that terminates all the processes
//  started by the specified process and them terminates the process itself
//
//  Parameters:
//        pInfo       - processes information
//        dwProcessId - identifier of the process to terminate
//
//  Returns:
//        Win32 error code.
//
static
BOOL
WINAPI
KillProcessTreeNtHelper(
        IN PSYSTEM_PROCESSES pInfo,
        IN DWORD dwProcessId
        )
{
  if(!pInfo)
    {
    return 0;
    }

    PSYSTEM_PROCESSES p = pInfo;

    // kill all children first
    for (;;)
    {
                if (p->InheritedFromProcessId == dwProcessId)
                        KillProcessTreeNtHelper(pInfo, p->ProcessId);

                if (p->NextEntryDelta == 0)
                        break;

                // find the address of the next process structure
                p = (PSYSTEM_PROCESSES)(((LPBYTE)p) + p->NextEntryDelta);
    }

        // kill the process itself
    if (!KillProcess(dwProcessId))
                return GetLastError();

        return ERROR_SUCCESS;
}

//---------------------------------------------------------------------------
// KillProcessTreeWinHelper
//
//  This is a recursive helper function that terminates all the processes
//  started by the specified process and them terminates the process itself
//
//  Parameters:
//        dwProcessId - identifier of the process to terminate
//
//  Returns:
//        Win32 error code.
//
static
BOOL
WINAPI
KillProcessTreeWinHelper(
        IN DWORD dwProcessId
        )
{
        HINSTANCE hKernel;
        HANDLE (WINAPI * _CreateToolhelp32Snapshot)(DWORD, DWORD);
        BOOL (WINAPI * _Process32First)(HANDLE, PROCESSENTRY32 *);
        BOOL (WINAPI * _Process32Next)(HANDLE, PROCESSENTRY32 *);

        // get handle to KERNEL32.DLL
        hKernel = GetModuleHandle(_T("kernel32.dll"));
        if(!hKernel)
          {
          return 0;
          }

        // locate necessary functions in KERNEL32.DLL
        *(FARPROC *)&_CreateToolhelp32Snapshot =
                GetProcAddress(hKernel, "CreateToolhelp32Snapshot");
        *(FARPROC *)&_Process32First =
                GetProcAddress(hKernel, "Process32First");
        *(FARPROC *)&_Process32Next =
                GetProcAddress(hKernel, "Process32Next");

        if (_CreateToolhelp32Snapshot == NULL ||
                _Process32First == NULL ||
                _Process32Next == NULL)
                return ERROR_PROC_NOT_FOUND;

        HANDLE hSnapshot;
        PROCESSENTRY32 Entry;

        // create a snapshot
        hSnapshot = _CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
        if (hSnapshot == INVALID_HANDLE_VALUE)
                return GetLastError();

        Entry.dwSize = sizeof(Entry);
        if (!_Process32First(hSnapshot, &Entry))
        {
                DWORD dwError = GetLastError();
                CloseHandle(hSnapshot);
                return dwError;
        }

        // kill all children first
        do
        {
                if (Entry.th32ParentProcessID == dwProcessId)
                        KillProcessTreeWinHelper(Entry.th32ProcessID);

                Entry.dwSize = sizeof(Entry);
        }
        while (_Process32Next(hSnapshot, &Entry));

        CloseHandle(hSnapshot);

        // kill the process itself
    if (!KillProcess(dwProcessId))
                return GetLastError();

        return ERROR_SUCCESS;
}

//---------------------------------------------------------------------------
// KillProcessEx
//
//  Terminates the specified process and, optionally, all processes started
//      from the specified process (the so-called process tree).
//
//  Parameters:
//        dwProcessId - identifier of the process to terminate
//        bTree           - specifies whether the entire process tree should be
//                                      terminated
//
//  Returns:
//        TRUE, if successful, FALSE - otherwise.
//
static BOOL
WINAPI
KillProcessEx(
        IN DWORD dwProcessId,
        IN BOOL bTree
        )
{
        if (!bTree)
                return KillProcess(dwProcessId);

        OSVERSIONINFO osvi;
        DWORD dwError;

        // determine operating system version
        osvi.dwOSVersionInfoSize = sizeof(osvi);
        GetVersionEx(&osvi);

        if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT &&
                osvi.dwMajorVersion < 5)
        {
                HINSTANCE hNtDll;
                NTSTATUS (WINAPI * _ZwQuerySystemInformation)(UINT, PVOID, ULONG, PULONG);

                // get handle to NTDLL.DLL
                hNtDll = GetModuleHandle(_T("ntdll.dll"));
                if(!hNtDll)
                  {
                  return 0;
                  }

                // find the address of ZwQuerySystemInformation
                *(FARPROC *)&_ZwQuerySystemInformation =
                        GetProcAddress(hNtDll, "ZwQuerySystemInformation");
                if (_ZwQuerySystemInformation == NULL)
                        return SetLastError(ERROR_PROC_NOT_FOUND), NULL;

                // obtain a handle to the default process heap
                HANDLE hHeap = GetProcessHeap();

                NTSTATUS Status;
                ULONG cbBuffer = 0x8000;
                PVOID pBuffer = NULL;

                // it is difficult to say a priory which size of the buffer
                // will be enough to retrieve all information, so we start
                // with 32K buffer and increase its size until we get the
                // information successfully
                do
                {
                        pBuffer = HeapAlloc(hHeap, 0, cbBuffer);
                        if (pBuffer == NULL)
                                return SetLastError(ERROR_NOT_ENOUGH_MEMORY), FALSE;

                        Status = _ZwQuerySystemInformation(
                                                        SystemProcessesAndThreadsInformation,
                                                        pBuffer, cbBuffer, NULL);

                        if (Status == STATUS_INFO_LENGTH_MISMATCH)
                        {
                                HeapFree(hHeap, 0, pBuffer);
                                cbBuffer *= 2;
                        }
                        else if (!NT_SUCCESS(Status))
                        {
                                HeapFree(hHeap, 0, pBuffer);
                                return SetLastError(Status), NULL;
                        }
                }
                while (Status == STATUS_INFO_LENGTH_MISMATCH);

                // call the helper function
                dwError = KillProcessTreeNtHelper((PSYSTEM_PROCESSES)pBuffer,
                                                                                dwProcessId);

                HeapFree(hHeap, 0, pBuffer);
        }
        else
        {
                // call the helper function
                dwError = KillProcessTreeWinHelper(dwProcessId);
        }

        SetLastError(dwError);
        return dwError == ERROR_SUCCESS;
}

extern "C" {
int kwsysProcessWin32Kill(int pid)
{
  return KillProcessEx(pid, 1)? 1:0;
}
}
<|endoftext|>


<commit_before>//=====================================================================//
/*!	@file
	@brief	R8C RC-Servo テスター・メイン
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include "system.hpp"
#include "clock.hpp"
#include "port.hpp"
#include "common/delay.hpp"
#include "common/intr_utils.hpp"
#include "common/port_map.hpp"
#include "common/adc_io.hpp"
#include "common/trc_io.hpp"
#include "common/fifo.hpp"
#include "common/uart_io.hpp"
#include "common/format.hpp"

// どちらか片方を有効にする
#define JR_TYPE_SERVO
// #define FUTABA_TYPE_SERVO

namespace {

#ifdef JR_TYPE_SERVO
	static const uint16_t rcs_n_ =  3750;  // ニュートラル(JR)：  1500uS --> 3750
	static const uint16_t rcs_d_ =  1500;  // 可動範囲(JR)：+-600uS --> +-1500
#endif

#ifdef FUTABA_TYPE_SERVO
	static const uint16_t rcs_n_ =  3800;  // ニュートラル(FUTABA)：  1520uS --> 3800
	static const uint16_t rcs_d_ =  1500;  // 可動範囲(JR)：+-600uS --> +-1500
#endif

	class timer_intr {
		static volatile uint8_t trc_sync_;

	public:
		void operator() () {
			++trc_sync_;
		}

		void sync() const {
			volatile uint8_t v = trc_sync_;
			while(v == trc_sync_) {
			}
		}
	};
	volatile uint8_t timer_intr::trc_sync_ = 0;

	typedef device::trc_io<timer_intr> trc_type;
	trc_type timer_c_;

	typedef utils::fifo<uint8_t, 16> buffer;
	typedef device::uart_io<device::UART0, buffer, buffer> uart;
	uart uart_;

	typedef device::adc_io<utils::null_task> adc;
	adc adc_;

	uint16_t calc_pwm_(uint16_t adc_value)
	{
		auto v = (static_cast<uint32_t>(adc_value) * (rcs_d_ * 2)) >> 10;
		return v - rcs_d_ + rcs_n_;
	}
}

extern "C" {
	void sci_putch(char ch) {
		uart_.putch(ch);
	}

	char sci_getch(void) {
		return uart_.getch();
	}

	uint16_t sci_length() {
		return uart_.length();
	}

	void sci_puts(const char* str) {
		uart_.puts(str);
	}

	const void* variable_vectors_[] __attribute__ ((section (".vvec"))) = {
		reinterpret_cast<void*>(brk_inst_),		nullptr,	// (0)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (1) flash_ready
		reinterpret_cast<void*>(null_task_),	nullptr,	// (2)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (3)

		reinterpret_cast<void*>(null_task_),	nullptr,	// (4) コンパレーターB1
		reinterpret_cast<void*>(null_task_),	nullptr,	// (5) コンパレーターB3
		reinterpret_cast<void*>(null_task_),	nullptr,	// (6)
		reinterpret_cast<void*>(timer_c_.itask),nullptr,	// (7) タイマＲＣ

		reinterpret_cast<void*>(null_task_),	nullptr,	// (8)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (9)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (10)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (11)

		reinterpret_cast<void*>(null_task_),	nullptr,	// (12)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (13) キー入力
		reinterpret_cast<void*>(null_task_),	nullptr,	// (14) A/D 変換
		reinterpret_cast<void*>(null_task_),	nullptr,	// (15)

		reinterpret_cast<void*>(null_task_),	nullptr,	// (16)
		reinterpret_cast<void*>(uart_.isend),	nullptr,	// (17) UART0 送信
		reinterpret_cast<void*>(uart_.irecv),	nullptr,	// (18) UART0 受信
		reinterpret_cast<void*>(null_task_),	nullptr,	// (19)

		reinterpret_cast<void*>(null_task_),	nullptr,	// (20)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (21) /INT2
		reinterpret_cast<void*>(null_task_),	nullptr,	// (22) タイマＲＪ２
		reinterpret_cast<void*>(null_task_),	nullptr,	// (23) 周期タイマ

		reinterpret_cast<void*>(null_task_),    nullptr,	// (24) タイマＲＢ２
		reinterpret_cast<void*>(null_task_),	nullptr,	// (25) /INT1
		reinterpret_cast<void*>(null_task_),	nullptr,	// (26) /INT3
		reinterpret_cast<void*>(null_task_),	nullptr,	// (27)

		reinterpret_cast<void*>(null_task_),	nullptr,	// (28)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (29) /INT0
		reinterpret_cast<void*>(null_task_),	nullptr,	// (30)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (31)
	};
}

int main(int argc, char *argv[])
{
	using namespace device;

// クロック関係レジスタ・プロテクト解除
	PRCR.PRC0 = 1;

// 高速オンチップオシレーターへ切り替え(20MHz)
// ※ F_CLK を設定する事（Makefile内）
	OCOCR.HOCOE = 1;
	utils::delay::micro_second(1);	// >=30uS(125KHz)
	SCKCR.HSCKSEL = 1;
	CKSTPR.SCKSEL = 1;

	// UART の設定 (P1_4: TXD0[in], P1_5: RXD0[in])
	// ※シリアルライターでは、RXD 端子は、P1_6 となっているので注意！
	{
		utils::PORT_MAP(utils::port_map::P14::TXD0);
		utils::PORT_MAP(utils::port_map::P15::RXD0);
		uint8_t ir_level = 1;
		uart_.start(57600, ir_level);
	}

	// ADC の設定（CH1のサイクルモード）
	// P10, P11 の A/D 変換
	{
		utils::PORT_MAP(utils::port_map::P11::AN1);
		adc_.start(adc::cnv_type::CH0_CH1, adc::ch_grp::AN0_AN1, true);
	}

	// ＰＷＭモード設定
	{
		utils::PORT_MAP(utils::port_map::P13::TRCIOC);
		bool pfl = 0;  // 0->1
		uint8_t ir_level = 2;
		// 2ms (50Hz)
		timer_c_.start_pwm(50000, trc_type::divide::f8, pfl, ir_level);
		timer_c_.set_pwm_c(rcs_n_);
	}

	sci_puts("Start R8C RC-Servo monitor\n");

	utils::PORT_MAP(utils::port_map::P37::PORT);
	PD3.B7 = 1;

	uint8_t cnt = 0;
	uint16_t ana = 0;
	uint8_t cmp = 0;
	uint8_t lim = 0;
	while(1) {
		timer_c_.task_.sync();
		adc_.scan();
		adc_.sync();

		ana = adc_.get_value(1);
		auto ch = calc_pwm_(ana);
		timer_c_.set_pwm_c(ch);

		cmp = ((1024 - ana) >> 4) + 6;
		++lim;
		if(lim >= cmp) {
			lim = 0;
		}
		if(lim < (cmp >> 1)) P3.B7 = 0;
		else P3.B7 = 1;

		++cnt;
		if(cnt >= 50) {
			cnt = 0;
			utils::format("%d\n") % ana;
		}
	}
}
<commit_msg>update led blink speed<commit_after>//=====================================================================//
/*!	@file
	@brief	R8C RC-Servo テスター・メイン @n
			・デバイス： R8C/M11A @n
			・アナログ入力： P1_1(14) @n
			・PWM 出力： P1_3(12) @n
			・インジケーター： P3_7(1) active-low
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include "system.hpp"
#include "clock.hpp"
#include "port.hpp"
#include "common/delay.hpp"
#include "common/intr_utils.hpp"
#include "common/port_map.hpp"
#include "common/adc_io.hpp"
#include "common/trc_io.hpp"
#include "common/fifo.hpp"
#include "common/uart_io.hpp"
#include "common/format.hpp"

// どちらか片方を有効にする
#define JR_TYPE_SERVO
// #define FUTABA_TYPE_SERVO

namespace {

#ifdef JR_TYPE_SERVO
	static const uint16_t rcs_n_ =  3750;  // ニュートラル(JR)：  1500uS --> 3750
	static const uint16_t rcs_d_ =  1500;  // 可動範囲(JR)：+-600uS --> +-1500
#endif

#ifdef FUTABA_TYPE_SERVO
	static const uint16_t rcs_n_ =  3800;  // ニュートラル(FUTABA)：  1520uS --> 3800
	static const uint16_t rcs_d_ =  1500;  // 可動範囲(JR)：+-600uS --> +-1500
#endif

	class timer_intr {
		static volatile uint8_t trc_sync_;

	public:
		void operator() () {
			++trc_sync_;
		}

		void sync() const {
			volatile uint8_t v = trc_sync_;
			while(v == trc_sync_) {
			}
		}
	};
	volatile uint8_t timer_intr::trc_sync_ = 0;

	typedef device::trc_io<timer_intr> trc_type;
	trc_type timer_c_;

	typedef utils::fifo<uint8_t, 16> buffer;
	typedef device::uart_io<device::UART0, buffer, buffer> uart;
	uart uart_;

	typedef device::adc_io<utils::null_task> adc;
	adc adc_;

	uint16_t calc_pwm_(uint16_t adc_value)
	{
		auto v = (static_cast<uint32_t>(adc_value) * (rcs_d_ * 2)) >> 10;
		return v - rcs_d_ + rcs_n_;
	}
}

extern "C" {
	void sci_putch(char ch) {
		uart_.putch(ch);
	}

	char sci_getch(void) {
		return uart_.getch();
	}

	uint16_t sci_length() {
		return uart_.length();
	}

	void sci_puts(const char* str) {
		uart_.puts(str);
	}

	const void* variable_vectors_[] __attribute__ ((section (".vvec"))) = {
		reinterpret_cast<void*>(brk_inst_),		nullptr,	// (0)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (1) flash_ready
		reinterpret_cast<void*>(null_task_),	nullptr,	// (2)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (3)

		reinterpret_cast<void*>(null_task_),	nullptr,	// (4) コンパレーターB1
		reinterpret_cast<void*>(null_task_),	nullptr,	// (5) コンパレーターB3
		reinterpret_cast<void*>(null_task_),	nullptr,	// (6)
		reinterpret_cast<void*>(timer_c_.itask),nullptr,	// (7) タイマＲＣ

		reinterpret_cast<void*>(null_task_),	nullptr,	// (8)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (9)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (10)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (11)

		reinterpret_cast<void*>(null_task_),	nullptr,	// (12)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (13) キー入力
		reinterpret_cast<void*>(null_task_),	nullptr,	// (14) A/D 変換
		reinterpret_cast<void*>(null_task_),	nullptr,	// (15)

		reinterpret_cast<void*>(null_task_),	nullptr,	// (16)
		reinterpret_cast<void*>(uart_.isend),	nullptr,	// (17) UART0 送信
		reinterpret_cast<void*>(uart_.irecv),	nullptr,	// (18) UART0 受信
		reinterpret_cast<void*>(null_task_),	nullptr,	// (19)

		reinterpret_cast<void*>(null_task_),	nullptr,	// (20)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (21) /INT2
		reinterpret_cast<void*>(null_task_),	nullptr,	// (22) タイマＲＪ２
		reinterpret_cast<void*>(null_task_),	nullptr,	// (23) 周期タイマ

		reinterpret_cast<void*>(null_task_),    nullptr,	// (24) タイマＲＢ２
		reinterpret_cast<void*>(null_task_),	nullptr,	// (25) /INT1
		reinterpret_cast<void*>(null_task_),	nullptr,	// (26) /INT3
		reinterpret_cast<void*>(null_task_),	nullptr,	// (27)

		reinterpret_cast<void*>(null_task_),	nullptr,	// (28)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (29) /INT0
		reinterpret_cast<void*>(null_task_),	nullptr,	// (30)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (31)
	};
}

int main(int argc, char *argv[])
{
	using namespace device;

// クロック関係レジスタ・プロテクト解除
	PRCR.PRC0 = 1;

// 高速オンチップオシレーターへ切り替え(20MHz)
// ※ F_CLK を設定する事（Makefile内）
	OCOCR.HOCOE = 1;
	utils::delay::micro_second(1);	// >=30uS(125KHz)
	SCKCR.HSCKSEL = 1;
	CKSTPR.SCKSEL = 1;

	// UART の設定 (P1_4: TXD0[in], P1_5: RXD0[in])
	// ※シリアルライターでは、RXD 端子は、P1_6 となっているので注意！
	{
		utils::PORT_MAP(utils::port_map::P14::TXD0);
		utils::PORT_MAP(utils::port_map::P15::RXD0);
		uint8_t ir_level = 1;
		uart_.start(57600, ir_level);
	}

	// ADC の設定（CH1のサイクルモード）
	// P10, P11 の A/D 変換
	{
		utils::PORT_MAP(utils::port_map::P11::AN1);
		adc_.start(adc::cnv_type::CH1, adc::ch_grp::AN0_AN1, true);
	}

	// ＰＷＭモード設定
	{
		utils::PORT_MAP(utils::port_map::P13::TRCIOC);
		bool pfl = 0;  // 0->1
		uint8_t ir_level = 2;
		// 2ms (50Hz)
		timer_c_.start_pwm(50000, trc_type::divide::f8, pfl, ir_level);
		timer_c_.set_pwm_c(rcs_n_);
	}

	sci_puts("Start R8C RC-Servo monitor\n");

	utils::PORT_MAP(utils::port_map::P37::PORT);
	PD3.B7 = 1;

	uint8_t cnt = 0;
	uint16_t ana = 0;
	uint8_t cmp = 0;
	uint8_t lim = 0;
	while(1) {
		timer_c_.task_.sync();
		adc_.scan();
		adc_.sync();

		ana = adc_.get_value(1);
		auto ch = calc_pwm_(ana);
		timer_c_.set_pwm_c(ch);

		cmp = ((1024 - ana) >> 4) + 6;
		++lim;
		if(lim >= cmp) {
			lim = 0;
		}
		if(lim < (cmp >> 1)) P3.B7 = 0;
		else P3.B7 = 1;

		++cnt;
		if(cnt >= 50) {
			cnt = 0;
			utils::format("%d\n") % ana;
		}
	}
}
<|endoftext|>


<commit_before>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2017 Gleb Mishchenko, The appleseedhq Organization
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "pythoninterpreter.h"

// Studio headers.
#include "mainwindow/outputredirector.h"

// Boost headers.
#include "boost/python.hpp"

#include <string>

namespace bpy = boost::python;

namespace appleseed {
namespace studio {

//
// PythonInterpreter class implementation
//

PythonInterpreter& PythonInterpreter::instance()
{
    static PythonInterpreter interpreter;
    return interpreter;
}

void PythonInterpreter::execute_command(const char* command)
{
    PyRun_SimpleString(command);
}

void PythonInterpreter::redirect_output(OutputRedirector redirector)
{
    bpy::class_<OutputRedirector>("OutputRedirector", bpy::no_init)
        .def("write", &OutputRedirector::write);

    bpy::object sys_module = bpy::import("sys");
    sys_module.attr("stdout") = redirector;
    sys_module.attr("stderr") = redirector;

}

PythonInterpreter::PythonInterpreter()
{
    Py_Initialize();
}

PythonInterpreter::~PythonInterpreter()
{
    Py_Finalize();
}

} // namespace studio
} // namespace appleseed<commit_msg>Import appleseed module to python interpreter on initialization<commit_after>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2017 Gleb Mishchenko, The appleseedhq Organization
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "pythoninterpreter.h"

// Studio headers.
#include "mainwindow/outputredirector.h"

// Boost headers.
#include "boost/python.hpp"

#include <string>

namespace bpy = boost::python;

namespace appleseed {
namespace studio {

//
// PythonInterpreter class implementation
//

PythonInterpreter& PythonInterpreter::instance()
{
    static PythonInterpreter interpreter;
    return interpreter;
}

void PythonInterpreter::execute_command(const char* command)
{
    PyRun_SimpleString(command);
}

void PythonInterpreter::redirect_output(OutputRedirector redirector)
{
    bpy::class_<OutputRedirector>("OutputRedirector", bpy::no_init)
        .def("write", &OutputRedirector::write);

    bpy::object sys_module = bpy::import("sys");
    sys_module.attr("stdout") = redirector;
    sys_module.attr("stderr") = redirector;

}

PythonInterpreter::PythonInterpreter()
{
    Py_Initialize();

    // Add path to appleseed module to sys.path so python can find it
    bpy::import("sys").attr("path").attr("append")("../../lib/Debug/python2.7");

    // Imports appleseed module and creates asd alias for it
    // so we can refer to it by both names
    PyRun_SimpleString("import appleseed\n"
                           "asr=appleseed");
}

PythonInterpreter::~PythonInterpreter()
{
    Py_Finalize();
}

} // namespace studio
} // namespace appleseed<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
 *
 * 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 "shared/view.h"
#include <dali/dali.h>
#include <dali-toolkit/dali-toolkit.h>
#include <dali-toolkit/devel-api/controls/slider/slider.h>

using namespace Dali;

namespace
{

const char* BACKGROUND_IMAGE( DALI_IMAGE_DIR "background-gradient.jpg" );
const char* TOOLBAR_IMAGE( DALI_IMAGE_DIR "top-bar.png" );
const char* APPLICATION_TITLE( "Image view" );

const char* IMAGE_PATH[] = {
    DALI_IMAGE_DIR "blocks-ball.png",
    DALI_IMAGE_DIR "gallery-small-23.jpg",
    DALI_IMAGE_DIR "selection-popup-bg.2.9.png",
    DALI_IMAGE_DIR "heartsframe.9.png",
};

const char* RESOURCE_IMAGE_PATH[] = {
    DALI_IMAGE_DIR "contacts-image.png",
    DALI_IMAGE_DIR "gallery-small-27.jpg",
    DALI_IMAGE_DIR "selection-popup-bg.8.9.png",
    DALI_IMAGE_DIR "heartsframe.9.png",
};

const unsigned int NUM_IMAGES = sizeof(IMAGE_PATH) / sizeof(char*);
const unsigned int NUM_RESOURCE_IMAGES = sizeof(RESOURCE_IMAGE_PATH) / sizeof(char*);

const unsigned int COLUMNS = 3;
const unsigned int ROWS = 4;

}  // namespace

class ImageViewController: public ConnectionTracker
{
 public:

  ImageViewController( Application& application )
    : mApplication( application ),
      mCurrentPositionToggle( 0, 0 ),
      mCurrentPositionImage( 0, 0 ),
      mToggleOff( true ),
      mUseResource( false ),
      mImageIdx( 1 )
  {
    // Connect to the Application's Init signal
    mApplication.InitSignal().Connect( this, &ImageViewController::Create );
  }

  ~ImageViewController()
  {
    // Nothing to do here
  }

  void Create( Application& application )
  {
    // The Init signal is received once (only) during the Application lifetime

    // Creates a default view with a default tool bar.
    // The view is added to the stage.
    mContentLayer = DemoHelper::CreateView( application,
                                            mView,
                                            mToolBar,
                                            BACKGROUND_IMAGE,
                                            TOOLBAR_IMAGE,
                                            APPLICATION_TITLE );

    mTable = Toolkit::TableView::New( ROWS, COLUMNS );
    mTable.SetAnchorPoint( AnchorPoint::CENTER );
    mTable.SetParentOrigin( ParentOrigin::CENTER );
    mTable.SetResizePolicy( ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT, Dimension::ALL_DIMENSIONS );
    Vector3 offset( -50.0f, -350.0f, 0.0f );
    mTable.SetSizeModeFactor( offset );

    mContentLayer.Add( mTable );

    for( unsigned int y = 0; y < ROWS; ++y )
    {
      for( unsigned int x = 0; x < COLUMNS; ++x )
      {
        mImageViews[x][y] = Toolkit::ImageView::New( IMAGE_PATH[ 0 ] );
        mImageViews[x][y].SetParentOrigin( ParentOrigin::CENTER );
        mImageViews[x][y].SetAnchorPoint( AnchorPoint::CENTER );
        mImageViews[x][y].SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );

        mTable.AddChild( mImageViews[x][y], Toolkit::TableView::CellPosition( y, x ) );
      }
    }

    Toolkit::TableView buttonsTable = Toolkit::TableView::New( 3, 1 );
    buttonsTable.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
    buttonsTable.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
    buttonsTable.SetFitHeight( 0 );
    buttonsTable.SetFitHeight( 1 );
    buttonsTable.SetFitHeight( 2 );
    buttonsTable.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );

    Toolkit::PushButton button = Toolkit::PushButton::New();
    button.SetLabelText( "Toggle on/off stage" );
    button.SetParentOrigin( ParentOrigin::CENTER );
    button.SetAnchorPoint( AnchorPoint::CENTER );
    button.ClickedSignal().Connect( this, &ImageViewController::ToggleImageOnStage );
    button.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
    buttonsTable.AddChild( button, Toolkit::TableView::CellPosition( 0, 0 ) );

    Toolkit::PushButton button2 = Toolkit::PushButton::New();
    button2.SetLabelText( "Change Image" );
    button2.SetParentOrigin( ParentOrigin::CENTER );
    button2.SetAnchorPoint( AnchorPoint::CENTER );
    button2.ClickedSignal().Connect( this, &ImageViewController::ChangeImageClicked );
    button2.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
    buttonsTable.AddChild( button2, Toolkit::TableView::CellPosition( 1, 0 ) );

    Toolkit::CheckBoxButton button3 = Toolkit::CheckBoxButton::New();
    button3.SetLabelText( "Use Resource Images" );
    button3.SetParentOrigin( ParentOrigin::CENTER );
    button3.SetAnchorPoint( AnchorPoint::CENTER );
    button3.ClickedSignal().Connect( this, &ImageViewController::UseResourceImagesClicked );
    button3.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
    buttonsTable.AddChild( button3, Toolkit::TableView::CellPosition( 2, 0 ) );

    mContentLayer.Add(buttonsTable);
  }

private:
  bool ToggleImageOnStage( Toolkit::Button button )
  {
    Toolkit::ImageView imageView =  mImageViews[ mCurrentPositionToggle.columnIndex ][ mCurrentPositionToggle.rowIndex ];

    if( mToggleOff )
    {
      imageView.Unparent();
    }
    else
    {
      mTable.AddChild( imageView, mCurrentPositionToggle );
    }

    ++mCurrentPositionToggle.columnIndex;
    if( mCurrentPositionToggle.columnIndex == COLUMNS )
    {
      mCurrentPositionToggle.columnIndex = 0;
      ++mCurrentPositionToggle.rowIndex;
    }
    if( mCurrentPositionToggle.rowIndex == ROWS )
    {
      mCurrentPositionToggle.rowIndex = 0;
      mToggleOff = !mToggleOff;
    }

    return true;
  }

  bool ChangeImageClicked( Toolkit::Button button )
  {
    Toolkit::ImageView imageView =  mImageViews[ mCurrentPositionImage.columnIndex ][ mCurrentPositionImage.rowIndex ];

    if( mUseResource )
    {
      ResourceImage image = ResourceImage::New( RESOURCE_IMAGE_PATH[ mImageIdx ] );
      imageView.SetImage( image );
    }
    else
    {
      imageView.SetImage( IMAGE_PATH[ mImageIdx ] );
    }

    ++mCurrentPositionImage.columnIndex;
    if( mCurrentPositionImage.columnIndex == COLUMNS )
    {
      mCurrentPositionImage.columnIndex = 0;
      ++mCurrentPositionImage.rowIndex;
    }
    if( mCurrentPositionImage.rowIndex == ROWS )
    {
      mCurrentPositionImage.rowIndex = 0;
      ++mImageIdx;

      int numImages = mUseResource ? NUM_RESOURCE_IMAGES : NUM_IMAGES;
      if( mImageIdx == numImages )
      {
        mImageIdx = 0;
      }
    }

    return true;
  }

  bool UseResourceImagesClicked( Toolkit::Button button )
  {
    mUseResource = !mUseResource;

    int numImages = mUseResource ? NUM_RESOURCE_IMAGES : NUM_IMAGES;
    if( mImageIdx >= numImages )
    {
      mImageIdx = 0;
    }

    return true;
  }

private:
  Application&  mApplication;

  Toolkit::Control           mView;                              ///< The View instance.
  Toolkit::ToolBar           mToolBar;                           ///< The View's Toolbar.
  Layer                      mContentLayer;                      ///< Content layer
  Toolkit::TableView         mTable;
  Toolkit::ImageView        mImageViews[ COLUMNS ][ ROWS ];

  Toolkit::TableView::CellPosition mCurrentPositionToggle;
  Toolkit::TableView::CellPosition mCurrentPositionImage;

  bool mToggleOff;
  bool mUseResource;
  int mImageIdx;

};

void RunTest( Application& application )
{
  ImageViewController test( application );

  application.MainLoop();
}

// Entry point for Linux & Tizen applications
//
int main( int argc, char **argv )
{
  Application application = Application::New( &argc, &argv, DALI_DEMO_THEME_PATH );

  RunTest( application );

  return 0;
}
<commit_msg>Added key event handling to image-view-example<commit_after>/*
 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
 *
 * 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 "shared/view.h"
#include <dali/dali.h>
#include <dali-toolkit/dali-toolkit.h>
#include <dali-toolkit/devel-api/controls/slider/slider.h>

using namespace Dali;

namespace
{

const char* BACKGROUND_IMAGE( DALI_IMAGE_DIR "background-gradient.jpg" );
const char* TOOLBAR_IMAGE( DALI_IMAGE_DIR "top-bar.png" );
const char* APPLICATION_TITLE( "Image view" );

const char* IMAGE_PATH[] = {
    DALI_IMAGE_DIR "blocks-ball.png",
    DALI_IMAGE_DIR "gallery-small-23.jpg",
    DALI_IMAGE_DIR "selection-popup-bg.2.9.png",
    DALI_IMAGE_DIR "heartsframe.9.png",
};

const char* RESOURCE_IMAGE_PATH[] = {
    DALI_IMAGE_DIR "contacts-image.png",
    DALI_IMAGE_DIR "gallery-small-27.jpg",
    DALI_IMAGE_DIR "selection-popup-bg.8.9.png",
    DALI_IMAGE_DIR "heartsframe.9.png",
};

const unsigned int NUM_IMAGES = sizeof(IMAGE_PATH) / sizeof(char*);
const unsigned int NUM_RESOURCE_IMAGES = sizeof(RESOURCE_IMAGE_PATH) / sizeof(char*);

const unsigned int COLUMNS = 3;
const unsigned int ROWS = 4;

}  // namespace

class ImageViewController: public ConnectionTracker
{
 public:

  ImageViewController( Application& application )
    : mApplication( application ),
      mCurrentPositionToggle( 0, 0 ),
      mCurrentPositionImage( 0, 0 ),
      mToggleOff( true ),
      mUseResource( false ),
      mImageIdx( 1 )
  {
    // Connect to the Application's Init signal
    mApplication.InitSignal().Connect( this, &ImageViewController::Create );
  }

  ~ImageViewController()
  {
    // Nothing to do here
  }

  void Create( Application& application )
  {
    // The Init signal is received once (only) during the Application lifetime

    // Creates a default view with a default tool bar.
    // The view is added to the stage.
    mContentLayer = DemoHelper::CreateView( application,
                                            mView,
                                            mToolBar,
                                            BACKGROUND_IMAGE,
                                            TOOLBAR_IMAGE,
                                            APPLICATION_TITLE );

    mTable = Toolkit::TableView::New( ROWS, COLUMNS );
    mTable.SetAnchorPoint( AnchorPoint::CENTER );
    mTable.SetParentOrigin( ParentOrigin::CENTER );
    mTable.SetResizePolicy( ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT, Dimension::ALL_DIMENSIONS );
    Vector3 offset( -50.0f, -350.0f, 0.0f );
    mTable.SetSizeModeFactor( offset );

    mContentLayer.Add( mTable );

    for( unsigned int y = 0; y < ROWS; ++y )
    {
      for( unsigned int x = 0; x < COLUMNS; ++x )
      {
        mImageViews[x][y] = Toolkit::ImageView::New( IMAGE_PATH[ 0 ] );
        mImageViews[x][y].SetParentOrigin( ParentOrigin::CENTER );
        mImageViews[x][y].SetAnchorPoint( AnchorPoint::CENTER );
        mImageViews[x][y].SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );

        mTable.AddChild( mImageViews[x][y], Toolkit::TableView::CellPosition( y, x ) );
      }
    }

    Toolkit::TableView buttonsTable = Toolkit::TableView::New( 3, 1 );
    buttonsTable.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
    buttonsTable.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
    buttonsTable.SetFitHeight( 0 );
    buttonsTable.SetFitHeight( 1 );
    buttonsTable.SetFitHeight( 2 );
    buttonsTable.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );

    Toolkit::PushButton button = Toolkit::PushButton::New();
    button.SetLabelText( "Toggle on/off stage" );
    button.SetParentOrigin( ParentOrigin::CENTER );
    button.SetAnchorPoint( AnchorPoint::CENTER );
    button.ClickedSignal().Connect( this, &ImageViewController::ToggleImageOnStage );
    button.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
    buttonsTable.AddChild( button, Toolkit::TableView::CellPosition( 0, 0 ) );

    Toolkit::PushButton button2 = Toolkit::PushButton::New();
    button2.SetLabelText( "Change Image" );
    button2.SetParentOrigin( ParentOrigin::CENTER );
    button2.SetAnchorPoint( AnchorPoint::CENTER );
    button2.ClickedSignal().Connect( this, &ImageViewController::ChangeImageClicked );
    button2.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
    buttonsTable.AddChild( button2, Toolkit::TableView::CellPosition( 1, 0 ) );

    Toolkit::CheckBoxButton button3 = Toolkit::CheckBoxButton::New();
    button3.SetLabelText( "Use Resource Images" );
    button3.SetParentOrigin( ParentOrigin::CENTER );
    button3.SetAnchorPoint( AnchorPoint::CENTER );
    button3.ClickedSignal().Connect( this, &ImageViewController::UseResourceImagesClicked );
    button3.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
    buttonsTable.AddChild( button3, Toolkit::TableView::CellPosition( 2, 0 ) );

    mContentLayer.Add(buttonsTable);

    Stage::GetCurrent().KeyEventSignal().Connect(this, &ImageViewController::OnKeyEvent);
  }

private:
  bool ToggleImageOnStage( Toolkit::Button button )
  {
    Toolkit::ImageView imageView =  mImageViews[ mCurrentPositionToggle.columnIndex ][ mCurrentPositionToggle.rowIndex ];

    if( mToggleOff )
    {
      imageView.Unparent();
    }
    else
    {
      mTable.AddChild( imageView, mCurrentPositionToggle );
    }

    ++mCurrentPositionToggle.columnIndex;
    if( mCurrentPositionToggle.columnIndex == COLUMNS )
    {
      mCurrentPositionToggle.columnIndex = 0;
      ++mCurrentPositionToggle.rowIndex;
    }
    if( mCurrentPositionToggle.rowIndex == ROWS )
    {
      mCurrentPositionToggle.rowIndex = 0;
      mToggleOff = !mToggleOff;
    }

    return true;
  }

  bool ChangeImageClicked( Toolkit::Button button )
  {
    Toolkit::ImageView imageView =  mImageViews[ mCurrentPositionImage.columnIndex ][ mCurrentPositionImage.rowIndex ];

    if( mUseResource )
    {
      ResourceImage image = ResourceImage::New( RESOURCE_IMAGE_PATH[ mImageIdx ] );
      imageView.SetImage( image );
    }
    else
    {
      imageView.SetImage( IMAGE_PATH[ mImageIdx ] );
    }

    ++mCurrentPositionImage.columnIndex;
    if( mCurrentPositionImage.columnIndex == COLUMNS )
    {
      mCurrentPositionImage.columnIndex = 0;
      ++mCurrentPositionImage.rowIndex;
    }
    if( mCurrentPositionImage.rowIndex == ROWS )
    {
      mCurrentPositionImage.rowIndex = 0;
      ++mImageIdx;

      int numImages = mUseResource ? NUM_RESOURCE_IMAGES : NUM_IMAGES;
      if( mImageIdx == numImages )
      {
        mImageIdx = 0;
      }
    }

    return true;
  }

  bool UseResourceImagesClicked( Toolkit::Button button )
  {
    mUseResource = !mUseResource;

    int numImages = mUseResource ? NUM_RESOURCE_IMAGES : NUM_IMAGES;
    if( mImageIdx >= numImages )
    {
      mImageIdx = 0;
    }

    return true;
  }

  /**
   * Main key event handler
   */
  void OnKeyEvent(const KeyEvent& event)
  {
    if(event.state == KeyEvent::Down)
    {
      if( IsKey( event, DALI_KEY_ESCAPE) || IsKey( event, DALI_KEY_BACK ) )
      {
        mApplication.Quit();
      }
    }
  }

private:
  Application&  mApplication;

  Toolkit::Control           mView;                              ///< The View instance.
  Toolkit::ToolBar           mToolBar;                           ///< The View's Toolbar.
  Layer                      mContentLayer;                      ///< Content layer
  Toolkit::TableView         mTable;
  Toolkit::ImageView        mImageViews[ COLUMNS ][ ROWS ];

  Toolkit::TableView::CellPosition mCurrentPositionToggle;
  Toolkit::TableView::CellPosition mCurrentPositionImage;

  bool mToggleOff;
  bool mUseResource;
  int mImageIdx;

};

void RunTest( Application& application )
{
  ImageViewController test( application );

  application.MainLoop();
}

// Entry point for Linux & Tizen applications
//
int main( int argc, char **argv )
{
  Application application = Application::New( &argc, &argv, DALI_DEMO_THEME_PATH );

  RunTest( application );

  return 0;
}
<|endoftext|>