<commit_before>#pragma once

#include <unordered_map>
#include <memory>
#include <type_traits>
#include <tuple>

namespace sioc {

struct NoDependencies {
	using DependenciesTypes = std::tuple<>;
};

template<typename... Types>
struct Dependency : NoDependencies {
	using DependenciesTypes = std::tuple<Types...>;
};

struct Single {
	using ParentTypes = std::tuple<>;
};

template<typename T>
struct Service;

template<typename... Types>
struct Overrides : Single {
	using ParentTypes = std::tuple<Types...>;
};

namespace detail {

template<int ...>
struct seq { };

template<int N, int ...S>
struct seq_gen : seq_gen<N-1, N-1, S...> { };

template<int ...S>
struct seq_gen<0, S...> {
  typedef seq<S...> type;
};

struct Holder {
	virtual ~Holder() {

	}
};

template<typename T>
struct InstanceHolder : Holder {
	InstanceHolder(std::shared_ptr<T> instance) : _instance{instance} {}

	std::shared_ptr<T> getInstance() const {
		return _instance;
	}

private:
	std::shared_ptr<T> _instance;
};

template<typename T, typename... Args>
struct CallbackHolder : Holder {
	CallbackHolder(std::function<std::shared_ptr<T>(Args...)> callback) : _callback{callback} {}

	std::function<std::shared_ptr<T>(Args...)> getCallback() const {
		return _callback;
	}

private:
	std::function<std::shared_ptr<T>(Args...)> _callback;
};

}

struct Container : std::enable_shared_from_this<Container> {
	template<typename T>
	void instance(std::shared_ptr<T> service) {
		static_assert(std::is_base_of<Single, Service<T>>::value, "instance only accept Single Service instance.");
		call_save_instance(service, typename detail::seq_gen<std::tuple_size<typename Service<T>::ParentTypes>::value>::type());
	}

	template<typename T>
	void instance() {
		auto dependencies = dependency<typename Service<T>::DependenciesTypes>(typename detail::seq_gen<std::tuple_size<typename Service<T>::DependenciesTypes>::value>::type());
		auto service = make_service<T, decltype(dependencies)>(typename detail::seq_gen<std::tuple_size<typename Service<T>::DependenciesTypes>::value>::type(), dependencies);
		call_save_instance(service, typename detail::seq_gen<std::tuple_size<typename Service<T>::ParentTypes>::value>::type());
	}

	template<typename T>
	typename std::enable_if<(!std::is_abstract<T>::value && !std::is_base_of<Container, T>::value), std::shared_ptr<T>>::type service() {
		return get_service<T>();
	}

	template<typename T>
	typename std::enable_if<(std::is_same<T, Container>::value), std::shared_ptr<T>>::type service() {
		return shared_from_this();
	}

	template<typename T>
	typename std::enable_if<(std::is_base_of<Container, T>::value && !std::is_same<T, Container>::value), std::shared_ptr<T>>::type service() {
		auto service = std::dynamic_pointer_cast<T>(shared_from_this());
		if (service) {
			return service;
		} else {
			return nullptr;
		}
	}

	template<typename T>
	typename std::enable_if<std::is_abstract<T>::value, std::shared_ptr<T>>::type service() {
		auto it = _services.find(typeid(T).name());
		if (it != _services.end()) {
			auto holder = dynamic_cast<detail::InstanceHolder<T>*>(it->second.get());
			if (holder) {
				return holder->getInstance();
			}
		}
		return nullptr;
	}

	template<typename T, typename ...Bases, typename U>
	void callback(U callback) {
		static_assert(!std::is_base_of<Single, Service<T>>::value, "instance does not accept Single Service.");
		save_callback<T, typename Service<T>::DependenciesTypes>(typename detail::seq_gen<std::tuple_size<typename Service<T>::DependenciesTypes>::value>::type(), callback);
	}

	virtual void init(){}

private:
	template<typename T>
	typename std::enable_if<std::is_base_of<Single, Service<T>>::value, std::shared_ptr<T>>::type get_service() {
		auto it = _services.find(typeid(T).name());
		if (it == _services.end()) {
			auto dependencies = dependency<typename Service<T>::DependenciesTypes>(typename detail::seq_gen<std::tuple_size<typename Service<T>::DependenciesTypes>::value>::type());
			auto service = make_service<T, decltype(dependencies)>(typename detail::seq_gen<std::tuple_size<typename Service<T>::DependenciesTypes>::value>::type(), dependencies);
			call_save_instance(service, typename detail::seq_gen<std::tuple_size<typename Service<T>::ParentTypes>::value>::type());
			return service;
		} else {
			auto holder = dynamic_cast<detail::InstanceHolder<T>*>(it->second.get());
			if (holder) {
				return holder->getInstance();
			} else {
				return nullptr;
			}
		}
	}

	template<typename T>
	typename std::enable_if<!std::is_base_of<Single, Service<T>>::value, std::shared_ptr<T>>::type get_service() {
		auto dependencies = dependency<typename Service<T>::DependenciesTypes>(typename detail::seq_gen<std::tuple_size<typename Service<T>::DependenciesTypes>::value>::type());
		auto service = make_service<T, decltype(dependencies)>(typename detail::seq_gen<std::tuple_size<typename Service<T>::DependenciesTypes>::value>::type(), dependencies);

		return service;
	}

	template<typename T, int ...S>
	void call_save_instance(std::shared_ptr<T> service, detail::seq<S...>) {
		save_instance<T, typename std::tuple_element<S, typename Service<T>::ParentTypes>::type...>(service);
	}

	template<typename Tuple, int ...S>
	std::tuple<std::shared_ptr<typename std::tuple_element<S, Tuple>::type>...> dependency(detail::seq<S...>) {
		return std::make_tuple(service<typename std::tuple_element<S, Tuple>::type>()...);
	}

	template<typename T, typename Tuple, int ...S>
	std::shared_ptr<T> callback_make_service(detail::seq<S...> seq, Tuple dependencies) const {
		auto it = _callbacks.find(typeid(T).name());
		if (it != _callbacks.end()) {
			auto holder = dynamic_cast<detail::CallbackHolder<T, typename std::tuple_element<S, Tuple>::type...>*>(it->second.get());
			if (holder) {
				return holder->getCallback()(std::get<S>(dependencies)...);
			}
		}
		return nullptr;
	}

	template<typename T, typename Tuple, int ...S>
	std::shared_ptr<T> make_service(detail::seq<S...> seq, Tuple dependencies) const {
		auto service = callback_make_service<T, Tuple>(seq, dependencies);
		if (service) {
			return service;
		}
		return std::make_shared<T>(std::get<S>(dependencies)...);
	}

	template<typename T, typename ...Others>
	typename std::enable_if<(sizeof...(Others) > 0), void>::type save_instance(std::shared_ptr<T> service) {
		save_instance<T>(service);
		save_instance<Others...>(service);
	}

	template<typename T>
	void save_instance (std::shared_ptr<T> service) {
		_services[typeid(T).name()] = std::unique_ptr<detail::InstanceHolder<T>>(new detail::InstanceHolder<T>(service));
	}

	template<typename T, typename Tuple, typename ...Others,  int ...S, typename U>
	typename std::enable_if<(sizeof...(Others) > 0), void>::type save_callback(detail::seq<S...> seq, U callback) {
		save_callback<T, Tuple>(seq, service);
		save_callback<T, Tuple, Others...>(seq, service);
	}

	template<typename T, typename Tuple, int ...S, typename U>
	void save_callback (detail::seq<S...>, U callback) {
		_callbacks[typeid(T).name()] = std::unique_ptr<detail::CallbackHolder<T, std::shared_ptr<typename std::tuple_element<S, Tuple>::type>...>>(new detail::CallbackHolder<T, std::shared_ptr<typename std::tuple_element<S, Tuple>::type>...>(callback));
	}

	std::unordered_map<std::string, std::unique_ptr<detail::Holder>> _callbacks;
	std::unordered_map<std::string, std::unique_ptr<detail::Holder>> _services;
};

template<typename T = Container, typename ...Args>
std::shared_ptr<T> make_container(Args&& ...args) {
	static_assert(std::is_base_of<Container, T>::value, "make_container only accept container types.");
	auto container = std::make_shared<T>(std::forward<Args>(args)...);
	container->init();
	return container;
}

}
<commit_msg>corrected callback saving error<commit_after>#pragma once

#include <unordered_map>
#include <memory>
#include <type_traits>
#include <tuple>

namespace sioc {

struct NoDependencies {
	using DependenciesTypes = std::tuple<>;
};

template<typename... Types>
struct Dependency : NoDependencies {
	using DependenciesTypes = std::tuple<Types...>;
};

struct Single {
	using ParentTypes = std::tuple<>;
};

template<typename T>
struct Service;

template<typename... Types>
struct Overrides : Single {
	using ParentTypes = std::tuple<Types...>;
};

namespace detail {

template<int ...>
struct seq { };

template<int N, int ...S>
struct seq_gen : seq_gen<N-1, N-1, S...> { };

template<int ...S>
struct seq_gen<0, S...> {
  typedef seq<S...> type;
};

struct Holder {
	virtual ~Holder() {

	}
};

template<typename T>
struct InstanceHolder : Holder {
	InstanceHolder(std::shared_ptr<T> instance) : _instance{instance} {}

	std::shared_ptr<T> getInstance() const {
		return _instance;
	}

private:
	std::shared_ptr<T> _instance;
};

template<typename T, typename... Args>
struct CallbackHolder : Holder {
	CallbackHolder(std::function<std::shared_ptr<T>(Args...)> callback) : _callback{callback} {}

	std::function<std::shared_ptr<T>(Args...)> getCallback() const {
		return _callback;
	}

private:
	std::function<std::shared_ptr<T>(Args...)> _callback;
};

}

struct Container : std::enable_shared_from_this<Container> {
	template<typename T>
	void instance(std::shared_ptr<T> service) {
		static_assert(std::is_base_of<Single, Service<T>>::value, "instance only accept Single Service instance.");
		call_save_instance(service, typename detail::seq_gen<std::tuple_size<typename Service<T>::ParentTypes>::value>::type());
	}

	template<typename T>
	void instance() {
		auto dependencies = dependency<typename Service<T>::DependenciesTypes>(typename detail::seq_gen<std::tuple_size<typename Service<T>::DependenciesTypes>::value>::type());
		auto service = make_service<T, decltype(dependencies)>(typename detail::seq_gen<std::tuple_size<typename Service<T>::DependenciesTypes>::value>::type(), dependencies);
		call_save_instance(service, typename detail::seq_gen<std::tuple_size<typename Service<T>::ParentTypes>::value>::type());
	}

	template<typename T>
	typename std::enable_if<(!std::is_abstract<T>::value && !std::is_base_of<Container, T>::value), std::shared_ptr<T>>::type service() {
		return get_service<T>();
	}

	template<typename T>
	typename std::enable_if<(std::is_same<T, Container>::value), std::shared_ptr<T>>::type service() {
		return shared_from_this();
	}

	template<typename T>
	typename std::enable_if<(std::is_base_of<Container, T>::value && !std::is_same<T, Container>::value), std::shared_ptr<T>>::type service() {
		auto service = std::dynamic_pointer_cast<T>(shared_from_this());
		if (service) {
			return service;
		} else {
			return nullptr;
		}
	}

	template<typename T>
	typename std::enable_if<std::is_abstract<T>::value, std::shared_ptr<T>>::type service() {
		auto it = _services.find(typeid(T).name());
		if (it != _services.end()) {
			auto holder = dynamic_cast<detail::InstanceHolder<T>*>(it->second.get());
			if (holder) {
				return holder->getInstance();
			}
		}
		return nullptr;
	}

	template<typename T, typename ...Bases, typename U>
	void callback(U callback) {
		static_assert(!std::is_base_of<Single, Service<T>>::value, "instance does not accept Single Service.");
		save_callback<T, typename Service<T>::DependenciesTypes>(typename detail::seq_gen<std::tuple_size<typename Service<T>::DependenciesTypes>::value>::type(), callback);
	}

	virtual void init(){}

private:
	template<typename T>
	typename std::enable_if<std::is_base_of<Single, Service<T>>::value, std::shared_ptr<T>>::type get_service() {
		auto it = _services.find(typeid(T).name());
		if (it == _services.end()) {
			auto dependencies = dependency<typename Service<T>::DependenciesTypes>(typename detail::seq_gen<std::tuple_size<typename Service<T>::DependenciesTypes>::value>::type());
			auto service = make_service<T, decltype(dependencies)>(typename detail::seq_gen<std::tuple_size<typename Service<T>::DependenciesTypes>::value>::type(), dependencies);
			call_save_instance(service, typename detail::seq_gen<std::tuple_size<typename Service<T>::ParentTypes>::value>::type());
			return service;
		} else {
			auto holder = dynamic_cast<detail::InstanceHolder<T>*>(it->second.get());
			if (holder) {
				return holder->getInstance();
			} else {
				return nullptr;
			}
		}
	}

	template<typename T>
	typename std::enable_if<!std::is_base_of<Single, Service<T>>::value, std::shared_ptr<T>>::type get_service() {
		auto dependencies = dependency<typename Service<T>::DependenciesTypes>(typename detail::seq_gen<std::tuple_size<typename Service<T>::DependenciesTypes>::value>::type());
		auto service = make_service<T, decltype(dependencies)>(typename detail::seq_gen<std::tuple_size<typename Service<T>::DependenciesTypes>::value>::type(), dependencies);

		return service;
	}

	template<typename T, int ...S>
	void call_save_instance(std::shared_ptr<T> service, detail::seq<S...>) {
		save_instance<T, typename std::tuple_element<S, typename Service<T>::ParentTypes>::type...>(service);
	}

	template<typename Tuple, int ...S>
	std::tuple<std::shared_ptr<typename std::tuple_element<S, Tuple>::type>...> dependency(detail::seq<S...>) {
		return std::make_tuple(service<typename std::tuple_element<S, Tuple>::type>()...);
	}

	template<typename T, typename Tuple, int ...S>
	std::shared_ptr<T> callback_make_service(detail::seq<S...> seq, Tuple dependencies) const {
		auto it = _callbacks.find(typeid(T).name());
		if (it != _callbacks.end()) {
			auto holder = dynamic_cast<detail::CallbackHolder<T, typename std::tuple_element<S, Tuple>::type...>*>(it->second.get());
			if (holder) {
				return holder->getCallback()(std::get<S>(dependencies)...);
			}
		}
		return nullptr;
	}

	template<typename T, typename Tuple, int ...S>
	std::shared_ptr<T> make_service(detail::seq<S...> seq, Tuple dependencies) const {
		auto service = callback_make_service<T, Tuple>(seq, dependencies);
		if (service) {
			return service;
		}
		return std::make_shared<T>(std::get<S>(dependencies)...);
	}

	template<typename T, typename ...Others>
	typename std::enable_if<(sizeof...(Others) > 0), void>::type save_instance(std::shared_ptr<T> service) {
		save_instance<T>(service);
		save_instance<Others...>(service);
	}

	template<typename T>
	void save_instance (std::shared_ptr<T> service) {
		_services[typeid(T).name()] = std::unique_ptr<detail::InstanceHolder<T>>(new detail::InstanceHolder<T>(service));
	}

	template<typename T, typename Tuple, typename ...Others,  int ...S, typename U>
	typename std::enable_if<(sizeof...(Others) > 0), void>::type save_callback(detail::seq<S...> seq, U callback) {
		save_callback<T, Tuple>(seq, callback);
		save_callback<T, Tuple, Others...>(seq, callback);
	}

	template<typename T, typename Tuple, int ...S, typename U>
	void save_callback (detail::seq<S...>, U callback) {
		_callbacks[typeid(T).name()] = std::unique_ptr<detail::CallbackHolder<T, std::shared_ptr<typename std::tuple_element<S, Tuple>::type>...>>(new detail::CallbackHolder<T, std::shared_ptr<typename std::tuple_element<S, Tuple>::type>...>(callback));
	}

	std::unordered_map<std::string, std::unique_ptr<detail::Holder>> _callbacks;
	std::unordered_map<std::string, std::unique_ptr<detail::Holder>> _services;
};

template<typename T = Container, typename ...Args>
std::shared_ptr<T> make_container(Args&& ...args) {
	static_assert(std::is_base_of<Container, T>::value, "make_container only accept container types.");
	auto container = std::make_shared<T>(std::forward<Args>(args)...);
	container->init();
	return container;
}

}
<|endoftext|>


<commit_before>#include "Arith256.h"
#include "Runtime.h"
#include "Type.h"

#include <llvm/IR/Function.h>

namespace dev
{
namespace eth
{
namespace jit
{

Arith256::Arith256(llvm::IRBuilder<>& _builder) :
	CompilerHelper(_builder)
{
	using namespace llvm;

	m_result = m_builder.CreateAlloca(Type::Word, nullptr, "arith.result");
	m_arg1 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg1");
	m_arg2 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg2");
	m_arg3 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg3");

	using Linkage = GlobalValue::LinkageTypes;

	llvm::Type* arg2Types[] = {Type::WordPtr, Type::WordPtr, Type::WordPtr};
	llvm::Type* arg3Types[] = {Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr};

	m_mul = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_mul", getModule());
	m_div = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_div", getModule());
	m_mod = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_mod", getModule());
	m_sdiv = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_sdiv", getModule());
	m_smod = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_smod", getModule());
	m_exp = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_exp", getModule());
	m_addmod = Function::Create(FunctionType::get(Type::Void, arg3Types, false), Linkage::ExternalLinkage, "arith_addmod", getModule());
	m_mulmod = Function::Create(FunctionType::get(Type::Void, arg3Types, false), Linkage::ExternalLinkage, "arith_mulmod", getModule());
}

Arith256::~Arith256()
{}

llvm::Value* Arith256::binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2)
{
	m_builder.CreateStore(_arg1, m_arg1);
	m_builder.CreateStore(_arg2, m_arg2);
	m_builder.CreateCall3(_op, m_arg1, m_arg2, m_result);
	return m_builder.CreateLoad(m_result);
}

llvm::Value* Arith256::ternaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3)
{
	m_builder.CreateStore(_arg1, m_arg1);
	m_builder.CreateStore(_arg2, m_arg2);
	m_builder.CreateStore(_arg3, m_arg3);
	m_builder.CreateCall4(_op, m_arg1, m_arg2, m_arg3, m_result);
	return m_builder.CreateLoad(m_result);
}

llvm::Value* Arith256::mul(llvm::Value* _arg1, llvm::Value* _arg2)
{
	return binaryOp(m_mul, _arg1, _arg2);
}

llvm::Value* Arith256::div(llvm::Value* _arg1, llvm::Value* _arg2)
{
	return binaryOp(m_div, _arg1, _arg2);
}

llvm::Value* Arith256::mod(llvm::Value* _arg1, llvm::Value* _arg2)
{
	return binaryOp(m_mod, _arg1, _arg2);
}

llvm::Value* Arith256::sdiv(llvm::Value* _arg1, llvm::Value* _arg2)
{
	return binaryOp(m_sdiv, _arg1, _arg2);
}

llvm::Value* Arith256::smod(llvm::Value* _arg1, llvm::Value* _arg2)
{
	return binaryOp(m_smod, _arg1, _arg2);
}

llvm::Value* Arith256::exp(llvm::Value* _arg1, llvm::Value* _arg2)
{
	return binaryOp(m_exp, _arg1, _arg2);
}

llvm::Value* Arith256::addmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3)
{
	return ternaryOp(m_addmod, _arg1, _arg2, _arg3);
}

llvm::Value* Arith256::mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3)
{
	return ternaryOp(m_mulmod, _arg1, _arg2, _arg3);
}

namespace
{
	using s256 = boost::multiprecision::int256_t;

	inline s256 u2s(u256 _u)
	{
		static const bigint c_end = (bigint)1 << 256;
		static const u256 c_send = (u256)1 << 255;
		if (_u < c_send)
			return (s256)_u;
		else
			return (s256)-(c_end - _u);
	}

	inline u256 s2u(s256 _u)
	{
		static const bigint c_end = (bigint)1 << 256;
		if (_u >= 0)
			return (u256)_u;
		else
			return (u256)(c_end + _u);
	}
}

}
}
}

extern "C"
{

	using namespace dev::eth::jit;

	EXPORT void arith_mul(i256* _arg1, i256* _arg2, i256* o_result)
	{
		auto arg1 = llvm2eth(*_arg1);
		auto arg2 = llvm2eth(*_arg2);
		*o_result = eth2llvm(arg1 * arg2);
	}

	EXPORT void arith_div(i256* _arg1, i256* _arg2, i256* o_result)
	{
		auto arg1 = llvm2eth(*_arg1);
		auto arg2 = llvm2eth(*_arg2);
		*o_result = eth2llvm(arg2 == 0 ? arg2 : arg1 / arg2);
	}

	EXPORT void arith_mod(i256* _arg1, i256* _arg2, i256* o_result)
	{
		auto arg1 = llvm2eth(*_arg1);
		auto arg2 = llvm2eth(*_arg2);
		*o_result = eth2llvm(arg2 == 0 ? arg2 : arg1 % arg2);
	}

	EXPORT void arith_sdiv(i256* _arg1, i256* _arg2, i256* o_result)
	{
		auto arg1 = llvm2eth(*_arg1);
		auto arg2 = llvm2eth(*_arg2);
		*o_result = eth2llvm(arg2 == 0 ? arg2 : s2u(u2s(arg1) / u2s(arg2)));
	}

	EXPORT void arith_smod(i256* _arg1, i256* _arg2, i256* o_result)
	{
		auto arg1 = llvm2eth(*_arg1);
		auto arg2 = llvm2eth(*_arg2);
		*o_result = eth2llvm(arg2 == 0 ? arg2 : s2u(u2s(arg1) % u2s(arg2)));
	}

	EXPORT void arith_exp(i256* _arg1, i256* _arg2, i256* o_result)
	{
		bigint left = llvm2eth(*_arg1);
		bigint right = llvm2eth(*_arg2);
		auto ret = static_cast<u256>(boost::multiprecision::powm(left, right, bigint(2) << 256));
		*o_result = eth2llvm(ret);
	}

	EXPORT void arith_mulmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* o_result)
	{
		auto arg1 = llvm2eth(*_arg1);
		auto arg2 = llvm2eth(*_arg2);
		auto arg3 = llvm2eth(*_arg3);
		if (arg3 != 0)
			*o_result = eth2llvm(u256((bigint(arg1) * bigint(arg2)) % arg3));
		else
			*o_result = {};
	}

	EXPORT void arith_addmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* o_result)
	{
		auto arg1 = llvm2eth(*_arg1);
		auto arg2 = llvm2eth(*_arg2);
		auto arg3 = llvm2eth(*_arg3);
		if (arg3 != 0)
			*o_result = eth2llvm(u256((bigint(arg1) + bigint(arg2)) % arg3));
		else
			*o_result = {};
	}

}

<commit_msg>Internal mul256 implementation<commit_after>#include "Arith256.h"
#include "Runtime.h"
#include "Type.h"

#include <llvm/IR/Function.h>

namespace dev
{
namespace eth
{
namespace jit
{

Arith256::Arith256(llvm::IRBuilder<>& _builder) :
	CompilerHelper(_builder)
{
	using namespace llvm;

	m_result = m_builder.CreateAlloca(Type::Word, nullptr, "arith.result");
	m_arg1 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg1");
	m_arg2 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg2");
	m_arg3 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg3");

	using Linkage = GlobalValue::LinkageTypes;

	llvm::Type* arg2Types[] = {Type::WordPtr, Type::WordPtr, Type::WordPtr};
	llvm::Type* arg3Types[] = {Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr};

	m_mul = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_mul", getModule());
	m_div = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_div", getModule());
	m_mod = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_mod", getModule());
	m_sdiv = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_sdiv", getModule());
	m_smod = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_smod", getModule());
	m_exp = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_exp", getModule());
	m_addmod = Function::Create(FunctionType::get(Type::Void, arg3Types, false), Linkage::ExternalLinkage, "arith_addmod", getModule());
	m_mulmod = Function::Create(FunctionType::get(Type::Void, arg3Types, false), Linkage::ExternalLinkage, "arith_mulmod", getModule());
}

Arith256::~Arith256()
{}

llvm::Value* Arith256::binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2)
{
	m_builder.CreateStore(_arg1, m_arg1);
	m_builder.CreateStore(_arg2, m_arg2);
	m_builder.CreateCall3(_op, m_arg1, m_arg2, m_result);
	return m_builder.CreateLoad(m_result);
}

llvm::Value* Arith256::ternaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3)
{
	m_builder.CreateStore(_arg1, m_arg1);
	m_builder.CreateStore(_arg2, m_arg2);
	m_builder.CreateStore(_arg3, m_arg3);
	m_builder.CreateCall4(_op, m_arg1, m_arg2, m_arg3, m_result);
	return m_builder.CreateLoad(m_result);
}

llvm::Value* Arith256::mul(llvm::Value* _arg1, llvm::Value* _arg2)
{
	return binaryOp(m_mul, _arg1, _arg2);
}

llvm::Value* Arith256::div(llvm::Value* _arg1, llvm::Value* _arg2)
{
	return binaryOp(m_div, _arg1, _arg2);
}

llvm::Value* Arith256::mod(llvm::Value* _arg1, llvm::Value* _arg2)
{
	return binaryOp(m_mod, _arg1, _arg2);
}

llvm::Value* Arith256::sdiv(llvm::Value* _arg1, llvm::Value* _arg2)
{
	return binaryOp(m_sdiv, _arg1, _arg2);
}

llvm::Value* Arith256::smod(llvm::Value* _arg1, llvm::Value* _arg2)
{
	return binaryOp(m_smod, _arg1, _arg2);
}

llvm::Value* Arith256::exp(llvm::Value* _arg1, llvm::Value* _arg2)
{
	return binaryOp(m_exp, _arg1, _arg2);
}

llvm::Value* Arith256::addmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3)
{
	return ternaryOp(m_addmod, _arg1, _arg2, _arg3);
}

llvm::Value* Arith256::mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3)
{
	return ternaryOp(m_mulmod, _arg1, _arg2, _arg3);
}

namespace
{
	using s256 = boost::multiprecision::int256_t;

	inline s256 u2s(u256 _u)
	{
		static const bigint c_end = (bigint)1 << 256;
		static const u256 c_send = (u256)1 << 255;
		if (_u < c_send)
			return (s256)_u;
		else
			return (s256)-(c_end - _u);
	}

	inline u256 s2u(s256 _u)
	{
		static const bigint c_end = (bigint)1 << 256;
		if (_u >= 0)
			return (u256)_u;
		else
			return (u256)(c_end + _u);
	}

	using uint128 = __uint128_t;

//	uint128 add(uint128 a, uint128 b) { return a + b; }
//	uint128 mul(uint128 a, uint128 b) { return a * b; }
//
//	uint128 mulq(uint64_t x, uint64_t y)
//	{
//		return (uint128)x * (uint128)y;
//	}
//
//	uint128 addc(uint64_t x, uint64_t y)
//	{
//		return (uint128)x * (uint128)y;
//	}

	struct uint256
	{
		uint64_t lo;
		uint64_t mid;
		uint128 hi;
	};

//	uint256 add(uint256 x, uint256 y)
//	{
//		auto lo = (uint128) x.lo + y.lo;
//		auto mid = (uint128) x.mid + y.mid + (lo >> 64);
//		return {lo, mid, x.hi + y.hi + (mid >> 64)};
//	}

	uint256 mul(uint256 x, uint256 y)
	{
		auto t1 = (uint128) x.lo * y.lo;
		auto t2 = (uint128) x.lo * y.mid;
		auto t3 = x.lo * y.hi;
		auto t4 = (uint128) x.mid * y.lo;
		auto t5 = (uint128) x.mid * y.mid;
		auto t6 = x.mid * y.hi;
		auto t7 = x.hi * y.lo;
		auto t8 = x.hi * y.mid;

		auto lo = (uint64_t) t1;
		auto m1 = (t1 >> 64) + (uint64_t) t2;
		auto m2 = (uint64_t) m1;
		auto mid = (uint128) m2 + (uint64_t) t4;
		auto hi = (t2 >> 64) + t3 + (t4 >> 64) + t5 + (t6 << 64) + t7
			 + (t8 << 64) + (m1 >> 64) + (mid >> 64);

		return {lo, (uint64_t)mid, hi};
	}
}

}
}
}

extern "C"
{

	using namespace dev::eth::jit;

	EXPORT void arith_mul(uint256* _arg1, uint256* _arg2, uint256* o_result)
	{
		*o_result = mul(*_arg1, *_arg2);
	}

	EXPORT void arith_div(i256* _arg1, i256* _arg2, i256* o_result)
	{
		auto arg1 = llvm2eth(*_arg1);
		auto arg2 = llvm2eth(*_arg2);
		*o_result = eth2llvm(arg2 == 0 ? arg2 : arg1 / arg2);
	}

	EXPORT void arith_mod(i256* _arg1, i256* _arg2, i256* o_result)
	{
		auto arg1 = llvm2eth(*_arg1);
		auto arg2 = llvm2eth(*_arg2);
		*o_result = eth2llvm(arg2 == 0 ? arg2 : arg1 % arg2);
	}

	EXPORT void arith_sdiv(i256* _arg1, i256* _arg2, i256* o_result)
	{
		auto arg1 = llvm2eth(*_arg1);
		auto arg2 = llvm2eth(*_arg2);
		*o_result = eth2llvm(arg2 == 0 ? arg2 : s2u(u2s(arg1) / u2s(arg2)));
	}

	EXPORT void arith_smod(i256* _arg1, i256* _arg2, i256* o_result)
	{
		auto arg1 = llvm2eth(*_arg1);
		auto arg2 = llvm2eth(*_arg2);
		*o_result = eth2llvm(arg2 == 0 ? arg2 : s2u(u2s(arg1) % u2s(arg2)));
	}

	EXPORT void arith_exp(i256* _arg1, i256* _arg2, i256* o_result)
	{
		bigint left = llvm2eth(*_arg1);
		bigint right = llvm2eth(*_arg2);
		auto ret = static_cast<u256>(boost::multiprecision::powm(left, right, bigint(2) << 256));
		*o_result = eth2llvm(ret);
	}

	EXPORT void arith_mulmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* o_result)
	{
		auto arg1 = llvm2eth(*_arg1);
		auto arg2 = llvm2eth(*_arg2);
		auto arg3 = llvm2eth(*_arg3);
		if (arg3 != 0)
			*o_result = eth2llvm(u256((bigint(arg1) * bigint(arg2)) % arg3));
		else
			*o_result = {};
	}

	EXPORT void arith_addmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* o_result)
	{
		auto arg1 = llvm2eth(*_arg1);
		auto arg2 = llvm2eth(*_arg2);
		auto arg3 = llvm2eth(*_arg3);
		if (arg3 != 0)
			*o_result = eth2llvm(u256((bigint(arg1) + bigint(arg2)) % arg3));
		else
			*o_result = {};
	}

}

<|endoftext|>


<commit_before>#include <cmath>
#include <iostream>
#include <sstream>

#include <pqxx/pqxx>

using namespace PGSTD;
using namespace pqxx;

// Streams test program for libpqxx.  Insert a result field into various
// types of streams.
//
// Usage: test046 [connect-string]
//
// Where connect-string is a set of connection options in Postgresql's
// PQconnectdb() format, eg. "dbname=template1" to select from a database
// called template1, or "host=foo.bar.net user=smith" to connect to a
// backend running on host foo.bar.net, logging in as user smith.
int main(int, char *argv[])
{
  try
  {
    connection C(argv[1]);
    work T(C, "test46");
    result R( T.exec("SELECT count(*) FROM pg_tables") );

    cout << "Count was " << R.at(0).at(0) << endl;

    // Read the value into a stringstream
    stringstream I;
    I << R[0][0];

    // Now convert the stringstream into a numeric type
    long L, L2;
    I >> L;
    cout << "As a long, it's " << L << endl;

    R[0][0].to(L2);
    if (L != L2)
      throw logic_error("Different conversion methods gave different results!");

    float F, F2;
    stringstream I2;
    I2 << R[0][0];
    I2 >> F;
    cout << "As a float, it's " << F << endl;
    R[0][0].to(F2);
    if (fabs(F2-F) > 0.01)
      throw logic_error("Inconsistent floating-point result: " + to_string(F2));

    float F3;
    from_string(R[0][0].c_str(), F3);
    if (fabs(F3-F) > 0.01)
      throw logic_error("Inconsistent float result from from_string");

    double D;
    from_string(R[0][0].c_str(), D);
    if (fabs(D-F) > 0.01)
      throw logic_error("Inconsistent double result from from_string");

    long double LD;
    from_string(R[0][0].c_str(), LD);
    if (fabs(LD-F) > 0.01)
      throw logic_error("Inconsistent long double result from from_string");

    string S, S2, S3;
    from_string(R[0][0].c_str(), S);
    from_string(string(R[0][0].c_str()), S2);
    from_string(R[0][0], S3);
    if (S != S2)
      throw runtime_error("from_string(const char[],std::string &) "
	  "is inconsistent with "
	  "from_string(const std::string &,std::string &)");
    if (S3 != S2)
      throw runtime_error("from_string(const result::field &,std::string &) "
	  "is inconsistent with "
	  "from_string(const std::string &,std::string &)");

    R = T.exec("SELECT 1=1");
    if (!R.at(0).at(0).as<bool>())
      throw logic_error("1=1 doesn't yield 'true'");
    R = T.exec("SELECT 2+2=5");
    if (R.at(0).at(0).as<bool>())
      throw logic_error("2+2=5 yields 'true'");
  }
  catch (const sql_error &e)
  {
    cerr << "SQL error: " << e.what() << endl
         << "Query was: '" << e.query() << "'" << endl;
    return 1;
  }
  catch (const exception &e)
  {
    cerr << "Exception: " << e.what() << endl;
    return 2;
  }

  return 0;
}

<commit_msg>Added check for "long double" support<commit_after>#include <cmath>
#include <iostream>
#include <sstream>

#include <pqxx/pqxx>

using namespace PGSTD;
using namespace pqxx;

// Streams test program for libpqxx.  Insert a result field into various
// types of streams.
//
// Usage: test046 [connect-string]
//
// Where connect-string is a set of connection options in Postgresql's
// PQconnectdb() format, eg. "dbname=template1" to select from a database
// called template1, or "host=foo.bar.net user=smith" to connect to a
// backend running on host foo.bar.net, logging in as user smith.
int main(int, char *argv[])
{
  try
  {
    connection C(argv[1]);
    work T(C, "test46");
    result R( T.exec("SELECT count(*) FROM pg_tables") );

    cout << "Count was " << R.at(0).at(0) << endl;

    // Read the value into a stringstream
    stringstream I;
    I << R[0][0];

    // Now convert the stringstream into a numeric type
    long L, L2;
    I >> L;
    cout << "As a long, it's " << L << endl;

    R[0][0].to(L2);
    if (L != L2)
      throw logic_error("Different conversion methods gave different results!");

    float F, F2;
    stringstream I2;
    I2 << R[0][0];
    I2 >> F;
    cout << "As a float, it's " << F << endl;
    R[0][0].to(F2);
    if (fabs(F2-F) > 0.01)
      throw logic_error("Inconsistent floating-point result: " + to_string(F2));

    float F3;
    from_string(R[0][0].c_str(), F3);
    if (fabs(F3-F) > 0.01)
      throw logic_error("Inconsistent float result from from_string");

    double D;
    from_string(R[0][0].c_str(), D);
    if (fabs(D-F) > 0.01)
      throw logic_error("Inconsistent double result from from_string");

#if defined(PQXX_HAVE_LONG_DOUBLE)
    long double LD;
    from_string(R[0][0].c_str(), LD);
    if (fabs(LD-F) > 0.01)
      throw logic_error("Inconsistent long double result from from_string");
#endif

    string S, S2, S3;
    from_string(R[0][0].c_str(), S);
    from_string(string(R[0][0].c_str()), S2);
    from_string(R[0][0], S3);
    if (S != S2)
      throw runtime_error("from_string(const char[],std::string &) "
	  "is inconsistent with "
	  "from_string(const std::string &,std::string &)");
    if (S3 != S2)
      throw runtime_error("from_string(const result::field &,std::string &) "
	  "is inconsistent with "
	  "from_string(const std::string &,std::string &)");

    R = T.exec("SELECT 1=1");
    if (!R.at(0).at(0).as<bool>())
      throw logic_error("1=1 doesn't yield 'true'");
    R = T.exec("SELECT 2+2=5");
    if (R.at(0).at(0).as<bool>())
      throw logic_error("2+2=5 yields 'true'");
  }
  catch (const sql_error &e)
  {
    cerr << "SQL error: " << e.what() << endl
         << "Query was: '" << e.query() << "'" << endl;
    return 1;
  }
  catch (const exception &e)
  {
    cerr << "Exception: " << e.what() << endl;
    return 2;
  }

  return 0;
}

<|endoftext|>


<commit_before>#include <pqxx/compiler.h>

#include <iostream>

#include <pqxx/binarystring>
#include <pqxx/connection>
#include <pqxx/transaction>
#include <pqxx/result>

using namespace PGSTD;
using namespace pqxx;

// Example program for libpqxx.  Test binarystring functionality.
//
// Usage: test062 [connect-string]
//
// Where connect-string is a set of connection options in Postgresql's
// PQconnectdb() format, eg. "dbname=template1" to select from a database
// called template1, or "host=foo.bar.net user=smith" to connect to a
// backend running on host foo.bar.net, logging in as user smith.

int main(int, char *argv[])
{
  try
  {
    const string TestStr = "Nasty\n\030Test\n\t String\r\0 With Trailer\\\\\0";

    connection C(argv[1]);
    work T(C, "test62");

    T.exec("CREATE TEMP TABLE pqxxbin (binfield bytea)");
    const string Esc = escape_binary(TestStr);
    T.exec("INSERT INTO pqxxbin VALUES ('" + Esc + "')");

    result R = T.exec("SELECT * from pqxxbin");
    binarystring B( R.at(0).at(0) );

    if (B.empty())
      throw logic_error("Binary string became empty in conversion");

    if (B.size() != TestStr.size())
      throw logic_error("Binary string got changed from " +
	  to_string(TestStr.size()) + " to " + to_string(B.size()) + " bytes");

    if (strncmp(TestStr.c_str(), B.c_ptr(), B.size()) != 0)
      throw logic_error("Binary string was changed before first zero byte: "
	  "'" + string(B.c_ptr(), B.size()) + "'");

    binarystring::const_iterator c;
    binarystring::size_type i;
    for (i=0, c=B.begin(); i<B.size(); ++i, ++c)
    {
      if (c == B.end())
	throw logic_error("Premature end to binary string at " + to_string(i));

      if (B.data()[i] != TestStr.at(i))
	throw logic_error("Binary string byte " + to_string(i) + " "
	    "got changed from '" + to_string(char(TestStr[i])) + "' "
	    "to '" + to_string(char(B.data()[i])) + "'");
      if (B.at(i) != B.data()[i])
	throw logic_error("Inconsistent byte at offset " + to_string(i) + ": "
	    "operator[] says '" + to_string(char(B.at(i))) + "', "
	    "data() says '" + to_string(char(B.data()[i])) + "'");
    }
    if (c != B.end())
      throw logic_error("end() of binary string not reached");

#ifdef PQXX_HAVE_REVERSE_ITERATOR
    binarystring::const_reverse_iterator r;
    for (i=B.length(), r=B.rbegin(); i>0; --i, ++r)
    {
      if (r == B.rend())
	throw logic_error("Premature rend to binary string at " + to_string(i));

      if (B[i-1] != TestStr.at(i-1))
	throw logic_error("Reverse iterator differs at " + to_string(i));
    }
    if (r != B.rend())
      throw logic_error("rend() of binary string not reached");
#endif

    if (B.str() != TestStr)
      throw logic_error("Binary string got mangled: '" + B.str() + "'");
  }
  catch (const sql_error &e)
  {
    // If we're interested in the text of a failed query, we can write separate
    // exception handling code for this type of exception
    cerr << "SQL error: " << e.what() << endl
         << "Query was: '" << e.query() << "'" << endl;
    return 1;
  }
  catch (const exception &e)
  {
    // All exceptions thrown by libpqxx are derived from std::exception
    cerr << "Exception: " << e.what() << endl;
    return 2;
  }
  catch (...)
  {
    // This is really unexpected (see above)
    cerr << "Unhandled exception" << endl;
    return 100;
  }

  return 0;
}

<commit_msg>Test binarystring front()/back() and swap()<commit_after>#include <pqxx/compiler.h>

#include <iostream>

#include <pqxx/binarystring>
#include <pqxx/connection>
#include <pqxx/transaction>
#include <pqxx/result>

using namespace PGSTD;
using namespace pqxx;

// Example program for libpqxx.  Test binarystring functionality.
//
// Usage: test062 [connect-string]
//
// Where connect-string is a set of connection options in Postgresql's
// PQconnectdb() format, eg. "dbname=template1" to select from a database
// called template1, or "host=foo.bar.net user=smith" to connect to a
// backend running on host foo.bar.net, logging in as user smith.

int main(int, char *argv[])
{
  try
  {
    const string TestStr = "Nasty\n\030Test\n\t String\r\0 With Trailer\\\\\0";

    connection C(argv[1]);
    work T(C, "test62");

    T.exec("CREATE TEMP TABLE pqxxbin (binfield bytea)");
    const string Esc = escape_binary(TestStr);
    T.exec("INSERT INTO pqxxbin VALUES ('" + Esc + "')");

    result R = T.exec("SELECT * from pqxxbin");
    T.exec("DELETE FROM pqxxbin");

    binarystring B( R.at(0).at(0) );

    if (B.empty())
      throw logic_error("Binary string became empty in conversion");

    if (B.size() != TestStr.size())
      throw logic_error("Binary string got changed from " +
	  to_string(TestStr.size()) + " to " + to_string(B.size()) + " bytes");

    if (strncmp(TestStr.c_str(), B.c_ptr(), B.size()) != 0)
      throw logic_error("Binary string was changed before first zero byte: "
	  "'" + string(B.c_ptr(), B.size()) + "'");

    binarystring::const_iterator c;
    binarystring::size_type i;
    for (i=0, c=B.begin(); i<B.size(); ++i, ++c)
    {
      if (c == B.end())
	throw logic_error("Premature end to binary string at " + to_string(i));

      if (B.data()[i] != TestStr.at(i))
	throw logic_error("Binary string byte " + to_string(i) + " "
	    "got changed from '" + to_string(char(TestStr[i])) + "' "
	    "to '" + to_string(char(B.data()[i])) + "'");
      if (B.at(i) != B.data()[i])
	throw logic_error("Inconsistent byte at offset " + to_string(i) + ": "
	    "operator[] says '" + to_string(char(B.at(i))) + "', "
	    "data() says '" + to_string(char(B.data()[i])) + "'");
    }
    if (B.at(0) != B.front())
      throw logic_error("Something wrong with binarystring::front()");
    if (c != B.end())
      throw logic_error("end() of binary string not reached");
    --c;
    if (*c != B.back())
      throw logic_error("Something wrong with binarystring::back()");

#ifdef PQXX_HAVE_REVERSE_ITERATOR
    binarystring::const_reverse_iterator r;
    for (i=B.length(), r=B.rbegin(); i>0; --i, ++r)
    {
      if (r == B.rend())
	throw logic_error("Premature rend to binary string at " + to_string(i));

      if (B[i-1] != TestStr.at(i-1))
	throw logic_error("Reverse iterator differs at " + to_string(i));
    }
    if (r != B.rend())
      throw logic_error("rend() of binary string not reached");
#endif

    if (B.str() != TestStr)
      throw logic_error("Binary string got mangled: '" + B.str() + "'");

    const string TestStr2("(More conventional text)");
    T.exec("INSERT INTO pqxxbin VALUES ('" + TestStr2 + "')");
    R = T.exec("SELECT * FROM pqxxbin");
    binarystring B2(R.front().front());

    if (B2 == B)
      throw logic_error("Two different binarystrings say they're equal!");
    if (!(B2 != B))
      throw logic_error("Problem with binarystring::operator!=");

    binarystring B1c(B), B2c(B2);
    if (B1c != B)
      throw logic_error("Copied binarystring differs from original");
    if (!(B2c == B2))
      throw logic_error("Copied binarystring not equal to original");

    B1c.swap(B2c);

    if (B2c == B1c)
      throw logic_error("Swapped binarystrings say they're identical!");
    if (B2c != B)
      throw logic_error("Problem with binarystring::swap()");
    if (!(B1c == B2))
      throw logic_error("Problem with one of two swapped binarystrings");
  }
  catch (const sql_error &e)
  {
    // If we're interested in the text of a failed query, we can write separate
    // exception handling code for this type of exception
    cerr << "SQL error: " << e.what() << endl
         << "Query was: '" << e.query() << "'" << endl;
    return 1;
  }
  catch (const exception &e)
  {
    // All exceptions thrown by libpqxx are derived from std::exception
    cerr << "Exception: " << e.what() << endl;
    return 2;
  }
  catch (...)
  {
    // This is really unexpected (see above)
    cerr << "Unhandled exception" << endl;
    return 100;
  }

  return 0;
}

<|endoftext|>


<commit_before>#include "module_wpad.hpp"
using namespace com::googlecode::libproxy;

static const char *DEFAULT_WPAD_ORDER[] = {
	"wpad_dhcp",
	"wpad_slp",
	"wpad_dns",
	"wpad_dnsdevolution",
	NULL
};

bool wpad_module::operator<(const wpad_module& module) const {
	for (int i=0 ; DEFAULT_WPAD_ORDER[i] ; i++) {
		if (module.get_id() == DEFAULT_WPAD_ORDER[i])
			break;
		if (this->get_id() == DEFAULT_WPAD_ORDER[i])
			return true;
	}
	return false;
}
<commit_msg>Fix wpad ordering table after wpad_dns -> wpad_dns_alias rename<commit_after>#include "module_wpad.hpp"
using namespace com::googlecode::libproxy;

static const char *DEFAULT_WPAD_ORDER[] = {
	"wpad_dhcp",
	"wpad_slp",
	"wpad_dns_srv",
	"wpad_dns_txt",
	"wpad_dns_alias",
	NULL
};

bool wpad_module::operator<(const wpad_module& module) const {
	for (int i=0 ; DEFAULT_WPAD_ORDER[i] ; i++) {
		if (module.get_id() == DEFAULT_WPAD_ORDER[i])
			break;
		if (this->get_id() == DEFAULT_WPAD_ORDER[i])
			return true;
	}
	return false;
}
<|endoftext|>


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

#ifndef HCKT_TREE_H
#define HCKT_TREE_H

#include <cassert>
#include <vector>
#include <iostream>
#include <bitset>
#include "lmemvector.hpp"

namespace hckt
{

template <typename T>
class tree
{
typedef T value_type;

protected:
    std::bitset<64>                     chiset;   //is child set to this position
    std::bitset<64>                     inv_leaf; //opposite of leaf
    hckt::lmemvector<value_type>        values;
    hckt::lmemvector<tree<value_type>*> children;

public:

    tree() : chiset { 0 }, inv_leaf { 0xFFFFFFFFFFFFFFFF }, values { }, children { }
    {
    }

    ~tree()
    {
        collapse();
    }

    //counts number of set bits
    static inline unsigned popcount(std::uint64_t x)
    {
#ifdef __SSE4_2__
        return _popcnt64(x);
#else
        constexpr std::uint64_t m1  { 0x5555555555555555 };
        constexpr std::uint64_t m2  { 0x3333333333333333 };
        constexpr std::uint64_t m4  { 0x0f0f0f0f0f0f0f0f };
        constexpr std::uint64_t h01 { 0x0101010101010101 };

        x -= (x >> 1) & m1;
        x  = (x & m2) + ((x >> 2) & m2);
        x  = (x + (x >> 4)) & m4;

        return (x * h01) >> 56;
#endif
    }

    std::uint64_t chidist() const
    {
        return (chiset.to_ullong() & inv_leaf.to_ullong());
    }

    unsigned children_amnt() const
    {
        return popcount(chidist());
    }

    unsigned leaf_amnt() const
    {
        return popcount(~inv_leaf.to_ullong());
    }

    unsigned get_children_position(const unsigned position) const
    {
        assert(position < 64);

        if(position == 0) {
            return 0;
        }

        return popcount(chidist() << (64 - position));
    }

    /*
     * check if we have any children
     */
    bool has_children() const
    {
        return chiset.any();
    }

    bool is_set(const unsigned position) const
    {
        assert(position < 64);
        return chiset[position];
    }

    bool is_leaf(const unsigned position) const
    {
        assert(position < 64);
        return !inv_leaf[position];
    }

    /*
     * destroy children
     */
    void collapse()
    {
        const unsigned c_amnt { children_amnt() };

        for(unsigned i=0; i<c_amnt; ++i) {
            children[i]->collapse();
        }

        children.clear(c_amnt);
        values.clear(c_amnt);
        chiset.reset();
    }

    /*
     * insert a tree into position of tree
     * position should be result of get_position
     */
    void insert(const unsigned position, const value_type value)
    {
        assert(position < 64);
        assert(! is_set(position));

        const unsigned cpos   { get_children_position(position) };
        const unsigned c_amnt { children_amnt() };

        children.insert(cpos, new tree<value_type>(), c_amnt);
        values.insert(cpos, value, c_amnt);
        chiset.set(position);
        inv_leaf.set(position);
    }

    /*
     * insert a leaf into position of tree
     * position should be result of get_position
     */
    void insert_leaf(const unsigned position, const value_type value)
    {
        assert(position < 64);
        assert(! is_set(position));

        const unsigned cpos   { get_children_position(position) };
        const unsigned c_amnt { children_amnt() };

        values.insert(cpos, value, c_amnt);
        chiset.set(position);
        inv_leaf.reset(position);
    }

    /*
     * removes an item from tree
     * position should be result of get_position
     */
    void remove(const unsigned position)
    {
        assert(position < 64);
        assert(is_set(position));
        assert(! is_leaf(position));

        const unsigned cpos   { get_children_position(position) };
        const unsigned c_amnt { children_amnt() };

        children[cpos]->collapse();
        children.erase(cpos);
        values.erase(cpos);
        chiset.reset(position);
    }

    /*
     * get child node
     * position should be result of get_position
     */
    tree<value_type> * child(const unsigned position) const
    {
        assert(position < 64);
        assert(is_set(position));
        assert(! is_leaf(position));

        const unsigned cpos { get_children_position(position) };

        return children[cpos];
    }

    /*
     * sets node to specific value
     * note: this does not check whether a value has been inserted here yet
     * position should be result of get_position
     */
    void set_value(const unsigned position, const value_type value)
    {
        assert(position < 64);
        assert(is_set(position));

        const unsigned cpos { get_children_position(position) };

        values[cpos] = value;
    }

    /*
     * gets value from specific position
     * note: this does not check whether a value has been inserted here yet
     * position should be result of get_position
     */
    value_type get_value(const unsigned position) const
    {
        assert(position < 64);

        const unsigned cpos { get_children_position(position) };

        return values[cpos];
    }

    /************************************************
     *
     * BENCHMARKING CODE
     *
     ***********************************************/

    std::size_t calculate_memory_size() const
    {
        const unsigned c_amnt { children_amnt() };
        const unsigned l_amnt { leaf_amnt() };
        const unsigned v_amnt { c_amnt + l_amnt };

        std::size_t size {
              sizeof(chiset)
            + sizeof(inv_leaf)
            + sizeof(values)   + (l_amnt * sizeof(value_type))
            + sizeof(children) + (c_amnt * sizeof(tree<value_type>*))
        };

        for(unsigned i=0; i<c_amnt; ++i) {
            size += children[i]->calculate_memory_size();
        }

        return size;
    }

    std::size_t calculate_children_amnt() const
    {
        std::size_t amount { children_amnt() };

        for(unsigned i=0, c_amnt = children_amnt(); i<c_amnt; ++i) {
            amount += children[i]->calculate_children_amnt();
        }

        return amount;
    }

    std::size_t calculate_leaf_amount() const
    {
        std::size_t amount { leaf_amnt() };

        for(unsigned i=0, c_amnt = children_amnt(); i<c_amnt; ++i) {
            amount += children[i]->calculate_leaf_amount();
        }

        return amount;
    }

    void mem_usage_info() const
    {
        const unsigned memsize { calculate_memory_size() };
        const unsigned c_amnt  { calculate_children_amnt() };
        const unsigned l_amnt  { calculate_leaf_amount() };
        const unsigned v_amnt  { c_amnt + l_amnt };

        std::cout << "total:     " << memsize << std::endl;

        std::cout << "tree-size: " << sizeof(tree<value_type>) << std::endl;
        std::cout << "val-size:  " << sizeof(value_type) << std::endl;

        std::cout << "values:    " << v_amnt << std::endl;
        std::cout << "children:  " << c_amnt << std::endl;
        std::cout << "leaves:    " << l_amnt << std::endl;

        std::cout << "per-val:   " << (static_cast<float>(memsize) / v_amnt) << std::endl;
        std::cout << "overhead:  " << (static_cast<float>(memsize - (v_amnt * sizeof(value_type))) / v_amnt) << std::endl;
    }

};

};

#endif
<commit_msg>move to ternary<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Jett
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#ifndef HCKT_TREE_H
#define HCKT_TREE_H

#include <cassert>
#include <vector>
#include <iostream>
#include <bitset>
#include "lmemvector.hpp"

namespace hckt
{

template <typename T>
class tree
{
typedef T value_type;

protected:
    std::bitset<64>                     chiset;   //is child set to this position
    std::bitset<64>                     inv_leaf; //opposite of leaf
    hckt::lmemvector<value_type>        values;
    hckt::lmemvector<tree<value_type>*> children;

public:

    tree() : chiset { 0 }, inv_leaf { 0xFFFFFFFFFFFFFFFF }, values { }, children { }
    {
    }

    ~tree()
    {
        collapse();
    }

    //counts number of set bits
    static inline unsigned popcount(std::uint64_t x)
    {
#ifdef __SSE4_2__
        return _popcnt64(x);
#else
        constexpr std::uint64_t m1  { 0x5555555555555555 };
        constexpr std::uint64_t m2  { 0x3333333333333333 };
        constexpr std::uint64_t m4  { 0x0f0f0f0f0f0f0f0f };
        constexpr std::uint64_t h01 { 0x0101010101010101 };

        x -= (x >> 1) & m1;
        x  = (x & m2) + ((x >> 2) & m2);
        x  = (x + (x >> 4)) & m4;

        return (x * h01) >> 56;
#endif
    }

    std::uint64_t chidist() const
    {
        return (chiset.to_ullong() & inv_leaf.to_ullong());
    }

    unsigned children_amnt() const
    {
        return popcount(chidist());
    }

    unsigned leaf_amnt() const
    {
        return popcount(~inv_leaf.to_ullong());
    }

    unsigned get_children_position(const unsigned position) const
    {
        assert(position < 64);

        return position == 0 ? position : popcount(chidist() << (64 - position));
    }

    /*
     * check if we have any children
     */
    bool has_children() const
    {
        return chiset.any();
    }

    bool is_set(const unsigned position) const
    {
        assert(position < 64);
        return chiset[position];
    }

    bool is_leaf(const unsigned position) const
    {
        assert(position < 64);
        return !inv_leaf[position];
    }

    /*
     * destroy children
     */
    void collapse()
    {
        const unsigned c_amnt { children_amnt() };

        for(unsigned i=0; i<c_amnt; ++i) {
            children[i]->collapse();
        }

        children.clear(c_amnt);
        values.clear(c_amnt);
        chiset.reset();
    }

    /*
     * insert a tree into position of tree
     * position should be result of get_position
     */
    void insert(const unsigned position, const value_type value)
    {
        assert(position < 64);
        assert(! is_set(position));

        const unsigned cpos   { get_children_position(position) };
        const unsigned c_amnt { children_amnt() };

        children.insert(cpos, new tree<value_type>(), c_amnt);
        values.insert(cpos, value, c_amnt);
        chiset.set(position);
        inv_leaf.set(position);
    }

    /*
     * insert a leaf into position of tree
     * position should be result of get_position
     */
    void insert_leaf(const unsigned position, const value_type value)
    {
        assert(position < 64);
        assert(! is_set(position));

        const unsigned cpos   { get_children_position(position) };
        const unsigned c_amnt { children_amnt() };

        values.insert(cpos, value, c_amnt);
        chiset.set(position);
        inv_leaf.reset(position);
    }

    /*
     * removes an item from tree
     * position should be result of get_position
     */
    void remove(const unsigned position)
    {
        assert(position < 64);
        assert(is_set(position));
        assert(! is_leaf(position));

        const unsigned cpos   { get_children_position(position) };
        const unsigned c_amnt { children_amnt() };

        children[cpos]->collapse();
        children.erase(cpos);
        values.erase(cpos);
        chiset.reset(position);
    }

    /*
     * get child node
     * position should be result of get_position
     */
    tree<value_type> * child(const unsigned position) const
    {
        assert(position < 64);
        assert(is_set(position));
        assert(! is_leaf(position));

        const unsigned cpos { get_children_position(position) };

        return children[cpos];
    }

    /*
     * sets node to specific value
     * note: this does not check whether a value has been inserted here yet
     * position should be result of get_position
     */
    void set_value(const unsigned position, const value_type value)
    {
        assert(position < 64);
        assert(is_set(position));

        const unsigned cpos { get_children_position(position) };

        values[cpos] = value;
    }

    /*
     * gets value from specific position
     * note: this does not check whether a value has been inserted here yet
     * position should be result of get_position
     */
    value_type get_value(const unsigned position) const
    {
        assert(position < 64);

        const unsigned cpos { get_children_position(position) };

        return values[cpos];
    }

    /************************************************
     *
     * BENCHMARKING CODE
     *
     ***********************************************/

    std::size_t calculate_memory_size() const
    {
        const unsigned c_amnt { children_amnt() };
        const unsigned l_amnt { leaf_amnt() };
        const unsigned v_amnt { c_amnt + l_amnt };

        std::size_t size {
              sizeof(chiset)
            + sizeof(inv_leaf)
            + sizeof(values)   + (l_amnt * sizeof(value_type))
            + sizeof(children) + (c_amnt * sizeof(tree<value_type>*))
        };

        for(unsigned i=0; i<c_amnt; ++i) {
            size += children[i]->calculate_memory_size();
        }

        return size;
    }

    std::size_t calculate_children_amnt() const
    {
        std::size_t amount { children_amnt() };

        for(unsigned i=0, c_amnt = children_amnt(); i<c_amnt; ++i) {
            amount += children[i]->calculate_children_amnt();
        }

        return amount;
    }

    std::size_t calculate_leaf_amount() const
    {
        std::size_t amount { leaf_amnt() };

        for(unsigned i=0, c_amnt = children_amnt(); i<c_amnt; ++i) {
            amount += children[i]->calculate_leaf_amount();
        }

        return amount;
    }

    void mem_usage_info() const
    {
        const unsigned memsize { calculate_memory_size() };
        const unsigned c_amnt  { calculate_children_amnt() };
        const unsigned l_amnt  { calculate_leaf_amount() };
        const unsigned v_amnt  { c_amnt + l_amnt };

        std::cout << "total:     " << memsize << std::endl;

        std::cout << "tree-size: " << sizeof(tree<value_type>) << std::endl;
        std::cout << "val-size:  " << sizeof(value_type) << std::endl;

        std::cout << "values:    " << v_amnt << std::endl;
        std::cout << "children:  " << c_amnt << std::endl;
        std::cout << "leaves:    " << l_amnt << std::endl;

        std::cout << "per-val:   " << (static_cast<float>(memsize) / v_amnt) << std::endl;
        std::cout << "overhead:  " << (static_cast<float>(memsize - (v_amnt * sizeof(value_type))) / v_amnt) << std::endl;
    }

};

};

#endif
<|endoftext|>


<commit_before>#pragma once
#include "base.hpp"
#include "internal/message.hpp"
#include "src_point.hpp"

namespace my
{
  enum LogLevel
  {
    LDEBUG,
    LINFO,
    LWARNING,
    LERROR,
    LCRITICAL
  };

  typedef void (*LogMessageFn)(LogLevel level, SrcPoint const &, string const &);

  extern LogMessageFn LogMessage;
  extern LogLevel g_LogLevel;

  /// @return Pointer to previous message function.
  LogMessageFn SetLogMessageFn(LogMessageFn fn);
}

using ::my::LDEBUG;
using ::my::LINFO;
using ::my::LWARNING;
using ::my::LERROR;
using ::my::LCRITICAL;

// Logging macro.
// Example usage: LOG(LINFO, (Calc(), m_Var, "Some string constant"));
#define LOG(level, msg) do { if (level < ::my::g_LogLevel) {} \
  else { ::my::LogMessage(level, SRC(), ::my::impl::Message msg);} } while (false)

// Logging macro with short info (without entry point)
#define LOG_SHORT(level, msg) do { if (level < ::my::g_LogLevel) {} \
  else { ::my::LogMessage(level, my::SrcPoint(), ::my::impl::Message msg);} } while (false)
<commit_msg>[core] Fixed LOG macros.<commit_after>#pragma once
#include "base.hpp"
#include "internal/message.hpp"
#include "src_point.hpp"

namespace my
{
  enum LogLevel
  {
    LDEBUG,
    LINFO,
    LWARNING,
    LERROR,
    LCRITICAL
  };

  typedef void (*LogMessageFn)(LogLevel level, SrcPoint const &, string const &);

  extern LogMessageFn LogMessage;
  extern LogLevel g_LogLevel;

  /// @return Pointer to previous message function.
  LogMessageFn SetLogMessageFn(LogMessageFn fn);
}

using ::my::LDEBUG;
using ::my::LINFO;
using ::my::LWARNING;
using ::my::LERROR;
using ::my::LCRITICAL;

// Logging macro.
// Example usage: LOG(LINFO, (Calc(), m_Var, "Some string constant"));
#define LOG(level, msg) do { if ((level) < ::my::g_LogLevel) {} \
  else { ::my::LogMessage(level, SRC(), ::my::impl::Message msg);} } while (false)

// Logging macro with short info (without entry point)
#define LOG_SHORT(level, msg) do { if ((level) < ::my::g_LogLevel) {} \
  else { ::my::LogMessage(level, my::SrcPoint(), ::my::impl::Message msg);} } while (false)
<|endoftext|>


<commit_before><commit_msg>throw a noncopyable pattern at oneToOneMappingWithFlag<commit_after><|endoftext|>


<commit_before>// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Engine - Network module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Network/Debug.hpp>

namespace Nz
{
	/*!
	* \brief Gets the last error
	* \return Socket error
	*/

	inline SocketError AbstractSocket::GetLastError() const
	{
		return m_lastError;
	}

	/*!
	* \brief Gets the internal socket handle
	* \return Socket handle
	*/

	inline SocketHandle AbstractSocket::GetNativeHandle() const
	{
		return m_handle;
	}

	/*!
	* \brief Gets the internal state
	* \return Socket state
	*/

	inline SocketState AbstractSocket::GetState() const
	{
		return m_state;
	}

	/*!
	* \brief Gets the internal type
	* \return Socket type
	*/

	inline SocketType AbstractSocket::GetType() const
	{
		return m_type;
	}

	/*!
	* \brief Checks whether the blocking is enabled
	* \return true If successful
	*/

	inline bool AbstractSocket::IsBlockingEnabled() const
	{
		return m_isBlockingEnabled;
	}

	/*!
	* \brief Updates the state of the socket
	*
	* \param newState Next state for the socket
	*/

	inline void AbstractSocket::UpdateState(SocketState newState)
	{
		if (m_state != newState)
		{
			SocketState oldState = m_state;
			m_state = newState;
			OnStateChange(this, oldState, newState);
		}
	}
}

#include <Nazara/Network/DebugOff.hpp>
<commit_msg>Forgot to save this file<commit_after>// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Engine - Network module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Network/Debug.hpp>

namespace Nz
{
	/*!
	* \brief Gets the last error
	* \return Socket error
	*/

	inline SocketError AbstractSocket::GetLastError() const
	{
		return m_lastError;
	}

	/*!
	* \brief Gets the internal socket handle
	* \return Socket handle
	*/

	inline SocketHandle AbstractSocket::GetNativeHandle() const
	{
		return m_handle;
	}

	/*!
	* \brief Gets the internal state
	* \return Socket state
	*/

	inline SocketState AbstractSocket::GetState() const
	{
		return m_state;
	}

	/*!
	* \brief Gets the internal type
	* \return Socket type
	*/

	inline SocketType AbstractSocket::GetType() const
	{
		return m_type;
	}

	/*!
	* \brief Checks whether the blocking is enabled
	* \return true If successful
	*/

	inline bool AbstractSocket::IsBlockingEnabled() const
	{
		return m_isBlockingEnabled;
	}

	/*!
	* \brief Updates the state of the socket
	*
	* \param newState Next state for the socket
	*/

	inline void AbstractSocket::UpdateState(SocketState newState)
	{
		if (m_state != newState)
		{
			SocketState oldState = m_state;
			m_state = newState;
			OnStateChanged(this, oldState, newState);
		}
	}
}

#include <Nazara/Network/DebugOff.hpp>
<|endoftext|>


<commit_before>/*******************************************************************************
 *
 * Generic implementation of non-relational domains.
 *
 * Author: Arnaud J. Venet (arnaud.j.venet@nasa.gov)
 *
 * Notices:
 *
 * Copyright (c) 2011 United States Government as represented by the
 * Administrator of the National Aeronautics and Space Administration.
 * All Rights Reserved.
 *
 * Disclaimers:
 *
 * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF
 * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED
 * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS,
 * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
 * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE
 * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO
 * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN
 * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS,
 * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS
 * RESULTING FROM USE OF THE SUBJECT SOFTWARE.  FURTHER, GOVERNMENT AGENCY
 * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE,
 * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS."
 *
 * Waiver and Indemnity:  RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST
 * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL
 * AS ANY PRIOR RECIPIENT.  IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS
 * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH
 * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM,
 * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD
 * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS,
 * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW.
 * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE,
 * UNILATERAL TERMINATION OF THIS AGREEMENT.
 *
 ******************************************************************************/

#pragma once

#include <crab/domains/patricia_trees.hpp>
#include <crab/support/debug.hpp>

#include <boost/optional.hpp>

namespace ikos {

template <typename Key, typename Value> class separate_domain {

private:
  using patricia_tree_t = patricia_tree<Key, Value>;
  using unary_op_t = typename patricia_tree_t::unary_op_t;
  using binary_op_t = typename patricia_tree_t::binary_op_t;
  using partial_order_t = typename patricia_tree_t::partial_order_t;

public:
  using separate_domain_t = separate_domain<Key, Value>;
  using iterator = typename patricia_tree_t::iterator;
  using key_type = Key;
  using value_type = Value;

private:
  bool _is_bottom;
  patricia_tree_t _tree;

public:
  class join_op : public binary_op_t {
    std::pair<bool, boost::optional<Value>> apply(Value x, Value y) {
      Value z = x.operator|(y);
      if (z.is_top()) {
        return {false, boost::optional<Value>()};
      } else {
        return {false, boost::optional<Value>(z)};
      }
    };

    bool default_is_absorbing() { return true; }
  }; // class join_op

  class widening_op : public binary_op_t {
    std::pair<bool, boost::optional<Value>> apply(Value x, Value y) {
      Value z = x.operator||(y);
      if (z.is_top()) {
        return {false, boost::optional<Value>()};
      } else {
        return {false, boost::optional<Value>(z)};
      }
    };

    bool default_is_absorbing() { return true; }

  }; // class widening_op

  template <typename Thresholds>
  class widening_thresholds_op : public binary_op_t {
    const Thresholds &m_ts;

  public:
    widening_thresholds_op(const Thresholds &ts) : m_ts(ts) {}

    std::pair<bool, boost::optional<Value>> apply(Value x, Value y) {
      Value z = x.widening_thresholds(y, m_ts);
      if (z.is_top()) {
        return {false, boost::optional<Value>()};
      } else {
        return {false, boost::optional<Value>(z)};
      }
    };

    bool default_is_absorbing() { return true; }

  }; // class widening_thresholds_op

  class meet_op : public binary_op_t {
    std::pair<bool, boost::optional<Value>> apply(Value x, Value y) {
      Value z = x.operator&(y);
      if (z.is_bottom()) {
        return {true, boost::optional<Value>()};
      } else {
        return {false, boost::optional<Value>(z)};
      }
    };

    bool default_is_absorbing() { return false; }

  }; // class meet_op

  class narrowing_op : public binary_op_t {
    std::pair<bool, boost::optional<Value>> apply(Value x, Value y) {
      Value z = x.operator&&(y);
      if (z.is_bottom()) {
        return {true, boost::optional<Value>()};
      } else {
        return {false, boost::optional<Value>(z)};
      }
    };

    bool default_is_absorbing() { return false; }

  }; // class narrowing_op

  class domain_po : public partial_order_t {
    bool leq(Value x, Value y) { return x.operator<=(y); }

    bool default_is_top() { return true; }

  }; // class domain_po

public:
  static separate_domain_t top() { return separate_domain_t(); }

  static separate_domain_t bottom() { return separate_domain_t(false); }

private:
  static patricia_tree_t apply_operation(binary_op_t &o, patricia_tree_t t1,
                                         const patricia_tree_t &t2,
                                         bool &is_bottom) {
    is_bottom = t1.merge_with(t2, o);
    return t1;
  }

  separate_domain(patricia_tree_t t) : _is_bottom(false), _tree(t) {}

  separate_domain(bool b) : _is_bottom(!b) {}

public:
  separate_domain() : _is_bottom(false) {}

  separate_domain(const separate_domain_t &e)
      : _is_bottom(e._is_bottom), _tree(e._tree) {}

  separate_domain(const separate_domain_t &&e)
      : _is_bottom(e._is_bottom), _tree(std::move(e._tree)) {}

  separate_domain_t &operator=(separate_domain_t e) {
    this->_is_bottom = e._is_bottom;
    this->_tree = e._tree;
    return *this;
  }

  iterator begin() const {
    if (this->is_bottom()) {
      CRAB_ERROR("Separate domain: trying to invoke iterator on bottom");
    } else {
      return this->_tree.begin();
    }
  }

  iterator end() const {
    if (this->is_bottom()) {
      CRAB_ERROR("Separate domain: trying to invoke iterator on bottom");
    } else {
      return this->_tree.end();
    }
  }

  bool is_bottom() const { return this->_is_bottom; }

  bool is_top() const {
    return (!this->is_bottom() && this->_tree.size() == 0);
  }

  bool operator<=(const separate_domain_t &e) const {
    if (this->is_bottom()) {
      return true;
    } else if (e.is_bottom()) {
      return false;
    } else {
      domain_po po;
      return this->_tree.leq(e._tree, po);
    }
  }

  bool operator==(const separate_domain_t &e) const {
    return (this->operator<=(e) && e.operator<=(*this));
  }

  // Join
  separate_domain_t operator|(const separate_domain_t &e) const {
    if (this->is_bottom()) {
      return e;
    } else if (e.is_bottom()) {
      return *this;
    } else {
      join_op o;
      bool is_bottom;
      patricia_tree_t res = apply_operation(o, this->_tree, e._tree, is_bottom);
      return separate_domain_t(std::move(res));
    }
  }

  // Meet
  separate_domain_t operator&(const separate_domain_t &e) const {
    if (this->is_bottom() || e.is_bottom()) {
      return this->bottom();
    } else {
      meet_op o;
      bool is_bottom;
      patricia_tree_t res = apply_operation(o, this->_tree, e._tree, is_bottom);
      if (is_bottom) {
        return this->bottom();
      } else {
        return separate_domain_t(std::move(res));
      }
    }
  }

  // Widening
  separate_domain_t operator||(const separate_domain_t &e) const {
    if (this->is_bottom()) {
      return e;
    } else if (e.is_bottom()) {
      return *this;
    } else {
      widening_op o;
      bool is_bottom;
      patricia_tree_t res = apply_operation(o, this->_tree, e._tree, is_bottom);
      return separate_domain_t(std::move(res));
    }
  }

  // Widening with thresholds
  template <typename Thresholds>
  separate_domain_t widening_thresholds(const separate_domain_t &e,
                                        const Thresholds &ts) const {
    if (this->is_bottom()) {
      return e;
    } else if (e.is_bottom()) {
      return *this;
    } else {
      widening_thresholds_op<Thresholds> o(ts);
      bool is_bottom;
      patricia_tree_t res = apply_operation(o, this->_tree, e._tree, is_bottom);
      return separate_domain_t(std::move(res));
    }
  }

  // Narrowing
  separate_domain_t operator&&(const separate_domain_t &e) const {
    if (this->is_bottom() || e.is_bottom()) {
      return separate_domain_t(false);
    } else {
      narrowing_op o;
      bool is_bottom;
      patricia_tree_t res = apply_operation(o, this->_tree, e._tree, is_bottom);
      if (is_bottom) {
        return this->bottom();
      } else {
        return separate_domain_t(std::move(res));
      }
    }
  }

  void set(Key k, Value v) {
    if (!this->is_bottom()) {
      if (v.is_bottom()) {
        this->_is_bottom = true;
        this->_tree = patricia_tree_t();
      } else if (v.is_top()) {
        this->_tree.remove(k);
      } else {
        this->_tree.insert(k, v);
      }
    }
  }

  void set_to_bottom() {
    this->_is_bottom = true;
    this->_tree = patricia_tree_t();
  }

  separate_domain_t &operator-=(const Key &k) {
    if (!this->is_bottom()) {
      this->_tree.remove(k);
    }
    return *this;
  }

  Value operator[](const Key &k) const {
    if (this->is_bottom()) {
      return Value::bottom();
    } else {
      boost::optional<Value> v = this->_tree.lookup(k);
      if (v) {
        return *v;
      } else {
        return Value::top();
      }
    }
  }

  std::size_t size() const {
    if (is_bottom()) {
      return 0;
    } else if (is_top()) {
      CRAB_ERROR("separate_domains::size() is undefined if top");
    } else {
      return this->_tree.size();
    }
  }

  void write(crab::crab_os &o) const {
    if (this->is_bottom()) {
      o << "_|_";
    } else {
      o << "{";
      for (typename patricia_tree_t::iterator it = this->_tree.begin();
           it != this->_tree.end();) {
        Key k = it->first;
        k.write(o);
        o << " -> ";
        Value v = it->second;
        v.write(o);
        ++it;
        if (it != this->_tree.end()) {
          o << "; ";
        }
      }
      o << "}";
    }
  }

  // Assume that from does not have duplicates.
  void rename(const std::vector<Key> &from, const std::vector<Key> &to) {
    if (from.size() != to.size()) {
      CRAB_ERROR(
          "separate_domain::rename received input vectors of different sizes");
    }

    if (is_top() || is_bottom()) {
      // nothing to rename
      return;
    }

    for (unsigned i = 0, sz = from.size(); i < sz; ++i) {
      Key k = from[i];
      Key new_k = to[i];
      if (k == new_k) { // nothing to rename
        continue;
      }

      if (_tree.lookup(new_k)) {
        CRAB_ERROR("separate_domain::rename assumes that  ", new_k,
                   " does not exist");
      }

      if (boost::optional<Value> k_val_opt = _tree.lookup(k)) {
        if (!(*k_val_opt).is_top()) {
          _tree.insert(new_k, *k_val_opt);
        }
        _tree.remove(k);
      }
    }
  }

  friend crab::crab_os &operator<<(crab::crab_os &o,
                                   const separate_domain<Key, Value> &d) {
    d.write(o);
    return o;
  }
}; // class separate_domain

} // namespace ikos
<commit_msg>refactor(separate_domains): sanity checks for rename<commit_after>/*******************************************************************************
 *
 * Generic implementation of non-relational domains.
 *
 * Author: Arnaud J. Venet (arnaud.j.venet@nasa.gov)
 *
 * Notices:
 *
 * Copyright (c) 2011 United States Government as represented by the
 * Administrator of the National Aeronautics and Space Administration.
 * All Rights Reserved.
 *
 * Disclaimers:
 *
 * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF
 * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED
 * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS,
 * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
 * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE
 * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO
 * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN
 * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS,
 * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS
 * RESULTING FROM USE OF THE SUBJECT SOFTWARE.  FURTHER, GOVERNMENT AGENCY
 * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE,
 * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS."
 *
 * Waiver and Indemnity:  RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST
 * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL
 * AS ANY PRIOR RECIPIENT.  IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS
 * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH
 * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM,
 * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD
 * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS,
 * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW.
 * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE,
 * UNILATERAL TERMINATION OF THIS AGREEMENT.
 *
 ******************************************************************************/

#pragma once

#include <crab/domains/patricia_trees.hpp>
#include <crab/support/debug.hpp>

#include <boost/optional.hpp>

#include <vector>
#include <set>

namespace ikos {

template <typename Key, typename Value> class separate_domain {

private:
  using patricia_tree_t = patricia_tree<Key, Value>;
  using unary_op_t = typename patricia_tree_t::unary_op_t;
  using binary_op_t = typename patricia_tree_t::binary_op_t;
  using partial_order_t = typename patricia_tree_t::partial_order_t;

public:
  using separate_domain_t = separate_domain<Key, Value>;
  using iterator = typename patricia_tree_t::iterator;
  using key_type = Key;
  using value_type = Value;

private:
  bool _is_bottom;
  patricia_tree_t _tree;

public:
  class join_op : public binary_op_t {
    std::pair<bool, boost::optional<Value>> apply(Value x, Value y) {
      Value z = x.operator|(y);
      if (z.is_top()) {
        return {false, boost::optional<Value>()};
      } else {
        return {false, boost::optional<Value>(z)};
      }
    };

    bool default_is_absorbing() { return true; }
  }; // class join_op

  class widening_op : public binary_op_t {
    std::pair<bool, boost::optional<Value>> apply(Value x, Value y) {
      Value z = x.operator||(y);
      if (z.is_top()) {
        return {false, boost::optional<Value>()};
      } else {
        return {false, boost::optional<Value>(z)};
      }
    };

    bool default_is_absorbing() { return true; }

  }; // class widening_op

  template <typename Thresholds>
  class widening_thresholds_op : public binary_op_t {
    const Thresholds &m_ts;

  public:
    widening_thresholds_op(const Thresholds &ts) : m_ts(ts) {}

    std::pair<bool, boost::optional<Value>> apply(Value x, Value y) {
      Value z = x.widening_thresholds(y, m_ts);
      if (z.is_top()) {
        return {false, boost::optional<Value>()};
      } else {
        return {false, boost::optional<Value>(z)};
      }
    };

    bool default_is_absorbing() { return true; }

  }; // class widening_thresholds_op

  class meet_op : public binary_op_t {
    std::pair<bool, boost::optional<Value>> apply(Value x, Value y) {
      Value z = x.operator&(y);
      if (z.is_bottom()) {
        return {true, boost::optional<Value>()};
      } else {
        return {false, boost::optional<Value>(z)};
      }
    };

    bool default_is_absorbing() { return false; }

  }; // class meet_op

  class narrowing_op : public binary_op_t {
    std::pair<bool, boost::optional<Value>> apply(Value x, Value y) {
      Value z = x.operator&&(y);
      if (z.is_bottom()) {
        return {true, boost::optional<Value>()};
      } else {
        return {false, boost::optional<Value>(z)};
      }
    };

    bool default_is_absorbing() { return false; }

  }; // class narrowing_op

  class domain_po : public partial_order_t {
    bool leq(Value x, Value y) { return x.operator<=(y); }

    bool default_is_top() { return true; }

  }; // class domain_po

public:
  static separate_domain_t top() { return separate_domain_t(); }

  static separate_domain_t bottom() { return separate_domain_t(false); }

private:
  static patricia_tree_t apply_operation(binary_op_t &o, patricia_tree_t t1,
                                         const patricia_tree_t &t2,
                                         bool &is_bottom) {
    is_bottom = t1.merge_with(t2, o);
    return t1;
  }

  separate_domain(patricia_tree_t t) : _is_bottom(false), _tree(t) {}

  separate_domain(bool b) : _is_bottom(!b) {}

public:
  separate_domain() : _is_bottom(false) {}

  separate_domain(const separate_domain_t &e)
      : _is_bottom(e._is_bottom), _tree(e._tree) {}

  separate_domain(const separate_domain_t &&e)
      : _is_bottom(e._is_bottom), _tree(std::move(e._tree)) {}

  separate_domain_t &operator=(separate_domain_t e) {
    this->_is_bottom = e._is_bottom;
    this->_tree = e._tree;
    return *this;
  }

  iterator begin() const {
    if (this->is_bottom()) {
      CRAB_ERROR("Separate domain: trying to invoke iterator on bottom");
    } else {
      return this->_tree.begin();
    }
  }

  iterator end() const {
    if (this->is_bottom()) {
      CRAB_ERROR("Separate domain: trying to invoke iterator on bottom");
    } else {
      return this->_tree.end();
    }
  }

  bool is_bottom() const { return this->_is_bottom; }

  bool is_top() const {
    return (!this->is_bottom() && this->_tree.size() == 0);
  }

  bool operator<=(const separate_domain_t &e) const {
    if (this->is_bottom()) {
      return true;
    } else if (e.is_bottom()) {
      return false;
    } else {
      domain_po po;
      return this->_tree.leq(e._tree, po);
    }
  }

  bool operator==(const separate_domain_t &e) const {
    return (this->operator<=(e) && e.operator<=(*this));
  }

  // Join
  separate_domain_t operator|(const separate_domain_t &e) const {
    if (this->is_bottom()) {
      return e;
    } else if (e.is_bottom()) {
      return *this;
    } else {
      join_op o;
      bool is_bottom;
      patricia_tree_t res = apply_operation(o, this->_tree, e._tree, is_bottom);
      return separate_domain_t(std::move(res));
    }
  }

  // Meet
  separate_domain_t operator&(const separate_domain_t &e) const {
    if (this->is_bottom() || e.is_bottom()) {
      return this->bottom();
    } else {
      meet_op o;
      bool is_bottom;
      patricia_tree_t res = apply_operation(o, this->_tree, e._tree, is_bottom);
      if (is_bottom) {
        return this->bottom();
      } else {
        return separate_domain_t(std::move(res));
      }
    }
  }

  // Widening
  separate_domain_t operator||(const separate_domain_t &e) const {
    if (this->is_bottom()) {
      return e;
    } else if (e.is_bottom()) {
      return *this;
    } else {
      widening_op o;
      bool is_bottom;
      patricia_tree_t res = apply_operation(o, this->_tree, e._tree, is_bottom);
      return separate_domain_t(std::move(res));
    }
  }

  // Widening with thresholds
  template <typename Thresholds>
  separate_domain_t widening_thresholds(const separate_domain_t &e,
                                        const Thresholds &ts) const {
    if (this->is_bottom()) {
      return e;
    } else if (e.is_bottom()) {
      return *this;
    } else {
      widening_thresholds_op<Thresholds> o(ts);
      bool is_bottom;
      patricia_tree_t res = apply_operation(o, this->_tree, e._tree, is_bottom);
      return separate_domain_t(std::move(res));
    }
  }

  // Narrowing
  separate_domain_t operator&&(const separate_domain_t &e) const {
    if (this->is_bottom() || e.is_bottom()) {
      return separate_domain_t(false);
    } else {
      narrowing_op o;
      bool is_bottom;
      patricia_tree_t res = apply_operation(o, this->_tree, e._tree, is_bottom);
      if (is_bottom) {
        return this->bottom();
      } else {
        return separate_domain_t(std::move(res));
      }
    }
  }

  void set(Key k, Value v) {
    if (!this->is_bottom()) {
      if (v.is_bottom()) {
        this->_is_bottom = true;
        this->_tree = patricia_tree_t();
      } else if (v.is_top()) {
        this->_tree.remove(k);
      } else {
        this->_tree.insert(k, v);
      }
    }
  }

  void set_to_bottom() {
    this->_is_bottom = true;
    this->_tree = patricia_tree_t();
  }

  separate_domain_t &operator-=(const Key &k) {
    if (!this->is_bottom()) {
      this->_tree.remove(k);
    }
    return *this;
  }

  Value operator[](const Key &k) const {
    if (this->is_bottom()) {
      return Value::bottom();
    } else {
      boost::optional<Value> v = this->_tree.lookup(k);
      if (v) {
        return *v;
      } else {
        return Value::top();
      }
    }
  }

  std::size_t size() const {
    if (is_bottom()) {
      return 0;
    } else if (is_top()) {
      CRAB_ERROR("separate_domains::size() is undefined if top");
    } else {
      return this->_tree.size();
    }
  }

  void write(crab::crab_os &o) const {
    if (this->is_bottom()) {
      o << "_|_";
    } else {
      o << "{";
      for (typename patricia_tree_t::iterator it = this->_tree.begin();
           it != this->_tree.end();) {
        Key k = it->first;
        k.write(o);
        o << " -> ";
        Value v = it->second;
        v.write(o);
        ++it;
        if (it != this->_tree.end()) {
          o << "; ";
        }
      }
      o << "}";
    }
  }

  // Assume that from does not have duplicates.
  void rename(const std::vector<Key> &from, const std::vector<Key> &to) {
    if (is_top() || is_bottom()) {
      // nothing to rename
      return;
    }
    if (from.size() != to.size()) {
      CRAB_ERROR(
          "separate_domain::rename with input vectors of different sizes");
    }

    if (::crab::CrabSanityCheckFlag) {
      std::set<Key> s1, s2;
      s1.insert(from.begin(), from.end());
      if (s1.size() != from.size()) {
	CRAB_ERROR("separate_domain::rename expects no duplicates");
      }
      s2.insert(to.begin(), to.end());
      if (s2.size() != to.size()) {
	CRAB_ERROR("separate_domain::rename expects no duplicates");
      }
    }

    for (unsigned i=0, sz=from.size(); i<sz; ++i) {
      Key k = from[i];
      Key new_k = to[i];
      if (k == new_k) { // nothing to rename
        continue;
      }
      if (::crab::CrabSanityCheckFlag) {
      	if (_tree.lookup(new_k)) {
      	  CRAB_ERROR("separate_domain::rename assumes that  ", new_k,
      		     " does not exist in ", *this);
      	}
      }
      if (boost::optional<Value> k_val_opt = _tree.lookup(k)) {
        if (!(*k_val_opt).is_top()) {
          _tree.insert(new_k, *k_val_opt);
        }
        _tree.remove(k);
      }
    }
  }

  friend crab::crab_os &operator<<(crab::crab_os &o,
                                   const separate_domain<Key, Value> &d) {
    d.write(o);
    return o;
  }
}; // class separate_domain

} // namespace ikos
<|endoftext|>