<commit_before>#include <stingraykit/log/Logger.h>

#include <cstdio>
#include <cstring>

#include <map>
#include <sstream>

#include <stingraykit/log/SystemLogger.h>
#include <stingraykit/diagnostics/Backtrace.h>
#include <stingraykit/FunctionToken.h>
#include <stingraykit/PhoenixSingleton.h>
#include <stingraykit/SafeSingleton.h>
#include <stingraykit/string/StringFormat.h>
#include <stingraykit/collection/iterators.h>

namespace stingray
{

	namespace Detail {
	namespace LoggerDetail
	{
		NullPtrType		s_logger; // Static logger fallback
	}}

	class NamedLoggerRegistry : public PhoenixSingleton<NamedLoggerRegistry>
	{
		STINGRAYKIT_PHOENIXSINGLETON(NamedLoggerRegistry);

		struct StrLess
		{
			bool operator() (const char* l, const char* r) const { return strcmp(l, r) < 0; }
		};

		typedef std::multimap<const char*, NamedLogger*, StrLess> LoggerRegistry;

	private:
		LoggerRegistry	_registry;
		Mutex			_registryMutex;

		NamedLoggerRegistry() { }

	public:
		void Register(const char* loggerName, NamedLogger* logger)
		{
			MutexLock l(_registryMutex);
			_registry.insert(std::make_pair(loggerName, logger));
		}

		void Unregister(const char* loggerName, NamedLogger* logger)
		{
			MutexLock l(_registryMutex);
			std::pair<LoggerRegistry::iterator, LoggerRegistry::iterator> range = _registry.equal_range(loggerName);
			for (LoggerRegistry::iterator it = range.first; it != range.second; ++it)
			{
				if (it->second == logger)
				{
					_registry.erase(it);
					return;
				}
			}
			SystemLogger::Log(LogLevel::Error, StringBuilder() % "Unknown named logger: " % loggerName);
		}

		void GetLoggerNames(std::set<std::string>& out) const
		{
			MutexLock l(_registryMutex);
			out.clear();
			std::copy(keys_iterator(_registry.begin()), keys_iterator(_registry.end()), std::inserter(out, out.begin()));
		}

		void SetLogLevel(const std::string& loggerName, LogLevel logLevel)
		{
			MutexLock l(_registryMutex);
			std::pair<LoggerRegistry::iterator, LoggerRegistry::iterator> range = _registry.equal_range(loggerName.c_str());
			for (LoggerRegistry::iterator it = range.first; it != range.second; ++it)
				it->second->SetLogLevel(logLevel);
		}

		LogLevel GetLogLevel(const std::string& loggerName)
		{
			MutexLock l(_registryMutex);
			LoggerRegistry::const_iterator it = _registry.find(loggerName.c_str());
			if (it == _registry.end())
				return Logger::GetLogLevel();
			return it->second->GetLogLevel();
		}

		void SetBacktraceEnabled(const std::string& loggerName, bool enable)
		{
			MutexLock l(_registryMutex);
			std::pair<LoggerRegistry::iterator, LoggerRegistry::iterator> range = _registry.equal_range(loggerName.c_str());
			for (LoggerRegistry::iterator it = range.first; it != range.second; ++it)
				it->second->EnableBacktrace(enable);
		}

		bool GetBacktraceEnabled(const std::string& loggerName)
		{
			MutexLock l(_registryMutex);
			LoggerRegistry::const_iterator it = _registry.find(loggerName.c_str());
			if (it == _registry.end())
				return false;
			return it->second->BacktraceEnabled();
		}
	};

	class LoggerImpl
	{
		typedef std::vector<ILoggerSinkPtr> SinksBundle;

	private:
		SinksBundle					_sinks;
		atomic<LogLevel>			_logLevel;
		Mutex						_logMutex;

	public:
		LoggerImpl() : _logLevel(LogLevel::Info)
		{ }

		~LoggerImpl()
		{ }

		void AddSink(const ILoggerSinkPtr& sink)
		{
			MutexLock l(_logMutex);
			_sinks.push_back(sink);
		}

		void RemoveSink(const ILoggerSinkPtr& sink)
		{
			MutexLock l(_logMutex);
			SinksBundle::iterator it = std::find(_sinks.begin(), _sinks.end(), sink);
			if (it != _sinks.end())
				_sinks.erase(it);
		}

		LogLevel GetLogLevel() const throw()
		{ return _logLevel.load(memory_order_relaxed); }

		void SetLogLevel(LogLevel logLevel) throw()
		{ _logLevel.store(logLevel, memory_order_relaxed); }

		void Log(LogLevel logLevel, const std::string& message) throw()
		{
			try
			{
				EnableInterruptionPoints eip(false);
				DoLog(logLevel, message);
			}
			catch (const std::exception&)
			{ }
		}

		void Log(const std::string& loggerName, LogLevel logLevel, const std::string& message) throw()
		{
			try
			{
				EnableInterruptionPoints eip(false);
				DoLog(loggerName, logLevel, message);
			}
			catch (const std::exception&)
			{ }
		}

	private:
		void DoLog(LogLevel logLevel, const std::string& message)
		{
			SinksBundle sinks;

			{
				MutexLock l(_logMutex);
				sinks = _sinks;
			}

			if (sinks.empty())
				SystemLogger::Log(logLevel, message);
			else
				DoLog(sinks, LoggerMessage(logLevel, message));
		}

		void DoLog(const std::string& loggerName, LogLevel logLevel, const std::string& message)
		{
			SinksBundle sinks;

			{
				MutexLock l(_logMutex);
				sinks = _sinks;
			}

			if (sinks.empty())
				SystemLogger::Log(loggerName, logLevel, message);
			else
				DoLog(sinks, LoggerMessage(loggerName, logLevel, message));
		}

		void DoLog(const SinksBundle& sinks, const LoggerMessage& message)
		{
			for (SinksBundle::const_iterator it = sinks.begin(); it != sinks.end(); ++it)
			{
				try
				{
					ILoggerSinkPtr sink = *it;
					sink->Log(message);
				}
				catch (const std::exception&)
				{ }
			}
		}
	};
	STINGRAYKIT_DECLARE_PTR(LoggerImpl);

	typedef SafeSingleton<LoggerImpl> LoggerSingleton;

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

	NamedLogger::NamedLogger(const char* name) :
		_name(name),
		_logLevel(OptionalLogLevel::Null),
		_backtrace(false)
	{ NamedLoggerRegistry::Instance().Register(_name, this); }

	NamedLogger::~NamedLogger()
	{ NamedLoggerRegistry::Instance().Unregister(_name, this); }

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

	struct LogLevelHolder
	{
		static u32 s_logLevel;
	};

	u32 LogLevelHolder::s_logLevel = (u32)LogLevel::Info;

	void Logger::SetLogLevel(LogLevel logLevel)
	{ Atomic::Store(LogLevelHolder::s_logLevel, (u32)logLevel.val(), memory_order_relaxed); }

	LogLevel Logger::GetLogLevel()
	{ return (LogLevel::Enum)Atomic::Load(LogLevelHolder::s_logLevel, memory_order_relaxed); }

	struct LoggerStreamHelper
	{
		static void Log(const char* loggerName, LogLevel logLevel, const std::string& message)
		{
			if (loggerName)
				Logger::Log(loggerName, logLevel, message);
			else
				Logger::Log(logLevel, message);
		}
	};

	LoggerStream Logger::Stream(LogLevel logLevel, DuplicatingLogsFilter* duplicatingLogsFilter)
	{ return LoggerStream(null, GetLogLevel(), logLevel, duplicatingLogsFilter, &LoggerStreamHelper::Log); }

	void Logger::SetLogLevel(const std::string& loggerName, LogLevel logLevel)
	{ NamedLoggerRegistry::Instance().SetLogLevel(loggerName, logLevel); }

	LogLevel Logger::GetLogLevel(const std::string& loggerName)
	{ return NamedLoggerRegistry::Instance().GetLogLevel(loggerName); }

	void Logger::SetBacktraceEnabled(const std::string& loggerName, bool enable)
	{ NamedLoggerRegistry::Instance().SetBacktraceEnabled(loggerName, enable); }

	bool Logger::GetBacktraceEnabled(const std::string& loggerName)
	{ return NamedLoggerRegistry::Instance().GetBacktraceEnabled(loggerName); }

	void Logger::GetLoggerNames(std::set<std::string>& out)
	{ NamedLoggerRegistry::Instance().GetLoggerNames(out); }

	Token Logger::AddSink(const ILoggerSinkPtr& sink)
	{
		LoggerImplPtr logger = LoggerSingleton::Instance();
		if (!logger)
			return null;

		logger->AddSink(sink);
		return make_shared<FunctionToken>(bind(&LoggerImpl::RemoveSink, logger, sink));
	}

	void Logger::Log(LogLevel logLevel, const std::string& message)
	{
		LoggerImplPtr logger = LoggerSingleton::Instance();
		LogLevel ll = logger ? logger->GetLogLevel() : LogLevel(LogLevel::Debug);
		if (logLevel < ll)
			return;

		if (logger)
			return logger->Log(logLevel, message);
		else
			SystemLogger::Log(logLevel, message);
	}

	void Logger::Log(const std::string& loggerName, LogLevel logLevel, const std::string& message)
	{
		LoggerImplPtr logger = LoggerSingleton::Instance();
		if (logger)
			logger->Log(loggerName, logLevel, message + (GetBacktraceEnabled(loggerName) ? ": " + Backtrace().Get() : std::string()));
		else
			SystemLogger::Log(loggerName, logLevel, message + (GetBacktraceEnabled(loggerName) ? ": " + Backtrace().Get() : std::string()));
	}

	LogLevel NamedLogger::GetLogLevel() const
	{
		optional<LogLevel> logLevel = OptionalLogLevel::ToLogLevel(_logLevel.load(memory_order_relaxed));
		return logLevel ? *logLevel : Logger::GetLogLevel();
	}

	void NamedLogger::SetLogLevel(LogLevel logLevel)
	{ _logLevel.store(OptionalLogLevel::FromLogLevel(logLevel), memory_order_relaxed); }

	bool NamedLogger::BacktraceEnabled() const
	{ return _backtrace; }

	void NamedLogger::EnableBacktrace(bool enable)
	{ _backtrace = enable; }

	LoggerStream NamedLogger::Stream(LogLevel logLevel) const
	{ return LoggerStream(_name, GetLogLevel(), logLevel, &_duplicatingLogsFilter, &LoggerStreamHelper::Log); }

	void NamedLogger::Log(LogLevel logLevel, const std::string& message)
	{ Stream(logLevel) << message; }

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

	ActionLogger::ActionLogger(const std::string& action)
		: _namedLogger(NULL), _action(action)
	{ Logger::Info() << _action << "..."; }

	ActionLogger::ActionLogger(NamedLogger& namedLogger, const std::string& action)
		: _namedLogger(&namedLogger), _action(action)
	{ _namedLogger->Info() << _action << "..."; }

	ActionLogger::~ActionLogger()
	{
		s64 ms = 0;
		int mms = 0;
		try { s64 e = _elapsedTime.ElapsedMicroseconds(); ms = e / 1000; mms = e % 1000; } catch(const std::exception&) { }
		if (std::uncaught_exception())
		{
			try
			{
				if (_namedLogger)
					_namedLogger->Info() << _action << " completed with exception in " << ms << "." << mms << " ms";
				else
					Logger::Info() << _action << " completed with exception in " << ms << "." << mms << " ms";
			}
			catch (const std::exception&)
			{ return; }
		}
		else
		{
			if (_namedLogger)
				_namedLogger->Info() << _action << " completed in " << ms << "." << mms << " ms";
			else
				Logger::Info() << _action << " completed in " << ms << "." << mms << " ms";
		}
	}

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

	Tracer::Tracer(const Detail::NamedLoggerAccessor& logger, const char* funcName)
		: _logger(logger), _funcName(funcName)
	{
		if (_logger.GetLogLevel() >= LogLevel::Trace)
			_logger.Trace() << "TRACER: entering function '" <<  _funcName << "'";
	}

	Tracer::~Tracer()
	{
		s64 ms = 0;
		int mms = 0;
		try { s64 e = _elapsedTime.ElapsedMicroseconds(); ms = e / 1000; mms = e % 1000; } catch(const std::exception&) {}
		if (std::uncaught_exception())
		{
			try
			{
				if (_logger.GetLogLevel() >= LogLevel::Trace)
					_logger.Trace() << "TRACER: leaving function '" << _funcName << "' due to an exception (" << StringFormat("%1%.%2$3%", ms, mms) << " ms)";
			}
			catch(const std::exception&)
			{ return; }
		}
		else
		{
			if (_logger.GetLogLevel() >= LogLevel::Trace)
				_logger.Trace() << "TRACER: leaving function '" << _funcName << "' (" << StringFormat("%1%.%2$3%", ms, mms) << " ms)";
		}

	}

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

	void LogException(const std::exception& ex)
	{ Logger::Error() << diagnostic_information(ex); }

	void LogExceptionTo(NamedLogger& namedLogger, const std::exception& ex)
	{ namedLogger.Error() << diagnostic_information(ex); }

}
<commit_msg>Replaced make_shared<FunctionToken> with MakeToken<commit_after>#include <stingraykit/log/Logger.h>

#include <cstdio>
#include <cstring>

#include <map>
#include <sstream>

#include <stingraykit/log/SystemLogger.h>
#include <stingraykit/diagnostics/Backtrace.h>
#include <stingraykit/FunctionToken.h>
#include <stingraykit/PhoenixSingleton.h>
#include <stingraykit/SafeSingleton.h>
#include <stingraykit/string/StringFormat.h>
#include <stingraykit/collection/iterators.h>

namespace stingray
{

	namespace Detail {
	namespace LoggerDetail
	{
		NullPtrType		s_logger; // Static logger fallback
	}}

	class NamedLoggerRegistry : public PhoenixSingleton<NamedLoggerRegistry>
	{
		STINGRAYKIT_PHOENIXSINGLETON(NamedLoggerRegistry);

		struct StrLess
		{
			bool operator() (const char* l, const char* r) const { return strcmp(l, r) < 0; }
		};

		typedef std::multimap<const char*, NamedLogger*, StrLess> LoggerRegistry;

	private:
		LoggerRegistry	_registry;
		Mutex			_registryMutex;

		NamedLoggerRegistry() { }

	public:
		void Register(const char* loggerName, NamedLogger* logger)
		{
			MutexLock l(_registryMutex);
			_registry.insert(std::make_pair(loggerName, logger));
		}

		void Unregister(const char* loggerName, NamedLogger* logger)
		{
			MutexLock l(_registryMutex);
			std::pair<LoggerRegistry::iterator, LoggerRegistry::iterator> range = _registry.equal_range(loggerName);
			for (LoggerRegistry::iterator it = range.first; it != range.second; ++it)
			{
				if (it->second == logger)
				{
					_registry.erase(it);
					return;
				}
			}
			SystemLogger::Log(LogLevel::Error, StringBuilder() % "Unknown named logger: " % loggerName);
		}

		void GetLoggerNames(std::set<std::string>& out) const
		{
			MutexLock l(_registryMutex);
			out.clear();
			std::copy(keys_iterator(_registry.begin()), keys_iterator(_registry.end()), std::inserter(out, out.begin()));
		}

		void SetLogLevel(const std::string& loggerName, LogLevel logLevel)
		{
			MutexLock l(_registryMutex);
			std::pair<LoggerRegistry::iterator, LoggerRegistry::iterator> range = _registry.equal_range(loggerName.c_str());
			for (LoggerRegistry::iterator it = range.first; it != range.second; ++it)
				it->second->SetLogLevel(logLevel);
		}

		LogLevel GetLogLevel(const std::string& loggerName)
		{
			MutexLock l(_registryMutex);
			LoggerRegistry::const_iterator it = _registry.find(loggerName.c_str());
			if (it == _registry.end())
				return Logger::GetLogLevel();
			return it->second->GetLogLevel();
		}

		void SetBacktraceEnabled(const std::string& loggerName, bool enable)
		{
			MutexLock l(_registryMutex);
			std::pair<LoggerRegistry::iterator, LoggerRegistry::iterator> range = _registry.equal_range(loggerName.c_str());
			for (LoggerRegistry::iterator it = range.first; it != range.second; ++it)
				it->second->EnableBacktrace(enable);
		}

		bool GetBacktraceEnabled(const std::string& loggerName)
		{
			MutexLock l(_registryMutex);
			LoggerRegistry::const_iterator it = _registry.find(loggerName.c_str());
			if (it == _registry.end())
				return false;
			return it->second->BacktraceEnabled();
		}
	};

	class LoggerImpl
	{
		typedef std::vector<ILoggerSinkPtr> SinksBundle;

	private:
		SinksBundle					_sinks;
		atomic<LogLevel>			_logLevel;
		Mutex						_logMutex;

	public:
		LoggerImpl() : _logLevel(LogLevel::Info)
		{ }

		~LoggerImpl()
		{ }

		void AddSink(const ILoggerSinkPtr& sink)
		{
			MutexLock l(_logMutex);
			_sinks.push_back(sink);
		}

		void RemoveSink(const ILoggerSinkPtr& sink)
		{
			MutexLock l(_logMutex);
			SinksBundle::iterator it = std::find(_sinks.begin(), _sinks.end(), sink);
			if (it != _sinks.end())
				_sinks.erase(it);
		}

		LogLevel GetLogLevel() const throw()
		{ return _logLevel.load(memory_order_relaxed); }

		void SetLogLevel(LogLevel logLevel) throw()
		{ _logLevel.store(logLevel, memory_order_relaxed); }

		void Log(LogLevel logLevel, const std::string& message) throw()
		{
			try
			{
				EnableInterruptionPoints eip(false);
				DoLog(logLevel, message);
			}
			catch (const std::exception&)
			{ }
		}

		void Log(const std::string& loggerName, LogLevel logLevel, const std::string& message) throw()
		{
			try
			{
				EnableInterruptionPoints eip(false);
				DoLog(loggerName, logLevel, message);
			}
			catch (const std::exception&)
			{ }
		}

	private:
		void DoLog(LogLevel logLevel, const std::string& message)
		{
			SinksBundle sinks;

			{
				MutexLock l(_logMutex);
				sinks = _sinks;
			}

			if (sinks.empty())
				SystemLogger::Log(logLevel, message);
			else
				DoLog(sinks, LoggerMessage(logLevel, message));
		}

		void DoLog(const std::string& loggerName, LogLevel logLevel, const std::string& message)
		{
			SinksBundle sinks;

			{
				MutexLock l(_logMutex);
				sinks = _sinks;
			}

			if (sinks.empty())
				SystemLogger::Log(loggerName, logLevel, message);
			else
				DoLog(sinks, LoggerMessage(loggerName, logLevel, message));
		}

		void DoLog(const SinksBundle& sinks, const LoggerMessage& message)
		{
			for (SinksBundle::const_iterator it = sinks.begin(); it != sinks.end(); ++it)
			{
				try
				{
					ILoggerSinkPtr sink = *it;
					sink->Log(message);
				}
				catch (const std::exception&)
				{ }
			}
		}
	};
	STINGRAYKIT_DECLARE_PTR(LoggerImpl);

	typedef SafeSingleton<LoggerImpl> LoggerSingleton;

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

	NamedLogger::NamedLogger(const char* name) :
		_name(name),
		_logLevel(OptionalLogLevel::Null),
		_backtrace(false)
	{ NamedLoggerRegistry::Instance().Register(_name, this); }

	NamedLogger::~NamedLogger()
	{ NamedLoggerRegistry::Instance().Unregister(_name, this); }

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

	struct LogLevelHolder
	{
		static u32 s_logLevel;
	};

	u32 LogLevelHolder::s_logLevel = (u32)LogLevel::Info;

	void Logger::SetLogLevel(LogLevel logLevel)
	{ Atomic::Store(LogLevelHolder::s_logLevel, (u32)logLevel.val(), memory_order_relaxed); }

	LogLevel Logger::GetLogLevel()
	{ return (LogLevel::Enum)Atomic::Load(LogLevelHolder::s_logLevel, memory_order_relaxed); }

	struct LoggerStreamHelper
	{
		static void Log(const char* loggerName, LogLevel logLevel, const std::string& message)
		{
			if (loggerName)
				Logger::Log(loggerName, logLevel, message);
			else
				Logger::Log(logLevel, message);
		}
	};

	LoggerStream Logger::Stream(LogLevel logLevel, DuplicatingLogsFilter* duplicatingLogsFilter)
	{ return LoggerStream(null, GetLogLevel(), logLevel, duplicatingLogsFilter, &LoggerStreamHelper::Log); }

	void Logger::SetLogLevel(const std::string& loggerName, LogLevel logLevel)
	{ NamedLoggerRegistry::Instance().SetLogLevel(loggerName, logLevel); }

	LogLevel Logger::GetLogLevel(const std::string& loggerName)
	{ return NamedLoggerRegistry::Instance().GetLogLevel(loggerName); }

	void Logger::SetBacktraceEnabled(const std::string& loggerName, bool enable)
	{ NamedLoggerRegistry::Instance().SetBacktraceEnabled(loggerName, enable); }

	bool Logger::GetBacktraceEnabled(const std::string& loggerName)
	{ return NamedLoggerRegistry::Instance().GetBacktraceEnabled(loggerName); }

	void Logger::GetLoggerNames(std::set<std::string>& out)
	{ NamedLoggerRegistry::Instance().GetLoggerNames(out); }

	Token Logger::AddSink(const ILoggerSinkPtr& sink)
	{
		LoggerImplPtr logger = LoggerSingleton::Instance();
		if (!logger)
			return null;

		logger->AddSink(sink);
		return MakeToken<FunctionToken>(bind(&LoggerImpl::RemoveSink, logger, sink));
	}

	void Logger::Log(LogLevel logLevel, const std::string& message)
	{
		LoggerImplPtr logger = LoggerSingleton::Instance();
		LogLevel ll = logger ? logger->GetLogLevel() : LogLevel(LogLevel::Debug);
		if (logLevel < ll)
			return;

		if (logger)
			return logger->Log(logLevel, message);
		else
			SystemLogger::Log(logLevel, message);
	}

	void Logger::Log(const std::string& loggerName, LogLevel logLevel, const std::string& message)
	{
		LoggerImplPtr logger = LoggerSingleton::Instance();
		if (logger)
			logger->Log(loggerName, logLevel, message + (GetBacktraceEnabled(loggerName) ? ": " + Backtrace().Get() : std::string()));
		else
			SystemLogger::Log(loggerName, logLevel, message + (GetBacktraceEnabled(loggerName) ? ": " + Backtrace().Get() : std::string()));
	}

	LogLevel NamedLogger::GetLogLevel() const
	{
		optional<LogLevel> logLevel = OptionalLogLevel::ToLogLevel(_logLevel.load(memory_order_relaxed));
		return logLevel ? *logLevel : Logger::GetLogLevel();
	}

	void NamedLogger::SetLogLevel(LogLevel logLevel)
	{ _logLevel.store(OptionalLogLevel::FromLogLevel(logLevel), memory_order_relaxed); }

	bool NamedLogger::BacktraceEnabled() const
	{ return _backtrace; }

	void NamedLogger::EnableBacktrace(bool enable)
	{ _backtrace = enable; }

	LoggerStream NamedLogger::Stream(LogLevel logLevel) const
	{ return LoggerStream(_name, GetLogLevel(), logLevel, &_duplicatingLogsFilter, &LoggerStreamHelper::Log); }

	void NamedLogger::Log(LogLevel logLevel, const std::string& message)
	{ Stream(logLevel) << message; }

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

	ActionLogger::ActionLogger(const std::string& action)
		: _namedLogger(NULL), _action(action)
	{ Logger::Info() << _action << "..."; }

	ActionLogger::ActionLogger(NamedLogger& namedLogger, const std::string& action)
		: _namedLogger(&namedLogger), _action(action)
	{ _namedLogger->Info() << _action << "..."; }

	ActionLogger::~ActionLogger()
	{
		s64 ms = 0;
		int mms = 0;
		try { s64 e = _elapsedTime.ElapsedMicroseconds(); ms = e / 1000; mms = e % 1000; } catch(const std::exception&) { }
		if (std::uncaught_exception())
		{
			try
			{
				if (_namedLogger)
					_namedLogger->Info() << _action << " completed with exception in " << ms << "." << mms << " ms";
				else
					Logger::Info() << _action << " completed with exception in " << ms << "." << mms << " ms";
			}
			catch (const std::exception&)
			{ return; }
		}
		else
		{
			if (_namedLogger)
				_namedLogger->Info() << _action << " completed in " << ms << "." << mms << " ms";
			else
				Logger::Info() << _action << " completed in " << ms << "." << mms << " ms";
		}
	}

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

	Tracer::Tracer(const Detail::NamedLoggerAccessor& logger, const char* funcName)
		: _logger(logger), _funcName(funcName)
	{
		if (_logger.GetLogLevel() >= LogLevel::Trace)
			_logger.Trace() << "TRACER: entering function '" <<  _funcName << "'";
	}

	Tracer::~Tracer()
	{
		s64 ms = 0;
		int mms = 0;
		try { s64 e = _elapsedTime.ElapsedMicroseconds(); ms = e / 1000; mms = e % 1000; } catch(const std::exception&) {}
		if (std::uncaught_exception())
		{
			try
			{
				if (_logger.GetLogLevel() >= LogLevel::Trace)
					_logger.Trace() << "TRACER: leaving function '" << _funcName << "' due to an exception (" << StringFormat("%1%.%2$3%", ms, mms) << " ms)";
			}
			catch(const std::exception&)
			{ return; }
		}
		else
		{
			if (_logger.GetLogLevel() >= LogLevel::Trace)
				_logger.Trace() << "TRACER: leaving function '" << _funcName << "' (" << StringFormat("%1%.%2$3%", ms, mms) << " ms)";
		}

	}

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

	void LogException(const std::exception& ex)
	{ Logger::Error() << diagnostic_information(ex); }

	void LogExceptionTo(NamedLogger& namedLogger, const std::exception& ex)
	{ namedLogger.Error() << diagnostic_information(ex); }

}
<|endoftext|>


<commit_before>
<commit_msg>Delete OBB.cpp<commit_after><|endoftext|>


<commit_before>#ifndef ENTT_META_CONTAINER_HPP
#define ENTT_META_CONTAINER_HPP

#include <array>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
#include "../config/config.h"
#include "type_traits.hpp"

namespace entt {

namespace internal {

template<typename Container, template<typename> class... Trait>
struct container_traits: public Trait<Container>... {};

/**
 * @brief Basic STL-compatible container traits
 * @tparam Container The type of the container.
 */
template<typename Container>
struct basic_container {
    /*! @brief Iterator type of the container. */
    using iterator = typename Container::iterator;
    /*! @brief Unsigned integer type. */
    using size_type = typename Container::size_type;
    /*! @brief Value type of the container. */
    using value_type = typename Container::value_type;

    /**
     * @brief Returns the size of the given container.
     * @param cont The container for which to return the size.
     * @return The size of the given container.
     */
    [[nodiscard]] static size_type size(const Container &cont) ENTT_NOEXCEPT {
        return cont.size();
    }

    /**
     * @brief Returns an iterator to the first element of the given container.
     * @param cont The container for which to return the iterator.
     * @return An iterator to the first element of the given container.
     */
    [[nodiscard]] static iterator begin(Container &cont) {
        return cont.begin();
    }

    /**
     * @brief Returns an iterator past the last element of the given container.
     * @param cont The container for which to return the iterator.
     * @return An iterator past the last element of the given container.
     */
    [[nodiscard]] static iterator end(Container &cont) {
        return cont.end();
    }
};

/**
 * @brief Basic STL-compatible associative container traits
 * @tparam Container The type of the container.
 */
template<typename Container>
struct basic_associative_container {
    /*! @brief Key type of the sequence container. */
    using key_type = typename Container::key_type;

    /**
     * @brief Returns an iterator to the element with key equivalent to the given
     * one, if any.
     * @param cont The container in which to search for the element.
     * @param key The key of the element to search.
     * @return An iterator to the element with the given key, if any.
     */
    [[nodiscard]] static typename Container::iterator find(Container &cont, const key_type &key) {
        return cont.find(key);
    }
};

/**
 * @brief Basic STL-compatible dynamic container traits
 * @tparam Container The type of the container.
 */
template<typename Container>
struct basic_dynamic_container {
    /**
     * @brief Clears the content of the given container.
     * @param cont The container for which to clear the content.
     * @return True in case of success, false otherwise.
     */
    [[nodiscard]] static bool clear(Container &cont) {
        return cont.clear(), true;
    }
};

/**
 * @brief Basic STL-compatible dynamic associative container traits
 * @tparam Container The type of the container.
 */
template<typename Container>
struct basic_dynamic_associative_container {
    /**
     * @brief Removes the specified element from the given container.
     * @param cont The container from which to remove the element.
     * @param key The element to remove.
     * @return A bool denoting whether the removal took place.
     */
    [[nodiscard]] static bool erase(Container &cont, const typename Container::key_type &key) {
        const auto sz = cont.size();
        return cont.erase(key) != sz;
    }
};

/**
 * @brief Basic STL-compatible sequence container traits
 * @tparam Container The type of the container.
 */
template<typename Container>
struct basic_sequence_container {
    /**
     * @brief Returns a reference to the element at the specified location of the
     * given container (no bounds checking is performed).
     * @param cont The container from which to get the element.
     * @param pos The position of the element to return.
     * @return A reference to the requested element.
     */
    [[nodiscard]] static typename Container::value_type & get(Container &cont, typename Container::size_type pos) {
        return cont[pos];
    }
};

/**
 * @brief STL-compatible dynamic associative key-only container traits
 * @tparam Container The type of the container.
 */
template<typename Container>
struct dynamic_associative_key_only_container {
    /**
     * @brief Inserts an element into the given container.
     * @param cont The container in which to insert the element.
     * @param key The element to insert.
     * @return A bool denoting whether the insertion took place.
     */
    [[nodiscard]] static bool insert(Container &cont, const typename Container::key_type &key) {
        return cont.insert(key).second;
    }
};

/**
 * @brief STL-compatible dynamic key-value associative container traits
 * @tparam Container The type of the container.
 */
template<typename Container>
struct dynamic_associative_key_value_container {
    /**
     * @brief Inserts an element (a key/value pair) into the given container.
     * @param cont The container in which to insert the element.
     * @param key The key of the element to insert.
     * @param value The value of the element to insert.
     * @return A bool denoting whether the insertion took place.
     */
    [[nodiscard]] static bool insert(Container &cont, const typename Container::key_type &key, const typename Container::mapped_type &value) {
        return cont.insert(std::make_pair(key, value)).second;
    }
};

/**
 * @brief STL-compatible dynamic sequence container traits
 * @tparam Container The type of the container.
 */
template<typename Container>
struct dynamic_sequence_container {
    /**
     * @brief Resizes the given container to contain the given number of elements.
     * @param cont The container to resize.
     * @param sz The new size of the container.
     * @return True in case of success, false otherwise.
     */
    [[nodiscard]] static bool resize(Container &cont, typename Container::size_type sz) {
        return (cont.resize(sz), true);
    }

    /**
     * @brief Inserts an element at the specified location of the given container.
     * @param cont The container into which to insert the element.
     * @param it Iterator before which the element will be inserted.
     * @param value Element value to insert.
     * @return A pair consisting of an iterator to the inserted element (in case
     * of success) and a bool denoting whether the insertion took place.
     */
    [[nodiscard]] static std::pair<typename Container::iterator, bool> insert(Container &cont, typename Container::iterator it, const typename Container::value_type &value) {
        return { cont.insert(it, value), true };
    }

    /**
     * @brief Removes the element at the specified location from the given container.
     * @param cont The container from which to remove the element.
     * @param it Iterator to the element to remove.
     * @return A pair consisting of an iterator following the last removed
     * element (in case of success) and a bool denoting whether the insertion
     * took place.
     */
    [[nodiscard]] static std::pair<typename Container::iterator, bool> erase(Container &cont, typename Container::iterator it) {
        return { cont.erase(it), true };
    }
};

/**
 * @brief STL-compatible fixed sequence container traits
 * @tparam Container The type of the container.
 */
template<typename Container>
struct fixed_sequence_container {
    /**
     * @brief Does nothing.
     * @return False to indicate failure in all cases.
     */
    [[nodiscard]] static bool resize(const Container &, typename Container::size_type) {
        return false;
    }

    /**
     * @brief Does nothing.
     * @return False to indicate failure in all cases.
     */
    [[nodiscard]] static bool clear(const Container &) {
        return false;
    }

    /**
     * @brief Does nothing.
     * @return A pair consisting of an invalid iterator and a false value to
     * indicate failure in all cases.
     */
    [[nodiscard]] static std::pair<typename Container::iterator, bool> insert(const Container &, typename Container::iterator, const typename Container::value_type &) {
        return { {}, false };
    }

    /**
     * @brief Does nothing.
     * @return A pair consisting of an invalid iterator and a false value to
     * indicate failure in all cases.
     */
    [[nodiscard]] static std::pair<typename Container::iterator, bool> erase(const Container &, typename Container::iterator) {
        return { {}, false };
    }
};

}

/**
 * @brief Meta sequence container traits for `std::vector`s of any type.
 * @tparam Type The type of elements.
 * @tparam Args Other arguments.
 */
template<typename Type, typename... Args>
struct meta_sequence_container_traits<std::vector<Type, Args...>>
        : internal::container_traits<
            std::vector<Type, Args...>,
            internal::basic_container,
            internal::basic_dynamic_container,
            internal::basic_sequence_container,
            internal::dynamic_sequence_container
        >
{};

/**
 * @brief Meta sequence container traits for `std::array`s of any type.
 * @tparam Type The type of elements.
 * @tparam N The number of elements.
 */
template<typename Type, auto N>
struct meta_sequence_container_traits<std::array<Type, N>>
        : internal::container_traits<
            std::array<Type, N>,
            internal::basic_container,
            internal::basic_sequence_container,
            internal::fixed_sequence_container
        >
{};

/**
 * @brief Meta associative container traits for `std::map`s of any type.
 * @tparam Key The key type of elements.
 * @tparam Value The value type of elements.
 * @tparam Args Other arguments.
 */
template<typename Key, typename Value, typename... Args>
struct meta_associative_container_traits<std::map<Key, Value, Args...>>
        : internal::container_traits<
            std::map<Key, Value, Args...>,
            internal::basic_container,
            internal::basic_associative_container,
            internal::basic_dynamic_container,
            internal::basic_dynamic_associative_container,
            internal::dynamic_associative_key_value_container
        >
{
    /*! @brief Mapped type of the sequence container. */
    using mapped_type = typename std::map<Key, Value, Args...>::mapped_type;
};

/**
 * @brief Meta associative container traits for `std::unordered_map`s of any
 * type.
 * @tparam Key The key type of elements.
 * @tparam Value The value type of elements.
 * @tparam Args Other arguments.
 */
template<typename Key, typename Value, typename... Args>
struct meta_associative_container_traits<std::unordered_map<Key, Value, Args...>>
        : internal::container_traits<
            std::unordered_map<Key, Value, Args...>,
            internal::basic_container,
            internal::basic_associative_container,
            internal::basic_dynamic_container,
            internal::basic_dynamic_associative_container,
            internal::dynamic_associative_key_value_container
        >
{
    /*! @brief Mapped type of the sequence container. */
    using mapped_type = typename std::unordered_map<Key, Value, Args...>::mapped_type;
};

/**
 * @brief Meta associative container traits for `std::set`s of any type.
 * @tparam Key The type of elements.
 * @tparam Args Other arguments.
 */
template<typename Key, typename... Args>
struct meta_associative_container_traits<std::set<Key, Args...>>
        : internal::container_traits<
            std::set<Key, Args...>,
            internal::basic_container,
            internal::basic_associative_container,
            internal::basic_dynamic_container,
            internal::basic_dynamic_associative_container,
            internal::dynamic_associative_key_only_container
        >
{};

/**
 * @brief Meta associative container traits for `std::unordered_set`s of any
 * type.
 * @tparam Key The type of elements.
 * @tparam Args Other arguments.
 */
template<typename Key, typename... Args>
struct meta_associative_container_traits<std::unordered_set<Key, Args...>>
        : internal::container_traits<
            std::unordered_set<Key, Args...>,
            internal::basic_container,
            internal::basic_associative_container,
            internal::basic_dynamic_container,
            internal::basic_dynamic_associative_container,
            internal::dynamic_associative_key_only_container
        >
{};

}

#endif
<commit_msg>meta: containers traits are no longer internal details only<commit_after>#ifndef ENTT_META_CONTAINER_HPP
#define ENTT_META_CONTAINER_HPP

#include <array>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
#include "../config/config.h"
#include "type_traits.hpp"

namespace entt {

/**
 * @brief Container traits.
 * @tparam Container Type of the underlying container.
 * @tparam Trait Traits associated with the underlying container.
 */
template<typename Container, template<typename> class... Trait>
struct container_traits: public Trait<Container>... {};

/**
 * @brief Basic STL-compatible container traits
 * @tparam Container The type of the container.
 */
template<typename Container>
struct basic_container {
    /*! @brief Iterator type of the container. */
    using iterator = typename Container::iterator;
    /*! @brief Unsigned integer type. */
    using size_type = typename Container::size_type;
    /*! @brief Value type of the container. */
    using value_type = typename Container::value_type;

    /**
     * @brief Returns the size of the given container.
     * @param cont The container for which to return the size.
     * @return The size of the given container.
     */
    [[nodiscard]] static size_type size(const Container &cont) ENTT_NOEXCEPT {
        return cont.size();
    }

    /**
     * @brief Returns an iterator to the first element of the given container.
     * @param cont The container for which to return the iterator.
     * @return An iterator to the first element of the given container.
     */
    [[nodiscard]] static iterator begin(Container &cont) {
        return cont.begin();
    }

    /**
     * @brief Returns an iterator past the last element of the given container.
     * @param cont The container for which to return the iterator.
     * @return An iterator past the last element of the given container.
     */
    [[nodiscard]] static iterator end(Container &cont) {
        return cont.end();
    }
};

/**
 * @brief Basic STL-compatible associative container traits
 * @tparam Container The type of the container.
 */
template<typename Container>
struct basic_associative_container {
    /*! @brief Key type of the sequence container. */
    using key_type = typename Container::key_type;

    /**
     * @brief Returns an iterator to the element with key equivalent to the given
     * one, if any.
     * @param cont The container in which to search for the element.
     * @param key The key of the element to search.
     * @return An iterator to the element with the given key, if any.
     */
    [[nodiscard]] static typename Container::iterator find(Container &cont, const key_type &key) {
        return cont.find(key);
    }
};

/**
 * @brief Basic STL-compatible dynamic container traits
 * @tparam Container The type of the container.
 */
template<typename Container>
struct basic_dynamic_container {
    /**
     * @brief Clears the content of the given container.
     * @param cont The container for which to clear the content.
     * @return True in case of success, false otherwise.
     */
    [[nodiscard]] static bool clear(Container &cont) {
        return cont.clear(), true;
    }
};

/**
 * @brief Basic STL-compatible dynamic associative container traits
 * @tparam Container The type of the container.
 */
template<typename Container>
struct basic_dynamic_associative_container {
    /**
     * @brief Removes the specified element from the given container.
     * @param cont The container from which to remove the element.
     * @param key The element to remove.
     * @return A bool denoting whether the removal took place.
     */
    [[nodiscard]] static bool erase(Container &cont, const typename Container::key_type &key) {
        const auto sz = cont.size();
        return cont.erase(key) != sz;
    }
};

/**
 * @brief Basic STL-compatible sequence container traits
 * @tparam Container The type of the container.
 */
template<typename Container>
struct basic_sequence_container {
    /**
     * @brief Returns a reference to the element at the specified location of the
     * given container (no bounds checking is performed).
     * @param cont The container from which to get the element.
     * @param pos The position of the element to return.
     * @return A reference to the requested element.
     */
    [[nodiscard]] static typename Container::value_type & get(Container &cont, typename Container::size_type pos) {
        return cont[pos];
    }
};

/**
 * @brief STL-compatible dynamic associative key-only container traits
 * @tparam Container The type of the container.
 */
template<typename Container>
struct dynamic_associative_key_only_container {
    /**
     * @brief Inserts an element into the given container.
     * @param cont The container in which to insert the element.
     * @param key The element to insert.
     * @return A bool denoting whether the insertion took place.
     */
    [[nodiscard]] static bool insert(Container &cont, const typename Container::key_type &key) {
        return cont.insert(key).second;
    }
};

/**
 * @brief STL-compatible dynamic key-value associative container traits
 * @tparam Container The type of the container.
 */
template<typename Container>
struct dynamic_associative_key_value_container {
    /**
     * @brief Inserts an element (a key/value pair) into the given container.
     * @param cont The container in which to insert the element.
     * @param key The key of the element to insert.
     * @param value The value of the element to insert.
     * @return A bool denoting whether the insertion took place.
     */
    [[nodiscard]] static bool insert(Container &cont, const typename Container::key_type &key, const typename Container::mapped_type &value) {
        return cont.insert(std::make_pair(key, value)).second;
    }
};

/**
 * @brief STL-compatible dynamic sequence container traits
 * @tparam Container The type of the container.
 */
template<typename Container>
struct dynamic_sequence_container {
    /**
     * @brief Resizes the given container to contain the given number of elements.
     * @param cont The container to resize.
     * @param sz The new size of the container.
     * @return True in case of success, false otherwise.
     */
    [[nodiscard]] static bool resize(Container &cont, typename Container::size_type sz) {
        return (cont.resize(sz), true);
    }

    /**
     * @brief Inserts an element at the specified location of the given container.
     * @param cont The container into which to insert the element.
     * @param it Iterator before which the element will be inserted.
     * @param value Element value to insert.
     * @return A pair consisting of an iterator to the inserted element (in case
     * of success) and a bool denoting whether the insertion took place.
     */
    [[nodiscard]] static std::pair<typename Container::iterator, bool> insert(Container &cont, typename Container::iterator it, const typename Container::value_type &value) {
        return { cont.insert(it, value), true };
    }

    /**
     * @brief Removes the element at the specified location from the given container.
     * @param cont The container from which to remove the element.
     * @param it Iterator to the element to remove.
     * @return A pair consisting of an iterator following the last removed
     * element (in case of success) and a bool denoting whether the insertion
     * took place.
     */
    [[nodiscard]] static std::pair<typename Container::iterator, bool> erase(Container &cont, typename Container::iterator it) {
        return { cont.erase(it), true };
    }
};

/**
 * @brief STL-compatible fixed sequence container traits
 * @tparam Container The type of the container.
 */
template<typename Container>
struct fixed_sequence_container {
    /**
     * @brief Does nothing.
     * @return False to indicate failure in all cases.
     */
    [[nodiscard]] static bool resize(const Container &, typename Container::size_type) {
        return false;
    }

    /**
     * @brief Does nothing.
     * @return False to indicate failure in all cases.
     */
    [[nodiscard]] static bool clear(const Container &) {
        return false;
    }

    /**
     * @brief Does nothing.
     * @return A pair consisting of an invalid iterator and a false value to
     * indicate failure in all cases.
     */
    [[nodiscard]] static std::pair<typename Container::iterator, bool> insert(const Container &, typename Container::iterator, const typename Container::value_type &) {
        return { {}, false };
    }

    /**
     * @brief Does nothing.
     * @return A pair consisting of an invalid iterator and a false value to
     * indicate failure in all cases.
     */
    [[nodiscard]] static std::pair<typename Container::iterator, bool> erase(const Container &, typename Container::iterator) {
        return { {}, false };
    }
};

/**
 * @brief Meta sequence container traits for `std::vector`s of any type.
 * @tparam Type The type of elements.
 * @tparam Args Other arguments.
 */
template<typename Type, typename... Args>
struct meta_sequence_container_traits<std::vector<Type, Args...>>
        : container_traits<
            std::vector<Type, Args...>,
            basic_container,
            basic_dynamic_container,
            basic_sequence_container,
            dynamic_sequence_container
        >
{};

/**
 * @brief Meta sequence container traits for `std::array`s of any type.
 * @tparam Type The type of elements.
 * @tparam N The number of elements.
 */
template<typename Type, auto N>
struct meta_sequence_container_traits<std::array<Type, N>>
        : container_traits<
            std::array<Type, N>,
            basic_container,
            basic_sequence_container,
            fixed_sequence_container
        >
{};

/**
 * @brief Meta associative container traits for `std::map`s of any type.
 * @tparam Key The key type of elements.
 * @tparam Value The value type of elements.
 * @tparam Args Other arguments.
 */
template<typename Key, typename Value, typename... Args>
struct meta_associative_container_traits<std::map<Key, Value, Args...>>
        : container_traits<
            std::map<Key, Value, Args...>,
            basic_container,
            basic_associative_container,
            basic_dynamic_container,
            basic_dynamic_associative_container,
            dynamic_associative_key_value_container
        >
{
    /*! @brief Mapped type of the sequence container. */
    using mapped_type = typename std::map<Key, Value, Args...>::mapped_type;
};

/**
 * @brief Meta associative container traits for `std::unordered_map`s of any
 * type.
 * @tparam Key The key type of elements.
 * @tparam Value The value type of elements.
 * @tparam Args Other arguments.
 */
template<typename Key, typename Value, typename... Args>
struct meta_associative_container_traits<std::unordered_map<Key, Value, Args...>>
        : container_traits<
            std::unordered_map<Key, Value, Args...>,
            basic_container,
            basic_associative_container,
            basic_dynamic_container,
            basic_dynamic_associative_container,
            dynamic_associative_key_value_container
        >
{
    /*! @brief Mapped type of the sequence container. */
    using mapped_type = typename std::unordered_map<Key, Value, Args...>::mapped_type;
};

/**
 * @brief Meta associative container traits for `std::set`s of any type.
 * @tparam Key The type of elements.
 * @tparam Args Other arguments.
 */
template<typename Key, typename... Args>
struct meta_associative_container_traits<std::set<Key, Args...>>
        : container_traits<
            std::set<Key, Args...>,
            basic_container,
            basic_associative_container,
            basic_dynamic_container,
            basic_dynamic_associative_container,
            dynamic_associative_key_only_container
        >
{};

/**
 * @brief Meta associative container traits for `std::unordered_set`s of any
 * type.
 * @tparam Key The type of elements.
 * @tparam Args Other arguments.
 */
template<typename Key, typename... Args>
struct meta_associative_container_traits<std::unordered_set<Key, Args...>>
        : container_traits<
            std::unordered_set<Key, Args...>,
            basic_container,
            basic_associative_container,
            basic_dynamic_container,
            basic_dynamic_associative_container,
            dynamic_associative_key_only_container
        >
{};

}

#endif
<|endoftext|>


<commit_before>/*
 * Copyright 2015 Realm Inc.
 *
 * 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 "io_realm_internal_CheckedRow.h"
#include "io_realm_internal_UncheckedRow.h"

#include "util.hpp"

using namespace realm;

JNIEXPORT jlong JNICALL Java_io_realm_internal_CheckedRow_nativeGetColumnCount(JNIEnv* env, jobject obj,
                                                                               jlong nativeRowPtr)
{
    if (!ROW(nativeRowPtr)->is_attached()) {
        return 0;
    }

    return Java_io_realm_internal_UncheckedRow_nativeGetColumnCount(env, obj, nativeRowPtr);
}

JNIEXPORT jstring JNICALL Java_io_realm_internal_CheckedRow_nativeGetColumnName(JNIEnv* env, jobject obj,
                                                                                jlong nativeRowPtr, jlong columnIndex)
{
    if (!ROW_AND_COL_INDEX_VALID(env, ROW(nativeRowPtr), columnIndex)) {
        return NULL;
    }

    return Java_io_realm_internal_UncheckedRow_nativeGetColumnName(env, obj, nativeRowPtr, columnIndex);
}

JNIEXPORT jlong JNICALL Java_io_realm_internal_CheckedRow_nativeGetColumnIndex(JNIEnv* env, jobject obj,
                                                                               jlong nativeRowPtr, jstring columnName)
{
    if (!ROW(nativeRowPtr)->is_attached())
        return 0;

    jlong ndx = Java_io_realm_internal_UncheckedRow_nativeGetColumnIndex(env, obj, nativeRowPtr, columnName);
    if (ndx == to_jlong_or_not_found(realm::not_found)) {
        JStringAccessor column_name(env, columnName);
        ThrowException(env, IllegalArgument, concat_stringdata("Field not found: ", column_name));
        return 0;
    }
    else {
        return ndx;
    }
}

JNIEXPORT jint JNICALL Java_io_realm_internal_CheckedRow_nativeGetColumnType(JNIEnv* env, jobject obj,
                                                                             jlong nativeRowPtr, jlong columnIndex)
{
    if (!ROW_AND_COL_INDEX_VALID(env, ROW(nativeRowPtr), columnIndex)) {
        return 0;
    }

    return Java_io_realm_internal_UncheckedRow_nativeGetColumnType(env, obj, nativeRowPtr, columnIndex);
}

JNIEXPORT jlong JNICALL Java_io_realm_internal_CheckedRow_nativeGetLong(JNIEnv* env, jobject obj, jlong nativeRowPtr,
                                                                        jlong columnIndex)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_Int)) {
        return 0;
    }

    return Java_io_realm_internal_UncheckedRow_nativeGetLong(env, obj, nativeRowPtr, columnIndex);
}

JNIEXPORT jboolean JNICALL Java_io_realm_internal_CheckedRow_nativeGetBoolean(JNIEnv* env, jobject obj,
                                                                              jlong nativeRowPtr, jlong columnIndex)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_Bool)) {
        return 0;
    }

    return Java_io_realm_internal_UncheckedRow_nativeGetBoolean(env, obj, nativeRowPtr, columnIndex);
}

JNIEXPORT jfloat JNICALL Java_io_realm_internal_CheckedRow_nativeGetFloat(JNIEnv* env, jobject obj,
                                                                          jlong nativeRowPtr, jlong columnIndex)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_Float)) {
        return 0;
    }

    return Java_io_realm_internal_UncheckedRow_nativeGetFloat(env, obj, nativeRowPtr, columnIndex);
}

JNIEXPORT jdouble JNICALL Java_io_realm_internal_CheckedRow_nativeGetDouble(JNIEnv* env, jobject obj,
                                                                            jlong nativeRowPtr, jlong columnIndex)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_Double)) {
        return 0;
    }

    return Java_io_realm_internal_UncheckedRow_nativeGetDouble(env, obj, nativeRowPtr, columnIndex);
}

JNIEXPORT jlong JNICALL Java_io_realm_internal_CheckedRow_nativeGetTimestamp(JNIEnv* env, jobject obj,
                                                                             jlong nativeRowPtr, jlong columnIndex)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_Timestamp)) {
        return 0;
    }

    return Java_io_realm_internal_UncheckedRow_nativeGetTimestamp(env, obj, nativeRowPtr, columnIndex);
}

JNIEXPORT jstring JNICALL Java_io_realm_internal_CheckedRow_nativeGetString(JNIEnv* env, jobject obj,
                                                                            jlong nativeRowPtr, jlong columnIndex)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_String)) {
        return 0;
    }

    return Java_io_realm_internal_UncheckedRow_nativeGetString(env, obj, nativeRowPtr, columnIndex);
}

JNIEXPORT jbyteArray JNICALL Java_io_realm_internal_CheckedRow_nativeGetByteArray(JNIEnv* env, jobject obj,
                                                                                jlong nativeRowPtr,
                                                                                jlong columnIndex)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_Binary)) {
        return 0;
    }

    return Java_io_realm_internal_UncheckedRow_nativeGetByteArray(env, obj, nativeRowPtr, columnIndex);
}

JNIEXPORT jlong JNICALL Java_io_realm_internal_CheckedRow_nativeGetLink(JNIEnv* env, jobject obj, jlong nativeRowPtr,
                                                                        jlong columnIndex)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_Link)) {
        return 0;
    }

    return Java_io_realm_internal_UncheckedRow_nativeGetLink(env, obj, nativeRowPtr, columnIndex);
}

JNIEXPORT jboolean JNICALL Java_io_realm_internal_CheckedRow_nativeIsNullLink(JNIEnv* env, jobject obj,
                                                                              jlong nativeRowPtr, jlong columnIndex)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_Link)) {
        return 0;
    }

    return Java_io_realm_internal_UncheckedRow_nativeIsNullLink(env, obj, nativeRowPtr, columnIndex);
}

JNIEXPORT jlong JNICALL Java_io_realm_internal_CheckedRow_nativeGetLinkView(JNIEnv* env, jobject obj,
                                                                            jlong nativeRowPtr, jlong columnIndex)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_LinkList)) {
        return 0;
    }

    return Java_io_realm_internal_UncheckedRow_nativeGetLinkView(env, obj, nativeRowPtr, columnIndex);
}

JNIEXPORT void JNICALL Java_io_realm_internal_CheckedRow_nativeSetLong(JNIEnv* env, jobject obj, jlong nativeRowPtr,
                                                                       jlong columnIndex, jlong value)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_Int)) {
        return;
    }

    Java_io_realm_internal_UncheckedRow_nativeSetLong(env, obj, nativeRowPtr, columnIndex, value);
}

JNIEXPORT void JNICALL Java_io_realm_internal_CheckedRow_nativeSetBoolean(JNIEnv* env, jobject obj,
                                                                          jlong nativeRowPtr, jlong columnIndex,
                                                                          jboolean value)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_Bool)) {
        return;
    }

    Java_io_realm_internal_UncheckedRow_nativeSetBoolean(env, obj, nativeRowPtr, columnIndex, value);
}

JNIEXPORT void JNICALL Java_io_realm_internal_CheckedRow_nativeSetFloat(JNIEnv* env, jobject obj, jlong nativeRowPtr,
                                                                        jlong columnIndex, jfloat value)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_Float)) {
        return;
    }

    Java_io_realm_internal_UncheckedRow_nativeSetFloat(env, obj, nativeRowPtr, columnIndex, value);
}

JNIEXPORT void JNICALL Java_io_realm_internal_CheckedRow_nativeSetDouble(JNIEnv* env, jobject obj, jlong nativeRowPtr,
                                                                         jlong columnIndex, jdouble value)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_Double)) {
        return;
    }

    Java_io_realm_internal_UncheckedRow_nativeSetDouble(env, obj, nativeRowPtr, columnIndex, value);
}

JNIEXPORT void JNICALL Java_io_realm_internal_CheckedRow_nativeSetTimestamp(JNIEnv* env, jobject obj,
                                                                            jlong nativeRowPtr, jlong columnIndex,
                                                                            jlong value)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_Timestamp)) {
        return;
    }

    Java_io_realm_internal_UncheckedRow_nativeSetTimestamp(env, obj, nativeRowPtr, columnIndex, value);
}

JNIEXPORT void JNICALL Java_io_realm_internal_CheckedRow_nativeSetString(JNIEnv* env, jobject obj, jlong nativeRowPtr,
                                                                         jlong columnIndex, jstring value)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_String)) {
        return;
    }

    Java_io_realm_internal_UncheckedRow_nativeSetString(env, obj, nativeRowPtr, columnIndex, value);
}

JNIEXPORT void JNICALL Java_io_realm_internal_CheckedRow_nativeSetByteArray(JNIEnv* env, jobject obj,
                                                                            jlong nativeRowPtr, jlong columnIndex,
                                                                            jbyteArray value)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_Binary)) {
        return;
    }

    Java_io_realm_internal_UncheckedRow_nativeSetByteArray(env, obj, nativeRowPtr, columnIndex, value);
}

JNIEXPORT void JNICALL Java_io_realm_internal_CheckedRow_nativeSetLink(JNIEnv* env, jobject obj, jlong nativeRowPtr,
                                                                       jlong columnIndex, jlong value)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_Link)) {
        return;
    }

    Java_io_realm_internal_UncheckedRow_nativeSetLink(env, obj, nativeRowPtr, columnIndex, value);
}

JNIEXPORT void JNICALL Java_io_realm_internal_CheckedRow_nativeNullifyLink(JNIEnv* env, jobject obj,
                                                                           jlong nativeRowPtr, jlong columnIndex)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_Link)) {
        return;
    }

    Java_io_realm_internal_UncheckedRow_nativeNullifyLink(env, obj, nativeRowPtr, columnIndex);
}
<commit_msg>Fix return values in JNI unchecked row<commit_after>/*
 * Copyright 2015 Realm Inc.
 *
 * 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 "io_realm_internal_CheckedRow.h"
#include "io_realm_internal_UncheckedRow.h"

#include "util.hpp"

using namespace realm;

JNIEXPORT jlong JNICALL Java_io_realm_internal_CheckedRow_nativeGetColumnCount(JNIEnv* env, jobject obj,
                                                                               jlong nativeRowPtr)
{
    if (!ROW(nativeRowPtr)->is_attached()) {
        return 0;
    }

    return Java_io_realm_internal_UncheckedRow_nativeGetColumnCount(env, obj, nativeRowPtr);
}

JNIEXPORT jstring JNICALL Java_io_realm_internal_CheckedRow_nativeGetColumnName(JNIEnv* env, jobject obj,
                                                                                jlong nativeRowPtr, jlong columnIndex)
{
    if (!ROW_AND_COL_INDEX_VALID(env, ROW(nativeRowPtr), columnIndex)) {
        return nullptr;
    }

    return Java_io_realm_internal_UncheckedRow_nativeGetColumnName(env, obj, nativeRowPtr, columnIndex);
}

JNIEXPORT jlong JNICALL Java_io_realm_internal_CheckedRow_nativeGetColumnIndex(JNIEnv* env, jobject obj,
                                                                               jlong nativeRowPtr, jstring columnName)
{
    if (!ROW(nativeRowPtr)->is_attached())
        return 0;

    jlong ndx = Java_io_realm_internal_UncheckedRow_nativeGetColumnIndex(env, obj, nativeRowPtr, columnName);
    if (ndx == to_jlong_or_not_found(realm::not_found)) {
        JStringAccessor column_name(env, columnName);
        ThrowException(env, IllegalArgument, concat_stringdata("Field not found: ", column_name));
        return 0;
    }
    else {
        return ndx;
    }
}

JNIEXPORT jint JNICALL Java_io_realm_internal_CheckedRow_nativeGetColumnType(JNIEnv* env, jobject obj,
                                                                             jlong nativeRowPtr, jlong columnIndex)
{
    if (!ROW_AND_COL_INDEX_VALID(env, ROW(nativeRowPtr), columnIndex)) {
        return 0;
    }

    return Java_io_realm_internal_UncheckedRow_nativeGetColumnType(env, obj, nativeRowPtr, columnIndex);
}

JNIEXPORT jlong JNICALL Java_io_realm_internal_CheckedRow_nativeGetLong(JNIEnv* env, jobject obj, jlong nativeRowPtr,
                                                                        jlong columnIndex)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_Int)) {
        return 0;
    }

    return Java_io_realm_internal_UncheckedRow_nativeGetLong(env, obj, nativeRowPtr, columnIndex);
}

JNIEXPORT jboolean JNICALL Java_io_realm_internal_CheckedRow_nativeGetBoolean(JNIEnv* env, jobject obj,
                                                                              jlong nativeRowPtr, jlong columnIndex)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_Bool)) {
        return JNI_FALSE;
    }

    return Java_io_realm_internal_UncheckedRow_nativeGetBoolean(env, obj, nativeRowPtr, columnIndex);
}

JNIEXPORT jfloat JNICALL Java_io_realm_internal_CheckedRow_nativeGetFloat(JNIEnv* env, jobject obj,
                                                                          jlong nativeRowPtr, jlong columnIndex)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_Float)) {
        return 0;
    }

    return Java_io_realm_internal_UncheckedRow_nativeGetFloat(env, obj, nativeRowPtr, columnIndex);
}

JNIEXPORT jdouble JNICALL Java_io_realm_internal_CheckedRow_nativeGetDouble(JNIEnv* env, jobject obj,
                                                                            jlong nativeRowPtr, jlong columnIndex)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_Double)) {
        return 0;
    }

    return Java_io_realm_internal_UncheckedRow_nativeGetDouble(env, obj, nativeRowPtr, columnIndex);
}

JNIEXPORT jlong JNICALL Java_io_realm_internal_CheckedRow_nativeGetTimestamp(JNIEnv* env, jobject obj,
                                                                             jlong nativeRowPtr, jlong columnIndex)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_Timestamp)) {
        return 0;
    }

    return Java_io_realm_internal_UncheckedRow_nativeGetTimestamp(env, obj, nativeRowPtr, columnIndex);
}

JNIEXPORT jstring JNICALL Java_io_realm_internal_CheckedRow_nativeGetString(JNIEnv* env, jobject obj,
                                                                            jlong nativeRowPtr, jlong columnIndex)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_String)) {
        return nullptr;
    }

    return Java_io_realm_internal_UncheckedRow_nativeGetString(env, obj, nativeRowPtr, columnIndex);
}

JNIEXPORT jbyteArray JNICALL Java_io_realm_internal_CheckedRow_nativeGetByteArray(JNIEnv* env, jobject obj,
                                                                                jlong nativeRowPtr,
                                                                                jlong columnIndex)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_Binary)) {
        return nullptr;
    }

    return Java_io_realm_internal_UncheckedRow_nativeGetByteArray(env, obj, nativeRowPtr, columnIndex);
}

JNIEXPORT jlong JNICALL Java_io_realm_internal_CheckedRow_nativeGetLink(JNIEnv* env, jobject obj, jlong nativeRowPtr,
                                                                        jlong columnIndex)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_Link)) {
        return 0;
    }

    return Java_io_realm_internal_UncheckedRow_nativeGetLink(env, obj, nativeRowPtr, columnIndex);
}

JNIEXPORT jboolean JNICALL Java_io_realm_internal_CheckedRow_nativeIsNullLink(JNIEnv* env, jobject obj,
                                                                              jlong nativeRowPtr, jlong columnIndex)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_Link)) {
        return JNI_FALSE;
    }

    return Java_io_realm_internal_UncheckedRow_nativeIsNullLink(env, obj, nativeRowPtr, columnIndex);
}

JNIEXPORT jlong JNICALL Java_io_realm_internal_CheckedRow_nativeGetLinkView(JNIEnv* env, jobject obj,
                                                                            jlong nativeRowPtr, jlong columnIndex)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_LinkList)) {
        return 0;
    }

    return Java_io_realm_internal_UncheckedRow_nativeGetLinkView(env, obj, nativeRowPtr, columnIndex);
}

JNIEXPORT void JNICALL Java_io_realm_internal_CheckedRow_nativeSetLong(JNIEnv* env, jobject obj, jlong nativeRowPtr,
                                                                       jlong columnIndex, jlong value)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_Int)) {
        return;
    }

    Java_io_realm_internal_UncheckedRow_nativeSetLong(env, obj, nativeRowPtr, columnIndex, value);
}

JNIEXPORT void JNICALL Java_io_realm_internal_CheckedRow_nativeSetBoolean(JNIEnv* env, jobject obj,
                                                                          jlong nativeRowPtr, jlong columnIndex,
                                                                          jboolean value)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_Bool)) {
        return;
    }

    Java_io_realm_internal_UncheckedRow_nativeSetBoolean(env, obj, nativeRowPtr, columnIndex, value);
}

JNIEXPORT void JNICALL Java_io_realm_internal_CheckedRow_nativeSetFloat(JNIEnv* env, jobject obj, jlong nativeRowPtr,
                                                                        jlong columnIndex, jfloat value)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_Float)) {
        return;
    }

    Java_io_realm_internal_UncheckedRow_nativeSetFloat(env, obj, nativeRowPtr, columnIndex, value);
}

JNIEXPORT void JNICALL Java_io_realm_internal_CheckedRow_nativeSetDouble(JNIEnv* env, jobject obj, jlong nativeRowPtr,
                                                                         jlong columnIndex, jdouble value)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_Double)) {
        return;
    }

    Java_io_realm_internal_UncheckedRow_nativeSetDouble(env, obj, nativeRowPtr, columnIndex, value);
}

JNIEXPORT void JNICALL Java_io_realm_internal_CheckedRow_nativeSetTimestamp(JNIEnv* env, jobject obj,
                                                                            jlong nativeRowPtr, jlong columnIndex,
                                                                            jlong value)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_Timestamp)) {
        return;
    }

    Java_io_realm_internal_UncheckedRow_nativeSetTimestamp(env, obj, nativeRowPtr, columnIndex, value);
}

JNIEXPORT void JNICALL Java_io_realm_internal_CheckedRow_nativeSetString(JNIEnv* env, jobject obj, jlong nativeRowPtr,
                                                                         jlong columnIndex, jstring value)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_String)) {
        return;
    }

    Java_io_realm_internal_UncheckedRow_nativeSetString(env, obj, nativeRowPtr, columnIndex, value);
}

JNIEXPORT void JNICALL Java_io_realm_internal_CheckedRow_nativeSetByteArray(JNIEnv* env, jobject obj,
                                                                            jlong nativeRowPtr, jlong columnIndex,
                                                                            jbyteArray value)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_Binary)) {
        return;
    }

    Java_io_realm_internal_UncheckedRow_nativeSetByteArray(env, obj, nativeRowPtr, columnIndex, value);
}

JNIEXPORT void JNICALL Java_io_realm_internal_CheckedRow_nativeSetLink(JNIEnv* env, jobject obj, jlong nativeRowPtr,
                                                                       jlong columnIndex, jlong value)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_Link)) {
        return;
    }

    Java_io_realm_internal_UncheckedRow_nativeSetLink(env, obj, nativeRowPtr, columnIndex, value);
}

JNIEXPORT void JNICALL Java_io_realm_internal_CheckedRow_nativeNullifyLink(JNIEnv* env, jobject obj,
                                                                           jlong nativeRowPtr, jlong columnIndex)
{
    if (!ROW_AND_COL_INDEX_AND_TYPE_VALID(env, ROW(nativeRowPtr), columnIndex, type_Link)) {
        return;
    }

    Java_io_realm_internal_UncheckedRow_nativeNullifyLink(env, obj, nativeRowPtr, columnIndex);
}
<|endoftext|>


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

/*
 * ErrorDescriptor.cpp
 *
 *  Created on: Jan 10, 2012
 *      Author: Dimitar Asenov
 */

#include "expression_editor/ErrorDescriptor.h"

namespace Interaction {

ErrorDescriptor::ErrorDescriptor(const QString& prefix_text, const QString& postfix_text)
	:OperatorDescriptor("Error: " + prefix_text + postfix_text, prefix_text + " expr " + postfix_text, 1, 0,
		prefix_text.isEmpty() ? OperatorDescriptor::LeftAssociative : OperatorDescriptor::RightAssociative),
		errorPrefix_(prefix_text), errorPostfix_(postfix_text)
{
	setTransient(true);
}

} /* namespace InteractionBase */
<commit_msg>Fix a bug where creating an ErrorExpression with space operator crashes<commit_after>/***********************************************************************************************************************
**
** Copyright (c) 2011, 2012 ETH Zurich
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
** following conditions are met:
**
**    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
**      disclaimer.
**    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
**      following disclaimer in the documentation and/or other materials provided with the distribution.
**    * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
**      derived from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
***********************************************************************************************************************/

/*
 * ErrorDescriptor.cpp
 *
 *  Created on: Jan 10, 2012
 *      Author: Dimitar Asenov
 */

#include "expression_editor/ErrorDescriptor.h"

namespace Interaction {

ErrorDescriptor::ErrorDescriptor(const QString& prefix_text, const QString& postfix_text)
	:OperatorDescriptor("Error: " + prefix_text + postfix_text,
		QString(prefix_text).replace(" ", " space ") + " expr " + QString(postfix_text).replace(" ", " space "),
		1, 0,
		prefix_text.isEmpty() ? OperatorDescriptor::LeftAssociative : OperatorDescriptor::RightAssociative),
		errorPrefix_(prefix_text), errorPostfix_(postfix_text)
{
	setTransient(true);
}

} /* namespace InteractionBase */
<|endoftext|>


<commit_before>#include <algorithm>
#include <cassert>
#include <cstdint>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <locale>
#include <numeric>
#include <string>
#include <stdexcept>
#include <tuple>
#include <vector>

#include <parallel/algorithm>

#include <immintrin.h>

#ifdef HAVE_PAPI
    #include <papi.h>
#endif

#ifdef HAVE_MKL
    #include <mkl.h>
    #include <abhsf/utils/mkl_csr_spmv_helper.h>
#endif

#include <abhsf/utils/colors.h>
#include <abhsf/utils/coo2csr.h>
#include <abhsf/utils/matrix_properties.h>
#include <abhsf/utils/matrix_market_reader.h>
#include <abhsf/utils/restrict.h>
#include <abhsf/utils/synthetic.h>
#include <abhsf/utils/timer.h>
#include <abhsf/utils/thousands_separator.h>

static const int warmup_iters = 4;
static const int n_iters = 40;

using element_t = std::tuple<int, int, double>;
using elements_t = std::vector<element_t>;

template <typename REAL_T, typename ROW_PTR_T, typename COL_IND_T>
class csr_matrix
{
    public:
        void from_elements(elements_t& elements, const matrix_properties& props)
        {
            m_ = props.m;
            n_ = props.n;
            nnz_ = elements.size();
            coo2csr(elements, m_, a_, ia_, ja_);
        }

        void spmv(const REAL_T* RESTRICT x, REAL_T* RESTRICT y)
        {
         // mkl_csr_spmv_helper<REAL_T>::spmv(m_, n_, a_.data(), ia_.data(), ja_.data(), x, y); // MKL version
         // spmv_naive(x, y);
            spmv_naive_1_nnz_per_row(x, y);
        }

        void spmv_naive(const REAL_T* RESTRICT x, REAL_T* RESTRICT y)
        {
            #pragma omp parallel for schedule(static)
            for (long row = 0; row < m_; row++)
                for (long k = ia_[row]; k < ia_[row + 1]; k++)
                    y[row] += a_[k] * x[ja_[k]];
        }

        void spmv_naive_1_nnz_per_row(const REAL_T* RESTRICT x, REAL_T* RESTRICT y)
        {
/*
            #pragma omp parallel for schedule(static)
            for (long first_row = 0; first_row < m_; first_row += 8) {
                _mm_prefetch((const char*)(x + ja_[first_row + 64 + 0]), _MM_HINT_T2);
                _mm_prefetch((const char*)(x + ja_[first_row + 64 + 1]), _MM_HINT_T2);
                _mm_prefetch((const char*)(x + ja_[first_row + 64 + 2]), _MM_HINT_T2);
                _mm_prefetch((const char*)(x + ja_[first_row + 64 + 3]), _MM_HINT_T2);
                _mm_prefetch((const char*)(x + ja_[first_row + 64 + 4]), _MM_HINT_T2);
                _mm_prefetch((const char*)(x + ja_[first_row + 64 + 5]), _MM_HINT_T2);
                _mm_prefetch((const char*)(x + ja_[first_row + 64 + 6]), _MM_HINT_T2);
                _mm_prefetch((const char*)(x + ja_[first_row + 64 + 7]), _MM_HINT_T2);

                for (long j = 0; j < 8; j++) {
                    long row = first_row + j;
                    long k = row; // ia_[row];
                    y[row] += a_[k] * x[ja_[k]];
                }
            }
*/

            #pragma omp parallel for schedule(static)
            for (long row = 0; row < m_; row++) {
                long k = ia_[row];
                y[row] += a_[k] * x[ja_[k]];
            }
        }

/*
        void spmv(const real_type* RESTRICT x, real_type* RESTRICT y)
        {
#pragma omp parallel for schedule(static)
            for (index_type row = 0; row < m_; row++) {
                index_type k = ia_[row];
                while (k + 63 < ia_[row + 1]) {
                    for (int i = 0; i < 64; i++)
                        y[row] += x[ja_[k + i]];
                    k += 64;
                }
                while (k < ia_[row + 1])
                    y[row] += x[ja_[k++]];
/ *
                for (index_type k = ia_[row]; k < ia_[row + 1]; k++) {
                 // y[row] += a_[k] * x[ja_[k]];
                    y[row] += x[ja_[k]];
                }
* /
            }
        }
*/

        void release()
        {
            a_.clear();
            a_.shrink_to_fit();
            ia_.clear();
            ia_.shrink_to_fit();
            ja_.clear();
            ja_.shrink_to_fit();
        }

    private:
        std::vector<REAL_T> a_;
        std::vector<ROW_PTR_T> ia_;
        std::vector<COL_IND_T> ja_;
        long m_, n_, nnz_;
};

/*
class coo_matrix
{
    public:
        void from_elements(elements_t& elements, const matrix_properties& props)
        {
         // std::sort(elements.begin(), elements.end());
            __gnu_parallel::sort(elements.begin(), elements.end());

            m_ = props.m;
            n_ = props.n;
            nnz_ = elements.size();

            a_.resize(nnz_);
            ia_.resize(nnz_);
            ja_.resize(nnz_);

            for (size_t k = 0; k < nnz_; k++) {
                a_[k] = std::get<2>(elements[k]);
                ia_[k] = std::get<0>(elements[k]);
                ja_[k] = std::get<1>(elements[k]);
            }
        }

        void spmv(const real_type* RESTRICT x, real_type* RESTRICT y)
        {
#pragma omp parallel for
            for (size_t k = 0; k < nnz_; k++)
#pragma omp atomic update
                y[ia_[k]] += a_[k] * x[ja_[k]];
        }

        void spmv_clever(const real_type* RESTRICT x, real_type* RESTRICT y)
        {
#pragma omp parallel
            {
                // split work
                long per = nnz_ / omp_get_num_threads();
                long first = omp_get_thread_num() * per;
                long last = first + per - 1;
                if (last > (nnz_ - 1))
                    last = nnz_ - 1;

                long row = ia_[first];
             // real_type y_ = a_[first] * x[ja_[first]];
                real_type y_ = x[ja_[first]];

                long k = first + 1;
                while (k <= last) {
                    if (ia_[k] != row) {
#pragma omp atomic update
                        y[row] += y_;
                        row = ia_[k];
                     // y_ = a_[k] * x[ja_[k]];
                        y_ = x[ja_[k]];
                        k++;
                        break;
                    }
                 // y_ += a_[k] * x[ja_[k]];
                    y_ += x[ja_[k]];
                    k++;
                }
                while (k <= last) {
                    if (ia_[k] != row) {
                        y[row] += y_;
                        y_ = 0.0;
                        row = ia_[k];
                    }
                 // y_ += a_[k] * x[ja_[k]];
                    y_ += x[ja_[k]];
                    k++;
                }
#pragma omp atomic update
                y[row] += y_;
            }
        }

        void release()
        {
            a_.clear();
            a_.shrink_to_fit();
            ia_.clear();
            ia_.shrink_to_fit();
            ja_.clear();
            ja_.shrink_to_fit();
        }

    private:
        std::vector<real_type> a_;
     // std::vector<index_type> ia_, ja_;
        std::vector<uint16_t> ia_, ja_;
        index_type m_, n_, nnz_;
};
*/

template <typename Iter>
double result(Iter begin, Iter end)
{
    double res = 0.0;
    while (begin != end) {
        res += *begin * *begin;
        ++begin;
    }
    return sqrt(res);
}

int main(int argc, char* argv[])
{
    std::cout.imbue(std::locale(std::locale(), new thousands_separator));

    using real_type = double;
    using timer_type = chrono_timer<>;

    matrix_properties props;
    elements_t elements;

    // matrix type selection:
    if (strcmp(argv[1], "dense") == 0) {
        std::cout << "Matrix: " << yellow << "DENSE" << reset << std::endl;
        synthetise_dense_matrix(props, elements, 20000);
    }
    else if (strcmp(argv[1], "diagonal") == 0) {
        std::cout << "Matrix: " << yellow << "DIAGONAL" << reset << std::endl;
        synthetise_diagonal_matrix(props, elements, 200000000);
    }
    else if (strcmp(argv[1], "single-column") == 0) {
        std::cout << "Matrix: " << yellow << "SINGLE-COLUMN" << reset << std::endl;
        synthetise_single_column_matrix(props, elements, 200000000);
    }
    else if (strcmp(argv[1], "random-column") == 0) {
        std::cout << "Matrix: " << yellow << "RANDOM-COLUMN" << reset << std::endl;
        synthetise_random_column_matrix(props, elements, 200000000);
    }
    else if (strcmp(argv[1], "single-row-column") == 0) {
        std::cout << "Matrix: " << yellow << "SINGLE-ROW-COLUMN" << reset << std::endl;
        synthetise_single_row_column_matrix(props, elements, 100000000);
    }
    else if (strcmp(argv[1], "single-row") == 0) {
        std::cout << "Matrix: " << yellow << "SINGLE-ROW" << reset << std::endl;
        synthetise_single_row_matrix(props, elements, 200000000);
    }
    else // read from file if not synthetic
        read_mtx_real_or_binary(argv[1], elements, props);

    // print out final dimensions
    std::cout << "Matrix dimensions: " << magenta <<
        props.m << " x " << props.n << " : " << props.nnz << " = " << elements.size() << reset << std::endl;

    // check matrix:
    if (props.symmetry != matrix_symmetry_t::UNSYMMETRIC)
        throw std::runtime_error("This program does support unsymmetric matrices only!");
    if (props.m != props.n)
        throw std::runtime_error("This program does support square matrices only!");

    // vectors:
    static const double x_element = 0.5;
    real_type *x, *y;
    posix_memalign((void**)(&x), 64, props.n * sizeof(real_type));
    posix_memalign((void**)(&y), 64, props.m * sizeof(real_type));
    std::fill(x, x + props.n, x_element);
    std::fill(y, y + props.m, 0.0);

    // verification
    std::vector<double> y_temp(props.m, 0.0);
    for (const auto& element : elements)
        y_temp[std::get<0>(element)] += std::get<2>(element) * x_element;
    std::cout << "Expected result = " << green << result(y_temp.cbegin(), y_temp.cend()) << reset << std::endl;
    y_temp.clear();
    y_temp.shrink_to_fit();

    const long nnz = elements.size();
    const double n_mflops = (double)(nnz * 2 * n_iters) / 1.0e6;

 // csr_matrix<real_type, MKL_INT, MKL_INT> A;
    csr_matrix<real_type, int, int> A;
 // coo_matrix A;

    A.from_elements(elements, props);
    timer_type timer;

    std::fill(y, y + props.m, 0.0);
    for (int iter = 0; iter < warmup_iters; iter++)
        A.spmv(x, y);
    timer.start();
    for (int iter = 0; iter < n_iters - 1; iter++)
        A.spmv(x, y);
    // last iteration:
#ifdef HAVE_PAPI
    int papi_events[4] = { PAPI_L1_TCM, PAPI_L2_TCM, PAPI_L3_TCM, PAPI_TLB_DM };
    long long papi_values[4];
    PAPI_start_counters(papi_events, 4);
#endif
    A.spmv(x, y);
#ifdef HAVE_PAPI
    PAPI_stop_counters(papi_values, 4);
    std::cout << "L1 cache misses: "
        << magenta << std::right << std::setw(20) << papi_values[0] << reset << std::endl;
    std::cout << "L2 cache misses: "
        << magenta << std::right << std::setw(20) << papi_values[1] << reset << std::endl;
    std::cout << "L3 cache misses: "
        << magenta << std::right << std::setw(20) << papi_values[2] << reset << std::endl;
    std::cout << "TLB misses:      "
        << magenta << std::right << std::setw(20) << papi_values[3] << reset << std::endl;
#endif

    timer.stop();

    // result
    std::cout << std::left << std::setw(24) << "Measured MFLOP/s:"
        << yellow << std::right << std::fixed << std::setprecision(1) << std::setw(10)
        << n_mflops / timer.seconds() << reset << ", result = " << green << std::setprecision(3)
        << result(y, y + props.m) / (double)(warmup_iters + n_iters) << reset << std::endl;

    A.release();

    free(x);
    free(y);
}
<commit_msg>PAPI updated<commit_after>#include <algorithm>
#include <cassert>
#include <cstdint>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <locale>
#include <numeric>
#include <string>
#include <stdexcept>
#include <tuple>
#include <vector>

#include <parallel/algorithm>

#include <immintrin.h>

#ifdef HAVE_PAPI
    #include <papi.h>
#endif

#ifdef HAVE_MKL
    #include <mkl.h>
    #include <abhsf/utils/mkl_csr_spmv_helper.h>
#endif

#include <abhsf/utils/colors.h>
#include <abhsf/utils/coo2csr.h>
#include <abhsf/utils/matrix_properties.h>
#include <abhsf/utils/matrix_market_reader.h>
#include <abhsf/utils/restrict.h>
#include <abhsf/utils/synthetic.h>
#include <abhsf/utils/timer.h>
#include <abhsf/utils/thousands_separator.h>

static const int warmup_iters = 4;
static const int n_iters = 40;

using element_t = std::tuple<int, int, double>;
using elements_t = std::vector<element_t>;

template <typename REAL_T, typename ROW_PTR_T, typename COL_IND_T>
class csr_matrix
{
    public:
        void from_elements(elements_t& elements, const matrix_properties& props)
        {
            m_ = props.m;
            n_ = props.n;
            nnz_ = elements.size();
            coo2csr(elements, m_, a_, ia_, ja_);
        }

        void spmv(const REAL_T* RESTRICT x, REAL_T* RESTRICT y, bool papi = false)
        {
         // mkl_csr_spmv_helper<REAL_T>::spmv(m_, n_, a_.data(), ia_.data(), ja_.data(), x, y); // MKL version
         // spmv_naive(x, y);
            spmv_naive_1_nnz_per_row(x, y, papi);
        }

        void spmv_naive(const REAL_T* RESTRICT x, REAL_T* RESTRICT y)
        {
            #pragma omp parallel for schedule(static)
            for (long row = 0; row < m_; row++)
                for (long k = ia_[row]; k < ia_[row + 1]; k++)
                    y[row] += a_[k] * x[ja_[k]];
        }

        void spmv_naive_1_nnz_per_row(const REAL_T* RESTRICT x, REAL_T* RESTRICT y, bool papi)
        {
/*
            #pragma omp parallel for schedule(static)
            for (long first_row = 0; first_row < m_; first_row += 8) {
                _mm_prefetch((const char*)(x + ja_[first_row + 64 + 0]), _MM_HINT_T2);
                _mm_prefetch((const char*)(x + ja_[first_row + 64 + 1]), _MM_HINT_T2);
                _mm_prefetch((const char*)(x + ja_[first_row + 64 + 2]), _MM_HINT_T2);
                _mm_prefetch((const char*)(x + ja_[first_row + 64 + 3]), _MM_HINT_T2);
                _mm_prefetch((const char*)(x + ja_[first_row + 64 + 4]), _MM_HINT_T2);
                _mm_prefetch((const char*)(x + ja_[first_row + 64 + 5]), _MM_HINT_T2);
                _mm_prefetch((const char*)(x + ja_[first_row + 64 + 6]), _MM_HINT_T2);
                _mm_prefetch((const char*)(x + ja_[first_row + 64 + 7]), _MM_HINT_T2);

                for (long j = 0; j < 8; j++) {
                    long row = first_row + j;
                    long k = row; // ia_[row];
                    y[row] += a_[k] * x[ja_[k]];
                }
            }
*/
            long long l1_tcm = 0, l2_tcm = 0, l3_tcm = 0, tlb_dm = 0;
            #pragma omp parallel reduction(+:l1_tcm,l2_tcm,l3_tcm,tlb_dm)
            {
#ifdef HAVE_PAPI
             // int papi_events[4] = { PAPI_L1_TCM, PAPI_L2_TCM, PAPI_L3_TCM, PAPI_TLB_DM };
                int papi_events[1] = { PAPI_L1_TCM };
             // if (papi)
                    PAPI_start_counters(papi_events, 1);
#endif

                #pragma omp for schedule(static)
                for (long row = 0; row < m_; row++) {
                    long k = ia_[row];
                    y[row] += a_[k] * x[ja_[k]];
                }

                /*
#ifdef HAVE_PAPI
                if (papi) {
                    long long papi_values[4];
                    PAPI_stop_counters(papi_values, 4);
                    l1_tcm = papi_values[0];
                    l2_tcm = papi_values[1];
                    l3_tcm = papi_values[2];
                    tlb_dm = papi_values[3];
                }
#endif
                */
            }
/*
#ifdef HAVE_PAPI
            if (papi) {
                std::cout << "L1 cache misses: "
                    << magenta << std::right << std::setw(20) << l1_tcm << reset << std::endl;
                std::cout << "L2 cache misses: "
                    << magenta << std::right << std::setw(20) << l2_tcm << reset << std::endl;
                std::cout << "L3 cache misses: "
                    << magenta << std::right << std::setw(20) << l3_tcm << reset << std::endl;
                std::cout << "TLB misses:      "
                    << magenta << std::right << std::setw(20) << tlb_dm << reset << std::endl;
            }
#endif
*/
        }

/*
        void spmv(const real_type* RESTRICT x, real_type* RESTRICT y)
        {
#pragma omp parallel for schedule(static)
            for (index_type row = 0; row < m_; row++) {
                index_type k = ia_[row];
                while (k + 63 < ia_[row + 1]) {
                    for (int i = 0; i < 64; i++)
                        y[row] += x[ja_[k + i]];
                    k += 64;
                }
                while (k < ia_[row + 1])
                    y[row] += x[ja_[k++]];
/ *
                for (index_type k = ia_[row]; k < ia_[row + 1]; k++) {
                 // y[row] += a_[k] * x[ja_[k]];
                    y[row] += x[ja_[k]];
                }
* /
            }
        }
*/

        void release()
        {
            a_.clear();
            a_.shrink_to_fit();
            ia_.clear();
            ia_.shrink_to_fit();
            ja_.clear();
            ja_.shrink_to_fit();
        }

    private:
        std::vector<REAL_T> a_;
        std::vector<ROW_PTR_T> ia_;
        std::vector<COL_IND_T> ja_;
        long m_, n_, nnz_;
};

/*
class coo_matrix
{
    public:
        void from_elements(elements_t& elements, const matrix_properties& props)
        {
         // std::sort(elements.begin(), elements.end());
            __gnu_parallel::sort(elements.begin(), elements.end());

            m_ = props.m;
            n_ = props.n;
            nnz_ = elements.size();

            a_.resize(nnz_);
            ia_.resize(nnz_);
            ja_.resize(nnz_);

            for (size_t k = 0; k < nnz_; k++) {
                a_[k] = std::get<2>(elements[k]);
                ia_[k] = std::get<0>(elements[k]);
                ja_[k] = std::get<1>(elements[k]);
            }
        }

        void spmv(const real_type* RESTRICT x, real_type* RESTRICT y)
        {
#pragma omp parallel for
            for (size_t k = 0; k < nnz_; k++)
#pragma omp atomic update
                y[ia_[k]] += a_[k] * x[ja_[k]];
        }

        void spmv_clever(const real_type* RESTRICT x, real_type* RESTRICT y)
        {
#pragma omp parallel
            {
                // split work
                long per = nnz_ / omp_get_num_threads();
                long first = omp_get_thread_num() * per;
                long last = first + per - 1;
                if (last > (nnz_ - 1))
                    last = nnz_ - 1;

                long row = ia_[first];
             // real_type y_ = a_[first] * x[ja_[first]];
                real_type y_ = x[ja_[first]];

                long k = first + 1;
                while (k <= last) {
                    if (ia_[k] != row) {
#pragma omp atomic update
                        y[row] += y_;
                        row = ia_[k];
                     // y_ = a_[k] * x[ja_[k]];
                        y_ = x[ja_[k]];
                        k++;
                        break;
                    }
                 // y_ += a_[k] * x[ja_[k]];
                    y_ += x[ja_[k]];
                    k++;
                }
                while (k <= last) {
                    if (ia_[k] != row) {
                        y[row] += y_;
                        y_ = 0.0;
                        row = ia_[k];
                    }
                 // y_ += a_[k] * x[ja_[k]];
                    y_ += x[ja_[k]];
                    k++;
                }
#pragma omp atomic update
                y[row] += y_;
            }
        }

        void release()
        {
            a_.clear();
            a_.shrink_to_fit();
            ia_.clear();
            ia_.shrink_to_fit();
            ja_.clear();
            ja_.shrink_to_fit();
        }

    private:
        std::vector<real_type> a_;
     // std::vector<index_type> ia_, ja_;
        std::vector<uint16_t> ia_, ja_;
        index_type m_, n_, nnz_;
};
*/

template <typename Iter>
double result(Iter begin, Iter end)
{
    double res = 0.0;
    while (begin != end) {
        res += *begin * *begin;
        ++begin;
    }
    return sqrt(res);
}

int main(int argc, char* argv[])
{
    std::cout.imbue(std::locale(std::locale(), new thousands_separator));

    using real_type = double;
    using timer_type = chrono_timer<>;

    matrix_properties props;
    elements_t elements;

    // matrix type selection:
    if (strcmp(argv[1], "dense") == 0) {
        std::cout << "Matrix: " << yellow << "DENSE" << reset << std::endl;
        synthetise_dense_matrix(props, elements, 20000);
    }
    else if (strcmp(argv[1], "diagonal") == 0) {
        std::cout << "Matrix: " << yellow << "DIAGONAL" << reset << std::endl;
        synthetise_diagonal_matrix(props, elements, 200000000);
    }
    else if (strcmp(argv[1], "single-column") == 0) {
        std::cout << "Matrix: " << yellow << "SINGLE-COLUMN" << reset << std::endl;
        synthetise_single_column_matrix(props, elements, 200000000);
    }
    else if (strcmp(argv[1], "random-column") == 0) {
        std::cout << "Matrix: " << yellow << "RANDOM-COLUMN" << reset << std::endl;
        synthetise_random_column_matrix(props, elements, 200000000);
    }
    else if (strcmp(argv[1], "single-row-column") == 0) {
        std::cout << "Matrix: " << yellow << "SINGLE-ROW-COLUMN" << reset << std::endl;
        synthetise_single_row_column_matrix(props, elements, 100000000);
    }
    else if (strcmp(argv[1], "single-row") == 0) {
        std::cout << "Matrix: " << yellow << "SINGLE-ROW" << reset << std::endl;
        synthetise_single_row_matrix(props, elements, 200000000);
    }
    else // read from file if not synthetic
        read_mtx_real_or_binary(argv[1], elements, props);

    // print out final dimensions
    std::cout << "Matrix dimensions: " << magenta <<
        props.m << " x " << props.n << " : " << props.nnz << " = " << elements.size() << reset << std::endl;

    // check matrix:
    if (props.symmetry != matrix_symmetry_t::UNSYMMETRIC)
        throw std::runtime_error("This program does support unsymmetric matrices only!");
    if (props.m != props.n)
        throw std::runtime_error("This program does support square matrices only!");

    // vectors:
    static const double x_element = 0.5;
    real_type *x, *y;
    posix_memalign((void**)(&x), 64, props.n * sizeof(real_type));
    posix_memalign((void**)(&y), 64, props.m * sizeof(real_type));
    std::fill(x, x + props.n, x_element);
    std::fill(y, y + props.m, 0.0);

    // verification
    std::vector<double> y_temp(props.m, 0.0);
    for (const auto& element : elements)
        y_temp[std::get<0>(element)] += std::get<2>(element) * x_element;
    std::cout << "Expected result = " << green << result(y_temp.cbegin(), y_temp.cend()) << reset << std::endl;
    y_temp.clear();
    y_temp.shrink_to_fit();

    const long nnz = elements.size();
    const double n_mflops = (double)(nnz * 2 * n_iters) / 1.0e6;

 // csr_matrix<real_type, MKL_INT, MKL_INT> A;
    csr_matrix<real_type, int, int> A;
 // coo_matrix A;

    A.from_elements(elements, props);
    timer_type timer;

    std::fill(y, y + props.m, 0.0);
    for (int iter = 0; iter < warmup_iters; iter++)
        A.spmv(x, y);
    timer.start();
    for (int iter = 0; iter < n_iters - 1; iter++)
        A.spmv(x, y);
    // last iteration:
    A.spmv(x, y, true);
    timer.stop();

    // result
    std::cout << std::left << std::setw(24) << "Measured MFLOP/s:"
        << yellow << std::right << std::fixed << std::setprecision(1) << std::setw(10)
        << n_mflops / timer.seconds() << reset << ", result = " << green << std::setprecision(3)
        << result(y, y + props.m) / (double)(warmup_iters + n_iters) << reset << std::endl;

    A.release();

    free(x);
    free(y);
}
<|endoftext|>