<commit_before>/*************************************************************************/
/*  remote_transform.cpp                                                 */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md)    */
/*                                                                       */
/* 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.                */
/*************************************************************************/

#include "remote_transform.h"

void RemoteTransform::_update_cache() {
	cache = 0;
	if (has_node(remote_node)) {
		Node *node = get_node(remote_node);
		if (!node || this == node || node->is_a_parent_of(this) || this->is_a_parent_of(node)) {
			return;
		}

		cache = node->get_instance_id();
	}
}

void RemoteTransform::_update_remote() {

	if (!is_inside_tree())
		return;

	if (!cache)
		return;

	Spatial *n = Object::cast_to<Spatial>(ObjectDB::get_instance(cache));
	if (!n)
		return;

	if (!n->is_inside_tree())
		return;

	//todo make faster
	if (use_global_coordinates) {

		if (update_remote_position && update_remote_rotation && update_remote_scale) {
			n->set_global_transform(get_global_transform());
		} else {
			Transform n_trans = n->get_global_transform();
			Transform our_trans = get_global_transform();

			if (!update_remote_position)
				our_trans.set_origin(n_trans.get_origin());

			n->set_global_transform(our_trans);

			if (!update_remote_rotation)
				n->set_rotation(n_trans.basis.get_rotation());

			if (!update_remote_scale)
				n->set_scale(n_trans.basis.get_scale());
		}

	} else {
		if (update_remote_position && update_remote_rotation && update_remote_scale) {
			n->set_global_transform(get_global_transform());
		} else {
			Transform n_trans = n->get_transform();
			Transform our_trans = get_transform();

			if (!update_remote_position)
				our_trans.set_origin(n_trans.get_origin());

			n->set_transform(our_trans);

			if (!update_remote_rotation)
				n->set_rotation(n_trans.basis.get_rotation());

			if (!update_remote_scale)
				n->set_scale(n_trans.basis.get_scale());
		}
	}
}

void RemoteTransform::_notification(int p_what) {

	switch (p_what) {

		case NOTIFICATION_READY: {

			_update_cache();

		} break;
		case NOTIFICATION_TRANSFORM_CHANGED: {
			if (!is_inside_tree())
				break;

			if (cache) {

				_update_remote();
			}

		} break;
	}
}

void RemoteTransform::set_remote_node(const NodePath &p_remote_node) {

	remote_node = p_remote_node;
	if (is_inside_tree()) {
		_update_cache();
		_update_remote();
	}

	update_configuration_warning();
}

NodePath RemoteTransform::get_remote_node() const {

	return remote_node;
}

void RemoteTransform::set_use_global_coordinates(const bool p_enable) {
	use_global_coordinates = p_enable;
}

bool RemoteTransform::get_use_global_coordinates() const {
	return use_global_coordinates;
}

void RemoteTransform::set_update_position(const bool p_update) {
	update_remote_position = p_update;
	_update_remote();
}

bool RemoteTransform::get_update_position() const {
	return update_remote_position;
}

void RemoteTransform::set_update_rotation(const bool p_update) {
	update_remote_rotation = p_update;
	_update_remote();
}

bool RemoteTransform::get_update_rotation() const {
	return update_remote_rotation;
}

void RemoteTransform::set_update_scale(const bool p_update) {
	update_remote_scale = p_update;
	_update_remote();
}

bool RemoteTransform::get_update_scale() const {
	return update_remote_scale;
}

String RemoteTransform::get_configuration_warning() const {

	if (!has_node(remote_node) || !Object::cast_to<Spatial>(get_node(remote_node))) {
		return TTR("Path property must point to a valid Spatial node to work.");
	}

	return String();
}

void RemoteTransform::_bind_methods() {

	ClassDB::bind_method(D_METHOD("set_remote_node", "path"), &RemoteTransform::set_remote_node);
	ClassDB::bind_method(D_METHOD("get_remote_node"), &RemoteTransform::get_remote_node);

	ClassDB::bind_method(D_METHOD("set_use_global_coordinates", "use_global_coordinates"), &RemoteTransform::set_use_global_coordinates);
	ClassDB::bind_method(D_METHOD("get_use_global_coordinates"), &RemoteTransform::get_use_global_coordinates);

	ClassDB::bind_method(D_METHOD("set_update_position", "update_remote_position"), &RemoteTransform::set_update_position);
	ClassDB::bind_method(D_METHOD("get_update_position"), &RemoteTransform::get_update_position);
	ClassDB::bind_method(D_METHOD("set_update_rotation", "update_remote_rotation"), &RemoteTransform::set_update_rotation);
	ClassDB::bind_method(D_METHOD("get_update_rotation"), &RemoteTransform::get_update_rotation);
	ClassDB::bind_method(D_METHOD("set_update_scale", "update_remote_scale"), &RemoteTransform::set_update_scale);
	ClassDB::bind_method(D_METHOD("get_update_scale"), &RemoteTransform::get_update_scale);

	ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "remote_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Spatial"), "set_remote_node", "get_remote_node");
	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_global_coordinates"), "set_use_global_coordinates", "get_use_global_coordinates");

	ADD_GROUP("Update", "update_");
	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "update_position"), "set_update_position", "get_update_position");
	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "update_rotation"), "set_update_rotation", "get_update_rotation");
	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "update_scale"), "set_update_scale", "get_update_scale");
}

RemoteTransform::RemoteTransform() {

	use_global_coordinates = true;
	update_remote_position = true;
	update_remote_rotation = true;
	update_remote_scale = true;

	cache = 0;
	set_notify_transform(true);
}
<commit_msg>Fix properties update in remote transform<commit_after>/*************************************************************************/
/*  remote_transform.cpp                                                 */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md)    */
/*                                                                       */
/* 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.                */
/*************************************************************************/

#include "remote_transform.h"

void RemoteTransform::_update_cache() {
	cache = 0;
	if (has_node(remote_node)) {
		Node *node = get_node(remote_node);
		if (!node || this == node || node->is_a_parent_of(this) || this->is_a_parent_of(node)) {
			return;
		}

		cache = node->get_instance_id();
	}
}

void RemoteTransform::_update_remote() {

	if (!is_inside_tree())
		return;

	if (!cache)
		return;

	Spatial *n = Object::cast_to<Spatial>(ObjectDB::get_instance(cache));
	if (!n)
		return;

	if (!n->is_inside_tree())
		return;

	//todo make faster
	if (use_global_coordinates) {

		if (update_remote_position && update_remote_rotation && update_remote_scale) {
			n->set_global_transform(get_global_transform());
		} else {
			Transform our_trans = get_global_transform();

			if (update_remote_rotation)
				n->set_rotation(our_trans.basis.get_rotation());

			if (update_remote_scale)
				n->set_scale(our_trans.basis.get_scale());

			if (update_remote_position) {
				Transform n_trans = n->get_global_transform();

				n_trans.set_origin(our_trans.get_origin());
				n->set_global_transform(n_trans);
			}
		}

	} else {
		if (update_remote_position && update_remote_rotation && update_remote_scale) {
			n->set_transform(get_transform());
		} else {
			Transform our_trans = get_transform();

			if (update_remote_rotation)
				n->set_rotation(our_trans.basis.get_rotation());

			if (update_remote_scale)
				n->set_scale(our_trans.basis.get_scale());

			if (update_remote_position) {
				Transform n_trans = n->get_transform();

				n_trans.set_origin(our_trans.get_origin());
				n->set_transform(n_trans);
			}
		}
	}
}

void RemoteTransform::_notification(int p_what) {

	switch (p_what) {

		case NOTIFICATION_READY: {

			_update_cache();

		} break;
		case NOTIFICATION_TRANSFORM_CHANGED: {
			if (!is_inside_tree())
				break;

			if (cache) {

				_update_remote();
			}

		} break;
	}
}

void RemoteTransform::set_remote_node(const NodePath &p_remote_node) {

	remote_node = p_remote_node;
	if (is_inside_tree()) {
		_update_cache();
		_update_remote();
	}

	update_configuration_warning();
}

NodePath RemoteTransform::get_remote_node() const {

	return remote_node;
}

void RemoteTransform::set_use_global_coordinates(const bool p_enable) {
	use_global_coordinates = p_enable;
}

bool RemoteTransform::get_use_global_coordinates() const {
	return use_global_coordinates;
}

void RemoteTransform::set_update_position(const bool p_update) {
	update_remote_position = p_update;
	_update_remote();
}

bool RemoteTransform::get_update_position() const {
	return update_remote_position;
}

void RemoteTransform::set_update_rotation(const bool p_update) {
	update_remote_rotation = p_update;
	_update_remote();
}

bool RemoteTransform::get_update_rotation() const {
	return update_remote_rotation;
}

void RemoteTransform::set_update_scale(const bool p_update) {
	update_remote_scale = p_update;
	_update_remote();
}

bool RemoteTransform::get_update_scale() const {
	return update_remote_scale;
}

String RemoteTransform::get_configuration_warning() const {

	if (!has_node(remote_node) || !Object::cast_to<Spatial>(get_node(remote_node))) {
		return TTR("Path property must point to a valid Spatial node to work.");
	}

	return String();
}

void RemoteTransform::_bind_methods() {

	ClassDB::bind_method(D_METHOD("set_remote_node", "path"), &RemoteTransform::set_remote_node);
	ClassDB::bind_method(D_METHOD("get_remote_node"), &RemoteTransform::get_remote_node);

	ClassDB::bind_method(D_METHOD("set_use_global_coordinates", "use_global_coordinates"), &RemoteTransform::set_use_global_coordinates);
	ClassDB::bind_method(D_METHOD("get_use_global_coordinates"), &RemoteTransform::get_use_global_coordinates);

	ClassDB::bind_method(D_METHOD("set_update_position", "update_remote_position"), &RemoteTransform::set_update_position);
	ClassDB::bind_method(D_METHOD("get_update_position"), &RemoteTransform::get_update_position);
	ClassDB::bind_method(D_METHOD("set_update_rotation", "update_remote_rotation"), &RemoteTransform::set_update_rotation);
	ClassDB::bind_method(D_METHOD("get_update_rotation"), &RemoteTransform::get_update_rotation);
	ClassDB::bind_method(D_METHOD("set_update_scale", "update_remote_scale"), &RemoteTransform::set_update_scale);
	ClassDB::bind_method(D_METHOD("get_update_scale"), &RemoteTransform::get_update_scale);

	ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "remote_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Spatial"), "set_remote_node", "get_remote_node");
	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_global_coordinates"), "set_use_global_coordinates", "get_use_global_coordinates");

	ADD_GROUP("Update", "update_");
	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "update_position"), "set_update_position", "get_update_position");
	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "update_rotation"), "set_update_rotation", "get_update_rotation");
	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "update_scale"), "set_update_scale", "get_update_scale");
}

RemoteTransform::RemoteTransform() {

	use_global_coordinates = true;
	update_remote_position = true;
	update_remote_rotation = true;
	update_remote_scale = true;

	cache = 0;
	set_notify_transform(true);
}
<|endoftext|>


<commit_before>#include <sstream> // ostringstream
#include <iomanip> // std::setw
#include <stdio.h> // printf
#include "allocore/math/al_Constants.hpp"
#include "allocore/system/al_Time.hpp"

/* Windows */
#if defined(AL_WINDOWS)
#include <windows.h>
/*
Info on Windows timing:
http://windowstimestamp.com/description
*/
/*
// singleton object to force init/quit of timing
static struct TimeSingleton{
	TimeSingleton(){ timeBeginPeriod(1); }
	~TimeSingleton(){ timeEndPeriod(1); }
} timeSingleton;

// interface to Windows API
static DWORD time_ms(){ return timeGetTime(); }
static void sleep_ms(unsigned long long ms){ Sleep(DWORD(ms)); }

// allocore definitions
al_sec al_time(){				return time_ms() * 1e-3; }
al_nsec al_time_nsec(){			return al_nsec(time_ms()) * al_nsec(1e6); }
void al_sleep(al_sec v){		sleep_ms(v * 1e3); }
void al_sleep_nsec(al_nsec v){	sleep_ms(v / 1e6); }
//*/

//*
static void sleep_ms(unsigned long long ms){ Sleep(DWORD(ms)); }

// Method to supposedly get microsecond sleep
// From: http://blogs.msdn.com/b/cellfish/archive/2008/09/17/sleep-less-than-one-millisecond.aspx
/*
#include <Winsock2.h> // SOCKET
static int sleep_us(long usec){
	static bool first = true;
	if(first){
		first = false;
		WORD wVersionRequested = MAKEWORD(1,0);
		WSADATA wsaData;
		WSAStartup(wVersionRequested, &wsaData);
	}
	struct timeval tv;
	fd_set dummy;
	SOCKET s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
	FD_ZERO(&dummy);
	FD_SET(s, &dummy);
	tv.tv_sec = usec/1000000L;
	tv.tv_usec = usec%1000000L;
	return select(0, 0, 0, &dummy, &tv);
}*/

// system time as 100-nanosecond interval
al_nsec system_time_100ns(){
	SYSTEMTIME st;
	GetSystemTime(&st);
	//printf("%d/%d/%d %d:%d:%d\n", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
	FILETIME time;
	SystemTimeToFileTime(&st, &time);
	//GetSystemTimeAsFileTime(&time);
	ULARGE_INTEGER timeULI = {{time.dwLowDateTime, time.dwHighDateTime}};
	al_nsec res = timeULI.QuadPart; // in 100-nanosecond intervals
	res -= al_nsec(116444736000000000); // convert epoch from 1601 to 1970
	return res;
}

al_nsec steady_time_us(){
	// Windows 10 and above
	//PULONGLONG time;
	//QueryInterruptTimePrecise(&time);

	LARGE_INTEGER freq; // ticks/second
	LARGE_INTEGER time; // tick count
	QueryPerformanceFrequency(&freq);
	QueryPerformanceCounter(&time);
	// convert ticks to microseconds
	time.QuadPart *= 1000000;
	time.QuadPart /= freq.QuadPart;
	return al_nsec(time.QuadPart);
}

al_sec  al_system_time(){		return system_time_100ns() * 1e-7; }
al_nsec al_system_time_nsec(){	return system_time_100ns() * al_nsec(100); }
al_sec  al_steady_time(){		return steady_time_us() * 1e-6; }
al_nsec al_steady_time_nsec(){	return steady_time_us() * al_nsec(1e3); }
void al_sleep(al_sec v){		sleep_ms(v * 1e3); }
void al_sleep_nsec(al_nsec v){	sleep_ms(v / 1e6); }
//void al_sleep(al_sec v){		sleep_us(v * 1e6); }
//void al_sleep_nsec(al_nsec v){	sleep_us(v / 1e3); }
//*/

/* Posix (Mac, Linux) */
#else
#include <time.h> // nanosleep, clock_gettime
#include <sys/time.h> // gettimeofday
#include <unistd.h> // _POSIX_TIMERS

al_sec  al_system_time(){
	timeval t;
	gettimeofday(&t, NULL);
	return al_sec(t.tv_sec) + al_sec(t.tv_usec) * 1e-6;
}

al_nsec al_system_time_nsec(){
	timeval t;
	gettimeofday(&t, NULL);
	return al_nsec(t.tv_sec) * al_nsec(1e9) + al_nsec(t.tv_usec) * al_nsec(1e3);
}

#ifdef AL_OSX
#include <mach/mach_time.h>

// Code from:
// http://stackoverflow.com/questions/23378063/how-can-i-use-mach-absolute-time-without-overflowing

al_sec al_steady_time(){
	return al_steady_time_nsec() * 1e-9;
}

al_nsec al_steady_time_nsec(){
	uint64_t now = mach_absolute_time();
	static struct Data {
		Data(uint64_t bias_) : bias(bias_) {
			mach_timebase_info(&tb);
			if (tb.denom > 1024) {
				double frac = (double)tb.numer/tb.denom;
				tb.denom = 1024;
				tb.numer = tb.denom * frac + 0.5;
			}
		}
		mach_timebase_info_data_t tb;
		uint64_t bias;
	} data(now);
	return (now - data.bias) * data.tb.numer / data.tb.denom;
}

// Posix timers available?
#elif _POSIX_TIMERS > 0 && defined(_POSIX_MONOTONIC_CLOCK)
al_sec al_steady_time(){
	struct timespec t;
	clock_gettime(CLOCK_MONOTONIC, &t);
	return al_sec(t.tv_sec) + al_sec(t.tv_nsec) * 1e-9;
}

al_nsec al_steady_time_nsec(){
	struct timespec t;
	clock_gettime(CLOCK_MONOTONIC, &t);
	return al_nsec(t.tv_sec) * al_nsec(1e9) + al_nsec(t.tv_nsec);
}

// Otherwise fallback to system time
#else
al_sec  al_steady_time(){
	return al_system_time();
}

al_nsec al_steady_time_nsec(){
	return al_system_time_nsec();
}
#endif

void al_sleep(al_sec v) {
	time_t sec = (time_t)v;
	al_nsec nsec = al_time_s2ns * (v - (al_sec)sec);
	timespec tspec = { sec, nsec };
	while (nanosleep(&tspec, &tspec) == -1)
		continue;
}

void al_sleep_nsec(al_nsec v) {
	al_sleep((al_sec)v * al_time_ns2s);
}

#endif
/* end platform specific */

void al_sleep_until(al_sec target) {
	al_sec dt = target - al_time();
	if (dt > 0) al_sleep(dt);
}

al_sec  al_time(){				return al_system_time(); }
al_nsec al_time_nsec(){			return al_system_time_nsec(); }

namespace al {

std::string toTimecode(al_nsec t, const std::string& format){
	unsigned day = t/(al_nsec(1000000000) * 60 * 60 * 24); // basically for overflow
	unsigned hrs = t/(al_nsec(1000000000) * 60 * 60) % 24;
	unsigned min = t/(al_nsec(1000000000) * 60) % 60;
	unsigned sec = t/(al_nsec(1000000000)) % 60;
	unsigned msc = t/(al_nsec(1000000)) % 1000;
	unsigned usc = t/(al_nsec(1000)) % 1000;

	std::ostringstream s;
	s.fill('0');

	for(unsigned i=0; i<format.size(); ++i){
		const auto c = format[i];
		switch(c){
		case 'D': s << day; break;
		case 'H': s << std::setw(2) << hrs; break;
		case 'M': s << std::setw(2) << min; break;
		case 'S': s << std::setw(2) << sec; break;
		case 'm': s << std::setw(3) << msc; break;
		case 'u': s << std::setw(3) << usc; break;
		default:  s << c;
		}
	}

	return s.str();
}

std::string timecodeNow(const std::string& format){
	return toTimecode(al_system_time_nsec(), format);
}

void Timer::print() const {
	auto t = getTime();
	auto dt = t-mStart;
	double dtSec = al_time_ns2s * dt;
	printf("%g sec (%g ms) elapsed\n", dtSec, dtSec*1000.);
}

void DelayLockedLoop :: setBandwidth(double bandwidth) {
	double F = 1./tperiod;		// step rate
	double omega = M_PI * 2.8 * bandwidth/F;
	mB = omega * sqrt(2.);	// 1st-order weight
	mC = omega * omega;		// 2nd-order weight
}

void DelayLockedLoop :: step(al_sec realtime) {
	if (mReset) {
		// The first iteration sets initial conditions.

		// init loop
		t2 = tperiod;
		t0 = realtime;
		t1 = t0 + t2;	// t1 is ideally the timestamp of the next block start

		// subsequent iterations use the other branch:
		mReset = false;
	} else {
		// read timer and calculate loop error
		// e.g. if t1 underestimated, terr will be
		al_sec terr = realtime - t1;
		// update loop
		t0 = t1;				// 0th-order (distance)
		t1 += mB * terr + t2;	// integration of 1st-order (velocity)
		t2 += mC * terr;		// integration of 2nd-order (acceleration)
	}

//		// now t0 is the current system time, and t1 is the estimated system time at the next step
//		//
//		al_sec tper_estimate = t1-t0;	// estimated real duration between this step & the next one
//		double factor = tperiod/tper_estimate;	// <1 if we are too slow, >1 if we are too fast
//		double real_rate = 1./tper_estimate;
//		al_sec tper_estimate2 = t2;	// estimated real duration between this step & the next one
//		double factor2 = 1./t2;	// <1 if we are too slow, >1 if we are too fast
//		printf("factor %f %f rate %f\n", factor, factor2, real_rate);
}

} // al::
<commit_msg>Fix narrowing error in initializer<commit_after>#include <sstream> // ostringstream
#include <iomanip> // std::setw
#include <stdio.h> // printf
#include "allocore/math/al_Constants.hpp"
#include "allocore/system/al_Time.hpp"

/* Windows */
#if defined(AL_WINDOWS)
#include <windows.h>
/*
Info on Windows timing:
http://windowstimestamp.com/description
*/
/*
// singleton object to force init/quit of timing
static struct TimeSingleton{
	TimeSingleton(){ timeBeginPeriod(1); }
	~TimeSingleton(){ timeEndPeriod(1); }
} timeSingleton;

// interface to Windows API
static DWORD time_ms(){ return timeGetTime(); }
static void sleep_ms(unsigned long long ms){ Sleep(DWORD(ms)); }

// allocore definitions
al_sec al_time(){				return time_ms() * 1e-3; }
al_nsec al_time_nsec(){			return al_nsec(time_ms()) * al_nsec(1e6); }
void al_sleep(al_sec v){		sleep_ms(v * 1e3); }
void al_sleep_nsec(al_nsec v){	sleep_ms(v / 1e6); }
//*/

//*
static void sleep_ms(unsigned long long ms){ Sleep(DWORD(ms)); }

// Method to supposedly get microsecond sleep
// From: http://blogs.msdn.com/b/cellfish/archive/2008/09/17/sleep-less-than-one-millisecond.aspx
/*
#include <Winsock2.h> // SOCKET
static int sleep_us(long usec){
	static bool first = true;
	if(first){
		first = false;
		WORD wVersionRequested = MAKEWORD(1,0);
		WSADATA wsaData;
		WSAStartup(wVersionRequested, &wsaData);
	}
	struct timeval tv;
	fd_set dummy;
	SOCKET s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
	FD_ZERO(&dummy);
	FD_SET(s, &dummy);
	tv.tv_sec = usec/1000000L;
	tv.tv_usec = usec%1000000L;
	return select(0, 0, 0, &dummy, &tv);
}*/

// system time as 100-nanosecond interval
al_nsec system_time_100ns(){
	SYSTEMTIME st;
	GetSystemTime(&st);
	//printf("%d/%d/%d %d:%d:%d\n", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
	FILETIME time;
	SystemTimeToFileTime(&st, &time);
	//GetSystemTimeAsFileTime(&time);
	ULARGE_INTEGER timeULI = {{time.dwLowDateTime, time.dwHighDateTime}};
	al_nsec res = timeULI.QuadPart; // in 100-nanosecond intervals
	res -= al_nsec(116444736000000000); // convert epoch from 1601 to 1970
	return res;
}

al_nsec steady_time_us(){
	// Windows 10 and above
	//PULONGLONG time;
	//QueryInterruptTimePrecise(&time);

	LARGE_INTEGER freq; // ticks/second
	LARGE_INTEGER time; // tick count
	QueryPerformanceFrequency(&freq);
	QueryPerformanceCounter(&time);
	// convert ticks to microseconds
	time.QuadPart *= 1000000;
	time.QuadPart /= freq.QuadPart;
	return al_nsec(time.QuadPart);
}

al_sec  al_system_time(){		return system_time_100ns() * 1e-7; }
al_nsec al_system_time_nsec(){	return system_time_100ns() * al_nsec(100); }
al_sec  al_steady_time(){		return steady_time_us() * 1e-6; }
al_nsec al_steady_time_nsec(){	return steady_time_us() * al_nsec(1e3); }
void al_sleep(al_sec v){		sleep_ms(v * 1e3); }
void al_sleep_nsec(al_nsec v){	sleep_ms(v / 1e6); }
//void al_sleep(al_sec v){		sleep_us(v * 1e6); }
//void al_sleep_nsec(al_nsec v){	sleep_us(v / 1e3); }
//*/

/* Posix (Mac, Linux) */
#else
#include <time.h> // nanosleep, clock_gettime
#include <sys/time.h> // gettimeofday
#include <unistd.h> // _POSIX_TIMERS

al_sec  al_system_time(){
	timeval t;
	gettimeofday(&t, NULL);
	return al_sec(t.tv_sec) + al_sec(t.tv_usec) * 1e-6;
}

al_nsec al_system_time_nsec(){
	timeval t;
	gettimeofday(&t, NULL);
	return al_nsec(t.tv_sec) * al_nsec(1e9) + al_nsec(t.tv_usec) * al_nsec(1e3);
}

#ifdef AL_OSX
#include <mach/mach_time.h>

// Code from:
// http://stackoverflow.com/questions/23378063/how-can-i-use-mach-absolute-time-without-overflowing

al_sec al_steady_time(){
	return al_steady_time_nsec() * 1e-9;
}

al_nsec al_steady_time_nsec(){
	uint64_t now = mach_absolute_time();
	static struct Data {
		Data(uint64_t bias_) : bias(bias_) {
			mach_timebase_info(&tb);
			if (tb.denom > 1024) {
				double frac = (double)tb.numer/tb.denom;
				tb.denom = 1024;
				tb.numer = tb.denom * frac + 0.5;
			}
		}
		mach_timebase_info_data_t tb;
		uint64_t bias;
	} data(now);
	return (now - data.bias) * data.tb.numer / data.tb.denom;
}

// Posix timers available?
#elif _POSIX_TIMERS > 0 && defined(_POSIX_MONOTONIC_CLOCK)
al_sec al_steady_time(){
	struct timespec t;
	clock_gettime(CLOCK_MONOTONIC, &t);
	return al_sec(t.tv_sec) + al_sec(t.tv_nsec) * 1e-9;
}

al_nsec al_steady_time_nsec(){
	struct timespec t;
	clock_gettime(CLOCK_MONOTONIC, &t);
	return al_nsec(t.tv_sec) * al_nsec(1e9) + al_nsec(t.tv_nsec);
}

// Otherwise fallback to system time
#else
al_sec  al_steady_time(){
	return al_system_time();
}

al_nsec al_steady_time_nsec(){
	return al_system_time_nsec();
}
#endif

void al_sleep(al_sec v) {
	time_t sec = time_t(v);
	al_nsec nsec = al_time_s2ns * (v - al_sec(sec));
	timespec tspec = { sec, long(nsec) };
	while (nanosleep(&tspec, &tspec) == -1)
		continue;
}

void al_sleep_nsec(al_nsec v) {
	al_sleep(al_sec(v) * al_time_ns2s);
}

#endif
/* end platform specific */

void al_sleep_until(al_sec target) {
	al_sec dt = target - al_time();
	if (dt > 0) al_sleep(dt);
}

al_sec  al_time(){				return al_system_time(); }
al_nsec al_time_nsec(){			return al_system_time_nsec(); }

namespace al {

std::string toTimecode(al_nsec t, const std::string& format){
	unsigned day = t/(al_nsec(1000000000) * 60 * 60 * 24); // basically for overflow
	unsigned hrs = t/(al_nsec(1000000000) * 60 * 60) % 24;
	unsigned min = t/(al_nsec(1000000000) * 60) % 60;
	unsigned sec = t/(al_nsec(1000000000)) % 60;
	unsigned msc = t/(al_nsec(1000000)) % 1000;
	unsigned usc = t/(al_nsec(1000)) % 1000;

	std::ostringstream s;
	s.fill('0');

	for(unsigned i=0; i<format.size(); ++i){
		const auto c = format[i];
		switch(c){
		case 'D': s << day; break;
		case 'H': s << std::setw(2) << hrs; break;
		case 'M': s << std::setw(2) << min; break;
		case 'S': s << std::setw(2) << sec; break;
		case 'm': s << std::setw(3) << msc; break;
		case 'u': s << std::setw(3) << usc; break;
		default:  s << c;
		}
	}

	return s.str();
}

std::string timecodeNow(const std::string& format){
	return toTimecode(al_system_time_nsec(), format);
}

void Timer::print() const {
	auto t = getTime();
	auto dt = t-mStart;
	double dtSec = al_time_ns2s * dt;
	printf("%g sec (%g ms) elapsed\n", dtSec, dtSec*1000.);
}

void DelayLockedLoop :: setBandwidth(double bandwidth) {
	double F = 1./tperiod;		// step rate
	double omega = M_PI * 2.8 * bandwidth/F;
	mB = omega * sqrt(2.);	// 1st-order weight
	mC = omega * omega;		// 2nd-order weight
}

void DelayLockedLoop :: step(al_sec realtime) {
	if (mReset) {
		// The first iteration sets initial conditions.

		// init loop
		t2 = tperiod;
		t0 = realtime;
		t1 = t0 + t2;	// t1 is ideally the timestamp of the next block start

		// subsequent iterations use the other branch:
		mReset = false;
	} else {
		// read timer and calculate loop error
		// e.g. if t1 underestimated, terr will be
		al_sec terr = realtime - t1;
		// update loop
		t0 = t1;				// 0th-order (distance)
		t1 += mB * terr + t2;	// integration of 1st-order (velocity)
		t2 += mC * terr;		// integration of 2nd-order (acceleration)
	}

//		// now t0 is the current system time, and t1 is the estimated system time at the next step
//		//
//		al_sec tper_estimate = t1-t0;	// estimated real duration between this step & the next one
//		double factor = tperiod/tper_estimate;	// <1 if we are too slow, >1 if we are too fast
//		double real_rate = 1./tper_estimate;
//		al_sec tper_estimate2 = t2;	// estimated real duration between this step & the next one
//		double factor2 = 1./t2;	// <1 if we are too slow, >1 if we are too fast
//		printf("factor %f %f rate %f\n", factor, factor2, real_rate);
}

} // al::
<|endoftext|>


<commit_before>/**
 * \file
 * \brief ConditionVariableOperationsTestCase class implementation
 *
 * \author Copyright (C) 2014-2015 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2015-11-11
 */

#include "ConditionVariableOperationsTestCase.hpp"

#include "waitForNextTick.hpp"
#include "Mutex/mutexTestTryLockWhenLocked.hpp"

#include "distortos/ConditionVariable.hpp"
#include "distortos/Mutex.hpp"
#include "distortos/ThisThread.hpp"
#include "distortos/StaticSoftwareTimer.hpp"
#include "distortos/StaticThread.hpp"
#include "distortos/statistics.hpp"

#include <cerrno>

namespace distortos
{

namespace test
{

namespace
{

/*---------------------------------------------------------------------------------------------------------------------+
| local constants
+---------------------------------------------------------------------------------------------------------------------*/

/// single duration used in tests
constexpr auto singleDuration = TickClock::duration{1};

/// long duration used in tests
constexpr auto longDuration = singleDuration * 10;

/// expected number of context switches in waitForNextTick(): main -> idle -> main
constexpr decltype(statistics::getContextSwitchCount()) waitForNextTickContextSwitchCount {2};

/// expected number of context switches in testMutexAndUnlock(): main -> idle -> main
constexpr decltype(statistics::getContextSwitchCount()) testMutexAndUnlockContextSwitchCount
{
		waitForNextTickContextSwitchCount + 2
};

/// expected number of context switches in phase1 block involving waitFor() or waitUntil() (excluding
/// waitForNextTick() and testMutexAndUnlock()): 1 - main thread blocks on condition variable (main -> idle), 2 - main
/// thread wakes up (idle -> main)
constexpr decltype(statistics::getContextSwitchCount()) phase1WaitForUntilContextSwitchCount {2};

/// expected number of context switches in phase2 block involving test thread (excluding waitForNextTick() and
/// testMutexAndUnlock()): 1 - test thread starts (main -> test), 2 - test thread goes to sleep (test -> main), 3 - main
/// thread blocks on condition variable (main -> idle), 4 - test thread wakes (idle -> test), 5 - test thread terminates
/// (test -> main)
constexpr decltype(statistics::getContextSwitchCount()) phase2ThreadContextSwitchCount {5};

/// expected number of context switches in phase3 block involving software timer (excluding waitForNextTick() and
/// testMutexAndUnlock()): 1 - main thread blocks on condition variable (main -> idle), 2 - main thread is unblocked by
/// interrupt (idle -> main)
constexpr decltype(statistics::getContextSwitchCount()) phase3SoftwareTimerContextSwitchCount {2};

/*---------------------------------------------------------------------------------------------------------------------+
| local functions
+---------------------------------------------------------------------------------------------------------------------*/

/**
 * \brief Tests whether supplied mutex is properly locked and unlocks it.
 *
 * \param [in] mutex is a reference to mutex that will be tested and unlocked
 *
 * \return true if test succeeded and mutex was sucessfully unlocked, false otherwise
 */

bool testMutexAndUnlock(Mutex& mutex)
{
	const auto testRet = mutexTestTryLockWhenLocked(mutex, UINT8_MAX);
	const auto unlockRet = mutex.unlock();

	return testRet == true && unlockRet == 0;
}

/**
 * \brief Phase 1 of test case.
 *
 * Tests whether both waitFor() and waitUntil() functions properly return some error and properly handle mutex when
 * timing out without notification.
 *
 * \param [in] mutex is a reference to mutex used with condition variable, must be unlocked
 *
 * \return true if test succeeded, false otherwise
 */

bool phase1(Mutex& mutex)
{
	ConditionVariable conditionVariable;

	{
		const auto ret = mutex.lock();
		if (ret != 0)
			return false;
	}

	{
		waitForNextTick();

		// there will be no notification, so waitFor() should time-out at expected time
		const auto contextSwitchCount = statistics::getContextSwitchCount();
		const auto start = TickClock::now();
		const auto ret = conditionVariable.waitFor(mutex, singleDuration);
		const auto realDuration = TickClock::now() - start;
		const auto contextSwitches = statistics::getContextSwitchCount() - contextSwitchCount;

		const auto mutexTest = testMutexAndUnlock(mutex);
		if (ret != ETIMEDOUT || realDuration != singleDuration + decltype(singleDuration){1} || mutexTest != true ||
				contextSwitches != phase1WaitForUntilContextSwitchCount)
			return false;
	}

	{
		const auto ret = mutex.lock();
		if (ret != 0)
			return false;
	}

	{
		waitForNextTick();

		// there will be no notification, so waitUntil() should time-out at exact expected time
		const auto contextSwitchCount = statistics::getContextSwitchCount();
		const auto wakeUpTimePoint = TickClock::now() + singleDuration;
		const auto ret = conditionVariable.waitUntil(mutex, wakeUpTimePoint);
		const auto wokenUpTimePoint = TickClock::now();
		const auto contextSwitches = statistics::getContextSwitchCount() - contextSwitchCount;

		const auto mutexTest = testMutexAndUnlock(mutex);
		if (ret != ETIMEDOUT || wakeUpTimePoint != wokenUpTimePoint || mutexTest != true ||
				contextSwitches != phase1WaitForUntilContextSwitchCount)
			return false;
	}

	return true;
}

/**
 * \brief Phase 2 of test case.
 *
 * Tests thread-thread signaling scenario. Main (current) thread waits for condition variable notification (using
 * wait(), waitFor() and waitUntil()). Test thread notifies one waiter at specified time point, main thread is expected
 * to wake up and acquire ownership of the mutex in the same moment.
 *
 * \param [in] mutex is a reference to mutex used with condition variable, must be unlocked
 *
 * \return true if test succeeded, false otherwise
 */

bool phase2(Mutex& mutex)
{
	constexpr size_t testThreadStackSize {384};

	ConditionVariable conditionVariable;

	const auto sleepUntilFunctor = [&conditionVariable](const TickClock::time_point timePoint)
			{
				ThisThread::sleepUntil(timePoint);
				conditionVariable.notifyOne();
			};

	{
		const auto ret = mutex.lock();
		if (ret != 0)
			return false;
	}

	{
		waitForNextTick();

		const auto contextSwitchCount = statistics::getContextSwitchCount();
		const auto wakeUpTimePoint = TickClock::now() + longDuration;
		auto thread = makeStaticThread<testThreadStackSize>(UINT8_MAX, sleepUntilFunctor, wakeUpTimePoint);

		thread.start();
		ThisThread::yield();

		// wait() should succeed at expected time
		const auto ret = conditionVariable.wait(mutex);
		const auto wokenUpTimePoint = TickClock::now();
		const auto contextSwitches = statistics::getContextSwitchCount() - contextSwitchCount;

		thread.join();
		const auto mutexTest = testMutexAndUnlock(mutex);
		if (ret != 0 || wakeUpTimePoint != wokenUpTimePoint || mutexTest != true ||
				contextSwitches != phase2ThreadContextSwitchCount)
			return false;
	}

	{
		const auto ret = mutex.lock();
		if (ret != 0)
			return false;
	}

	{
		waitForNextTick();

		const auto contextSwitchCount = statistics::getContextSwitchCount();
		const auto wakeUpTimePoint = TickClock::now() + longDuration;
		auto thread = makeStaticThread<testThreadStackSize>(UINT8_MAX, sleepUntilFunctor, wakeUpTimePoint);

		thread.start();
		ThisThread::yield();

		// waitFor() should succeed at expected time
		const auto ret = conditionVariable.waitFor(mutex, wakeUpTimePoint - TickClock::now() + longDuration);
		const auto wokenUpTimePoint = TickClock::now();
		const auto contextSwitches = statistics::getContextSwitchCount() - contextSwitchCount;

		thread.join();
		const auto mutexTest = testMutexAndUnlock(mutex);
		if (ret != 0 || wakeUpTimePoint != wokenUpTimePoint || mutexTest != true ||
				contextSwitches != phase2ThreadContextSwitchCount)
			return false;
	}

	{
		const auto ret = mutex.lock();
		if (ret != 0)
			return false;
	}

	{
		waitForNextTick();

		const auto contextSwitchCount = statistics::getContextSwitchCount();
		const auto wakeUpTimePoint = TickClock::now() + longDuration;
		auto thread = makeStaticThread<testThreadStackSize>(UINT8_MAX, sleepUntilFunctor, wakeUpTimePoint);

		thread.start();
		ThisThread::yield();

		// waitUntil() should succeed at expected time
		const auto ret = conditionVariable.waitUntil(mutex, wakeUpTimePoint + longDuration);
		const auto wokenUpTimePoint = TickClock::now();
		const auto contextSwitches = statistics::getContextSwitchCount() - contextSwitchCount;

		thread.join();
		const auto mutexTest = testMutexAndUnlock(mutex);
		if (ret != 0 || wakeUpTimePoint != wokenUpTimePoint || mutexTest != true ||
				contextSwitches != phase2ThreadContextSwitchCount)
			return false;
	}

	return true;
}

/**
 * \brief Phase 3 of test case.
 *
 * Tests interrupt-thread signaling scenario. Main (current) thread waits for condition variable notification (using
 * wait(), waitFor() and waitUntil()). Software timer is used to notify one waiter at specified time point from
 * interrupt context, main thread is expected to wake up and acquire ownership of the mutex in the same moment.
 *
 * \param [in] mutex is a reference to mutex used with condition variable, must be unlocked
 *
 * \return true if test succeeded, false otherwise
 */

bool phase3(Mutex& mutex)
{
	ConditionVariable conditionVariable;

	auto softwareTimer = makeStaticSoftwareTimer(&ConditionVariable::notifyOne, std::ref(conditionVariable));

	{
		const auto ret = mutex.lock();
		if (ret != 0)
			return false;
	}

	{
		waitForNextTick();

		const auto contextSwitchCount = statistics::getContextSwitchCount();
		const auto wakeUpTimePoint = TickClock::now() + longDuration;

		softwareTimer.start(wakeUpTimePoint);

		// wait() should succeed at expected time
		const auto ret = conditionVariable.wait(mutex);
		const auto wokenUpTimePoint = TickClock::now();
		const auto contextSwitches = statistics::getContextSwitchCount() - contextSwitchCount;

		const auto mutexTest = testMutexAndUnlock(mutex);
		if (ret != 0 || wakeUpTimePoint != wokenUpTimePoint || mutexTest != true ||
				contextSwitches != phase3SoftwareTimerContextSwitchCount)
			return false;
	}

	{
		const auto ret = mutex.lock();
		if (ret != 0)
			return false;
	}

	{
		waitForNextTick();

		const auto contextSwitchCount = statistics::getContextSwitchCount();
		const auto wakeUpTimePoint = TickClock::now() + longDuration;

		softwareTimer.start(wakeUpTimePoint);

		// waitFor() should succeed at expected time
		const auto ret = conditionVariable.waitFor(mutex, wakeUpTimePoint - TickClock::now() + longDuration);
		const auto wokenUpTimePoint = TickClock::now();
		const auto contextSwitches = statistics::getContextSwitchCount() - contextSwitchCount;

		const auto mutexTest = testMutexAndUnlock(mutex);
		if (ret != 0 || wakeUpTimePoint != wokenUpTimePoint || mutexTest != true ||
				contextSwitches != phase3SoftwareTimerContextSwitchCount)
			return false;
	}

	{
		const auto ret = mutex.lock();
		if (ret != 0)
			return false;
	}

	{
		waitForNextTick();

		const auto contextSwitchCount = statistics::getContextSwitchCount();
		const auto wakeUpTimePoint = TickClock::now() + longDuration;

		softwareTimer.start(wakeUpTimePoint);

		// waitUntil() should succeed at expected time
		const auto ret = conditionVariable.waitUntil(mutex, wakeUpTimePoint + longDuration);
		const auto wokenUpTimePoint = TickClock::now();
		const auto contextSwitches = statistics::getContextSwitchCount() - contextSwitchCount;

		const auto mutexTest = testMutexAndUnlock(mutex);
		if (ret != 0 || wakeUpTimePoint != wokenUpTimePoint || mutexTest != true ||
				contextSwitches != phase3SoftwareTimerContextSwitchCount)
			return false;
	}

	return true;
}

}	// namespace

/*---------------------------------------------------------------------------------------------------------------------+
| private functions
+---------------------------------------------------------------------------------------------------------------------*/

bool ConditionVariableOperationsTestCase::run_() const
{
	using Parameters = std::tuple<Mutex::Type, Mutex::Protocol, uint8_t>;
	static const std::array<Parameters, 9> parametersArray
	{{
			Parameters{Mutex::Type::Normal, Mutex::Protocol::None, {}},
			Parameters{Mutex::Type::Normal, Mutex::Protocol::PriorityProtect, UINT8_MAX},
			Parameters{Mutex::Type::Normal, Mutex::Protocol::PriorityInheritance, {}},
			Parameters{Mutex::Type::ErrorChecking, Mutex::Protocol::None, {}},
			Parameters{Mutex::Type::ErrorChecking, Mutex::Protocol::PriorityProtect, UINT8_MAX},
			Parameters{Mutex::Type::ErrorChecking, Mutex::Protocol::PriorityInheritance, {}},
			Parameters{Mutex::Type::Recursive, Mutex::Protocol::None, {}},
			Parameters{Mutex::Type::Recursive, Mutex::Protocol::PriorityProtect, UINT8_MAX},
			Parameters{Mutex::Type::Recursive, Mutex::Protocol::PriorityInheritance, {}},
	}};

	constexpr auto phase1ExpectedContextSwitchCount = 2 * (waitForNextTickContextSwitchCount +
			phase1WaitForUntilContextSwitchCount + testMutexAndUnlockContextSwitchCount);
	constexpr auto phase2ExpectedContextSwitchCount = 3 * (waitForNextTickContextSwitchCount +
			phase2ThreadContextSwitchCount + testMutexAndUnlockContextSwitchCount);
	constexpr auto phase3ExpectedContextSwitchCount = 3 * (waitForNextTickContextSwitchCount +
			phase3SoftwareTimerContextSwitchCount + testMutexAndUnlockContextSwitchCount);
	constexpr auto expectedContextSwitchCount = parametersArray.size() * (phase1ExpectedContextSwitchCount +
			phase2ExpectedContextSwitchCount + phase3ExpectedContextSwitchCount);

	const auto contextSwitchCount = statistics::getContextSwitchCount();

	for (const auto& parameters : parametersArray)
		for (const auto& function : {phase1, phase2, phase3})
		{
			Mutex mutex {std::get<0>(parameters), std::get<1>(parameters), std::get<2>(parameters)};
			const auto ret = function(mutex);
			if (ret != true)
				return ret;
		}

	if (statistics::getContextSwitchCount() - contextSwitchCount != expectedContextSwitchCount)
		return false;

	return true;
}

}	// namespace test

}	// namespace distortos
<commit_msg>test: convert ConditionVariableOperationsTestCase to use dynamic threads<commit_after>/**
 * \file
 * \brief ConditionVariableOperationsTestCase class implementation
 *
 * \author Copyright (C) 2014-2016 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2016-01-04
 */

#include "ConditionVariableOperationsTestCase.hpp"

#include "waitForNextTick.hpp"
#include "Mutex/mutexTestTryLockWhenLocked.hpp"

#include "distortos/ConditionVariable.hpp"
#include "distortos/DynamicThread.hpp"
#include "distortos/Mutex.hpp"
#include "distortos/ThisThread.hpp"
#include "distortos/StaticSoftwareTimer.hpp"
#include "distortos/statistics.hpp"

namespace distortos
{

namespace test
{

namespace
{

/*---------------------------------------------------------------------------------------------------------------------+
| local constants
+---------------------------------------------------------------------------------------------------------------------*/

/// single duration used in tests
constexpr auto singleDuration = TickClock::duration{1};

/// long duration used in tests
constexpr auto longDuration = singleDuration * 10;

/// expected number of context switches in waitForNextTick(): main -> idle -> main
constexpr decltype(statistics::getContextSwitchCount()) waitForNextTickContextSwitchCount {2};

/// expected number of context switches in testMutexAndUnlock(): main -> idle -> main
constexpr decltype(statistics::getContextSwitchCount()) testMutexAndUnlockContextSwitchCount
{
		waitForNextTickContextSwitchCount + 2
};

/// expected number of context switches in phase1 block involving waitFor() or waitUntil() (excluding
/// waitForNextTick() and testMutexAndUnlock()): 1 - main thread blocks on condition variable (main -> idle), 2 - main
/// thread wakes up (idle -> main)
constexpr decltype(statistics::getContextSwitchCount()) phase1WaitForUntilContextSwitchCount {2};

/// expected number of context switches in phase2 block involving test thread (excluding waitForNextTick() and
/// testMutexAndUnlock()): 1 - test thread starts (main -> test), 2 - test thread goes to sleep (test -> main), 3 - main
/// thread blocks on condition variable (main -> idle), 4 - test thread wakes (idle -> test), 5 - test thread terminates
/// (test -> main)
constexpr decltype(statistics::getContextSwitchCount()) phase2ThreadContextSwitchCount {5};

/// expected number of context switches in phase3 block involving software timer (excluding waitForNextTick() and
/// testMutexAndUnlock()): 1 - main thread blocks on condition variable (main -> idle), 2 - main thread is unblocked by
/// interrupt (idle -> main)
constexpr decltype(statistics::getContextSwitchCount()) phase3SoftwareTimerContextSwitchCount {2};

/*---------------------------------------------------------------------------------------------------------------------+
| local functions
+---------------------------------------------------------------------------------------------------------------------*/

/**
 * \brief Tests whether supplied mutex is properly locked and unlocks it.
 *
 * \param [in] mutex is a reference to mutex that will be tested and unlocked
 *
 * \return true if test succeeded and mutex was sucessfully unlocked, false otherwise
 */

bool testMutexAndUnlock(Mutex& mutex)
{
	const auto testRet = mutexTestTryLockWhenLocked(mutex, UINT8_MAX);
	const auto unlockRet = mutex.unlock();

	return testRet == true && unlockRet == 0;
}

/**
 * \brief Phase 1 of test case.
 *
 * Tests whether both waitFor() and waitUntil() functions properly return some error and properly handle mutex when
 * timing out without notification.
 *
 * \param [in] mutex is a reference to mutex used with condition variable, must be unlocked
 *
 * \return true if test succeeded, false otherwise
 */

bool phase1(Mutex& mutex)
{
	ConditionVariable conditionVariable;

	{
		const auto ret = mutex.lock();
		if (ret != 0)
			return false;
	}

	{
		waitForNextTick();

		// there will be no notification, so waitFor() should time-out at expected time
		const auto contextSwitchCount = statistics::getContextSwitchCount();
		const auto start = TickClock::now();
		const auto ret = conditionVariable.waitFor(mutex, singleDuration);
		const auto realDuration = TickClock::now() - start;
		const auto contextSwitches = statistics::getContextSwitchCount() - contextSwitchCount;

		const auto mutexTest = testMutexAndUnlock(mutex);
		if (ret != ETIMEDOUT || realDuration != singleDuration + decltype(singleDuration){1} || mutexTest != true ||
				contextSwitches != phase1WaitForUntilContextSwitchCount)
			return false;
	}

	{
		const auto ret = mutex.lock();
		if (ret != 0)
			return false;
	}

	{
		waitForNextTick();

		// there will be no notification, so waitUntil() should time-out at exact expected time
		const auto contextSwitchCount = statistics::getContextSwitchCount();
		const auto wakeUpTimePoint = TickClock::now() + singleDuration;
		const auto ret = conditionVariable.waitUntil(mutex, wakeUpTimePoint);
		const auto wokenUpTimePoint = TickClock::now();
		const auto contextSwitches = statistics::getContextSwitchCount() - contextSwitchCount;

		const auto mutexTest = testMutexAndUnlock(mutex);
		if (ret != ETIMEDOUT || wakeUpTimePoint != wokenUpTimePoint || mutexTest != true ||
				contextSwitches != phase1WaitForUntilContextSwitchCount)
			return false;
	}

	return true;
}

/**
 * \brief Phase 2 of test case.
 *
 * Tests thread-thread signaling scenario. Main (current) thread waits for condition variable notification (using
 * wait(), waitFor() and waitUntil()). Test thread notifies one waiter at specified time point, main thread is expected
 * to wake up and acquire ownership of the mutex in the same moment.
 *
 * \param [in] mutex is a reference to mutex used with condition variable, must be unlocked
 *
 * \return true if test succeeded, false otherwise
 */

bool phase2(Mutex& mutex)
{
	constexpr size_t testThreadStackSize {384};

	ConditionVariable conditionVariable;

	const auto sleepUntilFunctor = [&conditionVariable](const TickClock::time_point timePoint)
			{
				ThisThread::sleepUntil(timePoint);
				conditionVariable.notifyOne();
			};

	{
		const auto ret = mutex.lock();
		if (ret != 0)
			return false;
	}

	{
		waitForNextTick();

		const auto contextSwitchCount = statistics::getContextSwitchCount();
		const auto wakeUpTimePoint = TickClock::now() + longDuration;
		auto thread = makeDynamicThread({testThreadStackSize, UINT8_MAX}, sleepUntilFunctor, wakeUpTimePoint);

		thread.start();
		ThisThread::yield();

		// wait() should succeed at expected time
		const auto ret = conditionVariable.wait(mutex);
		const auto wokenUpTimePoint = TickClock::now();
		const auto contextSwitches = statistics::getContextSwitchCount() - contextSwitchCount;

		thread.join();
		const auto mutexTest = testMutexAndUnlock(mutex);
		if (ret != 0 || wakeUpTimePoint != wokenUpTimePoint || mutexTest != true ||
				contextSwitches != phase2ThreadContextSwitchCount)
			return false;
	}

	{
		const auto ret = mutex.lock();
		if (ret != 0)
			return false;
	}

	{
		waitForNextTick();

		const auto contextSwitchCount = statistics::getContextSwitchCount();
		const auto wakeUpTimePoint = TickClock::now() + longDuration;
		auto thread = makeDynamicThread({testThreadStackSize, UINT8_MAX}, sleepUntilFunctor, wakeUpTimePoint);

		thread.start();
		ThisThread::yield();

		// waitFor() should succeed at expected time
		const auto ret = conditionVariable.waitFor(mutex, wakeUpTimePoint - TickClock::now() + longDuration);
		const auto wokenUpTimePoint = TickClock::now();
		const auto contextSwitches = statistics::getContextSwitchCount() - contextSwitchCount;

		thread.join();
		const auto mutexTest = testMutexAndUnlock(mutex);
		if (ret != 0 || wakeUpTimePoint != wokenUpTimePoint || mutexTest != true ||
				contextSwitches != phase2ThreadContextSwitchCount)
			return false;
	}

	{
		const auto ret = mutex.lock();
		if (ret != 0)
			return false;
	}

	{
		waitForNextTick();

		const auto contextSwitchCount = statistics::getContextSwitchCount();
		const auto wakeUpTimePoint = TickClock::now() + longDuration;
		auto thread = makeDynamicThread({testThreadStackSize, UINT8_MAX}, sleepUntilFunctor, wakeUpTimePoint);

		thread.start();
		ThisThread::yield();

		// waitUntil() should succeed at expected time
		const auto ret = conditionVariable.waitUntil(mutex, wakeUpTimePoint + longDuration);
		const auto wokenUpTimePoint = TickClock::now();
		const auto contextSwitches = statistics::getContextSwitchCount() - contextSwitchCount;

		thread.join();
		const auto mutexTest = testMutexAndUnlock(mutex);
		if (ret != 0 || wakeUpTimePoint != wokenUpTimePoint || mutexTest != true ||
				contextSwitches != phase2ThreadContextSwitchCount)
			return false;
	}

	return true;
}

/**
 * \brief Phase 3 of test case.
 *
 * Tests interrupt-thread signaling scenario. Main (current) thread waits for condition variable notification (using
 * wait(), waitFor() and waitUntil()). Software timer is used to notify one waiter at specified time point from
 * interrupt context, main thread is expected to wake up and acquire ownership of the mutex in the same moment.
 *
 * \param [in] mutex is a reference to mutex used with condition variable, must be unlocked
 *
 * \return true if test succeeded, false otherwise
 */

bool phase3(Mutex& mutex)
{
	ConditionVariable conditionVariable;

	auto softwareTimer = makeStaticSoftwareTimer(&ConditionVariable::notifyOne, std::ref(conditionVariable));

	{
		const auto ret = mutex.lock();
		if (ret != 0)
			return false;
	}

	{
		waitForNextTick();

		const auto contextSwitchCount = statistics::getContextSwitchCount();
		const auto wakeUpTimePoint = TickClock::now() + longDuration;

		softwareTimer.start(wakeUpTimePoint);

		// wait() should succeed at expected time
		const auto ret = conditionVariable.wait(mutex);
		const auto wokenUpTimePoint = TickClock::now();
		const auto contextSwitches = statistics::getContextSwitchCount() - contextSwitchCount;

		const auto mutexTest = testMutexAndUnlock(mutex);
		if (ret != 0 || wakeUpTimePoint != wokenUpTimePoint || mutexTest != true ||
				contextSwitches != phase3SoftwareTimerContextSwitchCount)
			return false;
	}

	{
		const auto ret = mutex.lock();
		if (ret != 0)
			return false;
	}

	{
		waitForNextTick();

		const auto contextSwitchCount = statistics::getContextSwitchCount();
		const auto wakeUpTimePoint = TickClock::now() + longDuration;

		softwareTimer.start(wakeUpTimePoint);

		// waitFor() should succeed at expected time
		const auto ret = conditionVariable.waitFor(mutex, wakeUpTimePoint - TickClock::now() + longDuration);
		const auto wokenUpTimePoint = TickClock::now();
		const auto contextSwitches = statistics::getContextSwitchCount() - contextSwitchCount;

		const auto mutexTest = testMutexAndUnlock(mutex);
		if (ret != 0 || wakeUpTimePoint != wokenUpTimePoint || mutexTest != true ||
				contextSwitches != phase3SoftwareTimerContextSwitchCount)
			return false;
	}

	{
		const auto ret = mutex.lock();
		if (ret != 0)
			return false;
	}

	{
		waitForNextTick();

		const auto contextSwitchCount = statistics::getContextSwitchCount();
		const auto wakeUpTimePoint = TickClock::now() + longDuration;

		softwareTimer.start(wakeUpTimePoint);

		// waitUntil() should succeed at expected time
		const auto ret = conditionVariable.waitUntil(mutex, wakeUpTimePoint + longDuration);
		const auto wokenUpTimePoint = TickClock::now();
		const auto contextSwitches = statistics::getContextSwitchCount() - contextSwitchCount;

		const auto mutexTest = testMutexAndUnlock(mutex);
		if (ret != 0 || wakeUpTimePoint != wokenUpTimePoint || mutexTest != true ||
				contextSwitches != phase3SoftwareTimerContextSwitchCount)
			return false;
	}

	return true;
}

}	// namespace

/*---------------------------------------------------------------------------------------------------------------------+
| private functions
+---------------------------------------------------------------------------------------------------------------------*/

bool ConditionVariableOperationsTestCase::run_() const
{
	using Parameters = std::tuple<Mutex::Type, Mutex::Protocol, uint8_t>;
	static const std::array<Parameters, 9> parametersArray
	{{
			Parameters{Mutex::Type::Normal, Mutex::Protocol::None, {}},
			Parameters{Mutex::Type::Normal, Mutex::Protocol::PriorityProtect, UINT8_MAX},
			Parameters{Mutex::Type::Normal, Mutex::Protocol::PriorityInheritance, {}},
			Parameters{Mutex::Type::ErrorChecking, Mutex::Protocol::None, {}},
			Parameters{Mutex::Type::ErrorChecking, Mutex::Protocol::PriorityProtect, UINT8_MAX},
			Parameters{Mutex::Type::ErrorChecking, Mutex::Protocol::PriorityInheritance, {}},
			Parameters{Mutex::Type::Recursive, Mutex::Protocol::None, {}},
			Parameters{Mutex::Type::Recursive, Mutex::Protocol::PriorityProtect, UINT8_MAX},
			Parameters{Mutex::Type::Recursive, Mutex::Protocol::PriorityInheritance, {}},
	}};

	constexpr auto phase1ExpectedContextSwitchCount = 2 * (waitForNextTickContextSwitchCount +
			phase1WaitForUntilContextSwitchCount + testMutexAndUnlockContextSwitchCount);
	constexpr auto phase2ExpectedContextSwitchCount = 3 * (waitForNextTickContextSwitchCount +
			phase2ThreadContextSwitchCount + testMutexAndUnlockContextSwitchCount);
	constexpr auto phase3ExpectedContextSwitchCount = 3 * (waitForNextTickContextSwitchCount +
			phase3SoftwareTimerContextSwitchCount + testMutexAndUnlockContextSwitchCount);
	constexpr auto expectedContextSwitchCount = parametersArray.size() * (phase1ExpectedContextSwitchCount +
			phase2ExpectedContextSwitchCount + phase3ExpectedContextSwitchCount);

	const auto contextSwitchCount = statistics::getContextSwitchCount();

	for (const auto& parameters : parametersArray)
		for (const auto& function : {phase1, phase2, phase3})
		{
			Mutex mutex {std::get<0>(parameters), std::get<1>(parameters), std::get<2>(parameters)};
			const auto ret = function(mutex);
			if (ret != true)
				return ret;
		}

	if (statistics::getContextSwitchCount() - contextSwitchCount != expectedContextSwitchCount)
		return false;

	return true;
}

}	// namespace test

}	// namespace distortos
<|endoftext|>


<commit_before>#include "gc_mark_queue.h"

#include "logging.h"

namespace precisegc { namespace details {

gc_mark_queue::gc_mark_queue()
    : m_queue(MAX_SIZE)
{}

//gc_mark_queue& gc_mark_queue::instance()
//{
//    static gc_mark_queue queue;
//    return queue;
//}

bool gc_mark_queue::empty()
{
    return m_queue.empty();
}

bool gc_mark_queue::push(void* ptr)
{
    return m_queue.push(ptr);
}

bool gc_mark_queue::pop(void*& p)
{
    return m_queue.pop(p);
}

void gc_mark_queue::clear()
{
    void* ret;
    while (m_queue.pop(ret)) {}
}
}}<commit_msg>dijcstra write-barrier<commit_after>#include "gc_mark_queue.h"

#include "managed_ptr.h"

#include "logging.h"

namespace precisegc { namespace details {

gc_mark_queue::gc_mark_queue()
    : m_queue(MAX_SIZE)
{}

//gc_mark_queue& gc_mark_queue::instance()
//{
//    static gc_mark_queue queue;
//    return queue;
//}

bool gc_mark_queue::empty()
{
    return m_queue.empty();
}

bool gc_mark_queue::push(void* ptr)
{
    return m_queue.push(ptr);
}

bool gc_mark_queue::pop(void*& p)
{
    p = nullptr;
    void* ptr = nullptr;
    if (m_queue.pop(ptr)) {
        managed_cell_ptr cell_ptr(managed_ptr(reinterpret_cast<byte*>(ptr)), 0);
        if (!cell_ptr.get_mark()) {
            p = ptr;
        }
        return true;
    }
    return false;

//    // this check will be failed only when ptr is pointed to non gc_heap memory,
//    // that is not possible in correct program (i.e. when gc_new is used to create managed objects),
//    // but could occur during testing.
//    try {
//        cell_ptr.lock_descriptor();
//        if (!cell_ptr.get_mark()) {
////            static gc_mark_queue& queue = gc_mark_queue::instance();
//            queue->push(ptr);
//        }
//    } catch (managed_cell_ptr::unindexed_memory_exception& exc) {
//        return;
//    }
    return m_queue.pop(p);
}

void gc_mark_queue::clear()
{
    void* ret;
    while (m_queue.pop(ret)) {}
}
}}<|endoftext|>


<commit_before>#include <stdio.h>      // for printf()
#include <stdlib.h>     // for malloc()

#include <algorithm>
#include <fstream>      // for std::ifstream
#include <iostream>     // for std::cout
#include <map>          // for std::map

std::vector<char> bases = {'A', 'T', 'C', 'G'};
std::map<char, char> complement_map = {{'A', 'T'}, {'T', 'A'}, {'C', 'G'}, {'G', 'C'}};

std::string ReverseComplement(const std::string &src) {
  int len = src.size();
  std::string ret_str = src;
  for (int i = 0; i < len; ++i) {
    ret_str[len - 1 - i] = complement_map[src[i]];
  }
  return ret_str;
}

bool ValidSequence(std::string str) {
  for (char c : str) {
    if (c != 'A' && c != 'T' && c != 'C' && c != 'G') {
      return false;
    }
  }
  return true;
}

int DpAlignment(const std::string &seq1, const std::string &seq2) {
  std::vector<std::vector<std::pair<unsigned, char>>> table;
  // char is the direction you follow back to the (0, 0).
  // L is left, U is down, D is diagonal.
  unsigned cols = seq1.size() + 1;
  unsigned rows = seq2.size() + 1;
  std::vector<std::pair<unsigned, char>> zero_row(cols, {0, '\0'});
  for (unsigned i = 0; i < rows; ++i) table.push_back(zero_row);
  for (unsigned i = 0; i < cols; ++i) table.at(0).at(i) = {i, 'L'};
  for (unsigned i = 0; i < rows; ++i) table.at(i).at(0) = {i, 'U'};

  // write table
  unsigned min;
  for (unsigned i = 1; i < cols; ++i) {
    for (unsigned j = 1; j < rows; ++j) {
      if (seq1.at(i - 1) == seq2.at(j - 1)) {
        table.at(j).at(i) = {table.at(j - 1).at(i - 1).first, 'D'};
        min = table.at(j).at(i).first;
      } else {
        table.at(j).at(i) = {table.at(j - 1).at(i - 1).first + 1, 'D'};;
        min = table.at(j).at(i).first;
      }
      if (table.at(j - 1).at(i).first + 1 < min) {
        table.at(j).at(i) = {table.at(j - 1).at(i).first + 1, 'U'};
        min = table.at(j).at(i).first;
      }
      if (table.at(j).at(i - 1).first + 1 < min) {
        table.at(j).at(i) = {table.at(j).at(i - 1).first + 1, 'L'};
        min = table.at(j).at(i).first;
      }
    }
  }

  // print table
  /*
  for (unsigned i = 0; i < cols; ++i) {
    for (unsigned j = 0; j < rows; ++j) {
      printf("%2d ", table.at(j).at(i).first);
    }
    std::cout << '\n';
  }
  */

  // trace path back to origin and visualise
  std::string out_top, out_mid, out_bot;
  for (unsigned col = cols - 1, row = rows - 1; col + row != 0; ) {
    if (row == 0 || table.at(row).at(col).second == 'L') {
      out_top.append(1, seq1.at(col - 1));
      out_bot.append(1, ' ');
      out_mid.append(1, '-');
      --col;
    } else if (col == 0 || table.at(row).at(col).second == 'L') {
      out_top.append(1, ' ');
      out_bot.append(1, seq2.at(row - 1));
      out_mid.append(1, '-');
      --row;
    } else if (table.at(row).at(col).second == 'D') {
      out_top.append(1, seq1.at(col - 1));
      out_bot.append(1, seq2.at(row - 1));
      if (seq1.at(col - 1) == seq2.at(row - 1)) {
        out_mid.append(1, '|');
      } else {
        out_mid.append(1, ' ');
      }
      --row;
      --col;
    } else {
      std::cout << "error\n";
      exit(EXIT_FAILURE);
    }
  }
  std::reverse(std::begin(out_top), std::end(out_top));
  std::reverse(std::begin(out_mid), std::end(out_mid));
  std::reverse(std::begin(out_bot), std::end(out_bot));
  std::cout << out_top << "\n";
  std::cout << out_mid << "\n";
  std::cout << out_bot << "\n";

	return table.at(rows - 1).at(cols - 1).first;
}

int main(int argc, char* argv[]) {
  if (argc < 2) std::cout << "please supply one input argument, the input file path\n";
  std::string input_file_name;
  input_file_name = argv[1];
  std::cout << "input_file_name = " << input_file_name << '\n';

  // check file exists
  std::ifstream instream(input_file_name);
  if (!instream.is_open()) {
    std::cout << "Could not open input file.\n";
    std::exit(EXIT_FAILURE);
  }

  // read file
  std::string seq1, seq2;
  std::getline(instream, seq1, '\n');
  std::getline(instream, seq2, '\n');
  std::transform(seq1.begin(), seq1.end(), seq1.begin(), ::toupper);
  std::transform(seq2.begin(), seq2.end(), seq2.begin(), ::toupper);
  instream.close();

  // check valid sequence
  if (!ValidSequence(seq1)) {
    std::cout << "seq1 = " << seq1 << " is invalid\n";
  }
  if (!ValidSequence(seq2)) {
    std::cout << "seq2 = " << seq2 << " is invalid\n";
  }

  // print input strings
  std::cout << '\n';
  std::cout << "input sequences:\n";
  std::cout << "seq1 = " << seq1 << '\n';
  std::cout << "seq2 = " << seq2 << '\n';
  std::cout << '\n';

  // align using dynamic programming
  DpAlignment(ReverseComplement(seq1), seq2);

  return 0;
}
<commit_msg>fixed dp_alignment bug<commit_after>#include <stdio.h>      // for printf()
#include <stdlib.h>     // for malloc()

#include <algorithm>
#include <fstream>      // for std::ifstream
#include <iostream>     // for std::cout
#include <map>          // for std::map

std::vector<char> bases = {'A', 'T', 'C', 'G'};
std::map<char, char> complement_map = {{'A', 'T'}, {'T', 'A'}, {'C', 'G'}, {'G', 'C'}};

std::string ReverseComplement(const std::string &src) {
  int len = src.size();
  std::string ret_str = src;
  for (int i = 0; i < len; ++i) {
    ret_str[len - 1 - i] = complement_map[src[i]];
  }
  return ret_str;
}

bool ValidSequence(std::string str) {
  for (char c : str) {
    if (c != 'A' && c != 'T' && c != 'C' && c != 'G') {
      return false;
    }
  }
  return true;
}

int DpAlignment(const std::string &seq1, const std::string &seq2) {
  std::vector<std::vector<std::pair<unsigned, char>>> table;
  // char is the direction you follow back to the (0, 0).
  // L is left, U is down, D is diagonal.

  std::cout << "aligning the following sequences:\n";
  std::cout << seq1 << '\n' << seq2 << "\n\n";

  unsigned cols = seq1.size() + 1;
  unsigned rows = seq2.size() + 1;
  std::vector<std::pair<unsigned, char>> zero_row(cols, {0, '\0'});
  for (unsigned i = 0; i < rows; ++i) table.push_back(zero_row);
  for (unsigned i = 0; i < cols; ++i) table.at(0).at(i) = {i, 'U'};
  for (unsigned i = 0; i < rows; ++i) table.at(i).at(0) = {i, 'L'};

  // write table
  unsigned min;
  for (unsigned row = 1; row < rows; ++row) {
    for (unsigned col = 1; col < cols; ++col) {
      std::cout << "new\n";
      if (seq1.at(col - 1) == seq2.at(row - 1)) {
        std::cout << "1\n";
        table.at(row).at(col) = {table.at(row - 1).at(col - 1).first, 'D'};
        min = table.at(row).at(col).first;
      } else {
        std::cout << "2\n";
        table.at(row).at(col) = {table.at(row - 1).at(col - 1).first + 1, 'D'};;
        min = table.at(row).at(col).first;
      }
      if (table.at(row - 1).at(col).first + 1 < min) {
        std::cout << "val = " << table.at(row - 1).at(col).first + 1 << '\n';
        std::cout << "3\n";
        table.at(row).at(col) = {table.at(row - 1).at(col).first + 1, 'U'};
        min = table.at(row).at(col).first;
      }
      if (table.at(row).at(col - 1).first + 1 < min) {
        std::cout << "val = " << table.at(row).at(col - 1).first + 1 << '\n';
        std::cout << "4\n";
        table.at(row).at(col) = {table.at(row).at(col - 1).first + 1, 'L'};
        min = table.at(row).at(col).first;
      }
    }
  }

  // print table
  /*
  for (unsigned j = 0; j < rows; ++j) {
    for (unsigned i = 0; i < cols; ++i) {
      printf("%2d ", table.at(j).at(i).first);
      printf("%c ", table.at(j).at(i).second);
    }
    std::cout << '\n';
  }
  */

  // trace path back to origin and visualise
  std::string out_top, out_mid, out_bot;
  for (unsigned col = cols - 1, row = rows - 1; col + row != 0; ) {
    //std::cout << row << ',' << col << ',' << table.at(row).at(col).second << '\n';
    if (row == 0 || table.at(row).at(col).second == 'L') {
      out_top.append(1, seq1.at(col - 1));
      out_bot.append(1, ' ');
      out_mid.append(1, '-');
      --col;
    } else if (col == 0 || table.at(row).at(col).second == 'U') {
      out_top.append(1, ' ');
      out_bot.append(1, seq2.at(row - 1));
      out_mid.append(1, '-');
      --row;
    } else if (table.at(row).at(col).second == 'D') {
      out_top.append(1, seq1.at(col - 1));
      out_bot.append(1, seq2.at(row - 1));
      if (seq1.at(col - 1) == seq2.at(row - 1)) {
        out_mid.append(1, '|');
      } else {
        out_mid.append(1, ' ');
      }
      --row;
      --col;
    } else {
      std::cout << "error\n";
      exit(EXIT_FAILURE);
    }
  }
  std::reverse(std::begin(out_top), std::end(out_top));
  std::reverse(std::begin(out_mid), std::end(out_mid));
  std::reverse(std::begin(out_bot), std::end(out_bot));
  std::cout << out_top << "\n";
  std::cout << out_mid << "\n";
  std::cout << out_bot << "\n";

	return table.at(rows - 1).at(cols - 1).first;
}

int main(int argc, char* argv[]) {
  if (argc < 2) std::cout << "please supply one input argument, the input file path\n";
  std::string input_file_name;
  input_file_name = argv[1];
  std::cout << "input_file_name = " << input_file_name << '\n';

  // check file exists
  std::ifstream instream(input_file_name);
  if (!instream.is_open()) {
    std::cout << "Could not open input file.\n";
    std::exit(EXIT_FAILURE);
  }

  // read file
  std::string seq1, seq2;
  std::getline(instream, seq1, '\n');
  std::getline(instream, seq2, '\n');
  std::transform(seq1.begin(), seq1.end(), seq1.begin(), ::toupper);
  std::transform(seq2.begin(), seq2.end(), seq2.begin(), ::toupper);
  instream.close();

  // check valid sequence
  if (!ValidSequence(seq1)) {
    std::cout << "seq1 = " << seq1 << " is invalid\n";
  }
  if (!ValidSequence(seq2)) {
    std::cout << "seq2 = " << seq2 << " is invalid\n";
  }

  // print input strings
  std::cout << '\n';
  std::cout << "input sequences:\n";
  std::cout << "seq1 = " << seq1 << '\n';
  std::cout << "seq2 = " << seq2 << '\n';
  std::cout << '\n';

  // align using dynamic programming
  DpAlignment(ReverseComplement(seq1), seq2);

  return 0;
}
<|endoftext|>


<commit_before>/***********************************************************************
    filename:   NavigationStrategies.cpp
    created:    25/08/2013
    author:     Timotei Dolean
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2013 Paul D Turner & The CEGUI Development Team
 *
 *   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 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.
 ***************************************************************************/
#include "NavigationStrategies.h"

using namespace CEGUI;
using namespace NavigationStrategiesPayloads;

Window* LinearNavigationStrategy::getWindow(Window* neighbour, const String& payload)
{
    std::vector<Window*>::const_iterator itor;
    // start at the beginning
    if (neighbour == 0)
        return *d_windows.begin();
    else
        itor = std::find(d_windows.begin(), d_windows.end(), neighbour);

    // no such neighbour window in here
    if (itor == d_windows.end())
        return 0;

    if (payload == NAVIGATE_PREVIOUS)
    {
        // first item. wrap to end
        if (itor == d_windows.begin())
            return *(d_windows.end() - 1);

        return *(itor - 1);
    }
    else if (payload == NAVIGATE_NEXT)
    {
        // last item. wrap to beginning
        if (itor == d_windows.end() - 1)
            return *d_windows.begin();

        return *(itor + 1);
    }

    // no payload handling, just return the same window
    return neighbour;
}

Window* MatrixNavigationStrategy::getWindow(Window* neighbour, const String& payload)
{
    size_t rows = d_windows.size();

    for (size_t row = 0; row < rows; ++row)
    {
        std::vector<Window*> column = d_windows.at(row);
        size_t cols = column.size();

        for (size_t col = 0; col < cols; ++col)
        {
            if (neighbour == column.at(col))
            {
                // compute the new window (wrapping)
                if (payload == NAVIGATE_RIGHT)
                    col = (col + 1) % cols;
                else if (payload == NAVIGATE_DOWN)
                    row = (row + 1) % rows;
                else if (payload == NAVIGATE_LEFT)
                {
                    if (col == 0)
                        col = cols - 1;
                    else
                        col --;
                }
                else if (payload == NAVIGATE_UP)
                {
                    if (row == 0)
                        row = rows - 1;
                    else
                        row --;
                }

                return d_windows.at(row).at(col);
            }
        }
    }

    // first button
    return d_windows.at(0).at(0);
}
<commit_msg>Fix compilation error on non-MSVC compilers (missed including the algorithm header)<commit_after>/***********************************************************************
    filename:   NavigationStrategies.cpp
    created:    25/08/2013
    author:     Timotei Dolean
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2013 Paul D Turner & The CEGUI Development Team
 *
 *   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 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.
 ***************************************************************************/
#include "NavigationStrategies.h"

#include <algorithm>

using namespace CEGUI;
using namespace NavigationStrategiesPayloads;

Window* LinearNavigationStrategy::getWindow(Window* neighbour, const String& payload)
{
    std::vector<Window*>::const_iterator itor;
    // start at the beginning
    if (neighbour == 0)
        return *d_windows.begin();
    else
        itor = std::find(d_windows.begin(), d_windows.end(), neighbour);

    // no such neighbour window in here
    if (itor == d_windows.end())
        return 0;

    if (payload == NAVIGATE_PREVIOUS)
    {
        // first item. wrap to end
        if (itor == d_windows.begin())
            return *(d_windows.end() - 1);

        return *(itor - 1);
    }
    else if (payload == NAVIGATE_NEXT)
    {
        // last item. wrap to beginning
        if (itor == d_windows.end() - 1)
            return *d_windows.begin();

        return *(itor + 1);
    }

    // no payload handling, just return the same window
    return neighbour;
}

Window* MatrixNavigationStrategy::getWindow(Window* neighbour, const String& payload)
{
    size_t rows = d_windows.size();

    for (size_t row = 0; row < rows; ++row)
    {
        std::vector<Window*> column = d_windows.at(row);
        size_t cols = column.size();

        for (size_t col = 0; col < cols; ++col)
        {
            if (neighbour == column.at(col))
            {
                // compute the new window (wrapping)
                if (payload == NAVIGATE_RIGHT)
                    col = (col + 1) % cols;
                else if (payload == NAVIGATE_DOWN)
                    row = (row + 1) % rows;
                else if (payload == NAVIGATE_LEFT)
                {
                    if (col == 0)
                        col = cols - 1;
                    else
                        col --;
                }
                else if (payload == NAVIGATE_UP)
                {
                    if (row == 0)
                        row = rows - 1;
                    else
                        row --;
                }

                return d_windows.at(row).at(col);
            }
        }
    }

    // first button
    return d_windows.at(0).at(0);
}
<|endoftext|>