<commit_before>/*
 * Copyright (C) 2016 deipi.com LLC and contributors. All rights reserved.
 *
 * 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 "logger.h"

#include <stdarg.h>      // for va_list, va_end, va_start
#include <stdio.h>       // for fileno, vsnprintf, stderr
#include <unistd.h>      // for isatty
#include <ctime>         // for time_t
#include <functional>    // for ref
#include <iostream>      // for cerr
#include <regex>         // for regex_replace, regex
#include <stdexcept>     // for out_of_range
#include <system_error>  // for system_error

#include "datetime.h"    // for to_string
#include "exception.h"   // for traceback
#include "utils.h"       // for get_thread_name

#define BUFFER_SIZE (10 * 1024)
#define STACKED_INDENT "<indent>"

const std::regex filter_re("\033\\[[;\\d]*m");
std::mutex Log::stack_mtx;
std::unordered_map<std::thread::id, unsigned> Log::stack_levels;
int Log::log_level = DEFAULT_LOG_LEVEL;

const char *priorities[] = {
	EMERG_COL "█" NO_COL,   // LOG_EMERG    0 = System is unusable
	ALERT_COL "▉" NO_COL,   // LOG_ALERT    1 = Action must be taken immediately
	CRIT_COL "▊" NO_COL,    // LOG_CRIT     2 = Critical conditions
	ERR_COL "▋" NO_COL,     // LOG_ERR      3 = Error conditions
	WARNING_COL "▌" NO_COL, // LOG_WARNING  4 = Warning conditions
	NOTICE_COL "▍" NO_COL,  // LOG_NOTICE   5 = Normal but significant condition
	INFO_COL "▎" NO_COL,    // LOG_INFO     6 = Informational
	DEBUG_COL "▏" NO_COL,   // LOG_DEBUG    7 = Debug-level messages
};

void
StreamLogger::log(int priority, const std::string& str)
{
	ofs << std::regex_replace(priorities[priority < 0 ? -priority : priority] + str, filter_re, "") << std::endl;
}

void
StderrLogger::log(int priority, const std::string& str)
{
	if (isatty(fileno(stderr))) {
		std::cerr << priorities[priority < 0 ? -priority : priority] + str << std::endl;
	} else {
		std::cerr << std::regex_replace(priorities[priority < 0 ? -priority : priority] + str, filter_re, "") << std::endl;
	}
}

SysLog::SysLog(const char *ident, int option, int facility)
{
	openlog(ident, option, facility);
}

SysLog::~SysLog()
{
	closelog();
}

void
SysLog::log(int priority, const std::string& str)
{
	syslog(priority, "%s", std::regex_replace(priorities[priority < 0 ? -priority : priority] + str, filter_re, "").c_str());
}

Log::Log(const std::string& str, bool clean_, bool stacked_, int priority_, std::chrono::time_point<std::chrono::system_clock> created_at_)
	: stack_level(0),
	  stacked(stacked_),
	  clean(clean_),
	  created_at(created_at_),
	  cleared_at(created_at_),
	  str_start(str),
	  priority(priority_),
	  cleared(false),
	  cleaned(false) {

	if (stacked) {
		std::lock_guard<std::mutex> lk(stack_mtx);
		thread_id = std::this_thread::get_id();
		try {
			stack_level = ++stack_levels.at(thread_id);
		} catch (const std::out_of_range&) {
			stack_levels[thread_id] = 0;
		}
	}
}

Log::~Log()
{
	cleanup();
}

void
Log::cleanup()
{
	bool f = false;
	if (cleared.compare_exchange_strong(f, clean)) {
		cleared_at = std::chrono::system_clock::now();
	}

	if (!cleaned.exchange(true)) {
		if (stacked) {
			std::lock_guard<std::mutex> lk(stack_mtx);
			if (stack_levels.at(thread_id)-- == 0) {
				stack_levels.erase(thread_id);
			}
		}
	}
}

long double
Log::age()
{
	auto now = (cleared_at > created_at) ? cleared_at : std::chrono::system_clock::now();
	return std::chrono::duration_cast<std::chrono::nanoseconds>(now - created_at).count();
}

LogQueue::LogQueue()
	: queue(now())
{ }

LogType&
LogQueue::next(bool final, uint64_t final_key, bool keep_going)
{
	return queue.next(final, final_key, keep_going, false);
}

LogType&
LogQueue::peep()
{
	return queue.next(false, 0, true, true);
}

void
LogQueue::add(const LogType& l_ptr, uint64_t key)
{
	queue.add(l_ptr, key);
}

/*
 * https://isocpp.org/wiki/faq/ctors#static-init-order
 * Avoid the "static initialization order fiasco"
 */

LogThread&
Log::_thread()
{
	static std::unique_ptr<LogThread> thread(std::make_unique<LogThread>());
	return *thread;
}

std::vector<std::unique_ptr<Logger>>&
Log::handlers()
{
	static std::unique_ptr<std::vector<std::unique_ptr<Logger>>> handlers(std::make_unique<std::vector<std::unique_ptr<Logger>>>());
	return *handlers;
}

std::string
Log::str_format(bool stacked, int priority, const std::string& exc, const char *file, int line, const char *suffix, const char *prefix, const void* obj, const char *format, va_list argptr)
{
	char* buffer = new char[BUFFER_SIZE];
	vsnprintf(buffer, BUFFER_SIZE, format, argptr);
	std::string msg(buffer);
	auto iso8601 = "[" + Datetime::to_string(std::chrono::system_clock::now()) + "]";
	auto tid = " (" + get_thread_name() + ")";
	std::string result = iso8601 + tid;
#ifdef LOG_OBJ_ADDRESS
	if (obj) {
		snprintf(buffer, BUFFER_SIZE, " [%p]", obj);
		result += buffer;
	}
#endif
#ifdef TRACEBACK
	auto location = (priority >= LOCATION_LOG_LEVEL) ? " " + std::string(file) + ":" + std::to_string(line) : std::string();
	result += location + ": ";
#else
	result += " ";
	(void)obj;
#endif
	if (stacked) {
		result += STACKED_INDENT;
	}
	result += prefix + msg + suffix;
	delete []buffer;
	if (priority < 0) {
		if (exc.empty()) {
			result += DARK_GREY + traceback(file, line) + NO_COL;
		} else {
			result += NO_COL + exc + NO_COL;
		}
	}
	return result;
}

LogWrapper
Log::log(bool clean, bool stacked, std::chrono::time_point<std::chrono::system_clock> wakeup, int priority, const std::string& exc, const char *file, int line, const char *suffix, const char *prefix, const void *obj, const char *format, ...)
{
	va_list argptr;
	va_start(argptr, format);
	std::string str(str_format(stacked, priority, exc, file, line, suffix, prefix, obj, format, argptr));
	va_end(argptr);

	return print(str, clean, stacked, wakeup, priority);
}

bool
Log::clear()
{
	if (!cleared.exchange(true)) {
		cleared_at = std::chrono::system_clock::now();
		return true;
	}
	return false;
}

bool
Log::unlog(int priority, const char *file, int line, const char *suffix, const char *prefix, const void *obj, const char *format, ...)
{
	if (!clear()) {
		va_list argptr;
		va_start(argptr, format);
		std::string str(str_format(stacked, priority, std::string(), file, line, suffix, prefix, obj, format, argptr));
		va_end(argptr);

		print(str, false, stacked, 0, priority, created_at);

		return true;
	}
	return false;
}

LogWrapper
Log::add(const std::string& str, bool clean, bool stacked, std::chrono::time_point<std::chrono::system_clock> wakeup, int priority, std::chrono::time_point<std::chrono::system_clock> created_at)
{
	auto l_ptr = std::make_shared<Log>(str, clean, stacked, priority, created_at);

	_thread().add(l_ptr, wakeup);

	return LogWrapper(l_ptr);
}

void
Log::log(int priority, std::string str, int indent)
{
	static std::mutex log_mutex;
	std::lock_guard<std::mutex> lk(log_mutex);
	auto needle = str.find(STACKED_INDENT);
	if (needle != std::string::npos) {
		str.replace(needle, sizeof(STACKED_INDENT) - 1, std::string(indent, ' '));
	}
	for (auto& handler : handlers()) {
		handler->log(priority, str);
	}
}

LogWrapper
Log::print(const std::string& str, bool clean, bool stacked, std::chrono::time_point<std::chrono::system_clock> wakeup, int priority, std::chrono::time_point<std::chrono::system_clock> created_at)
{
	if (priority > log_level) {
		return LogWrapper(std::make_shared<Log>(str, clean, stacked, priority, created_at));
	}

	if (priority >= ASYNC_LOG_LEVEL || wakeup > std::chrono::system_clock::now()) {
		return add(str, clean, stacked, wakeup, priority, created_at);
	} else {
		auto l_ptr = std::make_shared<Log>(str, clean, stacked, priority, created_at);
		log(priority, str, l_ptr->stack_level * 2);
		return LogWrapper(l_ptr);
	}
}

void
Log::finish(int wait)
{
	_thread().finish(wait);
}

LogThread::LogThread()
	: running(-1),
	  inner_thread(&LogThread::run, this) { }

LogThread::~LogThread()
{
	finish(true);
}

void
LogThread::finish(int wait)
{
	running = wait;
	wakeup_signal.notify_all();
	if (wait) {
		try {
			inner_thread.join();
		} catch (const std::system_error&) { }
	}
}

void
LogThread::add(const LogType& l_ptr, std::chrono::time_point<std::chrono::system_clock> wakeup)
{
	if (running != 0) {
		auto now = std::chrono::system_clock::now();
		if (wakeup < now + 2ms) {
			wakeup = now + 2ms;  // defer log so we make sure we're not adding messages to the current slot
		}

		auto wt = time_point_to_ullong(wakeup);
		l_ptr->wakeup_time = wt;

		log_queue.add(l_ptr, LogQueue::time_point_to_key(wakeup));

		bool notify;
		auto nwt = next_wakeup_time.load();
		do {
			notify = nwt >= wt;
		} while (notify && !next_wakeup_time.compare_exchange_weak(nwt, wt));

		if (notify) {
			wakeup_signal.notify_one();
		}
	}
}

void
LogThread::run_one(LogType& l_ptr)
{
	if (!l_ptr->cleared) {
		auto msg = l_ptr->str_start;
		auto age = l_ptr->age();
		if (age > 2e8) {
			msg += " ~" + delta_string(age, true);
		}
		if (l_ptr->clear()) {
			Log::log(l_ptr->priority, msg, l_ptr->stack_level * 2);
		}
	}
}

void
LogThread::run()
{
	std::mutex mtx;
	std::unique_lock<std::mutex> lk(mtx);

	next_wakeup_time = time_point_to_ullong(std::chrono::system_clock::now() + 100ms);

	while (running != 0) {
		if (--running < 0) {
			running = -1;
		}

		auto now = std::chrono::system_clock::now();
		auto wt = time_point_to_ullong(now + (running < 0 ? 3s : 100ms));
		try {
			auto& l_ptr = log_queue.peep();
			if (l_ptr) {
				wt = l_ptr->wakeup_time;
			}
		} catch(const StashContinue&) { }

		auto nwt = next_wakeup_time.load();
		while (nwt >= wt && !next_wakeup_time.compare_exchange_weak(nwt, wt));

		wakeup_signal.wait_until(lk, time_point_from_ullong(next_wakeup_time.load()));

		try {
			do {
				auto& l_ptr = log_queue.next(running < 0);
				if (l_ptr) {
					run_one(l_ptr);
					l_ptr.reset();
				}
			} while (true);
		} catch(const StashContinue&) { }

		if (running >= 0) {
			break;
		}
	}
}
<commit_msg>Logger: Initialize wakeup_time<commit_after>/*
 * Copyright (C) 2016 deipi.com LLC and contributors. All rights reserved.
 *
 * 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 "logger.h"

#include <stdarg.h>      // for va_list, va_end, va_start
#include <stdio.h>       // for fileno, vsnprintf, stderr
#include <unistd.h>      // for isatty
#include <ctime>         // for time_t
#include <functional>    // for ref
#include <iostream>      // for cerr
#include <regex>         // for regex_replace, regex
#include <stdexcept>     // for out_of_range
#include <system_error>  // for system_error

#include "datetime.h"    // for to_string
#include "exception.h"   // for traceback
#include "utils.h"       // for get_thread_name

#define BUFFER_SIZE (10 * 1024)
#define STACKED_INDENT "<indent>"

const std::regex filter_re("\033\\[[;\\d]*m");
std::mutex Log::stack_mtx;
std::unordered_map<std::thread::id, unsigned> Log::stack_levels;
int Log::log_level = DEFAULT_LOG_LEVEL;

const char *priorities[] = {
	EMERG_COL "█" NO_COL,   // LOG_EMERG    0 = System is unusable
	ALERT_COL "▉" NO_COL,   // LOG_ALERT    1 = Action must be taken immediately
	CRIT_COL "▊" NO_COL,    // LOG_CRIT     2 = Critical conditions
	ERR_COL "▋" NO_COL,     // LOG_ERR      3 = Error conditions
	WARNING_COL "▌" NO_COL, // LOG_WARNING  4 = Warning conditions
	NOTICE_COL "▍" NO_COL,  // LOG_NOTICE   5 = Normal but significant condition
	INFO_COL "▎" NO_COL,    // LOG_INFO     6 = Informational
	DEBUG_COL "▏" NO_COL,   // LOG_DEBUG    7 = Debug-level messages
};

void
StreamLogger::log(int priority, const std::string& str)
{
	ofs << std::regex_replace(priorities[priority < 0 ? -priority : priority] + str, filter_re, "") << std::endl;
}

void
StderrLogger::log(int priority, const std::string& str)
{
	if (isatty(fileno(stderr))) {
		std::cerr << priorities[priority < 0 ? -priority : priority] + str << std::endl;
	} else {
		std::cerr << std::regex_replace(priorities[priority < 0 ? -priority : priority] + str, filter_re, "") << std::endl;
	}
}

SysLog::SysLog(const char *ident, int option, int facility)
{
	openlog(ident, option, facility);
}

SysLog::~SysLog()
{
	closelog();
}

void
SysLog::log(int priority, const std::string& str)
{
	syslog(priority, "%s", std::regex_replace(priorities[priority < 0 ? -priority : priority] + str, filter_re, "").c_str());
}

Log::Log(const std::string& str, bool clean_, bool stacked_, int priority_, std::chrono::time_point<std::chrono::system_clock> created_at_)
	: stack_level(0),
	  stacked(stacked_),
	  clean(clean_),
	  created_at(created_at_),
	  cleared_at(created_at_),
	  wakeup_time(0),
	  str_start(str),
	  priority(priority_),
	  cleared(false),
	  cleaned(false) {

	if (stacked) {
		std::lock_guard<std::mutex> lk(stack_mtx);
		thread_id = std::this_thread::get_id();
		try {
			stack_level = ++stack_levels.at(thread_id);
		} catch (const std::out_of_range&) {
			stack_levels[thread_id] = 0;
		}
	}
}

Log::~Log()
{
	cleanup();
}

void
Log::cleanup()
{
	bool f = false;
	if (cleared.compare_exchange_strong(f, clean)) {
		cleared_at = std::chrono::system_clock::now();
	}

	if (!cleaned.exchange(true)) {
		if (stacked) {
			std::lock_guard<std::mutex> lk(stack_mtx);
			if (stack_levels.at(thread_id)-- == 0) {
				stack_levels.erase(thread_id);
			}
		}
	}
}

long double
Log::age()
{
	auto now = (cleared_at > created_at) ? cleared_at : std::chrono::system_clock::now();
	return std::chrono::duration_cast<std::chrono::nanoseconds>(now - created_at).count();
}

LogQueue::LogQueue()
	: queue(now())
{ }

LogType&
LogQueue::next(bool final, uint64_t final_key, bool keep_going)
{
	return queue.next(final, final_key, keep_going, false);
}

LogType&
LogQueue::peep()
{
	return queue.next(false, 0, true, true);
}

void
LogQueue::add(const LogType& l_ptr, uint64_t key)
{
	queue.add(l_ptr, key);
}

/*
 * https://isocpp.org/wiki/faq/ctors#static-init-order
 * Avoid the "static initialization order fiasco"
 */

LogThread&
Log::_thread()
{
	static std::unique_ptr<LogThread> thread(std::make_unique<LogThread>());
	return *thread;
}

std::vector<std::unique_ptr<Logger>>&
Log::handlers()
{
	static std::unique_ptr<std::vector<std::unique_ptr<Logger>>> handlers(std::make_unique<std::vector<std::unique_ptr<Logger>>>());
	return *handlers;
}

std::string
Log::str_format(bool stacked, int priority, const std::string& exc, const char *file, int line, const char *suffix, const char *prefix, const void* obj, const char *format, va_list argptr)
{
	char* buffer = new char[BUFFER_SIZE];
	vsnprintf(buffer, BUFFER_SIZE, format, argptr);
	std::string msg(buffer);
	auto iso8601 = "[" + Datetime::to_string(std::chrono::system_clock::now()) + "]";
	auto tid = " (" + get_thread_name() + ")";
	std::string result = iso8601 + tid;
#ifdef LOG_OBJ_ADDRESS
	if (obj) {
		snprintf(buffer, BUFFER_SIZE, " [%p]", obj);
		result += buffer;
	}
#endif
#ifdef TRACEBACK
	auto location = (priority >= LOCATION_LOG_LEVEL) ? " " + std::string(file) + ":" + std::to_string(line) : std::string();
	result += location + ": ";
#else
	result += " ";
	(void)obj;
#endif
	if (stacked) {
		result += STACKED_INDENT;
	}
	result += prefix + msg + suffix;
	delete []buffer;
	if (priority < 0) {
		if (exc.empty()) {
			result += DARK_GREY + traceback(file, line) + NO_COL;
		} else {
			result += NO_COL + exc + NO_COL;
		}
	}
	return result;
}

LogWrapper
Log::log(bool clean, bool stacked, std::chrono::time_point<std::chrono::system_clock> wakeup, int priority, const std::string& exc, const char *file, int line, const char *suffix, const char *prefix, const void *obj, const char *format, ...)
{
	va_list argptr;
	va_start(argptr, format);
	std::string str(str_format(stacked, priority, exc, file, line, suffix, prefix, obj, format, argptr));
	va_end(argptr);

	return print(str, clean, stacked, wakeup, priority);
}

bool
Log::clear()
{
	if (!cleared.exchange(true)) {
		cleared_at = std::chrono::system_clock::now();
		return true;
	}
	return false;
}

bool
Log::unlog(int priority, const char *file, int line, const char *suffix, const char *prefix, const void *obj, const char *format, ...)
{
	if (!clear()) {
		va_list argptr;
		va_start(argptr, format);
		std::string str(str_format(stacked, priority, std::string(), file, line, suffix, prefix, obj, format, argptr));
		va_end(argptr);

		print(str, false, stacked, 0, priority, created_at);

		return true;
	}
	return false;
}

LogWrapper
Log::add(const std::string& str, bool clean, bool stacked, std::chrono::time_point<std::chrono::system_clock> wakeup, int priority, std::chrono::time_point<std::chrono::system_clock> created_at)
{
	auto l_ptr = std::make_shared<Log>(str, clean, stacked, priority, created_at);

	_thread().add(l_ptr, wakeup);

	return LogWrapper(l_ptr);
}

void
Log::log(int priority, std::string str, int indent)
{
	static std::mutex log_mutex;
	std::lock_guard<std::mutex> lk(log_mutex);
	auto needle = str.find(STACKED_INDENT);
	if (needle != std::string::npos) {
		str.replace(needle, sizeof(STACKED_INDENT) - 1, std::string(indent, ' '));
	}
	for (auto& handler : handlers()) {
		handler->log(priority, str);
	}
}

LogWrapper
Log::print(const std::string& str, bool clean, bool stacked, std::chrono::time_point<std::chrono::system_clock> wakeup, int priority, std::chrono::time_point<std::chrono::system_clock> created_at)
{
	if (priority > log_level) {
		return LogWrapper(std::make_shared<Log>(str, clean, stacked, priority, created_at));
	}

	if (priority >= ASYNC_LOG_LEVEL || wakeup > std::chrono::system_clock::now()) {
		return add(str, clean, stacked, wakeup, priority, created_at);
	} else {
		auto l_ptr = std::make_shared<Log>(str, clean, stacked, priority, created_at);
		log(priority, str, l_ptr->stack_level * 2);
		return LogWrapper(l_ptr);
	}
}

void
Log::finish(int wait)
{
	_thread().finish(wait);
}

LogThread::LogThread()
	: running(-1),
	  inner_thread(&LogThread::run, this) { }

LogThread::~LogThread()
{
	finish(true);
}

void
LogThread::finish(int wait)
{
	running = wait;
	wakeup_signal.notify_all();
	if (wait) {
		try {
			inner_thread.join();
		} catch (const std::system_error&) { }
	}
}

void
LogThread::add(const LogType& l_ptr, std::chrono::time_point<std::chrono::system_clock> wakeup)
{
	if (running != 0) {
		auto now = std::chrono::system_clock::now();
		if (wakeup < now + 2ms) {
			wakeup = now + 2ms;  // defer log so we make sure we're not adding messages to the current slot
		}

		auto wt = time_point_to_ullong(wakeup);
		l_ptr->wakeup_time = wt;

		log_queue.add(l_ptr, LogQueue::time_point_to_key(wakeup));

		bool notify;
		auto nwt = next_wakeup_time.load();
		do {
			notify = nwt >= wt;
		} while (notify && !next_wakeup_time.compare_exchange_weak(nwt, wt));

		if (notify) {
			wakeup_signal.notify_one();
		}
	}
}

void
LogThread::run_one(LogType& l_ptr)
{
	if (!l_ptr->cleared) {
		auto msg = l_ptr->str_start;
		auto age = l_ptr->age();
		if (age > 2e8) {
			msg += " ~" + delta_string(age, true);
		}
		if (l_ptr->clear()) {
			Log::log(l_ptr->priority, msg, l_ptr->stack_level * 2);
		}
	}
}

void
LogThread::run()
{
	std::mutex mtx;
	std::unique_lock<std::mutex> lk(mtx);

	next_wakeup_time = time_point_to_ullong(std::chrono::system_clock::now() + 100ms);

	while (running != 0) {
		if (--running < 0) {
			running = -1;
		}

		auto now = std::chrono::system_clock::now();
		auto wt = time_point_to_ullong(now + (running < 0 ? 3s : 100ms));
		try {
			auto& l_ptr = log_queue.peep();
			if (l_ptr) {
				wt = l_ptr->wakeup_time;
			}
		} catch(const StashContinue&) { }

		auto nwt = next_wakeup_time.load();
		while (nwt >= wt && !next_wakeup_time.compare_exchange_weak(nwt, wt));

		wakeup_signal.wait_until(lk, time_point_from_ullong(next_wakeup_time.load()));

		try {
			do {
				auto& l_ptr = log_queue.next(running < 0);
				if (l_ptr) {
					run_one(l_ptr);
					l_ptr.reset();
				}
			} while (true);
		} catch(const StashContinue&) { }

		if (running >= 0) {
			break;
		}
	}
}
<|endoftext|>


<commit_before>/**
 * @file
 */
#pragma once

#include "libbirch/external.hpp"
#include "libbirch/memory.hpp"
#include "libbirch/class.hpp"
#include "libbirch/Atomic.hpp"

namespace libbirch {
/**
 * Base class for reference counted objects.
 *
 * @attention In order to work correctly, Counted must be the *first* base
 * class in any inheritance hierarchy. This is particularly important when
 * multiple inheritance is used.
 *
 * @ingroup libbirch
 */
class Counted {
public:
  /**
   * Constructor.
   */
  Counted() :
      sharedCount(0u),
      weakCount(1u),
      memoCount(1u) {
    // no need to set size or tid, handled by operator new
  }

  /**
   * Copy constructor.
   */
  Counted(const Counted& o) : Counted() {
    //
  }

  /**
   * Assignment operator.
   */
  Counted& operator=(const Counted&) {
    return *this;
  }

  /**
   * Destructor.
   */
  virtual ~Counted() {
    assert(sharedCount.load() == 0u);
  }

  /**
   * New operator.
   */
  void* operator new(std::size_t size) {
    auto ptr = (Counted*)allocate(size);
    ptr->size = (unsigned)size;
    ptr->tid = get_thread_num();
    return ptr;
  }

  /**
   * Delete operator.
   */
  void operator delete(void* ptr) {
    auto counted = (Counted*)ptr;
    counted->destroy();
    counted->deallocate();
  }

  /**
   * Get the size, in bytes, of the object.
   */
  unsigned getSize() const;

  /**
   * Used by a shared pointer when it is known that the object has not yet
   * been assigned to any smart pointer. Sets the shared count to one, but
   * not atomically.
   */
  void init();

  /**
   * Increment the shared count.
   */
  void incShared();

  /**
   * Decrement the shared count.
   */
  void decShared();

  /**
   * Increment the shared count twice, as one operation.
   */
  void doubleIncShared();

  /**
   * Decrement the shared count twice, as one operation.
   */
  void doubleDecShared();

  /**
   * Shared count.
   */
  unsigned numShared() const;

  /**
   * Increment the weak count.
   */
  void incWeak();

  /**
   * Decrement the weak count.
   */
  void decWeak();

  /**
   * Weak count.
   */
  unsigned numWeak() const;

  /**
   * Increment the memo count (implies an increment of the weak count also).
   */
  void incMemo();

  /**
   * Decrement the memo count (implies a decrement of the weak count also).
   */
  void decMemo();

  /**
   * Memo count.
   */
  unsigned numMemo() const;

  /**
   * Is this object reachable? An object is reachable if it contains a shared
   * count of one or more, or a weak count greater than the memo count. When
   * the weak count equals the memo count (it cannot be less), the object
   * is only reachable via keys in memos, which will never be triggered, and
   * so the object is not considered reachable.
   */
  bool isReachable() const;

  /**
   * Name of the class.
   */
  virtual const char* name_() const {
    return "Counted";
  }

protected:
  /**
   * Destroy, but do not deallocate, the object.
   */
  void destroy() {
    assert(sharedCount.load() == 0u);
    this->~Counted();
  }

  /**
   * Deallocate the object. It should have previously been destroyed.
   */
  void deallocate() {
    assert(sharedCount.load() == 0u);
    assert(weakCount.load() == 0u);
    assert(memoCount.load() == 0u);
    libbirch::deallocate(this, size, tid);
  }

  /**
   * Shared count.
   */
  Atomic<unsigned> sharedCount;

  /**
   * Weak count. This is one plus the number of times that the object is held
   * by a weak pointer. The plus one is a self-reference that is released
   * when the shared count reaches zero.
   */
  Atomic<unsigned> weakCount;

  /**
   * Memo count. This is one plus the number of times that the object occurs
   * as a key in a memo. The plus one is a self-reference that is relased
   * when the weak count reaches zero.
   */
  Atomic<unsigned> memoCount;

  /**
   * Size of the object. This is set immediately after construction. A value
   * of zero is also indicative that the object is still being constructed.
   * Consequently, if the shared count reaches zero while the size is zero,
   * the object is not destroyed. This can happen when constructors create
   * shared pointers to `this`.
   */
  unsigned size;

  /**
   * Id of the thread associated with the object. This is used to return the
   * allocation to the correct pool after use, even when returned by a
   * different thread.
   */
  int tid;
};
}

#include "libbirch/thread.hpp"

inline unsigned libbirch::Counted::getSize() const {
  return size;
}

inline void libbirch::Counted::init() {
  assert(sharedCount.load() == 0u);
  sharedCount.init(1u);
}

inline void libbirch::Counted::incShared() {
  //assert(sharedCount.load() > 0u);
  sharedCount.increment();
}

inline void libbirch::Counted::decShared() {
  assert(sharedCount.load() > 0u);
  if (--sharedCount == 0u && size > 0u) {
    // ^ size == 0u during construction, never destroy in that case
    destroy();
    decWeak();  // release weak self-reference
  }
}

inline void libbirch::Counted::doubleIncShared() {
  //assert(sharedCount.load() > 0u);
  sharedCount.doubleIncrement();
}

inline void libbirch::Counted::doubleDecShared() {
  assert(sharedCount.load() > 0u);
  if ((sharedCount -= 2u) == 0u && size > 0u) {
    // ^ size == 0u during construction, never destroy in that case
    destroy();
    decWeak();  // release weak self-reference
  }
}

inline unsigned libbirch::Counted::numShared() const {
  return sharedCount.load();
}

inline void libbirch::Counted::incWeak() {
  assert(weakCount.load() > 0u);
  weakCount.increment();
}

inline void libbirch::Counted::decWeak() {
  assert(weakCount.load() > 0u);
  if (--weakCount == 0u) {
    assert(sharedCount.load() == 0u);
    decMemo();  // release memo self-reference
  }
}

inline unsigned libbirch::Counted::numWeak() const {
  return weakCount.load();
}

inline void libbirch::Counted::incMemo() {
  memoCount.increment();
}

inline void libbirch::Counted::decMemo() {
  assert(memoCount.load() > 0u);
  if (--memoCount == 0u) {
    assert(sharedCount.load() == 0u);
    assert(weakCount.load() == 0u);
    deallocate();
  }
}

inline unsigned libbirch::Counted::numMemo() const {
  return memoCount.load();
}

inline bool libbirch::Counted::isReachable() const {
  return numWeak() > 0u;
}
<commit_msg>Removed now-obsolete size checks when decrementing shared counter in Counted.<commit_after>/**
 * @file
 */
#pragma once

#include "libbirch/external.hpp"
#include "libbirch/memory.hpp"
#include "libbirch/class.hpp"
#include "libbirch/Atomic.hpp"

namespace libbirch {
/**
 * Base class for reference counted objects.
 *
 * @attention In order to work correctly, Counted must be the *first* base
 * class in any inheritance hierarchy. This is particularly important when
 * multiple inheritance is used.
 *
 * @ingroup libbirch
 */
class Counted {
public:
  /**
   * Constructor.
   */
  Counted() :
      sharedCount(0u),
      weakCount(1u),
      memoCount(1u) {
    // no need to set size or tid, handled by operator new
  }

  /**
   * Copy constructor.
   */
  Counted(const Counted& o) : Counted() {
    //
  }

  /**
   * Assignment operator.
   */
  Counted& operator=(const Counted&) {
    return *this;
  }

  /**
   * Destructor.
   */
  virtual ~Counted() {
    assert(sharedCount.load() == 0u);
  }

  /**
   * New operator.
   */
  void* operator new(std::size_t size) {
    auto ptr = (Counted*)allocate(size);
    ptr->size = (unsigned)size;
    ptr->tid = get_thread_num();
    return ptr;
  }

  /**
   * Delete operator.
   */
  void operator delete(void* ptr) {
    auto counted = (Counted*)ptr;
    counted->destroy();
    counted->deallocate();
  }

  /**
   * Get the size, in bytes, of the object.
   */
  unsigned getSize() const;

  /**
   * Used by a shared pointer when it is known that the object has not yet
   * been assigned to any smart pointer. Sets the shared count to one, but
   * not atomically.
   */
  void init();

  /**
   * Increment the shared count.
   */
  void incShared();

  /**
   * Decrement the shared count.
   */
  void decShared();

  /**
   * Increment the shared count twice, as one operation.
   */
  void doubleIncShared();

  /**
   * Decrement the shared count twice, as one operation.
   */
  void doubleDecShared();

  /**
   * Shared count.
   */
  unsigned numShared() const;

  /**
   * Increment the weak count.
   */
  void incWeak();

  /**
   * Decrement the weak count.
   */
  void decWeak();

  /**
   * Weak count.
   */
  unsigned numWeak() const;

  /**
   * Increment the memo count (implies an increment of the weak count also).
   */
  void incMemo();

  /**
   * Decrement the memo count (implies a decrement of the weak count also).
   */
  void decMemo();

  /**
   * Memo count.
   */
  unsigned numMemo() const;

  /**
   * Is this object reachable? An object is reachable if it contains a shared
   * count of one or more, or a weak count greater than the memo count. When
   * the weak count equals the memo count (it cannot be less), the object
   * is only reachable via keys in memos, which will never be triggered, and
   * so the object is not considered reachable.
   */
  bool isReachable() const;

  /**
   * Name of the class.
   */
  virtual const char* name_() const {
    return "Counted";
  }

protected:
  /**
   * Destroy, but do not deallocate, the object.
   */
  void destroy() {
    assert(sharedCount.load() == 0u);
    this->~Counted();
  }

  /**
   * Deallocate the object. It should have previously been destroyed.
   */
  void deallocate() {
    assert(sharedCount.load() == 0u);
    assert(weakCount.load() == 0u);
    assert(memoCount.load() == 0u);
    libbirch::deallocate(this, size, tid);
  }

  /**
   * Shared count.
   */
  Atomic<unsigned> sharedCount;

  /**
   * Weak count. This is one plus the number of times that the object is held
   * by a weak pointer. The plus one is a self-reference that is released
   * when the shared count reaches zero.
   */
  Atomic<unsigned> weakCount;

  /**
   * Memo count. This is one plus the number of times that the object occurs
   * as a key in a memo. The plus one is a self-reference that is relased
   * when the weak count reaches zero.
   */
  Atomic<unsigned> memoCount;

  /**
   * Size of the object. This is set immediately after construction. A value
   * of zero is also indicative that the object is still being constructed.
   * Consequently, if the shared count reaches zero while the size is zero,
   * the object is not destroyed. This can happen when constructors create
   * shared pointers to `this`.
   */
  unsigned size;

  /**
   * Id of the thread associated with the object. This is used to return the
   * allocation to the correct pool after use, even when returned by a
   * different thread.
   */
  int tid;
};
}

#include "libbirch/thread.hpp"

inline unsigned libbirch::Counted::getSize() const {
  return size;
}

inline void libbirch::Counted::init() {
  assert(sharedCount.load() == 0u);
  sharedCount.init(1u);
}

inline void libbirch::Counted::incShared() {
  //assert(sharedCount.load() > 0u);
  sharedCount.increment();
}

inline void libbirch::Counted::decShared() {
  assert(sharedCount.load() > 0u);
  if (--sharedCount == 0u) {
    destroy();
    decWeak();  // release weak self-reference
  }
}

inline void libbirch::Counted::doubleIncShared() {
  //assert(sharedCount.load() > 0u);
  sharedCount.doubleIncrement();
}

inline void libbirch::Counted::doubleDecShared() {
  assert(sharedCount.load() > 0u);
  if ((sharedCount -= 2u) == 0u) {
    destroy();
    decWeak();  // release weak self-reference
  }
}

inline unsigned libbirch::Counted::numShared() const {
  return sharedCount.load();
}

inline void libbirch::Counted::incWeak() {
  assert(weakCount.load() > 0u);
  weakCount.increment();
}

inline void libbirch::Counted::decWeak() {
  assert(weakCount.load() > 0u);
  if (--weakCount == 0u) {
    assert(sharedCount.load() == 0u);
    decMemo();  // release memo self-reference
  }
}

inline unsigned libbirch::Counted::numWeak() const {
  return weakCount.load();
}

inline void libbirch::Counted::incMemo() {
  memoCount.increment();
}

inline void libbirch::Counted::decMemo() {
  assert(memoCount.load() > 0u);
  if (--memoCount == 0u) {
    assert(sharedCount.load() == 0u);
    assert(weakCount.load() == 0u);
    deallocate();
  }
}

inline unsigned libbirch::Counted::numMemo() const {
  return memoCount.load();
}

inline bool libbirch::Counted::isReachable() const {
  return numWeak() > 0u;
}
<|endoftext|>


<commit_before>/*
//  codepoint.cpp
//
//  Author:     Sophia Lee
//  Created:    2017. 03. 19. 12:37
//  Copyright (c) 2016 Sophia Lee. All rights reserved.
//
//
*/
#include <seshat/codepoint.h>

#include <seshat/utils.h>

#include <algorithm>

namespace seshat {

CodePoint::CodePoint(uint32_t code)
    : _code(code)
{
    if (code > 0x10FFFF) {
        throw IllegalCodePoint();
    }
}

CodePoint::~CodePoint()
{
}

uint32_t CodePoint::code() const
{
    return _code;
}

/*
Gc CodePoint::gc() const
{
    auto category = gc_table.find(_code);
    if (category != gc_table.end()) {
        return category->second;
    } else {
        if (CJK_IDEO_EXT_A_FRST <= _code && _code <= CJK_IDEO_EXT_A_LAST) {
            return Gc::Lo;
        }
        if (CJK_IDEO_FRST <= _code && _code <= CJK_IDEO_LAST) {
            return Gc::Lo;
        }
        if (HANGUL_SYLLAB_FRST <= _code && _code <= HANGUL_SYLLAB_LAST) {
            return Gc::Lo;
        }
        if (NON_PU_HIGH_SRG_FRST <= _code && _code <= NON_PU_HIGH_SRG_LAST) {
            return Gc::Cs;
        }
        if (PU_HIGH_SRG_FRST <= _code && _code <= PU_HIGH_SRG_LAST) {
            return Gc::Cs;
        }
        if (LOW_SRG_FRST <= _code && _code <= LOW_SRG_LAST) {
            return Gc::Cs;
        }
        if (PU_FRST <= _code && _code <= PU_LAST) {
            return Gc::Co;
        }
        if (TANGUT_IDEO_FRST <= _code && _code <= TANGUT_IDEO_LAST) {
            return Gc::Lo;
        }
        if (CJK_IDEO_EXT_B_FRST <= _code && _code <= CJK_IDEO_EXT_B_LAST) {
            return Gc::Lo;
        }
        if (CJK_IDEO_EXT_C_FRST <= _code && _code <= CJK_IDEO_EXT_C_LAST) {
            return Gc::Lo;
        }
        if (CJK_IDEO_EXT_D_FRST <= _code && _code <= CJK_IDEO_EXT_D_LAST) {
            return Gc::Lo;
        }
        if (CJK_IDEO_EXT_E_FRST <= _code && _code <= CJK_IDEO_EXT_E_LAST) {
            return Gc::Lo;
        }
        if (PLANE_15_PU_FRST <= _code && _code <= PLANE_15_PU_LAST) {
            return Gc::Co;
        }
        if (PLANE_16_PU_FRST <= _code && _code <= PLANE_16_PU_LAST) {
            return Gc::Co;
        }
        return Gc::Cn;
    }
}
*/

std::string CodePoint::to_string() const
{
    return code_point_to_string(_code);
}

CodePoint& CodePoint::operator=(const CodePoint& origin)
{
    _code = origin._code;
    return *this;
}

CodePoint& CodePoint::operator=(uint32_t code)
{
    _code = code;
    return *this;
}

bool CodePoint::operator==(const CodePoint& other) const
{
    return _code == other._code;
}

bool CodePoint::operator!=(const CodePoint& other) const
{
    return _code != other._code;
}

// class CodePointSequence
CodePointSequence::CodePointSequence()
    : _codes(std::vector<CodePoint>())
{
}

CodePointSequence::CodePointSequence(const CodePointSequence& origin)
    : _codes(std::vector<CodePoint>(origin._codes))
{
}

CodePointSequence::CodePointSequence(iterator first, iterator last)
    : _codes(std::vector<CodePoint>())
{
    for (auto it = first; it != last; it++) {
        this->_codes.push_back(*it);
    }
}

CodePointSequence::CodePointSequence(std::initializer_list<CodePoint> init)
    : _codes(init)
{
}

CodePointSequence::~CodePointSequence()
{
}

size_t CodePointSequence::length() const
{
    return this->_codes.size();
}

void CodePointSequence::append(const CodePoint& cp)
{
    this->_codes.push_back(cp);
}

CodePointSequence::iterator CodePointSequence::begin()
{
    iterator it = iterator(&*(_codes.begin()));
    return it;
}

CodePointSequence::const_iterator CodePointSequence::begin() const
{
    const_iterator it = const_iterator(&*(_codes.cbegin()));
    return it;
}

CodePointSequence::iterator CodePointSequence::end()
{
    iterator it = iterator(&*(_codes.end()));
    return it;
}

CodePointSequence::const_iterator CodePointSequence::end() const
{
    const_iterator it = const_iterator(&*(_codes.cend()));
    return it;
}

bool CodePointSequence::operator==(const CodePointSequence& other) const
{
    if (this->length() != other.length()) {
        return false;
    }
    auto other_iter = other.begin();
    for (auto this_ref: *this) {
        if (this_ref != *(other_iter++)) return false;
    }
    return true;
}

bool CodePointSequence::operator!=(const CodePointSequence& other) const
{
    return *this == other;
}

// class CodePointSequenceIter
CodePointSequenceIter::CodePointSequenceIter(pointer ptr)
    : _ptr(ptr)
{
}

bool
CodePointSequenceIter::operator==(const CodePointSequenceIter& other) const
{
    return this->_ptr == other._ptr;
}

bool
CodePointSequenceIter::operator!=(const CodePointSequenceIter& other) const
{
    return this->_ptr != other._ptr;
}

bool
CodePointSequenceIter::operator<(const CodePointSequenceIter& other) const
{
    return this->_ptr < other._ptr;
}

bool
CodePointSequenceIter::operator>(const CodePointSequenceIter& other) const
{
    return this->_ptr > other._ptr;
}

bool
CodePointSequenceIter::operator<=(const CodePointSequenceIter& other) const
{
    return this->_ptr <= other._ptr;
}

bool
CodePointSequenceIter::operator>=(const CodePointSequenceIter& other) const
{
    return this->_ptr >= other._ptr;
}

CodePointSequenceIter& CodePointSequenceIter::operator++()
{
    this->_ptr++;
    return *this;
}

CodePointSequenceIter CodePointSequenceIter::operator++(int)
{
    CodePointSequenceIter ret = *this;
    this->_ptr++;
    return ret;
}

CodePointSequenceIter& CodePointSequenceIter::operator--()
{
    this->_ptr--;
    return *this;
}

CodePointSequenceIter CodePointSequenceIter::operator--(int)
{
    CodePointSequenceIter ret = *this;
    this->_ptr--;
    return ret;
}

CodePointSequenceIter&
CodePointSequenceIter::operator+=(CodePointSequenceIter::difference_type n)
{
    auto m = n;
    if (m >= 0) {
        while (m--) ++(*this);
    } else {
        while (m++) --(*this);
    }
    return *this;
}

CodePointSequenceIter&
CodePointSequenceIter::operator-=(CodePointSequenceIter::difference_type n)
{
    return *this += -n;
}

CodePointSequenceIter CodePointSequenceIter::operator+(
        CodePointSequenceIter::difference_type n) const
{
    auto ret = *this;
    return ret += n;
}

CodePointSequenceIter CodePointSequenceIter::operator-(
        CodePointSequenceIter::difference_type n) const
{
    auto ret = *this;
    return ret -= n;
}

CodePointSequenceIter::difference_type
CodePointSequenceIter::operator-(const CodePointSequenceIter& other) const
{
    difference_type n = 0;
    auto temp = *this;
    if (*this > other) {
        while (temp != other) {
            --temp;
            ++n;
        }
    } else {
        while (temp != other) {
            ++temp;
            --n;
        }
    }
    return n;
}

CodePointSequenceIter::reference
CodePointSequenceIter::operator[](CodePointSequenceIter::difference_type n)
{
    return *(this->_ptr + n);
}

CodePoint& CodePointSequenceIter::operator*()
{
    return *_ptr;
}

// class CodePointSequenceConstIter
CodePointSequenceConstIter::CodePointSequenceConstIter(pointer ptr)
    : _ptr(ptr)
{}

bool
CodePointSequenceConstIter::operator==(
        const CodePointSequenceConstIter& other) const
{
    return this->_ptr == other._ptr;
}

bool
CodePointSequenceConstIter::operator!=(
        const CodePointSequenceConstIter& other) const
{
    return this->_ptr != other._ptr;
}

CodePointSequenceConstIter& CodePointSequenceConstIter::operator++()
{
    this->_ptr++;
    return *this;
}

CodePointSequenceConstIter CodePointSequenceConstIter::operator++(int)
{
    CodePointSequenceConstIter ret = *this;
    this->_ptr++;
    return ret;
}

CodePointSequenceConstIter& CodePointSequenceConstIter::operator--()
{
    this->_ptr--;
    return *this;
}

CodePointSequenceConstIter CodePointSequenceConstIter::operator--(int)
{
    decltype(*this) ret = *this;
    this->_ptr--;
    return ret;
}

const CodePoint& CodePointSequenceConstIter::operator*() const
{
    return *_ptr;
}

// Misc

} // namespace seshat<commit_msg>Critical logic error fixed.<commit_after>/*
//  codepoint.cpp
//
//  Author:     Sophia Lee
//  Created:    2017. 03. 19. 12:37
//  Copyright (c) 2016 Sophia Lee. All rights reserved.
//
//
*/
#include <seshat/codepoint.h>

#include <seshat/utils.h>

#include <algorithm>

namespace seshat {

CodePoint::CodePoint(uint32_t code)
    : _code(code)
{
    if (code > 0x10FFFF) {
        throw IllegalCodePoint();
    }
}

CodePoint::~CodePoint()
{
}

uint32_t CodePoint::code() const
{
    return _code;
}

/*
Gc CodePoint::gc() const
{
    auto category = gc_table.find(_code);
    if (category != gc_table.end()) {
        return category->second;
    } else {
        if (CJK_IDEO_EXT_A_FRST <= _code && _code <= CJK_IDEO_EXT_A_LAST) {
            return Gc::Lo;
        }
        if (CJK_IDEO_FRST <= _code && _code <= CJK_IDEO_LAST) {
            return Gc::Lo;
        }
        if (HANGUL_SYLLAB_FRST <= _code && _code <= HANGUL_SYLLAB_LAST) {
            return Gc::Lo;
        }
        if (NON_PU_HIGH_SRG_FRST <= _code && _code <= NON_PU_HIGH_SRG_LAST) {
            return Gc::Cs;
        }
        if (PU_HIGH_SRG_FRST <= _code && _code <= PU_HIGH_SRG_LAST) {
            return Gc::Cs;
        }
        if (LOW_SRG_FRST <= _code && _code <= LOW_SRG_LAST) {
            return Gc::Cs;
        }
        if (PU_FRST <= _code && _code <= PU_LAST) {
            return Gc::Co;
        }
        if (TANGUT_IDEO_FRST <= _code && _code <= TANGUT_IDEO_LAST) {
            return Gc::Lo;
        }
        if (CJK_IDEO_EXT_B_FRST <= _code && _code <= CJK_IDEO_EXT_B_LAST) {
            return Gc::Lo;
        }
        if (CJK_IDEO_EXT_C_FRST <= _code && _code <= CJK_IDEO_EXT_C_LAST) {
            return Gc::Lo;
        }
        if (CJK_IDEO_EXT_D_FRST <= _code && _code <= CJK_IDEO_EXT_D_LAST) {
            return Gc::Lo;
        }
        if (CJK_IDEO_EXT_E_FRST <= _code && _code <= CJK_IDEO_EXT_E_LAST) {
            return Gc::Lo;
        }
        if (PLANE_15_PU_FRST <= _code && _code <= PLANE_15_PU_LAST) {
            return Gc::Co;
        }
        if (PLANE_16_PU_FRST <= _code && _code <= PLANE_16_PU_LAST) {
            return Gc::Co;
        }
        return Gc::Cn;
    }
}
*/

std::string CodePoint::to_string() const
{
    return code_point_to_string(_code);
}

CodePoint& CodePoint::operator=(const CodePoint& origin)
{
    _code = origin._code;
    return *this;
}

CodePoint& CodePoint::operator=(uint32_t code)
{
    _code = code;
    return *this;
}

bool CodePoint::operator==(const CodePoint& other) const
{
    return _code == other._code;
}

bool CodePoint::operator!=(const CodePoint& other) const
{
    return _code != other._code;
}

// class CodePointSequence
CodePointSequence::CodePointSequence()
    : _codes(std::vector<CodePoint>())
{
}

CodePointSequence::CodePointSequence(const CodePointSequence& origin)
    : _codes(std::vector<CodePoint>(origin._codes))
{
}

CodePointSequence::CodePointSequence(iterator first, iterator last)
    : _codes(std::vector<CodePoint>())
{
    for (auto it = first; it != last; it++) {
        this->_codes.push_back(*it);
    }
}

CodePointSequence::CodePointSequence(std::initializer_list<CodePoint> init)
    : _codes(init)
{
}

CodePointSequence::~CodePointSequence()
{
}

size_t CodePointSequence::length() const
{
    return this->_codes.size();
}

void CodePointSequence::append(const CodePoint& cp)
{
    this->_codes.push_back(cp);
}

CodePointSequence::iterator CodePointSequence::begin()
{
    iterator it = iterator(&*(_codes.begin()));
    return it;
}

CodePointSequence::const_iterator CodePointSequence::begin() const
{
    const_iterator it = const_iterator(&*(_codes.cbegin()));
    return it;
}

CodePointSequence::iterator CodePointSequence::end()
{
    iterator it = iterator(&*(_codes.end()));
    return it;
}

CodePointSequence::const_iterator CodePointSequence::end() const
{
    const_iterator it = const_iterator(&*(_codes.cend()));
    return it;
}

bool CodePointSequence::operator==(const CodePointSequence& other) const
{
    if (this->length() != other.length()) {
        return false;
    }
    auto other_iter = other.begin();
    for (auto this_ref: *this) {
        if (this_ref != *(other_iter++)) return false;
    }
    return true;
}

bool CodePointSequence::operator!=(const CodePointSequence& other) const
{
    return !(*this == other);
}

// class CodePointSequenceIter
CodePointSequenceIter::CodePointSequenceIter(pointer ptr)
    : _ptr(ptr)
{
}

bool
CodePointSequenceIter::operator==(const CodePointSequenceIter& other) const
{
    return this->_ptr == other._ptr;
}

bool
CodePointSequenceIter::operator!=(const CodePointSequenceIter& other) const
{
    return this->_ptr != other._ptr;
}

bool
CodePointSequenceIter::operator<(const CodePointSequenceIter& other) const
{
    return this->_ptr < other._ptr;
}

bool
CodePointSequenceIter::operator>(const CodePointSequenceIter& other) const
{
    return this->_ptr > other._ptr;
}

bool
CodePointSequenceIter::operator<=(const CodePointSequenceIter& other) const
{
    return this->_ptr <= other._ptr;
}

bool
CodePointSequenceIter::operator>=(const CodePointSequenceIter& other) const
{
    return this->_ptr >= other._ptr;
}

CodePointSequenceIter& CodePointSequenceIter::operator++()
{
    this->_ptr++;
    return *this;
}

CodePointSequenceIter CodePointSequenceIter::operator++(int)
{
    CodePointSequenceIter ret = *this;
    this->_ptr++;
    return ret;
}

CodePointSequenceIter& CodePointSequenceIter::operator--()
{
    this->_ptr--;
    return *this;
}

CodePointSequenceIter CodePointSequenceIter::operator--(int)
{
    CodePointSequenceIter ret = *this;
    this->_ptr--;
    return ret;
}

CodePointSequenceIter&
CodePointSequenceIter::operator+=(CodePointSequenceIter::difference_type n)
{
    auto m = n;
    if (m >= 0) {
        while (m--) ++(*this);
    } else {
        while (m++) --(*this);
    }
    return *this;
}

CodePointSequenceIter&
CodePointSequenceIter::operator-=(CodePointSequenceIter::difference_type n)
{
    return *this += -n;
}

CodePointSequenceIter CodePointSequenceIter::operator+(
        CodePointSequenceIter::difference_type n) const
{
    auto ret = *this;
    return ret += n;
}

CodePointSequenceIter CodePointSequenceIter::operator-(
        CodePointSequenceIter::difference_type n) const
{
    auto ret = *this;
    return ret -= n;
}

CodePointSequenceIter::difference_type
CodePointSequenceIter::operator-(const CodePointSequenceIter& other) const
{
    difference_type n = 0;
    auto temp = *this;
    if (*this > other) {
        while (temp != other) {
            --temp;
            ++n;
        }
    } else {
        while (temp != other) {
            ++temp;
            --n;
        }
    }
    return n;
}

CodePointSequenceIter::reference
CodePointSequenceIter::operator[](CodePointSequenceIter::difference_type n)
{
    return *(this->_ptr + n);
}

CodePoint& CodePointSequenceIter::operator*()
{
    return *_ptr;
}

// class CodePointSequenceConstIter
CodePointSequenceConstIter::CodePointSequenceConstIter(pointer ptr)
    : _ptr(ptr)
{}

bool
CodePointSequenceConstIter::operator==(
        const CodePointSequenceConstIter& other) const
{
    return this->_ptr == other._ptr;
}

bool
CodePointSequenceConstIter::operator!=(
        const CodePointSequenceConstIter& other) const
{
    return this->_ptr != other._ptr;
}

CodePointSequenceConstIter& CodePointSequenceConstIter::operator++()
{
    this->_ptr++;
    return *this;
}

CodePointSequenceConstIter CodePointSequenceConstIter::operator++(int)
{
    CodePointSequenceConstIter ret = *this;
    this->_ptr++;
    return ret;
}

CodePointSequenceConstIter& CodePointSequenceConstIter::operator--()
{
    this->_ptr--;
    return *this;
}

CodePointSequenceConstIter CodePointSequenceConstIter::operator--(int)
{
    decltype(*this) ret = *this;
    this->_ptr--;
    return ret;
}

const CodePoint& CodePointSequenceConstIter::operator*() const
{
    return *_ptr;
}

// Misc

} // namespace seshat<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////////
//
//            Copyright (c) 2016 Ronnie Brohn (EpicBrownie)
//
//                Distributed under The MIT License (MIT).
//             (See accompanying file License.txt or copy at
//                 https://opensource.org/licenses/MIT)
//
//           Please report any bugs, typos, or suggestions to
//              https://github.com/epicbrownie/Epic/issues
//
//////////////////////////////////////////////////////////////////////////////

#pragma once

#include <Epic/Math/detail/VectorFwd.hpp>
#include <Epic/Math/detail/VectorHelpers.hpp>
#include <Epic/Math/detail/MathHelpers.hpp>
#include <Epic/Math/Swizzler.hpp>

//////////////////////////////////////////////////////////////////////////////

// SVector
template<class T, size_t S>
class Epic::SVector : public Epic::detail::SVectorHelper<T, S>::BaseType
{
public:
	using Base = typename Epic::detail::SVectorHelper<T, S>::BaseType;
	using Type = Epic::SVector<T, S>;

public:
	using value_type = T;
	constexpr static size_t Size = S;

	using VectorType = Epic::Vector<T, S>;

private:
	using Base::Values;

public:
	SVector() noexcept = delete;
	SVector(const Type&) noexcept = delete;
	Type& operator = (const Type&) = delete;

public:
	// Explicitly converts to vector
	VectorType& ToVector() noexcept
	{
		return reinterpret_cast<VectorType&>(*this);
	}

	// Explicitly converts to vector
	const VectorType& ToVector() const noexcept
	{
		return reinterpret_cast<VectorType&>(*this);
	}

	// Explicitly converts to Vector
	VectorType& operator() () noexcept
	{
		return ToVector();
	}

	// Explicitly converts to Vector
	const VectorType& operator() () const noexcept
	{
		return ToVector();
	}

	// Implicitly converts to Vector
	operator VectorType&() noexcept
	{
		return ToVector();
	}

	// Implicitly converts to Vector
	operator VectorType&() const noexcept
	{
		return ToVector();
	}

public:
	const T& operator[] (size_t index) const noexcept
	{
		assert(index >= 0 && index < Size);
		return Values[index];
	}

public:
	template<class U, size_t Sz>
	friend bool operator == (const SVector<U, Sz>& vecA, const SVector<U, Sz>& vecB) noexcept;

	template<class U, size_t Sz>
	friend bool operator != (const SVector<U, Sz>& vecA, const SVector<U, Sz>& vecB) noexcept;
};

//////////////////////////////////////////////////////////////////////////////

namespace Epic
{
	namespace
	{
		template<class T, size_t S>
		constexpr Epic::SVector<T, S>& Swizzle(Epic::Vector<T, S>& v)
		{
			static_assert(sizeof(Epic::SVector<T, S>) == sizeof(Epic::Vector<T, S>));
			return reinterpret_cast<Epic::SVector<T, S>&>(v);
		}

		template<class T, size_t S>
		constexpr const Epic::SVector<T, S>& Swizzle(const Epic::Vector<T, S>& v)
		{
			static_assert(sizeof(Epic::SVector<T, S>) == sizeof(Epic::Vector<T, S>));
			return reinterpret_cast<const Epic::SVector<T, S>&>(v);
		}
	}
}

//////////////////////////////////////////////////////////////////////////////

// Friend Operators
namespace Epic
{
	template<class U, size_t Sz>
	inline bool operator == (const SVector<U, Sz>& vecA, const SVector<U, Sz>& vecB) noexcept
	{
		bool result = true;

		for (size_t i = 0; i < Sz; ++i)
			result &= (vecA[i] == vecB[i]);

		return result;
	}

	template<class U, size_t Sz>
	inline bool operator != (const SVector<U, Sz>& vecA, const SVector<U, Sz>& vecB) noexcept
	{
		bool result = true;

		for (size_t i = 0; i < Sz; ++i)
			result &= (vecA[i] != vecB[i]);

		return result;
	}
}
<commit_msg>Removed conversion functions Removed comparison operators<commit_after>//////////////////////////////////////////////////////////////////////////////
//
//            Copyright (c) 2016 Ronnie Brohn (EpicBrownie)
//
//                Distributed under The MIT License (MIT).
//             (See accompanying file License.txt or copy at
//                 https://opensource.org/licenses/MIT)
//
//           Please report any bugs, typos, or suggestions to
//              https://github.com/epicbrownie/Epic/issues
//
//////////////////////////////////////////////////////////////////////////////

#pragma once

#include <Epic/Math/detail/SVectorFwd.hpp>
#include <Epic/Math/detail/VectorHelpers.hpp>
#include <Epic/Math/detail/MathHelpers.hpp>
#include <Epic/Math/Swizzler.hpp>
#include <cassert>

//////////////////////////////////////////////////////////////////////////////

// SVector
template<class T, size_t S>
class Epic::SVector : public Epic::detail::SVectorHelper<T, S>::BaseType
{
public:
	using Base = typename Epic::detail::SVectorHelper<T, S>::BaseType;
	using Type = Epic::SVector<T, S>;

public:
	using value_type = T;
	using VectorType = Epic::Vector<T, S>;

	constexpr static size_t Size = S;

private:
	using Base::Values;

public:
	SVector() noexcept = delete;
	SVector(const Type&) noexcept = delete;
	Type& operator = (const Type&) = delete;

public:
	const T& operator[] (size_t index) const noexcept
	{
		assert(index >= 0 && index < Size);
		return Values[index];
	}
};

//////////////////////////////////////////////////////////////////////////////

namespace Epic
{
	namespace
	{
		template<class T, size_t S>
		constexpr Epic::SVector<T, S>& Swizzle(Epic::Vector<T, S>& v)
		{
			static_assert(sizeof(Epic::SVector<T, S>) == sizeof(Epic::Vector<T, S>));
			return reinterpret_cast<Epic::SVector<T, S>&>(v);
		}

		template<class T, size_t S>
		constexpr const Epic::SVector<T, S>& Swizzle(const Epic::Vector<T, S>& v)
		{
			static_assert(sizeof(Epic::SVector<T, S>) == sizeof(Epic::Vector<T, S>));
			return reinterpret_cast<const Epic::SVector<T, S>&>(v);
		}
	}
}
<|endoftext|>


<commit_before>/*******************************************************************************
GPU OPTIMIZED MONTE CARLO (GOMC) 2.1
Copyright (C) 2016  GOMC Group
A copy of the GNU General Public License can be found in the COPYRIGHT.txt
along with this program, also can be found at <http://www.gnu.org/licenses/>.
********************************************************************************/
#include "MoveSettings.h" //header spec.
#include "BoxDimensions.h" //For axis sizes
#include "BoxDimensionsNonOrth.h"
#include "StaticVals.h" //For init info.

#include "NumLib.h" //For bounding functions.
#include "GeomLib.h"    //For M_PI

const double MoveSettings::TARGET_ACCEPT_FRACT = 0.50;
const double MoveSettings::TINY_AMOUNT = 0.0000001;

void MoveSettings::Init(StaticVals const& statV,
			pdb_setup::Remarks const& remarks)
{
   perAdjust = statV.simEventFreq.perAdjust;
   for (uint m = 0; m < mv::COUNT; m++)
   {
      if (m < mv::SCALEABLE)
      {
	 tempTries[m] = 0;
	 tempAccepted[m] = 0;
      }
      acceptPercent[m] = 0.0;
      accepted[m] = tries[m] = 0;
   }

   if(remarks.restart)
   {
     for(uint b; b < BOX_TOTAL; b++)
     {
       uint disp = mv::GetMoveSubIndex(mv::DISPLACE, b);
       scale[disp] = remarks.disp[b];
       uint rotate = mv::GetMoveSubIndex(mv::ROTATE, b);
       scale[rotate] = remarks.rotate[b];
#if ENSEMBLE == NPT || ENSEMBLE == GEMC
       uint volume = mv::GetMoveSubIndex(mv::VOL_TRANSFER, b);
       scale[volume] = remarks.vol[b];
#endif
     }
   }
   else
   {
     for(uint b; b < BOX_TOTAL; b++)
     {
       uint disp = mv::GetMoveSubIndex(mv::DISPLACE, b);
       scale[disp] = boxDimRef.axis.Min(b)/4;;
       uint rotate = mv::GetMoveSubIndex(mv::ROTATE, b);
       scale[rotate] = M_PI_4;
#if ENSEMBLE == NPT || ENSEMBLE == GEMC
       uint volume = mv::GetMoveSubIndex(mv::VOL_TRANSFER, b);
       scale[volume] = 500;
#endif
     }
   }

}

//Process results of move we just did in terms of acceptance counters
void MoveSettings::Update(const bool isAccepted, const uint moveIndex,
			  const uint step)
{
   if (moveIndex < mv::SCALEABLE)
   {
      tempTries[moveIndex]++;
   }
   else
   {
      tries[moveIndex]++;
   }

   //Store to appropriate acceptance counter, if accepted.
   if (isAccepted && moveIndex < mv::SCALEABLE)
   {
      tempAccepted[moveIndex]++;
   }
   else if (isAccepted)
   {
      accepted[moveIndex]++;
   }

   //Refresh acceptance percentage appropriately
   if (moveIndex < mv::SCALEABLE)
      acceptPercent[moveIndex] =
	 (double)(tempAccepted[moveIndex]+accepted[moveIndex]) /
	 (double)(tempTries[moveIndex]+tries[moveIndex]);
   else
      acceptPercent[moveIndex] = (double)(accepted[moveIndex]) /
	 (double)(tries[moveIndex]);

}

void MoveSettings::AdjustMoves(const uint step)
{
   //Check whether we need to adjust this move's scaling.
   if ((step + 1) % perAdjust == 0)
   {
      for (uint m = 0; m < mv::SCALEABLE; ++m)
      {
	 uint majMoveKind = m/BOX_TOTAL;

	 uint b = m - (majMoveKind*BOXES_WITH_U_NB);
	 Adjust(majMoveKind, m, b);
      }
   }
}

//Adjust responsibly
void MoveSettings::Adjust(const uint majMoveKind,
			  const uint moveIndex, const uint b)
{
   if (tempTries[moveIndex] > 0)
   {
      double currentAccept = (double)(tempAccepted[moveIndex])/
	(double)(tempTries[moveIndex]);

      double fractOfTargetAccept = currentAccept/TARGET_ACCEPT_FRACT;

      if (fractOfTargetAccept > 0.0)
      {
         scale[moveIndex] *= fractOfTargetAccept;
      }

      accepted[moveIndex] += tempAccepted[moveIndex];
      tries[moveIndex] += tempTries[moveIndex];
#if 0
      if (majMoveKind == mv::VOL_TRANSFER)
	 std::cout << "scale[moveIndex]: " << scale[moveIndex] << std::endl;
#endif
   }
   tempAccepted[moveIndex] = tempTries[moveIndex] = 0;
   //Bound our values to prevent to big or too small a move.
   switch (majMoveKind)
   {
   case mv::DISPLACE :
      num::Bound<double>(scale[moveIndex], 0.0000000001,
			 (boxDimRef.axis.Min(b)/2) - TINY_AMOUNT);
      break;
   case mv::ROTATE :
      num::Bound<double>(scale[moveIndex], 0.000001, M_PI-TINY_AMOUNT);
      break;
   default:
      break;
   }
}
<commit_msg>Update MoveSettings.cpp<commit_after>/*******************************************************************************
GPU OPTIMIZED MONTE CARLO (GOMC) 2.1
Copyright (C) 2016  GOMC Group
A copy of the GNU General Public License can be found in the COPYRIGHT.txt
along with this program, also can be found at <http://www.gnu.org/licenses/>.
********************************************************************************/
#include "MoveSettings.h" //header spec.
#include "BoxDimensions.h" //For axis sizes
#include "BoxDimensionsNonOrth.h"
#include "StaticVals.h" //For init info.

#include "NumLib.h" //For bounding functions.
#include "GeomLib.h"    //For M_PI

const double MoveSettings::TARGET_ACCEPT_FRACT = 0.50;
const double MoveSettings::TINY_AMOUNT = 0.0000001;

void MoveSettings::Init(StaticVals const& statV,
			pdb_setup::Remarks const& remarks)
{
   perAdjust = statV.simEventFreq.perAdjust;
   for (uint m = 0; m < mv::COUNT; m++)
   {
      if (m < mv::SCALEABLE)
      {
	 tempTries[m] = 0;
	 tempAccepted[m] = 0;
      }
      acceptPercent[m] = 0.0;
      accepted[m] = tries[m] = 0;
   }

   if(remarks.restart)
   {
     for(uint b = 0; b < BOX_TOTAL; b++)
     {
       uint disp = mv::GetMoveSubIndex(mv::DISPLACE, b);
       scale[disp] = remarks.disp[b];
       uint rotate = mv::GetMoveSubIndex(mv::ROTATE, b);
       scale[rotate] = remarks.rotate[b];
#if ENSEMBLE == NPT || ENSEMBLE == GEMC
       uint volume = mv::GetMoveSubIndex(mv::VOL_TRANSFER, b);
       scale[volume] = remarks.vol[b];
#endif
     }
   }
   else
   {
     for(uint b = 0; b < BOX_TOTAL; b++)
     {
       uint disp = mv::GetMoveSubIndex(mv::DISPLACE, b);
       scale[disp] = boxDimRef.axis.Min(b)/4;;
       uint rotate = mv::GetMoveSubIndex(mv::ROTATE, b);
       scale[rotate] = M_PI_4;
#if ENSEMBLE == NPT || ENSEMBLE == GEMC
       uint volume = mv::GetMoveSubIndex(mv::VOL_TRANSFER, b);
       scale[volume] = 500;
#endif
     }
   }

}

//Process results of move we just did in terms of acceptance counters
void MoveSettings::Update(const bool isAccepted, const uint moveIndex,
			  const uint step)
{
   if (moveIndex < mv::SCALEABLE)
   {
      tempTries[moveIndex]++;
   }
   else
   {
      tries[moveIndex]++;
   }

   //Store to appropriate acceptance counter, if accepted.
   if (isAccepted && moveIndex < mv::SCALEABLE)
   {
      tempAccepted[moveIndex]++;
   }
   else if (isAccepted)
   {
      accepted[moveIndex]++;
   }

   //Refresh acceptance percentage appropriately
   if (moveIndex < mv::SCALEABLE)
      acceptPercent[moveIndex] =
	 (double)(tempAccepted[moveIndex]+accepted[moveIndex]) /
	 (double)(tempTries[moveIndex]+tries[moveIndex]);
   else
      acceptPercent[moveIndex] = (double)(accepted[moveIndex]) /
	 (double)(tries[moveIndex]);

}

void MoveSettings::AdjustMoves(const uint step)
{
   //Check whether we need to adjust this move's scaling.
   if ((step + 1) % perAdjust == 0)
   {
      for (uint m = 0; m < mv::SCALEABLE; ++m)
      {
	 uint majMoveKind = m/BOX_TOTAL;

	 uint b = m - (majMoveKind*BOXES_WITH_U_NB);
	 Adjust(majMoveKind, m, b);
      }
   }
}

//Adjust responsibly
void MoveSettings::Adjust(const uint majMoveKind,
			  const uint moveIndex, const uint b)
{
   if (tempTries[moveIndex] > 0)
   {
      double currentAccept = (double)(tempAccepted[moveIndex])/
	(double)(tempTries[moveIndex]);

      double fractOfTargetAccept = currentAccept/TARGET_ACCEPT_FRACT;

      if (fractOfTargetAccept > 0.0)
      {
         scale[moveIndex] *= fractOfTargetAccept;
      }

      accepted[moveIndex] += tempAccepted[moveIndex];
      tries[moveIndex] += tempTries[moveIndex];
#if 0
      if (majMoveKind == mv::VOL_TRANSFER)
	 std::cout << "scale[moveIndex]: " << scale[moveIndex] << std::endl;
#endif
   }
   tempAccepted[moveIndex] = tempTries[moveIndex] = 0;
   //Bound our values to prevent to big or too small a move.
   switch (majMoveKind)
   {
   case mv::DISPLACE :
      num::Bound<double>(scale[moveIndex], 0.0000000001,
			 (boxDimRef.axis.Min(b)/2) - TINY_AMOUNT);
      break;
   case mv::ROTATE :
      num::Bound<double>(scale[moveIndex], 0.000001, M_PI-TINY_AMOUNT);
      break;
   default:
      break;
   }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015-2016, Georgia Tech Research Corporation
 * All rights reserved.
 *
 * Author(s): Michael X. Grey <mxgrey@gatech.edu>
 *
 * Georgia Tech Graphics Lab and Humanoid Robotics Lab
 *
 * Directed by Prof. C. Karen Liu and Prof. Mike Stilman
 * <karenliu@cc.gatech.edu> <mstilman@cc.gatech.edu>
 *
 * This file is provided under the following "BSD-style" License:
 *   Redistribution and use in source and binary forms, with or
 *   without modification, are permitted provided that the following
 *   conditions are met:
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 *   CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 *   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 *   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 *   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 *   AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *   POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef DART_COMMON_DETAIL_COMPOSITE_HPP_
#define DART_COMMON_DETAIL_COMPOSITE_HPP_

#include "dart/common/Composite.hpp"

#define DART_COMMON_CHECK_ILLEGAL_ASPECT_ERASE( Func, T, ReturnType )\
  if(requiresAspect< T >())\
  {\
    dterr << "[Composite::" #Func << "] Illegal request to remove required "\
          << "Aspect [" << typeid(T).name() << "]!\n";\
    assert(false);\
    return ReturnType ;\
  }

namespace dart {
namespace common {

//==============================================================================
template <class T>
bool Composite::has() const
{
  return (get<T>() != nullptr);
}

//==============================================================================
template <class T>
T* Composite::get()
{
  AspectMap::iterator it = mAspectMap.find( typeid(T) );
  if(mAspectMap.end() == it)
    return nullptr;

  return static_cast<T*>(it->second.get());
}

//==============================================================================
template <class T>
const T* Composite::get() const
{
  return const_cast<Composite*>(this)->get<T>();
}

//==============================================================================
template <class T>
void Composite::set(const T* aspect)
{
  _set(typeid(T), aspect);
}

//==============================================================================
template <class T>
void Composite::set(std::unique_ptr<T>&& aspect)
{
  _set(typeid(T), std::move(aspect));
}

//==============================================================================
template <class T, typename ...Args>
T* Composite::createAspect(Args&&... args)
{
  T* aspect = new T(this, std::forward<Args>(args)...);
  mAspectMap[typeid(T)] = std::unique_ptr<T>(aspect);
  addToComposite(aspect);

  return aspect;
}

//==============================================================================
template <class T>
void Composite::removeAspect()
{
  AspectMap::iterator it = mAspectMap.find( typeid(T) );
  DART_COMMON_CHECK_ILLEGAL_ASPECT_ERASE(removeAspect, T, DART_BLANK)
  if(mAspectMap.end() != it)
  {
    removeFromComposite(it->second.get());
    it->second = nullptr;
  }
}

//==============================================================================
template <class T>
std::unique_ptr<T> Composite::releaseAspect()
{
  std::unique_ptr<T> extraction = nullptr;
  AspectMap::iterator it = mAspectMap.find( typeid(T) );
  DART_COMMON_CHECK_ILLEGAL_ASPECT_ERASE(releaseAspect, T, nullptr)
  if(mAspectMap.end() != it)
  {
    removeFromComposite(it->second.get());
    extraction = std::unique_ptr<T>(static_cast<T*>(it->second.release()));
  }

  return extraction;
}

//==============================================================================
template <class T>
constexpr bool Composite::isSpecializedFor()
{
  return false;
}

//==============================================================================
template <class T>
bool Composite::requiresAspect() const
{
  return (mRequiredAspects.find(typeid(T)) != mRequiredAspects.end());
}

//==============================================================================
template <class T>
void createAspects(T* /*comp*/)
{
  // Do nothing
}

//==============================================================================
template <class T, class NextAspect, class... Aspects>
void createAspects(T* comp)
{
  comp->template createAspect<NextAspect>();

  createAspects<T, Aspects...>(comp);
}

} // namespace common
} // namespace dart

//==============================================================================
// Create non-template alternatives to Composite functions
#define DART_BAKE_SPECIALIZED_ASPECT_IRREGULAR( TypeName, AspectName )\
  inline bool has ## AspectName () const\
  {\
    return this->template has<TypeName>();\
  }\
\
  inline TypeName * get ## AspectName ()\
  {\
    return this->template get<TypeName>();\
  }\
\
  inline const TypeName* get ## AspectName () const\
  {\
    return this->template get<TypeName>();\
  }\
\
  inline TypeName * get ## AspectName (const bool createIfNull)\
  {\
    TypeName* aspect = get ## AspectName();\
\
    if (createIfNull && nullptr == aspect)\
      return create ## AspectName();\
\
    return aspect;\
  }\
\
  inline void set ## AspectName (const TypeName * aspect)\
  {\
    this->template set<TypeName>(aspect);\
  }\
\
  inline void set ## AspectName (std::unique_ptr< TypeName >&& aspect)\
  {\
    this->template set<TypeName>(std::move(aspect));\
  }\
\
  template <typename ...Args>\
  inline TypeName * create ## AspectName (Args&&... args)\
  {\
    return this->template createAspect<TypeName>(std::forward<Args>(args)...);\
  }\
\
  inline void erase ## AspectName ()\
  {\
    this->template removeAspect<TypeName>();\
  }\
\
  inline std::unique_ptr< TypeName > release ## AspectName ()\
  {\
    return this->template releaseAspect<TypeName>();\
  }

//==============================================================================
#define DART_BAKE_SPECIALIZED_ASPECT(AspectName)\
  DART_BAKE_SPECIALIZED_ASPECT_IRREGULAR(AspectName, AspectName);

#endif // DART_COMMON_DETAIL_COMPOSITE_HPP_
<commit_msg>Fix typo in utility macro for specialized aspect: erase --> remove<commit_after>/*
 * Copyright (c) 2015-2016, Georgia Tech Research Corporation
 * All rights reserved.
 *
 * Author(s): Michael X. Grey <mxgrey@gatech.edu>
 *
 * Georgia Tech Graphics Lab and Humanoid Robotics Lab
 *
 * Directed by Prof. C. Karen Liu and Prof. Mike Stilman
 * <karenliu@cc.gatech.edu> <mstilman@cc.gatech.edu>
 *
 * This file is provided under the following "BSD-style" License:
 *   Redistribution and use in source and binary forms, with or
 *   without modification, are permitted provided that the following
 *   conditions are met:
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 *   CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 *   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 *   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 *   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 *   AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *   POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef DART_COMMON_DETAIL_COMPOSITE_HPP_
#define DART_COMMON_DETAIL_COMPOSITE_HPP_

#include "dart/common/Composite.hpp"

#define DART_COMMON_CHECK_ILLEGAL_ASPECT_ERASE( Func, T, ReturnType )\
  if(requiresAspect< T >())\
  {\
    dterr << "[Composite::" #Func << "] Illegal request to remove required "\
          << "Aspect [" << typeid(T).name() << "]!\n";\
    assert(false);\
    return ReturnType ;\
  }

namespace dart {
namespace common {

//==============================================================================
template <class T>
bool Composite::has() const
{
  return (get<T>() != nullptr);
}

//==============================================================================
template <class T>
T* Composite::get()
{
  AspectMap::iterator it = mAspectMap.find( typeid(T) );
  if(mAspectMap.end() == it)
    return nullptr;

  return static_cast<T*>(it->second.get());
}

//==============================================================================
template <class T>
const T* Composite::get() const
{
  return const_cast<Composite*>(this)->get<T>();
}

//==============================================================================
template <class T>
void Composite::set(const T* aspect)
{
  _set(typeid(T), aspect);
}

//==============================================================================
template <class T>
void Composite::set(std::unique_ptr<T>&& aspect)
{
  _set(typeid(T), std::move(aspect));
}

//==============================================================================
template <class T, typename ...Args>
T* Composite::createAspect(Args&&... args)
{
  T* aspect = new T(this, std::forward<Args>(args)...);
  mAspectMap[typeid(T)] = std::unique_ptr<T>(aspect);
  addToComposite(aspect);

  return aspect;
}

//==============================================================================
template <class T>
void Composite::removeAspect()
{
  AspectMap::iterator it = mAspectMap.find( typeid(T) );
  DART_COMMON_CHECK_ILLEGAL_ASPECT_ERASE(removeAspect, T, DART_BLANK)
  if(mAspectMap.end() != it)
  {
    removeFromComposite(it->second.get());
    it->second = nullptr;
  }
}

//==============================================================================
template <class T>
std::unique_ptr<T> Composite::releaseAspect()
{
  std::unique_ptr<T> extraction = nullptr;
  AspectMap::iterator it = mAspectMap.find( typeid(T) );
  DART_COMMON_CHECK_ILLEGAL_ASPECT_ERASE(releaseAspect, T, nullptr)
  if(mAspectMap.end() != it)
  {
    removeFromComposite(it->second.get());
    extraction = std::unique_ptr<T>(static_cast<T*>(it->second.release()));
  }

  return extraction;
}

//==============================================================================
template <class T>
constexpr bool Composite::isSpecializedFor()
{
  return false;
}

//==============================================================================
template <class T>
bool Composite::requiresAspect() const
{
  return (mRequiredAspects.find(typeid(T)) != mRequiredAspects.end());
}

//==============================================================================
template <class T>
void createAspects(T* /*comp*/)
{
  // Do nothing
}

//==============================================================================
template <class T, class NextAspect, class... Aspects>
void createAspects(T* comp)
{
  comp->template createAspect<NextAspect>();

  createAspects<T, Aspects...>(comp);
}

} // namespace common
} // namespace dart

//==============================================================================
// Create non-template alternatives to Composite functions
#define DART_BAKE_SPECIALIZED_ASPECT_IRREGULAR( TypeName, AspectName )\
  inline bool has ## AspectName () const\
  {\
    return this->template has<TypeName>();\
  }\
\
  inline TypeName * get ## AspectName ()\
  {\
    return this->template get<TypeName>();\
  }\
\
  inline const TypeName* get ## AspectName () const\
  {\
    return this->template get<TypeName>();\
  }\
\
  inline TypeName * get ## AspectName (const bool createIfNull)\
  {\
    TypeName* aspect = get ## AspectName();\
\
    if (createIfNull && nullptr == aspect)\
      return create ## AspectName();\
\
    return aspect;\
  }\
\
  inline void set ## AspectName (const TypeName * aspect)\
  {\
    this->template set<TypeName>(aspect);\
  }\
\
  inline void set ## AspectName (std::unique_ptr< TypeName >&& aspect)\
  {\
    this->template set<TypeName>(std::move(aspect));\
  }\
\
  template <typename ...Args>\
  inline TypeName * create ## AspectName (Args&&... args)\
  {\
    return this->template createAspect<TypeName>(std::forward<Args>(args)...);\
  }\
\
  inline void remove ## AspectName ()\
  {\
    this->template removeAspect<TypeName>();\
  }\
\
  inline std::unique_ptr< TypeName > release ## AspectName ()\
  {\
    return this->template releaseAspect<TypeName>();\
  }

//==============================================================================
#define DART_BAKE_SPECIALIZED_ASPECT(AspectName)\
  DART_BAKE_SPECIALIZED_ASPECT_IRREGULAR(AspectName, AspectName);

#endif // DART_COMMON_DETAIL_COMPOSITE_HPP_
<|endoftext|>


<commit_before>/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 *
 * Drizzle Client & Protocol Library
 *
 * Copyright (C) 2012 Andrew Hutchings (andrew@linuxjedi.co.uk)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *
 *     * The names of its contributors may not be used to endorse or
 * promote products derived from this software without specific prior
 * written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include "config.h"
#include "libdrizzle/common.h"

drizzle_result_st *drizzle_start_binlog(drizzle_st *con,
                                            uint32_t server_id,
                                            const char *file,
                                            uint32_t start_position,
                                            drizzle_return_t *ret_ptr)
{
  uint8_t data[128];
  uint8_t *ptr;
  uint8_t len= 0, fn_len= 0;

  ptr= data;

  // Start position less than binlog magic size is wrong
  if (start_position < 4)
    start_position = 4;

  // Start position
  drizzle_set_byte4(ptr, start_position);
  ptr+= 4;
  // Binlog flags
  drizzle_set_byte2(ptr, 0);
  ptr+= 2;
  // Server ID
  drizzle_set_byte4(ptr, server_id);
  ptr+= 4;

  len= 4 +  // Start position
       2 +  // Binlog flags
       4;   // Server ID

  // Prevent buffer overflow with long binlog filenames
  if (file)
  {
    if (strlen(file) >= (size_t)(128 - len))
    {
      fn_len= 128 - len;
    }
    else
    {
      fn_len = strlen(file);
    }
    len+= fn_len;
    memcpy(ptr, file, fn_len);
  }

  return drizzle_command_write(con, NULL, DRIZZLE_COMMAND_BINLOG_DUMP,
                                   data, len, len, ret_ptr);
}

drizzle_return_t drizzle_binlog_get_next_event(drizzle_result_st *result)
{
  if (result == NULL)
  {
    return DRIZZLE_RETURN_INVALID_ARGUMENT;
  }

  drizzle_state_push(result->con, drizzle_state_binlog_read);
  drizzle_state_push(result->con, drizzle_state_packet_read);
  return drizzle_state_loop(result->con);
}

uint32_t drizzle_binlog_event_timestamp(drizzle_result_st *result)
{
  if ((result == NULL) || (result->binlog_event == NULL))
  {
    return 0;
  }

  return result->binlog_event->timestamp;
}

drizzle_binlog_event_types_t drizzle_binlog_event_type(drizzle_result_st *result)
{
  if ((result == NULL) || (result->binlog_event == NULL))
  {
    return drizzle_binlog_event_types_t();
  }

  return result->binlog_event->type;
}

uint32_t drizzle_binlog_event_server_id(drizzle_result_st *result)
{
  if ((result == NULL) || (result->binlog_event == NULL))
  {
    return 0;
  }

  return result->binlog_event->server_id;
}

uint32_t drizzle_binlog_event_length(drizzle_result_st *result)
{
  if ((result == NULL) || (result->binlog_event == NULL))
  {
    return 0;
  }

  return result->binlog_event->length;
}

uint32_t drizzle_binlog_event_next_pos(drizzle_result_st *result)
{
  if ((result == NULL) || (result->binlog_event == NULL))
  {
    return 0;
  }

  return result->binlog_event->next_pos;
}

uint16_t drizzle_binlog_event_flags(drizzle_result_st *result)
{
  if ((result == NULL) || (result->binlog_event == NULL))
  {
    return 0;
  }

  return result->binlog_event->flags;
}

uint16_t drizzle_binlog_event_extra_flags(drizzle_result_st *result)
{
  if ((result == NULL) || (result->binlog_event == NULL))
  {
    return 0;
  }

  return result->binlog_event->extra_flags;
}

const uint8_t *drizzle_binlog_event_data(drizzle_result_st *result)
{
  if ((result == NULL) || (result->binlog_event == NULL))
  {
    return NULL;
  }

  return result->binlog_event->data;
}

const uint8_t *drizzle_binlog_event_raw_data(drizzle_result_st *result)
{
  if ((result == NULL) || (result->binlog_event == NULL))
  {
    return NULL;
  }

  return result->binlog_event->raw_data;
}

uint32_t drizzle_binlog_event_raw_length(drizzle_result_st *result)
{
  if ((result == NULL) || (result->binlog_event == NULL))
  {
    return 0;
  }

  return result->binlog_event->raw_length;
}

drizzle_return_t drizzle_state_binlog_read(drizzle_st *con)
{
  drizzle_binlog_st *binlog_event;

  if (con == NULL)
  {
    return DRIZZLE_RETURN_INVALID_ARGUMENT;
  }

  if (con->result->binlog_event == NULL)
  {
    con->result->binlog_event= (drizzle_binlog_st*)malloc(sizeof(drizzle_binlog_st));
    con->result->binlog_event->data= NULL;
  }
  binlog_event= con->result->binlog_event;

  if (con->packet_size != 0 && con->buffer_size < con->packet_size)
  {
    drizzle_state_push(con, drizzle_state_read);
    return DRIZZLE_RETURN_OK;
  }

  if (con->packet_size == 5 && con->buffer_ptr[0] == 254)
  {
    /* Got EOF packet, no more data. */
    con->result->warning_count= drizzle_get_byte2(con->buffer_ptr + 1);
    con->status= (drizzle_status_t)drizzle_get_byte2(con->buffer_ptr + 3);
    con->buffer_ptr+= 5;
    con->buffer_size-= 5;
    drizzle_state_pop(con);
    return DRIZZLE_RETURN_EOF;
  }
  else
  {
    con->buffer_ptr++;
    con->packet_size--;
    con->buffer_size--;
    binlog_event->raw_data= con->buffer_ptr;
    binlog_event->timestamp= drizzle_get_byte4(con->buffer_ptr);
    binlog_event->type= (drizzle_binlog_event_types_t)con->buffer_ptr[4];
    binlog_event->server_id= drizzle_get_byte4(con->buffer_ptr + 5);
    binlog_event->raw_length= binlog_event->length= drizzle_get_byte4(con->buffer_ptr + 9);
    if (con->packet_size != binlog_event->length)
    {
        drizzle_set_error(con, "drizzle_state_binlog_read",
                          "packet size error:%zu:%zu", con->packet_size, binlog_event->length);
        return DRIZZLE_RETURN_UNEXPECTED_DATA;
    }
    if (binlog_event->length <= 27)
    {
      binlog_event->next_pos= drizzle_get_byte4(con->buffer_ptr + 13);
      binlog_event->flags= drizzle_get_byte2(con->buffer_ptr + 17);
      con->buffer_ptr+= binlog_event->length;
      con->buffer_size-= binlog_event->length;
      con->packet_size-= binlog_event->length;
      binlog_event->length= 0;
      free(binlog_event->data);
      binlog_event->data= NULL;
    }
    else
    {
      binlog_event->length= binlog_event->length -
                            19 - // Header length
                            8;   // Fixed rotate length
      binlog_event->next_pos= drizzle_get_byte4(con->buffer_ptr + 13);
      binlog_event->flags= drizzle_get_byte2(con->buffer_ptr + 17);

      con->buffer_ptr+= 27;
      con->buffer_size-= 27;
      con->packet_size-= 27;
      binlog_event->data= (uint8_t*)realloc(binlog_event->data, binlog_event->length);
      memcpy(binlog_event->data, con->buffer_ptr, binlog_event->length);
      con->buffer_ptr+= binlog_event->length;
      con->buffer_size-= binlog_event->length;
      con->packet_size-= binlog_event->length;
    }
    if (con->packet_size != 0)
    {
      drizzle_set_error(con, "drizzle_state_binlog_read",
                        "unexpected data after packet:%zu", con->buffer_size);
      return DRIZZLE_RETURN_UNEXPECTED_DATA;
    }
    drizzle_state_pop(con);
  }
  return DRIZZLE_RETURN_OK;
}

<commit_msg>Binlog errors were not handled correctly<commit_after>/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 *
 * Drizzle Client & Protocol Library
 *
 * Copyright (C) 2012 Andrew Hutchings (andrew@linuxjedi.co.uk)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *
 *     * The names of its contributors may not be used to endorse or
 * promote products derived from this software without specific prior
 * written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include "config.h"
#include "libdrizzle/common.h"

drizzle_result_st *drizzle_start_binlog(drizzle_st *con,
                                            uint32_t server_id,
                                            const char *file,
                                            uint32_t start_position,
                                            drizzle_return_t *ret_ptr)
{
  uint8_t data[128];
  uint8_t *ptr;
  uint8_t len= 0, fn_len= 0;

  ptr= data;

  // Start position less than binlog magic size is wrong
  if (start_position < 4)
    start_position = 4;

  // Start position
  drizzle_set_byte4(ptr, start_position);
  ptr+= 4;
  // Binlog flags
  drizzle_set_byte2(ptr, 0);
  ptr+= 2;
  // Server ID
  drizzle_set_byte4(ptr, server_id);
  ptr+= 4;

  len= 4 +  // Start position
       2 +  // Binlog flags
       4;   // Server ID

  // Prevent buffer overflow with long binlog filenames
  if (file)
  {
    if (strlen(file) >= (size_t)(128 - len))
    {
      fn_len= 128 - len;
    }
    else
    {
      fn_len = strlen(file);
    }
    len+= fn_len;
    memcpy(ptr, file, fn_len);
  }

  return drizzle_command_write(con, NULL, DRIZZLE_COMMAND_BINLOG_DUMP,
                                   data, len, len, ret_ptr);
}

drizzle_return_t drizzle_binlog_get_next_event(drizzle_result_st *result)
{
  if (result == NULL)
  {
    return DRIZZLE_RETURN_INVALID_ARGUMENT;
  }

  drizzle_state_push(result->con, drizzle_state_binlog_read);
  drizzle_state_push(result->con, drizzle_state_packet_read);
  return drizzle_state_loop(result->con);
}

uint32_t drizzle_binlog_event_timestamp(drizzle_result_st *result)
{
  if ((result == NULL) || (result->binlog_event == NULL))
  {
    return 0;
  }

  return result->binlog_event->timestamp;
}

drizzle_binlog_event_types_t drizzle_binlog_event_type(drizzle_result_st *result)
{
  if ((result == NULL) || (result->binlog_event == NULL))
  {
    return drizzle_binlog_event_types_t();
  }

  return result->binlog_event->type;
}

uint32_t drizzle_binlog_event_server_id(drizzle_result_st *result)
{
  if ((result == NULL) || (result->binlog_event == NULL))
  {
    return 0;
  }

  return result->binlog_event->server_id;
}

uint32_t drizzle_binlog_event_length(drizzle_result_st *result)
{
  if ((result == NULL) || (result->binlog_event == NULL))
  {
    return 0;
  }

  return result->binlog_event->length;
}

uint32_t drizzle_binlog_event_next_pos(drizzle_result_st *result)
{
  if ((result == NULL) || (result->binlog_event == NULL))
  {
    return 0;
  }

  return result->binlog_event->next_pos;
}

uint16_t drizzle_binlog_event_flags(drizzle_result_st *result)
{
  if ((result == NULL) || (result->binlog_event == NULL))
  {
    return 0;
  }

  return result->binlog_event->flags;
}

uint16_t drizzle_binlog_event_extra_flags(drizzle_result_st *result)
{
  if ((result == NULL) || (result->binlog_event == NULL))
  {
    return 0;
  }

  return result->binlog_event->extra_flags;
}

const uint8_t *drizzle_binlog_event_data(drizzle_result_st *result)
{
  if ((result == NULL) || (result->binlog_event == NULL))
  {
    return NULL;
  }

  return result->binlog_event->data;
}

const uint8_t *drizzle_binlog_event_raw_data(drizzle_result_st *result)
{
  if ((result == NULL) || (result->binlog_event == NULL))
  {
    return NULL;
  }

  return result->binlog_event->raw_data;
}

uint32_t drizzle_binlog_event_raw_length(drizzle_result_st *result)
{
  if ((result == NULL) || (result->binlog_event == NULL))
  {
    return 0;
  }

  return result->binlog_event->raw_length;
}

drizzle_return_t drizzle_state_binlog_read(drizzle_st *con)
{
  drizzle_binlog_st *binlog_event;

  if (con == NULL)
  {
    return DRIZZLE_RETURN_INVALID_ARGUMENT;
  }

  if (con->result->binlog_event == NULL)
  {
    con->result->binlog_event= (drizzle_binlog_st*)malloc(sizeof(drizzle_binlog_st));
    con->result->binlog_event->data= NULL;
  }
  binlog_event= con->result->binlog_event;

  if (con->packet_size != 0 && con->buffer_size < con->packet_size)
  {
    drizzle_state_push(con, drizzle_state_read);
    return DRIZZLE_RETURN_OK;
  }

  if (con->packet_size == 5 && con->buffer_ptr[0] == 254)
  {
    /* Got EOF packet, no more data. */
    con->result->warning_count= drizzle_get_byte2(con->buffer_ptr + 1);
    con->status= (drizzle_status_t)drizzle_get_byte2(con->buffer_ptr + 3);
    con->buffer_ptr+= 5;
    con->buffer_size-= 5;
    drizzle_state_pop(con);
    return DRIZZLE_RETURN_EOF;
  }
  else if (con->buffer_ptr[0] == 255)
  {
    con->result->error_code= drizzle_get_byte2(con->buffer_ptr + 1);
    con->error_code= con->result->error_code;
    /* Byte 3 is always a '#' character, skip it. */
    memcpy(con->result->sqlstate, con->buffer_ptr + 4,
           DRIZZLE_MAX_SQLSTATE_SIZE);
    con->result->sqlstate[DRIZZLE_MAX_SQLSTATE_SIZE]= 0;
    memcpy(con->sqlstate, con->result->sqlstate,
           DRIZZLE_MAX_SQLSTATE_SIZE + 1);
    con->buffer_ptr+= 9;
    con->buffer_size-= 9;
    con->packet_size-= 9;

    snprintf(con->last_error, DRIZZLE_MAX_ERROR_SIZE, "%.*s",
             (int32_t)con->packet_size, con->buffer_ptr);
    con->last_error[DRIZZLE_MAX_ERROR_SIZE-1]= 0;
    snprintf(con->result->info, DRIZZLE_MAX_INFO_SIZE, "%.*s",
             (int32_t)con->packet_size, con->buffer_ptr);
    con->result->info[DRIZZLE_MAX_INFO_SIZE-1]= 0;
    con->buffer_ptr+= con->packet_size;
    con->buffer_size-= con->packet_size;
    con->packet_size= 0;

    drizzle_state_pop(con);
    return DRIZZLE_RETURN_ERROR_CODE;
  }
  else
  {
    con->buffer_ptr++;
    con->packet_size--;
    con->buffer_size--;
    binlog_event->raw_data= con->buffer_ptr;
    binlog_event->timestamp= drizzle_get_byte4(con->buffer_ptr);
    binlog_event->type= (drizzle_binlog_event_types_t)con->buffer_ptr[4];
    binlog_event->server_id= drizzle_get_byte4(con->buffer_ptr + 5);
    binlog_event->raw_length= binlog_event->length= drizzle_get_byte4(con->buffer_ptr + 9);
    if (con->packet_size != binlog_event->length)
    {
        drizzle_set_error(con, "drizzle_state_binlog_read",
                          "packet size error:%zu:%zu", con->packet_size, binlog_event->length);
        return DRIZZLE_RETURN_UNEXPECTED_DATA;
    }
    if (binlog_event->length <= 27)
    {
      binlog_event->next_pos= drizzle_get_byte4(con->buffer_ptr + 13);
      binlog_event->flags= drizzle_get_byte2(con->buffer_ptr + 17);
      con->buffer_ptr+= binlog_event->length;
      con->buffer_size-= binlog_event->length;
      con->packet_size-= binlog_event->length;
      binlog_event->length= 0;
      free(binlog_event->data);
      binlog_event->data= NULL;
    }
    else
    {
      binlog_event->length= binlog_event->length -
                            19 - // Header length
                            8;   // Fixed rotate length
      binlog_event->next_pos= drizzle_get_byte4(con->buffer_ptr + 13);
      binlog_event->flags= drizzle_get_byte2(con->buffer_ptr + 17);

      con->buffer_ptr+= 27;
      con->buffer_size-= 27;
      con->packet_size-= 27;
      binlog_event->data= (uint8_t*)realloc(binlog_event->data, binlog_event->length);
      memcpy(binlog_event->data, con->buffer_ptr, binlog_event->length);
      con->buffer_ptr+= binlog_event->length;
      con->buffer_size-= binlog_event->length;
      con->packet_size-= binlog_event->length;
    }
    if (con->packet_size != 0)
    {
      drizzle_set_error(con, "drizzle_state_binlog_read",
                        "unexpected data after packet:%zu", con->buffer_size);
      return DRIZZLE_RETURN_UNEXPECTED_DATA;
    }
    drizzle_state_pop(con);
  }
  return DRIZZLE_RETURN_OK;
}

<|endoftext|>