<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;
std::vector<std::unique_ptr<Logger>> Log::handlers;

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
};

LogWrapper
log(bool cleanup, bool stacked, std::chrono::time_point<std::chrono::system_clock> wakeup, int priority, const void*, const char *file, int line, const char *suffix, const char *prefix, const void *obj, const char *format, ...)
{
	va_list argptr;
	va_start(argptr, format);
	auto ret = log(cleanup, stacked, wakeup, priority, std::string(), file, line, suffix, prefix, obj, format, argptr);
	va_end(argptr);
	return ret;
}

LogWrapper
log(bool cleanup, 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)
{
	return Log::log(cleanup, stacked, wakeup, priority, exc, file, line, suffix, prefix, obj, format, argptr);
}

LogWrapper::LogWrapper(LogWrapper&& o)
	: log(std::move(o.log))
{
	o.log.reset();
}

LogWrapper&
LogWrapper::operator=(LogWrapper&& o)
{
	log = std::move(o.log);
	o.log.reset();
	return *this;
}

LogWrapper::LogWrapper(LogType log_)
	: log(log_)
{
}

LogWrapper::~LogWrapper()
{
	if (log) {
		log->cleanup();
	}
	log.reset();
}

bool
LogWrapper::unlog(int priority, const char *file, int line, const char *suffix, const char *prefix, const void *obj, const char *format, va_list argptr)
{
	return log->unlog(priority, file, line, suffix, prefix, obj, format, argptr);
}

bool
LogWrapper::clear()
{
	return log->clear();
}

long double
LogWrapper::age()
{
	return log->age();
}

LogType
LogWrapper::release()
{
	auto ret = log;
	log.reset();
	return ret;
}

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_)
	: ScheduledTask(created_at_),
	  stack_level(0),
	  stacked(stacked_),
	  clean(clean_),
	  str_start(str),
	  priority(priority_),
	  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()
{
	unsigned long long c = 0;
	cleared_at.compare_exchange_strong(c, clean ? time_point_to_ullong(std::chrono::system_clock::now()) : 0);

	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) ? time_point_from_ullong(cleared_at) : std::chrono::system_clock::now();
	return std::chrono::duration_cast<std::chrono::nanoseconds>(now - time_point_from_ullong(created_at)).count();
}

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

Scheduler&
Log::scheduler()
{
	static Scheduler scheduler("LSC");
	return scheduler;
}

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

void
Log::join()
{
	scheduler().join();
}

void
Log::run()
{
	auto msg = str_start;
	auto log_age = age();
	if (log_age > 2e8) {
		msg += " ~" + delta_string(log_age, true);
	}
	Log::log(priority, msg, stack_level * 2);
}

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)
{
	std::string str(str_format(stacked, priority, exc, file, line, suffix, prefix, obj, format, argptr));

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

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);
	auto ret = log(clean, stacked, wakeup, priority, exc, file, line, suffix, prefix, obj, format, argptr);
	va_end(argptr);

	return ret;
}

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

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

		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, ...)
{
	va_list argptr;
	va_start(argptr, format);
	auto ret = unlog(priority, file, line, suffix, prefix, obj, format, argptr);
	va_end(argptr);

	return ret;
}

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);

	scheduler().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);
	}
}
<commit_msg>Logger: Changed scheduler thread name<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;
std::vector<std::unique_ptr<Logger>> Log::handlers;

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
};

LogWrapper
log(bool cleanup, bool stacked, std::chrono::time_point<std::chrono::system_clock> wakeup, int priority, const void*, const char *file, int line, const char *suffix, const char *prefix, const void *obj, const char *format, ...)
{
	va_list argptr;
	va_start(argptr, format);
	auto ret = log(cleanup, stacked, wakeup, priority, std::string(), file, line, suffix, prefix, obj, format, argptr);
	va_end(argptr);
	return ret;
}

LogWrapper
log(bool cleanup, 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)
{
	return Log::log(cleanup, stacked, wakeup, priority, exc, file, line, suffix, prefix, obj, format, argptr);
}

LogWrapper::LogWrapper(LogWrapper&& o)
	: log(std::move(o.log))
{
	o.log.reset();
}

LogWrapper&
LogWrapper::operator=(LogWrapper&& o)
{
	log = std::move(o.log);
	o.log.reset();
	return *this;
}

LogWrapper::LogWrapper(LogType log_)
	: log(log_)
{
}

LogWrapper::~LogWrapper()
{
	if (log) {
		log->cleanup();
	}
	log.reset();
}

bool
LogWrapper::unlog(int priority, const char *file, int line, const char *suffix, const char *prefix, const void *obj, const char *format, va_list argptr)
{
	return log->unlog(priority, file, line, suffix, prefix, obj, format, argptr);
}

bool
LogWrapper::clear()
{
	return log->clear();
}

long double
LogWrapper::age()
{
	return log->age();
}

LogType
LogWrapper::release()
{
	auto ret = log;
	log.reset();
	return ret;
}

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_)
	: ScheduledTask(created_at_),
	  stack_level(0),
	  stacked(stacked_),
	  clean(clean_),
	  str_start(str),
	  priority(priority_),
	  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()
{
	unsigned long long c = 0;
	cleared_at.compare_exchange_strong(c, clean ? time_point_to_ullong(std::chrono::system_clock::now()) : 0);

	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) ? time_point_from_ullong(cleared_at) : std::chrono::system_clock::now();
	return std::chrono::duration_cast<std::chrono::nanoseconds>(now - time_point_from_ullong(created_at)).count();
}

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

Scheduler&
Log::scheduler()
{
	static Scheduler scheduler("LOG");
	return scheduler;
}

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

void
Log::join()
{
	scheduler().join();
}

void
Log::run()
{
	auto msg = str_start;
	auto log_age = age();
	if (log_age > 2e8) {
		msg += " ~" + delta_string(log_age, true);
	}
	Log::log(priority, msg, stack_level * 2);
}

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)
{
	std::string str(str_format(stacked, priority, exc, file, line, suffix, prefix, obj, format, argptr));

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

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);
	auto ret = log(clean, stacked, wakeup, priority, exc, file, line, suffix, prefix, obj, format, argptr);
	va_end(argptr);

	return ret;
}

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

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

		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, ...)
{
	va_list argptr;
	va_start(argptr, format);
	auto ret = unlog(priority, file, line, suffix, prefix, obj, format, argptr);
	va_end(argptr);

	return ret;
}

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);

	scheduler().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);
	}
}
<|endoftext|>


<commit_before>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright 2011-2020 Dominik Charousset                                     *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#define CAF_SUITE uuid

#include "caf/uuid.hpp"

#include "caf/test/dsl.hpp"

using namespace caf;

namespace {

uuid operator"" _uuid(const char* cstr, size_t cstr_len) {
  if (cstr_len != 36)
    CAF_FAIL("malformed test input");
  std::string str{cstr, cstr_len};
  if (str[8] != '-' || str[13] != '-' || str[18] != '-' || str[23] != '-')
    CAF_FAIL("malformed test input");
  str.erase(std::remove(str.begin(), str.end(), '-'), str.end());
  if (str.size() != 32)
    CAF_FAIL("malformed test input");
  uuid result;
  for (size_t index = 0; index < 16; ++index) {
    auto input_index = index * 2;
    char buf[] = {str[input_index], str[input_index + 1], '\0'};
    result.bytes().at(index) = static_cast<byte>(std::stoi(buf, nullptr, 16));
  }
  return result;
}

struct fixture {
  uuid nil; // 00000000-0000-0000-0000-000000000000

  // A couple of UUIDs for version 1.
  uuid v1[3] = {
    "cbba341a-6ceb-11ea-bc55-0242ac130003"_uuid,
    "cbba369a-6ceb-11ea-bc55-0242ac130003"_uuid,
    "cbba38fc-6ceb-11ea-bc55-0242ac130003"_uuid,
  };

  // A couple of UUIDs for version 4.
  uuid v4[3] = {
    "2ee4ded7-69c0-4dd6-876d-02e446b21784"_uuid,
    "934a33b6-7f0c-4d70-9749-5ad4292358dd"_uuid,
    "bf761f7c-00f2-4161-855e-e286cfa63c11"_uuid,
  };

  uuid x;
};

} // namespace

CAF_TEST_FIXTURE_SCOPE(uuid_tests, fixture)

CAF_TEST(default generated UUIDs have all 128 bits set to zero) {
  uuid nil;
  CAF_CHECK(!nil);
  auto zero = [](byte x) { return to_integer<int>(x) == 0; };
  CAF_CHECK(std::all_of(nil.bytes().begin(), nil.bytes().end(), zero));
  CAF_CHECK(nil == uuid::nil());
}

CAF_TEST(UUIDs print in 4 2 2 2 6 format) {
  CAF_CHECK_EQUAL(to_string(nil), "00000000-0000-0000-0000-000000000000");
  CAF_CHECK_EQUAL(to_string(v1[0]), "cbba341a-6ceb-11ea-bc55-0242ac130003");
  CAF_CHECK_EQUAL(to_string(v1[1]), "cbba369a-6ceb-11ea-bc55-0242ac130003");
  CAF_CHECK_EQUAL(to_string(v1[2]), "cbba38fc-6ceb-11ea-bc55-0242ac130003");
}

CAF_TEST(make_uuid parses strings in 4 2 2 2 6 format) {
  CAF_CHECK_EQUAL(make_uuid("00000000-0000-0000-0000-000000000000"), nil);
  CAF_CHECK_EQUAL(make_uuid("cbba341a-6ceb-11ea-bc55-0242ac130003"), v1[0]);
  CAF_CHECK_EQUAL(make_uuid("cbba369a-6ceb-11ea-bc55-0242ac130003"), v1[1]);
  CAF_CHECK_EQUAL(make_uuid("cbba38fc-6ceb-11ea-bc55-0242ac130003"), v1[2]);
}

CAF_TEST(make_uuid rejects strings with invalid variant or version values) {
  CAF_CHECK(!uuid::can_parse("cbba341a-6ceb-81ea-bc55-0242ac130003"));
  CAF_CHECK(!uuid::can_parse("cbba369a-6ceb-F1ea-bc55-0242ac130003"));
  CAF_CHECK(!uuid::can_parse("cbba38fc-6ceb-01ea-bc55-0242ac130003"));
  CAF_CHECK_EQUAL(make_uuid("cbba341a-6ceb-81ea-bc55-0242ac130003"),
                  pec::invalid_argument);
  CAF_CHECK_EQUAL(make_uuid("cbba369a-6ceb-F1ea-bc55-0242ac130003"),
                  pec::invalid_argument);
  CAF_CHECK_EQUAL(make_uuid("cbba38fc-6ceb-01ea-bc55-0242ac130003"),
                  pec::invalid_argument);
}

#define WITH(uuid_str)                                                         \
  x = uuid_str##_uuid;                                                         \
  for (int dummy = 0; dummy < 1; ++dummy)

CAF_TEST(version 1 defines UUIDs that are based on time) {
  CAF_CHECK_EQUAL(v1[0].version(), uuid::time_based);
  CAF_CHECK_EQUAL(v1[1].version(), uuid::time_based);
  CAF_CHECK_EQUAL(v1[2].version(), uuid::time_based);
  CAF_CHECK_NOT_EQUAL(v4[0].version(), uuid::time_based);
  CAF_CHECK_NOT_EQUAL(v4[1].version(), uuid::time_based);
  CAF_CHECK_NOT_EQUAL(v4[2].version(), uuid::time_based);
  WITH("00000001-0000-1000-8122-334455667788") {
    CAF_CHECK_EQUAL(x.variant(), uuid::rfc4122);
    CAF_CHECK_EQUAL(x.version(), uuid::time_based);
    CAF_CHECK_EQUAL(x.timestamp(), 0x0000000000000001ull);
    CAF_CHECK_EQUAL(x.clock_sequence(), 0x0122u);
    CAF_CHECK_EQUAL(x.node(), 0x334455667788ull);
  }
  WITH("00000001-0001-1000-8122-334455667788") {
    CAF_CHECK_EQUAL(x.variant(), uuid::rfc4122);
    CAF_CHECK_EQUAL(x.version(), uuid::time_based);
    CAF_CHECK_EQUAL(x.timestamp(), 0x0000000100000001ull);
    CAF_CHECK_EQUAL(x.clock_sequence(), 0x0122u);
    CAF_CHECK_EQUAL(x.node(), 0x334455667788ull);
  }
  WITH("00000001-0001-1001-8122-334455667788") {
    CAF_CHECK_EQUAL(x.variant(), uuid::rfc4122);
    CAF_CHECK_EQUAL(x.version(), uuid::time_based);
    CAF_CHECK_EQUAL(x.timestamp(), 0x0001000100000001ull);
    CAF_CHECK_EQUAL(x.clock_sequence(), 0x0122u);
    CAF_CHECK_EQUAL(x.node(), 0x334455667788ull);
  }
  WITH("ffffffff-ffff-1fff-bfff-334455667788") {
    CAF_CHECK_EQUAL(x.variant(), uuid::rfc4122);
    CAF_CHECK_EQUAL(x.version(), uuid::time_based);
    CAF_CHECK_EQUAL(x.timestamp(), 0x0FFFFFFFFFFFFFFFull);
    CAF_CHECK_EQUAL(x.clock_sequence(), 0x3FFFu);
    CAF_CHECK_EQUAL(x.node(), 0x334455667788ull);
  }
}

CAF_TEST_FIXTURE_SCOPE_END()
<commit_msg>Integrate review feedback<commit_after>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright 2011-2020 Dominik Charousset                                     *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#define CAF_SUITE uuid

#include "caf/uuid.hpp"

#include "caf/test/dsl.hpp"

using namespace caf;

namespace {

uuid operator"" _uuid(const char* cstr, size_t cstr_len) {
  if (cstr_len != 36)
    CAF_FAIL("malformed test input");
  std::string str{cstr, cstr_len};
  if (str[8] != '-' || str[13] != '-' || str[18] != '-' || str[23] != '-')
    CAF_FAIL("malformed test input");
  str.erase(std::remove(str.begin(), str.end(), '-'), str.end());
  if (str.size() != 32)
    CAF_FAIL("malformed test input");
  uuid result;
  for (size_t index = 0; index < 16; ++index) {
    auto input_index = index * 2;
    char buf[] = {str[input_index], str[input_index + 1], '\0'};
    result.bytes().at(index) = static_cast<byte>(std::stoi(buf, nullptr, 16));
  }
  return result;
}

struct fixture {
  uuid nil; // 00000000-0000-0000-0000-000000000000

  // A couple of UUIDs for version 1.
  uuid v1[3] = {
    "cbba341a-6ceb-11ea-bc55-0242ac130003"_uuid,
    "cbba369a-6ceb-11ea-bc55-0242ac130003"_uuid,
    "cbba38fc-6ceb-11ea-bc55-0242ac130003"_uuid,
  };

  // A couple of UUIDs for version 4.
  uuid v4[3] = {
    "2ee4ded7-69c0-4dd6-876d-02e446b21784"_uuid,
    "934a33b6-7f0c-4d70-9749-5ad4292358dd"_uuid,
    "bf761f7c-00f2-4161-855e-e286cfa63c11"_uuid,
  };
};

} // namespace

CAF_TEST_FIXTURE_SCOPE(uuid_tests, fixture)

CAF_TEST(default generated UUIDs have all 128 bits set to zero) {
  uuid nil;
  CAF_CHECK(!nil);
  auto zero = [](byte x) { return to_integer<int>(x) == 0; };
  CAF_CHECK(std::all_of(nil.bytes().begin(), nil.bytes().end(), zero));
  CAF_CHECK(nil == uuid::nil());
}

CAF_TEST(UUIDs print in 4 2 2 2 6 format) {
  CAF_CHECK_EQUAL(to_string(nil), "00000000-0000-0000-0000-000000000000");
  CAF_CHECK_EQUAL(to_string(v1[0]), "cbba341a-6ceb-11ea-bc55-0242ac130003");
  CAF_CHECK_EQUAL(to_string(v1[1]), "cbba369a-6ceb-11ea-bc55-0242ac130003");
  CAF_CHECK_EQUAL(to_string(v1[2]), "cbba38fc-6ceb-11ea-bc55-0242ac130003");
}

CAF_TEST(make_uuid parses strings in 4 2 2 2 6 format) {
  CAF_CHECK_EQUAL(make_uuid("00000000-0000-0000-0000-000000000000"), nil);
  CAF_CHECK_EQUAL(make_uuid("cbba341a-6ceb-11ea-bc55-0242ac130003"), v1[0]);
  CAF_CHECK_EQUAL(make_uuid("cbba369a-6ceb-11ea-bc55-0242ac130003"), v1[1]);
  CAF_CHECK_EQUAL(make_uuid("cbba38fc-6ceb-11ea-bc55-0242ac130003"), v1[2]);
}

CAF_TEST(make_uuid rejects strings with invalid variant or version values) {
  CAF_CHECK(!uuid::can_parse("cbba341a-6ceb-81ea-bc55-0242ac130003"));
  CAF_CHECK(!uuid::can_parse("cbba369a-6ceb-F1ea-bc55-0242ac130003"));
  CAF_CHECK(!uuid::can_parse("cbba38fc-6ceb-01ea-bc55-0242ac130003"));
  CAF_CHECK_EQUAL(make_uuid("cbba341a-6ceb-81ea-bc55-0242ac130003"),
                  pec::invalid_argument);
  CAF_CHECK_EQUAL(make_uuid("cbba369a-6ceb-F1ea-bc55-0242ac130003"),
                  pec::invalid_argument);
  CAF_CHECK_EQUAL(make_uuid("cbba38fc-6ceb-01ea-bc55-0242ac130003"),
                  pec::invalid_argument);
}

#define WITH(uuid_str) if (auto x = uuid_str##_uuid; true)

CAF_TEST(version 1 defines UUIDs that are based on time) {
  CAF_CHECK_EQUAL(v1[0].version(), uuid::time_based);
  CAF_CHECK_EQUAL(v1[1].version(), uuid::time_based);
  CAF_CHECK_EQUAL(v1[2].version(), uuid::time_based);
  CAF_CHECK_NOT_EQUAL(v4[0].version(), uuid::time_based);
  CAF_CHECK_NOT_EQUAL(v4[1].version(), uuid::time_based);
  CAF_CHECK_NOT_EQUAL(v4[2].version(), uuid::time_based);
  WITH("00000001-0000-1000-8122-334455667788") {
    CAF_CHECK_EQUAL(x.variant(), uuid::rfc4122);
    CAF_CHECK_EQUAL(x.version(), uuid::time_based);
    CAF_CHECK_EQUAL(x.timestamp(), 0x0000000000000001ull);
    CAF_CHECK_EQUAL(x.clock_sequence(), 0x0122u);
    CAF_CHECK_EQUAL(x.node(), 0x334455667788ull);
  }
  WITH("00000001-0001-1000-8122-334455667788") {
    CAF_CHECK_EQUAL(x.variant(), uuid::rfc4122);
    CAF_CHECK_EQUAL(x.version(), uuid::time_based);
    CAF_CHECK_EQUAL(x.timestamp(), 0x0000000100000001ull);
    CAF_CHECK_EQUAL(x.clock_sequence(), 0x0122u);
    CAF_CHECK_EQUAL(x.node(), 0x334455667788ull);
  }
  WITH("00000001-0001-1001-8122-334455667788") {
    CAF_CHECK_EQUAL(x.variant(), uuid::rfc4122);
    CAF_CHECK_EQUAL(x.version(), uuid::time_based);
    CAF_CHECK_EQUAL(x.timestamp(), 0x0001000100000001ull);
    CAF_CHECK_EQUAL(x.clock_sequence(), 0x0122u);
    CAF_CHECK_EQUAL(x.node(), 0x334455667788ull);
  }
  WITH("ffffffff-ffff-1fff-bfff-334455667788") {
    CAF_CHECK_EQUAL(x.variant(), uuid::rfc4122);
    CAF_CHECK_EQUAL(x.version(), uuid::time_based);
    CAF_CHECK_EQUAL(x.timestamp(), 0x0FFFFFFFFFFFFFFFull);
    CAF_CHECK_EQUAL(x.clock_sequence(), 0x3FFFu);
    CAF_CHECK_EQUAL(x.node(), 0x334455667788ull);
  }
}

CAF_TEST_FIXTURE_SCOPE_END()
<|endoftext|>


<commit_before>/*
 *  Copyright 2007-2014 Adrian Thurston <thurston@complang.org>
 */

/*  This file is part of Colm.
 *
 *  Colm is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  Colm is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Colm; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "bytecode.h"
#include "parsedata.h"

#include <iostream>
#include <assert.h>

using std::cout;
using std::cerr;
using std::endl;

ObjectDef *UniqueType::objectDef()
{
	if ( typeId != TYPE_TREE && typeId != TYPE_REF ) {
		/* This should have generated a compiler error. */
		assert(false);
	}

	return langEl->objectDef;
}

/* Recurisve find through a single object def's scope. */
ObjectField *ObjectDef::findFieldInScope( const ObjNameScope *inScope, const String &name ) const
{
	ObjFieldMapEl *objDefMapEl = inScope->objFieldMap->find( name );
	if ( objDefMapEl != 0 )
		return objDefMapEl->value;
	if ( inScope->parentScope != 0 )
		return findFieldInScope( inScope->parentScope, name );
	return 0;
}

ObjectField *ObjNameScope::findField( const String &name ) const
{
	return owner->findFieldInScope( this, name );
}

ObjMethod *ObjectDef::findMethod( const String &name ) const
{
	ObjMethodMapEl *objMethodMapEl = objMethodMap->find( name );
	if ( objMethodMapEl != 0 )
		return objMethodMapEl->value;
	return 0;
}

VarRefLookup LangVarRef::lookupQualification( Compiler *pd, ObjNameScope *rootScope ) const
{
	int lastPtrInQual = -1;
	ObjNameScope *searchScope = rootScope;
	int firstConstPart = -1;

	for ( QualItemVect::Iter qi = *qual; qi.lte(); qi++ ) {
		/* Lookup the field int the current qualification. */
		ObjectField *el = searchScope->findField( qi->data );
		if ( el == 0 )
			error(qi->loc) << "cannot resolve qualification " << qi->data << endp;

		/* Lookup the type of the field. */
		UniqueType *qualUT = el->typeRef->uniqueType;

		/* If we are dealing with an iterator then dereference it. */
		if ( qualUT->typeId == TYPE_ITER )
			qualUT = el->typeRef->searchUniqueType;

		/* Is it const? */
		if ( firstConstPart < 0 && el->isConst )
			firstConstPart = qi.pos();

		/* Check for references. When loop is done we will have the last one
		 * present, if any. */
		if ( qualUT->typeId == TYPE_PTR )
			lastPtrInQual = qi.pos();

		if ( qi->form == QualItem::Dot ) {
			/* Cannot dot a reference. Iterator yes (access of the iterator
			 * not the current) */
			if ( qualUT->typeId == TYPE_PTR )
				error(loc) << "dot cannot be used to access a pointer" << endp;
		}
		else if ( qi->form == QualItem::Arrow ) {
			if ( qualUT->typeId == TYPE_ITER )
				qualUT = el->typeRef->searchUniqueType;
			else if ( qualUT->typeId == TYPE_PTR )
				qualUT = pd->findUniqueType( TYPE_TREE, qualUT->langEl );
		}

		ObjectDef *searchObjDef = qualUT->objectDef();
		searchScope = searchObjDef->rootScope;
	}

	return VarRefLookup( lastPtrInQual, firstConstPart, searchScope->owner, searchScope );
}

bool LangVarRef::isLocalRef() const
{
	if ( qual->length() > 0 ) {
		if ( scope->findField( qual->data[0].data ) != 0 )
			return true;
	}
	else if ( scope->findField( name ) != 0 )
		return true;
	else if ( scope->owner->findMethod( name ) != 0 )
		return true;

	return false;
}

bool LangVarRef::isContextRef() const
{
	if ( context != 0 ) {
		if ( qual->length() > 0 ) {
			if ( context->contextObjDef->rootScope->findField( qual->data[0].data ) != 0 )
				return true;
		}
		else if ( context->contextObjDef->rootScope->findField( name ) != 0 )
			return true;
		else if ( context->contextObjDef->findMethod( name ) != 0 )
			return true;
	}

	return false;
}

bool LangVarRef::isCustom() const
{
	if ( qual->length() > 0 ) {
		ObjectField *field = scope->findField( qual->data[0].data );
		if ( field != 0 && field->isCustom )
			return true;
	}
	else {
		ObjectField *field = scope->findField( name );
		if ( field != 0 ) {
			if ( field->isCustom )
				return true;
		}
		else {
			ObjMethod *method = scope->owner->findMethod( name );
			if ( method != 0 && method->isCustom )
				return true;
		}

	}
	return false;
}

VarRefLookup LangVarRef::lookupObj( Compiler *pd ) const
{
	ObjNameScope *rootScope;
	if ( isLocalRef() )
		rootScope = scope;
	else if ( isContextRef() )
		rootScope = context->contextObjDef->rootScope;
	else
		rootScope = pd->globalObjectDef->rootScope;

	return lookupQualification( pd, rootScope );
}

VarRefLookup LangVarRef::lookupField( Compiler *pd ) const
{
	/* Lookup the object that the field is in. */
	VarRefLookup lookup = lookupObj( pd );

	/* Lookup the field. */
	ObjectField *field = lookup.inScope->findField( name );
	if ( field == 0 )
		error(loc) << "cannot find name " << name << " in object" << endp;

	lookup.objField = field;
	lookup.uniqueType = field->typeRef->uniqueType;

	if ( field->typeRef->searchUniqueType != 0 )
		lookup.iterSearchUT = field->typeRef->searchUniqueType;

	return lookup;
}

UniqueType *LangVarRef::lookup( Compiler *pd ) const
{
	/* Lookup the loadObj. */
	VarRefLookup lookup = lookupField( pd );

	ObjectField *el = lookup.objField;
	UniqueType *elUT = el->typeRef->lookupType( pd );

	/* Deref iterators. */
	if ( elUT->typeId == TYPE_ITER )
		elUT = el->typeRef->searchUniqueType;

	return elUT;
}

VarRefLookup LangVarRef::lookupMethod( Compiler *pd ) const
{
	/* Lookup the object that the field is in. */
	VarRefLookup lookup = lookupObj( pd );

	/* Find the method. */
	assert( lookup.inObject->objMethodMap != 0 );
	ObjMethod *method = lookup.inObject->findMethod( name );
	if ( method == 0 ) {
		/* Not found as a method, try it as an object on which we will call a
		 * default function. */
		qual->append( QualItem( QualItem::Dot, loc, name ) );

		/* Lookup the object that the field is in. */
		VarRefLookup lookup = lookupObj( pd );

		/* Find the method. */
		assert( lookup.inObject->objMethodMap != 0 );
		method = lookup.inObject->findMethod( "finish" );
		if ( method == 0 )
			error(loc) << "cannot find " << name << "(...) in object" << endp;
	}

	lookup.objMethod = method;
	lookup.uniqueType = method->returnUT;

	return lookup;
}
<commit_msg>added missing type lookup in qual resolve<commit_after>/*
 *  Copyright 2007-2014 Adrian Thurston <thurston@complang.org>
 */

/*  This file is part of Colm.
 *
 *  Colm is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  Colm is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Colm; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "bytecode.h"
#include "parsedata.h"

#include <iostream>
#include <assert.h>

using std::cout;
using std::cerr;
using std::endl;

ObjectDef *UniqueType::objectDef()
{
	if ( typeId != TYPE_TREE && typeId != TYPE_REF ) {
		/* This should have generated a compiler error. */
		assert(false);
	}

	return langEl->objectDef;
}

/* Recurisve find through a single object def's scope. */
ObjectField *ObjectDef::findFieldInScope( const ObjNameScope *inScope, const String &name ) const
{
	ObjFieldMapEl *objDefMapEl = inScope->objFieldMap->find( name );
	if ( objDefMapEl != 0 )
		return objDefMapEl->value;
	if ( inScope->parentScope != 0 )
		return findFieldInScope( inScope->parentScope, name );
	return 0;
}

ObjectField *ObjNameScope::findField( const String &name ) const
{
	return owner->findFieldInScope( this, name );
}

ObjMethod *ObjectDef::findMethod( const String &name ) const
{
	ObjMethodMapEl *objMethodMapEl = objMethodMap->find( name );
	if ( objMethodMapEl != 0 )
		return objMethodMapEl->value;
	return 0;
}

VarRefLookup LangVarRef::lookupQualification( Compiler *pd, ObjNameScope *rootScope ) const
{
	int lastPtrInQual = -1;
	ObjNameScope *searchScope = rootScope;
	int firstConstPart = -1;

	for ( QualItemVect::Iter qi = *qual; qi.lte(); qi++ ) {
		/* Lookup the field int the current qualification. */
		ObjectField *el = searchScope->findField( qi->data );
		if ( el == 0 )
			error(qi->loc) << "cannot resolve qualification " << qi->data << endp;

		/* Lookup the type of the field. */
		el->typeRef->lookupType( pd );
		UniqueType *qualUT = el->typeRef->uniqueType;

		/* If we are dealing with an iterator then dereference it. */
		if ( qualUT->typeId == TYPE_ITER )
			qualUT = el->typeRef->searchUniqueType;

		/* Is it const? */
		if ( firstConstPart < 0 && el->isConst )
			firstConstPart = qi.pos();

		/* Check for references. When loop is done we will have the last one
		 * present, if any. */
		if ( qualUT->typeId == TYPE_PTR )
			lastPtrInQual = qi.pos();

		if ( qi->form == QualItem::Dot ) {
			/* Cannot dot a reference. Iterator yes (access of the iterator
			 * not the current) */
			if ( qualUT->typeId == TYPE_PTR )
				error(loc) << "dot cannot be used to access a pointer" << endp;
		}
		else if ( qi->form == QualItem::Arrow ) {
			if ( qualUT->typeId == TYPE_ITER )
				qualUT = el->typeRef->searchUniqueType;
			else if ( qualUT->typeId == TYPE_PTR )
				qualUT = pd->findUniqueType( TYPE_TREE, qualUT->langEl );
		}

		ObjectDef *searchObjDef = qualUT->objectDef();
		searchScope = searchObjDef->rootScope;
	}

	return VarRefLookup( lastPtrInQual, firstConstPart, searchScope->owner, searchScope );
}

bool LangVarRef::isLocalRef() const
{
	if ( qual->length() > 0 ) {
		if ( scope->findField( qual->data[0].data ) != 0 )
			return true;
	}
	else if ( scope->findField( name ) != 0 )
		return true;
	else if ( scope->owner->findMethod( name ) != 0 )
		return true;

	return false;
}

bool LangVarRef::isContextRef() const
{
	if ( context != 0 ) {
		if ( qual->length() > 0 ) {
			if ( context->contextObjDef->rootScope->findField( qual->data[0].data ) != 0 )
				return true;
		}
		else if ( context->contextObjDef->rootScope->findField( name ) != 0 )
			return true;
		else if ( context->contextObjDef->findMethod( name ) != 0 )
			return true;
	}

	return false;
}

bool LangVarRef::isCustom() const
{
	if ( qual->length() > 0 ) {
		ObjectField *field = scope->findField( qual->data[0].data );
		if ( field != 0 && field->isCustom )
			return true;
	}
	else {
		ObjectField *field = scope->findField( name );
		if ( field != 0 ) {
			if ( field->isCustom )
				return true;
		}
		else {
			ObjMethod *method = scope->owner->findMethod( name );
			if ( method != 0 && method->isCustom )
				return true;
		}

	}
	return false;
}

VarRefLookup LangVarRef::lookupObj( Compiler *pd ) const
{
	ObjNameScope *rootScope;
	if ( isLocalRef() )
		rootScope = scope;
	else if ( isContextRef() )
		rootScope = context->contextObjDef->rootScope;
	else
		rootScope = pd->globalObjectDef->rootScope;

	return lookupQualification( pd, rootScope );
}

VarRefLookup LangVarRef::lookupField( Compiler *pd ) const
{
	/* Lookup the object that the field is in. */
	VarRefLookup lookup = lookupObj( pd );

	/* Lookup the field. */
	ObjectField *field = lookup.inScope->findField( name );
	if ( field == 0 )
		error(loc) << "cannot find name " << name << " in object" << endp;

	lookup.objField = field;
	lookup.uniqueType = field->typeRef->uniqueType;

	if ( field->typeRef->searchUniqueType != 0 )
		lookup.iterSearchUT = field->typeRef->searchUniqueType;

	return lookup;
}

UniqueType *LangVarRef::lookup( Compiler *pd ) const
{
	/* Lookup the loadObj. */
	VarRefLookup lookup = lookupField( pd );

	ObjectField *el = lookup.objField;
	UniqueType *elUT = el->typeRef->lookupType( pd );

	/* Deref iterators. */
	if ( elUT->typeId == TYPE_ITER )
		elUT = el->typeRef->searchUniqueType;

	return elUT;
}

VarRefLookup LangVarRef::lookupMethod( Compiler *pd ) const
{
	/* Lookup the object that the field is in. */
	VarRefLookup lookup = lookupObj( pd );

	/* Find the method. */
	assert( lookup.inObject->objMethodMap != 0 );
	ObjMethod *method = lookup.inObject->findMethod( name );
	if ( method == 0 ) {
		/* Not found as a method, try it as an object on which we will call a
		 * default function. */
		qual->append( QualItem( QualItem::Dot, loc, name ) );

		/* Lookup the object that the field is in. */
		VarRefLookup lookup = lookupObj( pd );

		/* Find the method. */
		assert( lookup.inObject->objMethodMap != 0 );
		method = lookup.inObject->findMethod( "finish" );
		if ( method == 0 )
			error(loc) << "cannot find " << name << "(...) in object" << endp;
	}

	lookup.objMethod = method;
	lookup.uniqueType = method->returnUT;

	return lookup;
}
<|endoftext|>


<commit_before>/*    Copyright (c) 2010-2016, Delft University of Technology
 *    All rigths reserved
 *
 *    This file is part of the Tudat. Redistribution and use in source and
 *    binary forms, with or without modification, are permitted exclusively
 *    under the terms of the Modified BSD license. You should have received
 *    a copy of the license with this file. If not, please or visit:
 *    http://tudat.tudelft.nl/LICENSE.
 */

#include "Tudat/Astrodynamics/BasicAstrodynamics/accelerationModelTypes.h"
#include "Tudat/Astrodynamics/Propagators/createEnvironmentUpdater.h"

namespace tudat
{

namespace propagators
{

//! Function to check whether the requested environment updates are possible with the existing environment.
void checkValidityOfRequiredEnvironmentUpdates(
        const std::map< propagators::EnvironmentModelsToUpdate, std::vector< std::string > >&
        requestedUpdates,
        const simulation_setup::NamedBodyMap& bodyMap )
{
    using namespace propagators;

    // Iterate over all environment update types.
    for( std::map< propagators::EnvironmentModelsToUpdate, std::vector< std::string > >::const_iterator
         updateIterator = requestedUpdates.begin( );
         updateIterator != requestedUpdates.end( ); updateIterator++ )
    {
        // Iterate over all updated bodies.
        for( unsigned int i = 0; i < updateIterator->second.size( ); i++ )
        {
            // Ignore global required updates.
            if( updateIterator->second.at( i ) != "" )
            {
                // Check if body exists.
                if( bodyMap.count( updateIterator->second.at( i ) ) == 0 )
                {
                    throw std::runtime_error( "Error when making environment model update settings, could not find body " +
                                              boost::lexical_cast< std::string>( updateIterator->second.at( i ) ) );
                }

                // Check if requested environment model exists.
                switch( updateIterator->first )
                {
                case body_transational_state_update:
                {
                    if( bodyMap.at( updateIterator->second.at( i ) )->getEphemeris( ) == NULL )
                    {
                        throw std::runtime_error( "Error when making environment model update settings, could not find ephemeris of body " +
                                                  boost::lexical_cast< std::string>( updateIterator->second.at( i ) ) );
                    }
                    break;
                }
                case body_rotational_state_update:
                {
                    if( bodyMap.at( updateIterator->second.at( i ) )->getRotationalEphemeris( ) == NULL )
                    {
                        throw std::runtime_error( "Error when making environment model update settings, could not find rotational ephemeris of body " +
                                                  boost::lexical_cast< std::string>( updateIterator->second.at( i ) ) );
                    }
                    break;
                }
                case spherical_harmonic_gravity_field_update:
                {
                    boost::shared_ptr< gravitation::SphericalHarmonicsGravityField > gravityFieldModel =
                            boost::dynamic_pointer_cast< gravitation::SphericalHarmonicsGravityField >(
                                bodyMap.at( updateIterator->second.at( i ) )->getGravityFieldModel( ) );
                    if( gravityFieldModel == NULL )
                    {
                        throw std::runtime_error( "Error when making environment model update settings, could not find spherical harmonic gravity field of body " +
                                                  boost::lexical_cast< std::string>( updateIterator->second.at( i ) ) );
                    }
                    break;
                }
                case vehicle_flight_conditions_update:
                {
                    boost::shared_ptr< aerodynamics::FlightConditions > flightConditions = bodyMap.at(
                                updateIterator->second.at( i ) )->getFlightConditions( );
                    if( flightConditions == NULL )
                    {
                        throw std::runtime_error( "Error when making environment model update settings, could not find flight conditions of body " +
                                                  boost::lexical_cast< std::string>( updateIterator->second.at( i ) ) );
                    }
                    break;
                }
                case radiation_pressure_interface_update:
                {
                    std::map< std::string, boost::shared_ptr< electro_magnetism::RadiationPressureInterface > >
                            radiationPressureInterfaces = bodyMap.at( updateIterator->second.at( i ) )->getRadiationPressureInterfaces( );
                    if( radiationPressureInterfaces.size( ) == 0 )
                    {
                        throw std::runtime_error( "Error when making environment model update settings, could not find radiation pressure interface of body " +
                                                  boost::lexical_cast< std::string>( updateIterator->second.at( i ) ) );
                    }
                    break;
                }
                case body_mass_update:
                    if( bodyMap.at( updateIterator->second.at( i ) )->getBodyMassFunction( ) == NULL )
                    {
                        throw std::runtime_error( "Error when making environment model update settings, no body mass function of body " +
                                                  boost::lexical_cast< std::string>( updateIterator->second.at( i ) ) );
                    }

                    break;
                }
            }
        }
    }
}

//! Function to extend existing list of required environment update types
void addEnvironmentUpdates(
        std::map< propagators::EnvironmentModelsToUpdate, std::vector< std::string > >& environmentUpdateList,
        const std::map< propagators::EnvironmentModelsToUpdate, std::vector< std::string > > updatesToAdd )
{
    // Iterate over all environment update types.
    for( std::map< propagators::EnvironmentModelsToUpdate, std::vector< std::string > >::const_iterator
         environmentUpdateIterator = updatesToAdd.begin( );
         environmentUpdateIterator != updatesToAdd.end( ); environmentUpdateIterator++ )
    {
        bool addCurrentUpdate = 0;

        // Iterate over all updated bodies.
        for( unsigned int i = 0; i < environmentUpdateIterator->second.size( ); i++ )
        {
            addCurrentUpdate = 0;

            // Check if current update type exists.
            if( environmentUpdateList.count( environmentUpdateIterator->first ) == 0 )
            {
                addCurrentUpdate = 1;
            }
            // Check if current body exists for update type.
            else if( std::find( environmentUpdateList.at( environmentUpdateIterator->first ).begin( ),
                                environmentUpdateList.at( environmentUpdateIterator->first ).end( ),
                                environmentUpdateIterator->second.at( i ) ) ==
                     environmentUpdateList.at( environmentUpdateIterator->first ).end( ) )
            {
                addCurrentUpdate = 1;
            }

            // Add update type if required.
            if( addCurrentUpdate )
            {
                environmentUpdateList[ environmentUpdateIterator->first ].push_back(
                            environmentUpdateIterator->second.at( i ) );
            }
        }
    }
}

//! Get list of required environment model update settings from translational acceleration models.
std::map< propagators::EnvironmentModelsToUpdate, std::vector< std::string > >
createTranslationalEquationsOfMotionEnvironmentUpdaterSettings(
        const basic_astrodynamics::AccelerationMap& translationalAccelerationModels,
        const simulation_setup::NamedBodyMap& bodyMap )
{
    using namespace basic_astrodynamics;
    using namespace propagators;

    std::map< propagators::EnvironmentModelsToUpdate, std::vector< std::string > > environmentModelsToUpdate;
    std::map< propagators::EnvironmentModelsToUpdate, std::vector< std::string > > singleAccelerationUpdateNeeds;

    // Iterate over all bodies being accelerated
    for( AccelerationMap::const_iterator acceleratedBodyIterator = translationalAccelerationModels.begin( );
         acceleratedBodyIterator != translationalAccelerationModels.end( ); acceleratedBodyIterator++ )
    {
        // Iterate over all bodies exerting acceleration.
        for( SingleBodyAccelerationMap::const_iterator accelerationModelIterator = acceleratedBodyIterator->second.begin( );
             accelerationModelIterator != acceleratedBodyIterator->second.end( ); accelerationModelIterator++ )
        {
            singleAccelerationUpdateNeeds.clear( );
            for( unsigned int i = 0; i < accelerationModelIterator->second.size( ); i++ )
            {
                AvailableAcceleration currentAccelerationModelType =
                        getAccelerationModelType( accelerationModelIterator->second.at( i ) );

                // Add translational state of both bodies to update list for current acceleration model.
                if( translationalAccelerationModels.count( accelerationModelIterator->first ) == 0 )
                {
                    singleAccelerationUpdateNeeds[ body_transational_state_update ].push_back(
                                accelerationModelIterator->first );
                }

                // Check acceleration model type and change environment update list accordingly.
                switch( currentAccelerationModelType )
                {
                case central_gravity:
                    break;
                case third_body_central_gravity:
                {
                    boost::shared_ptr< gravitation::ThirdBodyCentralGravityAcceleration > thirdBodyAcceleration =
                            boost::dynamic_pointer_cast< gravitation::ThirdBodyCentralGravityAcceleration >(
                                accelerationModelIterator->second.at( i ) );
                    if( thirdBodyAcceleration != NULL && translationalAccelerationModels.count(
                                thirdBodyAcceleration->getCentralBodyName( ) ) == 0 )
                    {
                        singleAccelerationUpdateNeeds[ body_transational_state_update ].push_back(
                                    thirdBodyAcceleration->getCentralBodyName( ) );
                    }
                    else
                    {
                        throw std::runtime_error(
                                    std::string( "Error, incompatible input (ThirdBodyCentralGravityAcceleration) to" )
                                    + std::string(  "createTranslationalEquationsOfMotionEnvironmentUpdaterSettings" ) );
                    }
                    break;
                }
                case aerodynamic:
                    singleAccelerationUpdateNeeds[ body_rotational_state_update ].push_back(
                                accelerationModelIterator->first );
                    singleAccelerationUpdateNeeds[ vehicle_flight_conditions_update ].push_back(
                                acceleratedBodyIterator->first );
                    singleAccelerationUpdateNeeds[ body_mass_update ].push_back(
                                acceleratedBodyIterator->first );
                    break;
                case cannon_ball_radiation_pressure:
                    singleAccelerationUpdateNeeds[ radiation_pressure_interface_update ].push_back(
                                acceleratedBodyIterator->first );
                    singleAccelerationUpdateNeeds[ body_mass_update ].push_back(
                                acceleratedBodyIterator->first );
                    break;
                case spherical_harmonic_gravity:
                    singleAccelerationUpdateNeeds[ body_rotational_state_update ].push_back(
                                accelerationModelIterator->first );
                    singleAccelerationUpdateNeeds[ spherical_harmonic_gravity_field_update ].push_back(
                                accelerationModelIterator->first );
                    break;
                case third_body_spherical_harmonic_gravity:
                {
                    singleAccelerationUpdateNeeds[ body_rotational_state_update ].push_back(
                                accelerationModelIterator->first );
                    singleAccelerationUpdateNeeds[ spherical_harmonic_gravity_field_update ].push_back(
                                accelerationModelIterator->first );

                    boost::shared_ptr< gravitation::ThirdBodySphericalHarmonicsGravitationalAccelerationModel >
                            thirdBodyAcceleration = boost::dynamic_pointer_cast<
                            gravitation::ThirdBodySphericalHarmonicsGravitationalAccelerationModel >(
                                accelerationModelIterator->second.at( i ) );;
                    if( thirdBodyAcceleration != NULL && translationalAccelerationModels.count(
                                thirdBodyAcceleration->getCentralBodyName( ) ) == 0  )
                    {
                        singleAccelerationUpdateNeeds[ body_transational_state_update ].push_back(
                                    thirdBodyAcceleration->getCentralBodyName( ) );
                    }
                    else
                    {
                        throw std::runtime_error(
                                    std::string( "Error, incompatible input (ThirdBodySphericalHarmonicsGravitational" ) +
                                    std::string( "AccelerationModel) to createTranslationalEquationsOfMotion ") +
                                    std::string( "EnvironmentUpdaterSettings" ) );
                    }
                    break;
                }
                default:
                    break;
                }

            }

            // Check whether requested updates are possible.
            checkValidityOfRequiredEnvironmentUpdates( singleAccelerationUpdateNeeds, bodyMap );

            // Add requested updates of current acceleration model to full list of environment updates.
            addEnvironmentUpdates( environmentModelsToUpdate, singleAccelerationUpdateNeeds );
        }
    }

    return environmentModelsToUpdate;
}

//! Function to create 'brute-force' update settings, in which each environment model is updated.
std::map< propagators::EnvironmentModelsToUpdate, std::vector< std::string > > createFullEnvironmentUpdaterSettings(
        const simulation_setup::NamedBodyMap& bodyMap )
{
    using namespace basic_astrodynamics;
    using namespace electro_magnetism;
    using namespace gravitation;
    using namespace propagators;

    std::map< propagators::EnvironmentModelsToUpdate, std::vector< std::string > > environmentModelsToUpdate;
    std::map< propagators::EnvironmentModelsToUpdate, std::vector< std::string > > singleAccelerationUpdateNeeds;

    // Iterate over all bodies.
    for( simulation_setup::NamedBodyMap::const_iterator
         bodyIterator = bodyMap.begin( ); bodyIterator != bodyMap.end( ); bodyIterator++ )
    {
        singleAccelerationUpdateNeeds.clear( );

        // Check if current body is a vehicle.

        // Check if current body has flight conditions set.
        if( bodyIterator->second ->getFlightConditions( ) != NULL )
        {
            // If vehicle has flight conditions, add flight conditions update function to update list.
            singleAccelerationUpdateNeeds[ vehicle_flight_conditions_update ].push_back( bodyIterator->first );
        }

        // Get body radiation pressure interface(s) (one per source)
        std::map< std::string, boost::shared_ptr< RadiationPressureInterface > > radiationPressureInterfaces =
                bodyIterator->second->getRadiationPressureInterfaces( );

        // Add each interface update function to update list.
        for( std::map< std::string, boost::shared_ptr< RadiationPressureInterface > > ::iterator iterator =
             radiationPressureInterfaces.begin( );
             iterator != radiationPressureInterfaces.end( ); iterator++ )
        {
            singleAccelerationUpdateNeeds[ radiation_pressure_interface_update ].push_back( bodyIterator->first );
        }

        // If body has rotation model, update rotational state in each time step.
        boost::shared_ptr< ephemerides::RotationalEphemeris > rotationalEphemeris =
                bodyIterator->second->getRotationalEphemeris( );
        if( rotationalEphemeris != NULL )
        {
            singleAccelerationUpdateNeeds[ body_rotational_state_update ].push_back( bodyIterator->first );
        }

        boost::shared_ptr< TimeDependentSphericalHarmonicsGravityField > gravityField =
                boost::dynamic_pointer_cast< TimeDependentSphericalHarmonicsGravityField >
                ( bodyIterator->second->getGravityFieldModel( ) );
        if( gravityField != NULL )
        {
            singleAccelerationUpdateNeeds[ spherical_harmonic_gravity_field_update ].push_back( bodyIterator->first );
        }

        singleAccelerationUpdateNeeds[ body_mass_update ].push_back( bodyIterator->first );

        // Check whether requested updates are possible.
        checkValidityOfRequiredEnvironmentUpdates( singleAccelerationUpdateNeeds, bodyMap );

        // Add requested updates of current acceleration model to full list of environment updates.
        addEnvironmentUpdates( environmentModelsToUpdate, singleAccelerationUpdateNeeds );
    }
    return environmentModelsToUpdate;
}

}

}

<commit_msg>Minor correction to error handling<commit_after>/*    Copyright (c) 2010-2016, Delft University of Technology
 *    All rigths reserved
 *
 *    This file is part of the Tudat. Redistribution and use in source and
 *    binary forms, with or without modification, are permitted exclusively
 *    under the terms of the Modified BSD license. You should have received
 *    a copy of the license with this file. If not, please or visit:
 *    http://tudat.tudelft.nl/LICENSE.
 */

#include "Tudat/Astrodynamics/BasicAstrodynamics/accelerationModelTypes.h"
#include "Tudat/Astrodynamics/Propagators/createEnvironmentUpdater.h"

namespace tudat
{

namespace propagators
{

//! Function to check whether the requested environment updates are possible with the existing environment.
void checkValidityOfRequiredEnvironmentUpdates(
        const std::map< propagators::EnvironmentModelsToUpdate, std::vector< std::string > >&
        requestedUpdates,
        const simulation_setup::NamedBodyMap& bodyMap )
{
    using namespace propagators;

    // Iterate over all environment update types.
    for( std::map< propagators::EnvironmentModelsToUpdate, std::vector< std::string > >::const_iterator
         updateIterator = requestedUpdates.begin( );
         updateIterator != requestedUpdates.end( ); updateIterator++ )
    {
        // Iterate over all updated bodies.
        for( unsigned int i = 0; i < updateIterator->second.size( ); i++ )
        {
            // Ignore global required updates.
            if( updateIterator->second.at( i ) != "" )
            {
                // Check if body exists.
                if( bodyMap.count( updateIterator->second.at( i ) ) == 0 )
                {
                    throw std::runtime_error( "Error when making environment model update settings, could not find body " +
                                              boost::lexical_cast< std::string>( updateIterator->second.at( i ) ) );
                }

                // Check if requested environment model exists.
                switch( updateIterator->first )
                {
                case body_transational_state_update:
                {
                    if( bodyMap.at( updateIterator->second.at( i ) )->getEphemeris( ) == NULL )
                    {
                        throw std::runtime_error( "Error when making environment model update settings, could not find ephemeris of body " +
                                                  boost::lexical_cast< std::string>( updateIterator->second.at( i ) ) );
                    }
                    break;
                }
                case body_rotational_state_update:
                {
                    if( bodyMap.at( updateIterator->second.at( i ) )->getRotationalEphemeris( ) == NULL )
                    {
                        throw std::runtime_error( "Error when making environment model update settings, could not find rotational ephemeris of body " +
                                                  boost::lexical_cast< std::string>( updateIterator->second.at( i ) ) );
                    }
                    break;
                }
                case spherical_harmonic_gravity_field_update:
                {
                    boost::shared_ptr< gravitation::SphericalHarmonicsGravityField > gravityFieldModel =
                            boost::dynamic_pointer_cast< gravitation::SphericalHarmonicsGravityField >(
                                bodyMap.at( updateIterator->second.at( i ) )->getGravityFieldModel( ) );
                    if( gravityFieldModel == NULL )
                    {
                        throw std::runtime_error( "Error when making environment model update settings, could not find spherical harmonic gravity field of body " +
                                                  boost::lexical_cast< std::string>( updateIterator->second.at( i ) ) );
                    }
                    break;
                }
                case vehicle_flight_conditions_update:
                {
                    boost::shared_ptr< aerodynamics::FlightConditions > flightConditions = bodyMap.at(
                                updateIterator->second.at( i ) )->getFlightConditions( );
                    if( flightConditions == NULL )
                    {
                        throw std::runtime_error( "Error when making environment model update settings, could not find flight conditions of body " +
                                                  boost::lexical_cast< std::string>( updateIterator->second.at( i ) ) );
                    }
                    break;
                }
                case radiation_pressure_interface_update:
                {
                    std::map< std::string, boost::shared_ptr< electro_magnetism::RadiationPressureInterface > >
                            radiationPressureInterfaces = bodyMap.at( updateIterator->second.at( i ) )->getRadiationPressureInterfaces( );
                    if( radiationPressureInterfaces.size( ) == 0 )
                    {
                        throw std::runtime_error( "Error when making environment model update settings, could not find radiation pressure interface of body " +
                                                  boost::lexical_cast< std::string>( updateIterator->second.at( i ) ) );
                    }
                    break;
                }
                case body_mass_update:
                    if( bodyMap.at( updateIterator->second.at( i ) )->getBodyMassFunction( ) == NULL )
                    {
                        throw std::runtime_error( "Error when making environment model update settings, no body mass function of body " +
                                                  boost::lexical_cast< std::string>( updateIterator->second.at( i ) ) );
                    }

                    break;
                }
            }
        }
    }
}

//! Function to extend existing list of required environment update types
void addEnvironmentUpdates(
        std::map< propagators::EnvironmentModelsToUpdate, std::vector< std::string > >& environmentUpdateList,
        const std::map< propagators::EnvironmentModelsToUpdate, std::vector< std::string > > updatesToAdd )
{
    // Iterate over all environment update types.
    for( std::map< propagators::EnvironmentModelsToUpdate, std::vector< std::string > >::const_iterator
         environmentUpdateIterator = updatesToAdd.begin( );
         environmentUpdateIterator != updatesToAdd.end( ); environmentUpdateIterator++ )
    {
        bool addCurrentUpdate = 0;

        // Iterate over all updated bodies.
        for( unsigned int i = 0; i < environmentUpdateIterator->second.size( ); i++ )
        {
            addCurrentUpdate = 0;

            // Check if current update type exists.
            if( environmentUpdateList.count( environmentUpdateIterator->first ) == 0 )
            {
                addCurrentUpdate = 1;
            }
            // Check if current body exists for update type.
            else if( std::find( environmentUpdateList.at( environmentUpdateIterator->first ).begin( ),
                                environmentUpdateList.at( environmentUpdateIterator->first ).end( ),
                                environmentUpdateIterator->second.at( i ) ) ==
                     environmentUpdateList.at( environmentUpdateIterator->first ).end( ) )
            {
                addCurrentUpdate = 1;
            }

            // Add update type if required.
            if( addCurrentUpdate )
            {
                environmentUpdateList[ environmentUpdateIterator->first ].push_back(
                            environmentUpdateIterator->second.at( i ) );
            }
        }
    }
}

//! Get list of required environment model update settings from translational acceleration models.
std::map< propagators::EnvironmentModelsToUpdate, std::vector< std::string > >
createTranslationalEquationsOfMotionEnvironmentUpdaterSettings(
        const basic_astrodynamics::AccelerationMap& translationalAccelerationModels,
        const simulation_setup::NamedBodyMap& bodyMap )
{
    using namespace basic_astrodynamics;
    using namespace propagators;

    std::map< propagators::EnvironmentModelsToUpdate, std::vector< std::string > > environmentModelsToUpdate;
    std::map< propagators::EnvironmentModelsToUpdate, std::vector< std::string > > singleAccelerationUpdateNeeds;

    // Iterate over all bodies being accelerated
    for( AccelerationMap::const_iterator acceleratedBodyIterator = translationalAccelerationModels.begin( );
         acceleratedBodyIterator != translationalAccelerationModels.end( ); acceleratedBodyIterator++ )
    {
        // Iterate over all bodies exerting acceleration.
        for( SingleBodyAccelerationMap::const_iterator accelerationModelIterator = acceleratedBodyIterator->second.begin( );
             accelerationModelIterator != acceleratedBodyIterator->second.end( ); accelerationModelIterator++ )
        {
            singleAccelerationUpdateNeeds.clear( );
            for( unsigned int i = 0; i < accelerationModelIterator->second.size( ); i++ )
            {
                AvailableAcceleration currentAccelerationModelType =
                        getAccelerationModelType( accelerationModelIterator->second.at( i ) );

                // Add translational state of both bodies to update list for current acceleration model.
                if( translationalAccelerationModels.count( accelerationModelIterator->first ) == 0 )
                {
                    singleAccelerationUpdateNeeds[ body_transational_state_update ].push_back(
                                accelerationModelIterator->first );
                }

                // Check acceleration model type and change environment update list accordingly.
                switch( currentAccelerationModelType )
                {
                case central_gravity:
                    break;
                case third_body_central_gravity:
                {
                    boost::shared_ptr< gravitation::ThirdBodyCentralGravityAcceleration > thirdBodyAcceleration =
                            boost::dynamic_pointer_cast< gravitation::ThirdBodyCentralGravityAcceleration >(
                                accelerationModelIterator->second.at( i ) );
                    if( thirdBodyAcceleration != NULL && translationalAccelerationModels.count(
                                thirdBodyAcceleration->getCentralBodyName( ) ) == 0 )
                    {
                        singleAccelerationUpdateNeeds[ body_transational_state_update ].push_back(
                                    thirdBodyAcceleration->getCentralBodyName( ) );
                    }
                    else if( thirdBodyAcceleration == NULL )
                    {
                        throw std::runtime_error(
                                    std::string( "Error, incompatible input (ThirdBodyCentralGravityAcceleration) to" )
                                    + std::string(  "createTranslationalEquationsOfMotionEnvironmentUpdaterSettings" ) );
                    }
                    break;
                }
                case aerodynamic:
                    singleAccelerationUpdateNeeds[ body_rotational_state_update ].push_back(
                                accelerationModelIterator->first );
                    singleAccelerationUpdateNeeds[ vehicle_flight_conditions_update ].push_back(
                                acceleratedBodyIterator->first );
                    singleAccelerationUpdateNeeds[ body_mass_update ].push_back(
                                acceleratedBodyIterator->first );
                    break;
                case cannon_ball_radiation_pressure:
                    singleAccelerationUpdateNeeds[ radiation_pressure_interface_update ].push_back(
                                acceleratedBodyIterator->first );
                    singleAccelerationUpdateNeeds[ body_mass_update ].push_back(
                                acceleratedBodyIterator->first );
                    break;
                case spherical_harmonic_gravity:
                    singleAccelerationUpdateNeeds[ body_rotational_state_update ].push_back(
                                accelerationModelIterator->first );
                    singleAccelerationUpdateNeeds[ spherical_harmonic_gravity_field_update ].push_back(
                                accelerationModelIterator->first );
                    break;
                case third_body_spherical_harmonic_gravity:
                {
                    singleAccelerationUpdateNeeds[ body_rotational_state_update ].push_back(
                                accelerationModelIterator->first );
                    singleAccelerationUpdateNeeds[ spherical_harmonic_gravity_field_update ].push_back(
                                accelerationModelIterator->first );

                    boost::shared_ptr< gravitation::ThirdBodySphericalHarmonicsGravitationalAccelerationModel >
                            thirdBodyAcceleration = boost::dynamic_pointer_cast<
                            gravitation::ThirdBodySphericalHarmonicsGravitationalAccelerationModel >(
                                accelerationModelIterator->second.at( i ) );;
                    if( thirdBodyAcceleration != NULL && translationalAccelerationModels.count(
                                thirdBodyAcceleration->getCentralBodyName( ) ) == 0  )
                    {
                        singleAccelerationUpdateNeeds[ body_transational_state_update ].push_back(
                                    thirdBodyAcceleration->getCentralBodyName( ) );
                    }
                    else if( thirdBodyAcceleration == NULL )
                    {
                        throw std::runtime_error(
                                    std::string( "Error, incompatible input (ThirdBodySphericalHarmonicsGravitational" ) +
                                    std::string( "AccelerationModel) to createTranslationalEquationsOfMotion ") +
                                    std::string( "EnvironmentUpdaterSettings" ) );
                    }
                    break;
                }
                default:
                    break;
                }

            }

            // Check whether requested updates are possible.
            checkValidityOfRequiredEnvironmentUpdates( singleAccelerationUpdateNeeds, bodyMap );

            // Add requested updates of current acceleration model to full list of environment updates.
            addEnvironmentUpdates( environmentModelsToUpdate, singleAccelerationUpdateNeeds );
        }
    }

    return environmentModelsToUpdate;
}

//! Function to create 'brute-force' update settings, in which each environment model is updated.
std::map< propagators::EnvironmentModelsToUpdate, std::vector< std::string > > createFullEnvironmentUpdaterSettings(
        const simulation_setup::NamedBodyMap& bodyMap )
{
    using namespace basic_astrodynamics;
    using namespace electro_magnetism;
    using namespace gravitation;
    using namespace propagators;

    std::map< propagators::EnvironmentModelsToUpdate, std::vector< std::string > > environmentModelsToUpdate;
    std::map< propagators::EnvironmentModelsToUpdate, std::vector< std::string > > singleAccelerationUpdateNeeds;

    // Iterate over all bodies.
    for( simulation_setup::NamedBodyMap::const_iterator
         bodyIterator = bodyMap.begin( ); bodyIterator != bodyMap.end( ); bodyIterator++ )
    {
        singleAccelerationUpdateNeeds.clear( );

        // Check if current body is a vehicle.

        // Check if current body has flight conditions set.
        if( bodyIterator->second ->getFlightConditions( ) != NULL )
        {
            // If vehicle has flight conditions, add flight conditions update function to update list.
            singleAccelerationUpdateNeeds[ vehicle_flight_conditions_update ].push_back( bodyIterator->first );
        }

        // Get body radiation pressure interface(s) (one per source)
        std::map< std::string, boost::shared_ptr< RadiationPressureInterface > > radiationPressureInterfaces =
                bodyIterator->second->getRadiationPressureInterfaces( );

        // Add each interface update function to update list.
        for( std::map< std::string, boost::shared_ptr< RadiationPressureInterface > > ::iterator iterator =
             radiationPressureInterfaces.begin( );
             iterator != radiationPressureInterfaces.end( ); iterator++ )
        {
            singleAccelerationUpdateNeeds[ radiation_pressure_interface_update ].push_back( bodyIterator->first );
        }

        // If body has rotation model, update rotational state in each time step.
        boost::shared_ptr< ephemerides::RotationalEphemeris > rotationalEphemeris =
                bodyIterator->second->getRotationalEphemeris( );
        if( rotationalEphemeris != NULL )
        {
            singleAccelerationUpdateNeeds[ body_rotational_state_update ].push_back( bodyIterator->first );
        }

        boost::shared_ptr< TimeDependentSphericalHarmonicsGravityField > gravityField =
                boost::dynamic_pointer_cast< TimeDependentSphericalHarmonicsGravityField >
                ( bodyIterator->second->getGravityFieldModel( ) );
        if( gravityField != NULL )
        {
            singleAccelerationUpdateNeeds[ spherical_harmonic_gravity_field_update ].push_back( bodyIterator->first );
        }

        singleAccelerationUpdateNeeds[ body_mass_update ].push_back( bodyIterator->first );

        // Check whether requested updates are possible.
        checkValidityOfRequiredEnvironmentUpdates( singleAccelerationUpdateNeeds, bodyMap );

        // Add requested updates of current acceleration model to full list of environment updates.
        addEnvironmentUpdates( environmentModelsToUpdate, singleAccelerationUpdateNeeds );
    }
    return environmentModelsToUpdate;
}

}

}

<|endoftext|>


<commit_before>#pragma once

#include "AppEngine.hpp"

namespace s_engine {
namespace app {

class Context {};

class Event {
private:
  const Context* context = nullptr;
public:
  const Context* GetContext() const;
};

}
}<commit_msg>Remove ambigious Context class<commit_after>#pragma once

#include "AppEngine.hpp"

namespace s_engine {
namespace app {

class Event {
};

}
}<|endoftext|>


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

#include <fstream>
#include <boost/algorithm/string/replace.hpp>
#include <yaml-cpp/yaml.h>
#include "internal_ua_parser.h"

namespace ua_parser {
BrowserParser::BrowserParser(const YAML::Node &yaml_attributes) {
  yaml_attributes["regex"] >> pattern;
  regex = boost::regex(pattern);

  if (const YAML::Node *pName =yaml_attributes.FindValue("family_replacement"))
    overrides.family = pName->to<std::string>();
  if (const YAML::Node *pName =yaml_attributes.FindValue("v1_replacement"))
    *pName >> overrides.major;
  if (const YAML::Node *pName =yaml_attributes.FindValue("v2_replacement"))
    *pName >> overrides.minor;
}

Browser BrowserParser::Parse(const std::string &user_agent_string) {
  Browser browser;
  using namespace std;

  boost::smatch result;
  if (boost::regex_search(user_agent_string.begin(), user_agent_string.end(), result, regex)) {
    if (overrides.family.empty() && result.size()>1)
      browser.family = result[1].str();
    else {
      browser.family = overrides.family;
      boost::replace_all(browser.family, "$1", result[1].str());
    }

    // If the group is not found, use the override value even if it is blank

    if (overrides.major.empty()&&result.size()>2)
      browser.major = result[2].str();
    else
      browser.major = overrides.major;

    if (overrides.minor.empty()&&result.size()>3)
      browser.minor = result[3].str();
    else
      browser.minor = overrides.minor;

    if (overrides.patch.empty()&&result.size()>4)
      browser.patch = result[4].str();
    else
      browser.patch = overrides.patch;

    return browser;
  }

  return browser;

}

OperatingSystemParser::OperatingSystemParser(const YAML::Node &yaml_attributes) {
  yaml_attributes["regex"] >> pattern;
  regex = boost::regex(pattern);

  if (const YAML::Node *pName =yaml_attributes.FindValue("os_replacement"))
    *pName >> overrides.os;
  if (const YAML::Node *pName =yaml_attributes.FindValue("os_v1_replacement"))
    *pName >> overrides.major;
  if (const YAML::Node *pName =yaml_attributes.FindValue("os_v2_replacement"))
    *pName >> overrides.minor;
}

OperatingSystem OperatingSystemParser::Parse(const std::string &user_agent_string) {
  OperatingSystem os;
  using namespace std;

  boost::smatch result;
  if (boost::regex_search(user_agent_string.begin(), user_agent_string.end(), result, regex)) {
    if (overrides.os.empty() && result.size()>1)
      os.os = result[1].str();
    else {
      os.os = overrides.os;
      boost::replace_all(os.os, "$1", result[1].str());
    }

    // If the group is not found, use the override value even if it is blank

    if (overrides.major.empty()&&result.size()>2)
      os.major = result[2].str();
    else
      os.major = overrides.major;

    if (overrides.minor.empty()&&result.size()>3)
      os.minor = result[3].str();
    else
      os.minor = overrides.minor;

    if (overrides.patch.empty()&&result.size()>4)
      os.patch = result[4].str();
    else
      os.patch = overrides.patch;

    if (overrides.patch_minor.empty()&&result.size()>5)
      os.patch_minor = result[5].str();
    else
      os.patch_minor = overrides.patch_minor;

    return os;
  }
  return os;
}

DeviceParser::DeviceParser(const YAML::Node &yaml_attributes) {
  yaml_attributes["regex"] >> pattern;
  regex = boost::regex(pattern);

  if (const YAML::Node *pName=yaml_attributes.FindValue("device_replacement"))
    *pName >> overrides;
}

Device DeviceParser::Parse(const std::string &user_agent_string) {
  Device device;
  using namespace std;

  boost::smatch result;
  if (boost::regex_search(user_agent_string.begin(), user_agent_string.end(), result, regex)) {
    if (overrides.empty() && result.size()>1)
      device = result[1].str();
    else {
      device = overrides;
      boost::replace_all(device, "$1", result[1].str());
    }

    return device;
  }

  return device;
}

template<class ParserType>
static std::vector<ParserType> ParseYaml(const YAML::Node &yaml_regexes) {
  std::vector<ParserType> parsers;

  for (YAML::Iterator i=yaml_regexes.begin(); i!=yaml_regexes.end(); i++) {
    ParserType parser(*i);

    parsers.push_back(parser);
  }

  return parsers;
}

Parser::Parser(const std::string &yaml_file) {
  std::ifstream in(yaml_file.c_str());
  if (!in.good()) {
    std::cerr << "Could not open YAML file" << yaml_file << std::endl;
    return;
  }

  YAML::Parser parser(in);

  YAML::Node doc;
  parser.GetNextDocument(doc);

  _browser_parsers = ParseYaml<BrowserParser>(doc["user_agent_parsers"]);
  _os_parsers = ParseYaml<OperatingSystemParser>(doc["os_parsers"]);
  _device_parsers = ParseYaml<DeviceParser>(doc["device_parsers"]);

}

UserAgent Parser::Parse(const std::string &user_agent_string) {
  UserAgent user_agent;

  user_agent.browser.family = "Other";
  user_agent.os.os = "Other";
  user_agent.device = "Other";
  user_agent.browser.major = "Other";
  user_agent.browser.minor = "Other";

  for (std::vector<BrowserParser>::iterator i=_browser_parsers.begin(); i!=_browser_parsers.end(); i++) {
    Browser browser = i->Parse(user_agent_string);
    if (!browser.family.empty()) {
      user_agent.browser = browser;
      break;
    }

  }

  for (std::vector<OperatingSystemParser>::iterator i=_os_parsers.begin(); i!=_os_parsers.end(); i++) {
    OperatingSystem os = i->Parse(user_agent_string);
    if (!os.os.empty()) {
      user_agent.os = os;
      break;
    }

  }

  for (std::vector<DeviceParser>::iterator i=_device_parsers.begin(); i!=_device_parsers.end(); i++) {
    Device device = i->Parse(user_agent_string);
    if (!device.empty()) {
      user_agent.device = device;
      break;
    }

  }

  return user_agent;
}

}

<commit_msg>spacing, change error to be more Rcpplike.<commit_after>/*
# Copyright 2013 Andrew Punch
#
# Licensed under the Apache License, Version 2.0 (the 'License')
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an 'AS IS' BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
*/

#include <fstream>
#include <boost/algorithm/string/replace.hpp>
#include <yaml-cpp/yaml.h>
#include "internal_ua_parser.h"

namespace ua_parser {
BrowserParser::BrowserParser(const YAML::Node &yaml_attributes) {
  yaml_attributes["regex"] >> pattern;
  regex = boost::regex(pattern);

  if (const YAML::Node *pName =yaml_attributes.FindValue("family_replacement"))
    overrides.family = pName->to<std::string>();
  if (const YAML::Node *pName =yaml_attributes.FindValue("v1_replacement"))
    *pName >> overrides.major;
  if (const YAML::Node *pName =yaml_attributes.FindValue("v2_replacement"))
    *pName >> overrides.minor;
}

Browser BrowserParser::Parse(const std::string &user_agent_string) {
  Browser browser;
  using namespace std;

  boost::smatch result;
  if (boost::regex_search(user_agent_string.begin(), user_agent_string.end(), result, regex)) {
    if (overrides.family.empty() && result.size()>1)
      browser.family = result[1].str();
    else {
      browser.family = overrides.family;
      boost::replace_all(browser.family, "$1", result[1].str());
    }

    // If the group is not found, use the override value even if it is blank

    if (overrides.major.empty()&&result.size()>2)
      browser.major = result[2].str();
    else
      browser.major = overrides.major;

    if (overrides.minor.empty()&&result.size()>3)
      browser.minor = result[3].str();
    else
      browser.minor = overrides.minor;

    if (overrides.patch.empty()&&result.size()>4)
      browser.patch = result[4].str();
    else
      browser.patch = overrides.patch;

    return browser;
  }

  return browser;

}

OperatingSystemParser::OperatingSystemParser(const YAML::Node &yaml_attributes) {
  yaml_attributes["regex"] >> pattern;
  regex = boost::regex(pattern);

  if (const YAML::Node *pName =yaml_attributes.FindValue("os_replacement"))
    *pName >> overrides.os;
  if (const YAML::Node *pName =yaml_attributes.FindValue("os_v1_replacement"))
    *pName >> overrides.major;
  if (const YAML::Node *pName =yaml_attributes.FindValue("os_v2_replacement"))
    *pName >> overrides.minor;
}

OperatingSystem OperatingSystemParser::Parse(const std::string &user_agent_string) {
  OperatingSystem os;
  using namespace std;

  boost::smatch result;
  if (boost::regex_search(user_agent_string.begin(), user_agent_string.end(), result, regex)) {
    if (overrides.os.empty() && result.size()>1)
      os.os = result[1].str();
    else {
      os.os = overrides.os;
      boost::replace_all(os.os, "$1", result[1].str());
    }

    // If the group is not found, use the override value even if it is blank
    if (overrides.major.empty()&&result.size()>2)
      os.major = result[2].str();
    else
      os.major = overrides.major;

    if (overrides.minor.empty()&&result.size()>3)
      os.minor = result[3].str();
    else
      os.minor = overrides.minor;

    if (overrides.patch.empty()&&result.size()>4)
      os.patch = result[4].str();
    else
      os.patch = overrides.patch;

    if (overrides.patch_minor.empty()&&result.size()>5)
      os.patch_minor = result[5].str();
    else
      os.patch_minor = overrides.patch_minor;

    return os;
  }
  return os;
}

DeviceParser::DeviceParser(const YAML::Node &yaml_attributes) {
  yaml_attributes["regex"] >> pattern;
  regex = boost::regex(pattern);

  if (const YAML::Node *pName=yaml_attributes.FindValue("device_replacement"))
    *pName >> overrides;
}

Device DeviceParser::Parse(const std::string &user_agent_string) {
  Device device;
  using namespace std;

  boost::smatch result;
  if (boost::regex_search(user_agent_string.begin(), user_agent_string.end(), result, regex)) {
    if (overrides.empty() && result.size()>1)
      device = result[1].str();
    else {
      device = overrides;
      boost::replace_all(device, "$1", result[1].str());
    }

    return device;
  }

  return device;
}

template<class ParserType>
static std::vector<ParserType> ParseYaml(const YAML::Node &yaml_regexes) {
  std::vector<ParserType> parsers;

  for (YAML::Iterator i=yaml_regexes.begin(); i!=yaml_regexes.end(); i++) {
    ParserType parser(*i);

    parsers.push_back(parser);
  }

  return parsers;
}

Parser::Parser(const std::string &yaml_file) {
  std::ifstream in(yaml_file.c_str());
  if (!in.good()) {
    throw std::range_error("Could not open YAML file");
    return;
  }

  YAML::Parser parser(in);

  YAML::Node doc;
  parser.GetNextDocument(doc);

  _browser_parsers = ParseYaml<BrowserParser>(doc["user_agent_parsers"]);
  _os_parsers = ParseYaml<OperatingSystemParser>(doc["os_parsers"]);
  _device_parsers = ParseYaml<DeviceParser>(doc["device_parsers"]);

}

UserAgent Parser::Parse(const std::string &user_agent_string) {
  UserAgent user_agent;

  user_agent.browser.family = "Other";
  user_agent.os.os = "Other";
  user_agent.device = "Other";
  user_agent.browser.major = "Other";
  user_agent.browser.minor = "Other";

  for (std::vector<BrowserParser>::iterator i=_browser_parsers.begin(); i!=_browser_parsers.end(); i++) {
    Browser browser = i->Parse(user_agent_string);
    if (!browser.family.empty()) {
      user_agent.browser = browser;
      break;
    }

  }

  for (std::vector<OperatingSystemParser>::iterator i=_os_parsers.begin(); i!=_os_parsers.end(); i++) {
    OperatingSystem os = i->Parse(user_agent_string);
    if (!os.os.empty()) {
      user_agent.os = os;
      break;
    }

  }

  for (std::vector<DeviceParser>::iterator i=_device_parsers.begin(); i!=_device_parsers.end(); i++) {
    Device device = i->Parse(user_agent_string);
    if (!device.empty()) {
      user_agent.device = device;
      break;
    }

  }

  return user_agent;
}

}

<|endoftext|>