text:
// Copyright (c) 2003 Daniel Wallin and Arvid Norberg

// 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 LUABIND_CLASS_REP_HPP_INCLUDED
#define LUABIND_CLASS_REP_HPP_INCLUDED

//#include <cstdlib>

#include <boost/limits.hpp>
#include <boost/preprocessor/repetition/enum_params_with_a_default.hpp>

#include <luabind/config.hpp>
#include <luabind/detail/object_rep.hpp>
#include <luabind/detail/construct_rep.hpp>
#include <luabind/detail/method_rep.hpp>
#include <luabind/detail/garbage_collector.hpp>
#include <luabind/detail/operator_id.hpp>
#include <luabind/detail/signature_match.hpp>
#include <luabind/detail/class_registry.hpp>
#include <luabind/detail/find_best_match.hpp>
#include <luabind/detail/get_overload_signature.hpp>
#include <luabind/error.hpp>

namespace luabind
{

	template<BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(LUABIND_MAX_BASES, class A, detail::null_type)>
	struct bases {};
	typedef bases<detail::null_type> no_bases;

	struct class_base;

}

namespace luabind { namespace detail
{
	string_class stack_content_by_name(lua_State* L, int start_index);
	int construct_lua_class_callback(lua_State* L);

	// this is class-specific information, poor man's vtable
	// this is allocated statically (removed by the compiler)
	// a pointer to this structure is stored in the lua tables'
	// metatable with the name __classrep
	// it is used when matching parameters to function calls
	// to determine possible implicit casts
	// it is also used when finding the best match for overloaded
	// methods
	class class_rep
	{
	friend struct luabind::class_base;
	friend int super_callback(lua_State*);
//TODO: avoid the lua-prefix
	friend int lua_class_gettable(lua_State*);
	friend int lua_class_settable(lua_State*);
	friend int static_class_gettable(lua_State*);
	public:

		enum class_type
		{
			cpp_class = 0,
			lua_class = 1
		};

		// destructor is a lua callback function that is hooked as garbage collector event on every instance
		// of this class (including those that is not owned by lua). It gets an object_rep as argument
		// on the lua stack. It should delete the object pointed to by object_rep::ptr if object_pre::flags
		// is object_rep::owner (which means that lua owns the object)

		// EXPECTS THE TOP VALUE ON THE LUA STACK TO
		// BE THE USER DATA WHERE THIS CLASS IS BEING
		// INSTANTIATED!
		class_rep(LUABIND_TYPE_INFO t, const char* name, lua_State* L, void(*destructor)(void*), LUABIND_TYPE_INFO held_t, void*(*extractor)(void*))
			: m_type(t)
			, m_held_type(held_t)
			, m_extract_underlying_fun(extractor)
			, m_name(name)
			, m_class_type(cpp_class)
			, m_destructor(destructor)
		{

			// TODO: don't we need to copy the name?
			class_registry* r = class_registry::get_registry(L);
			assert((r->cpp_class() != LUA_NOREF) && "you must call luabind::open()"); // you must call luabind::open()

			detail::getref(L, r->cpp_class());
			lua_setmetatable(L, -2);

			lua_pushvalue(L, -1); // duplicate our user data
			m_self_ref = detail::ref(L); // pop one of them

			m_instance_metatable = r->cpp_instance();
		}

		// used when creating a lua class
		// EXPECTS THE TOP VALUE ON THE LUA STACK TO
		// BE THE USER DATA WHERE THIS CLASS IS BEING
		// INSTANTIATED!
		class_rep(lua_State* L, const char* name)
			: m_type(LUABIND_TYPEID(int))
			, m_held_type(0)
			, m_extract_underlying_fun(0)
			, m_name(name)
			, m_class_type(lua_class)
		{
			// TODO: don't we need to copy the name?
			lua_newtable(L);
			m_table_ref = detail::ref(L);

			class_registry* r = class_registry::get_registry(L);
			assert((r->cpp_class() != LUA_NOREF) && "you must call luabind::open()"); // you must call luabind::open()

			detail::getref(L, r->lua_class());
			lua_setmetatable(L, -2);
			lua_pushvalue(L, -1); // duplicate our user data
			m_self_ref = detail::ref(L); // pop one of them

			m_instance_metatable = r->lua_instance();
		}

		~class_rep()
		{
#ifndef LUABIND_DONT_COPY_STRINGS
			for (std::vector<char*>::iterator i = m_strings.begin(); i != m_strings.end(); ++i)
			{
				delete[] *i;
			}
#endif
		}

		// called from the metamethod for __index
		// the object pointer is passed on the lua stack
		int gettable(lua_State* L)
		{
			if (lua_isnil(L, 2))
			{
				lua_pushnil(L);
				return 1;
			}

			// we have to ignore the first argument since this may point to
			// a method that is not present in this class (but in a subclass)
			const char* key = lua_tostring(L, 2);
			std::map<const char*, method_rep, ltstr>::iterator i = m_methods.find(key);
			if (i != m_methods.end())
			{
				// the name is a method, return it
				lua_pushlightuserdata(L, &i->second);
				lua_pushcclosure(L, function_dispatcher, 1);
				return 1;
			}

			std::map<const char*, callback, ltstr>::iterator j = m_getters.find(key);
			if (j != m_getters.end())
			{
				// the name is a data member
				return j->second.func(L, j->second.pointer_offset);
			}

			lua_pushnil(L);
			return 1;
		}

		// called from the metamethod for __newindex
		// the object pointer is passed on the lua stack
		bool settable(lua_State* L)
		{
			if (lua_isnil(L, 2))
			{
				return false;
			}

			// we have to ignore the first argument since this may point to
			// a method that is not present in this class (but in a subclass)
			const char* key = lua_tostring(L, 2);
			std::map<const char*, callback, ltstr>::iterator j = m_setters.find(key);
			if (j != m_setters.end())
			{
				// the name is a data member
				j->second.func(L, j->second.pointer_offset);
				return true;
			}

			return false; // false means that we don't have a member with the given name
		}

		// this is called as __index metamethod on every instance of this class
		static int gettable_dispatcher(lua_State* L)
		{
			object_rep* obj = static_cast<object_rep*>(lua_touserdata(L, 1));
			return obj->crep()->gettable(L);
		}

		// this is called as __newindex metamethod on every instance of this class
		static int settable_dispatcher(lua_State* L)
		{
			object_rep* obj = static_cast<object_rep*>(lua_touserdata(L, 1));

			bool success = obj->crep()->settable(L);

#ifndef LUABIND_NO_ERROR_CHECKING

			if (!success)
			{
				// this block is needed to make sure the string_class is destructed before
				// lua_error() is called
#ifdef BOOST_MSVC
				{
					// msvc has a bug which deletes the string twice, that's
					// why we have to create it on the heap
					string_class* msg = new string_class("cannot set attribute '");
					*msg += obj->crep()->m_name;
					*msg += ".";
					*msg += lua_tostring(L, -2);
					*msg += "'";
					lua_pushstring(L, msg->c_str());
					delete msg;
				}
#else
				{
					string_class msg = "cannot set attribute '";
					msg += obj->crep()->m_name;
					msg += ".";
					msg += lua_tostring(L, -2);
					msg += "'";
					lua_pushstring(L, msg.c_str());
				}
#endif
				lua_error(L);
			}

#endif

			return 0;
		}

		static int operator_dispatcher(lua_State* L)
		{
			int id = static_cast<int>(lua_tonumber(L, lua_upvalueindex(1)));

			int operand_id = 0;

			object_rep* operand[2];
			for (int i = 0; i < 2; ++i)
				operand[i] = detail::is_class_object(L, i + 1);

			if (operand[0] && operand[1])
				if (LUABIND_TYPE_INFO_EQUAL(operand[0]->crep()->type(), operand[1]->crep()->type())) operand[1] = 0;

			std::vector<operator_callback>* overloads[2];
			for (int i = 0; i < 2; ++i)
				if (operand[i]) overloads[i] = &operand[i]->crep()->m_operators[id]; else overloads[i] = 0;

			std::size_t num_overloads[2];
			for (int i = 0; i < 2; ++i)
				if (overloads[i]) num_overloads[i] = overloads[i]->size(); else num_overloads[i] = 0;

			bool ambiguous = false;
			int match_index = -1;
			int min_match = std::numeric_limits<int>::max();

//			std::cout << "operator_dispatcher\n";
//			std::cout << "num overloads: " << num_overloads[0] + num_overloads[1] << "\n";
//			std::cout << "operator: " << id << "\n";

#ifdef LUABIND_NO_ERROR_CHECKING

			if (num_overloads[0] == 1 && num_overloads[1] == 0)
			{
				operand_id = 0;
				match_index = 0;
			}
			else if (num_overloads[0] == 0 && num_overloads[1] == 1)
			{
				operand_id = 1;
				match_index = 0;
			}
			else
			{

#endif

				int num_params = lua_gettop(L);
				if (overloads[0])
				{
					if (find_best_match(L, overloads[0]->begin(), overloads[0]->end(), ambiguous, min_match, match_index, num_params))
						operand_id = 0;
				}

				// have look at the right operand.
				// if the right operand is a class and
				// not the same class as this, we have to
				// try to match it's operators too

				if (overloads[1])
				{
					if(find_best_match(L, overloads[1]->begin(), overloads[1]->end(), ambiguous, min_match, match_index, num_params))
						operand_id = 1;
				}

#ifdef LUABIND_NO_ERROR_CHECKING

			}

#else

			if (match_index == -1)
			{
				// this block is needed to make sure the string_class is destructed before
				// lua_error() is called
				{
					string_class msg = "no operator ";
					msg += get_operator_symbol(id);
					msg += " matched the arguments (";
					msg += stack_content_by_name(L, 1);
					msg += ")\ncandidates are:\n";

					if (overloads[0])
						msg += get_overload_signatures(L, overloads[0]->begin(), overloads[0]->end(), get_operator_symbol(id));

					if (overloads[1])
						msg += get_overload_signatures(L, overloads[1]->begin(), overloads[1]->end(), get_operator_symbol(id));

					lua_pushstring(L, msg.c_str());
				}
				lua_error(L);
			}
			else if (ambiguous)
			{
				// this block is needed to make sure the string_class is destructed before
				// lua_error() is called
				{
					string_class msg = "call of overloaded operator ";
					msg += get_operator_symbol(id);
					msg += " (";
					msg += stack_content_by_name(L, 1);
					msg += ")' is ambiguous\nnone of the overloads have a best conversion:\n";

					std::vector<operator_callback> candidates;
					if (overloads[0])
						find_exact_match(L, overloads[0]->begin(), overloads[0]->end(), min_match, num_params, candidates);

					if (overloads[1])
						find_exact_match(L, overloads[1]->begin(), overloads[1]->end(), min_match, num_params, candidates);

					msg += get_overload_signatures(L, candidates.begin(), candidates.end(), get_operator_symbol(id));

					lua_pushstring(L, msg.c_str());
				}
				lua_error(L);
			}

#endif

			return (*overloads[operand_id])[match_index].call(L);
		}

		// this is called as metamethod __call on the class_rep.
		static int constructor_dispatcher(lua_State* L)
		{
			class_rep* crep = static_cast<class_rep*>(lua_touserdata(L, 1));
			construct_rep* rep = &crep->m_constructor;

			bool ambiguous = false;
			int match_index = -1;
			int min_match = std::numeric_limits<int>::max();
			bool found;

#ifdef LUABIND_NO_ERROR_CHECKING

			if (rep->overloads.size() == 1)
			{
				match_index = 0;
			}
			else
			{

#endif

				int num_params = lua_gettop(L) - 1;
				found = find_best_match(L, rep->overloads.begin(), rep->overloads.end(), ambiguous, min_match, match_index, num_params);

#ifdef LUABIND_NO_ERROR_CHECKING

			}

#else

			if (!found)
			{
				// this block is needed to make sure the string_class is destructed before
				// lua_error() is called
				{
					string_class msg = "no constructor of '";
					msg += crep->name();
					msg += "' matched the arguments (";
					msg += stack_content_by_name(L, 2);
					msg += ")\n candidates are:\n";

					msg += get_overload_signatures(L, rep->overloads.begin(), rep->overloads.end(), crep->name());

					lua_pushstring(L, msg.c_str());
				}
				lua_error(L);
			}
			else if (ambiguous)
			{
				// this block is needed to make sure the string_class is destructed before
				// lua_error() is called
				{
					string_class msg = "call of overloaded constructor '";
					msg += crep->m_name;
					msg +=  "(";
					msg += stack_content_by_name(L, 2);
					msg += ")' is ambiguous\nnone of the overloads have a best conversion:\n";

					std::vector<construct_rep::overload_t> candidates;
					find_exact_match(L, rep->overloads.begin(), rep->overloads.end(), min_match, num_params, candidates);
					msg += get_overload_signatures(L, candidates.begin(), candidates.end(), crep->name());

					lua_pushstring(L, msg.c_str());
				}
				lua_error(L);
			}

#endif

#ifndef LUABIND_NO_EXCEPTIONS

			try
			{

#endif

				void* object_ptr = rep->overloads[match_index].construct(L);

				void* obj_rep = lua_newuserdata(L, sizeof(object_rep));
				new(obj_rep) object_rep(object_ptr, crep, object_rep::owner, crep->destructor());

				detail::getref(L, crep->m_instance_metatable);
				lua_setmetatable(L, -2);
				return 1;

#ifndef LUABIND_NO_EXCEPTIONS

			}

			catch(const std::exception& e)
			{
				lua_pushstring(L, e.what());
			}
			catch(const char* s)
			{
				lua_pushstring(L, s);
			}
			catch(...)
			{
				{
					string_class msg = crep->name();
					msg += "() threw an exception";
					lua_pushstring(L, msg.c_str());
				}
			}

			// we can only reach this line if an exception was thrown
			lua_error(L);
			return 0; // will never be reached

#endif

		}

		static int implicit_cast(const class_rep* from, const class_rep* to, int& pointer_offset)
		{
			int offset = 0;
			if (LUABIND_TYPE_INFO_EQUAL(from->type(), to->type())) return 0;

			for (std::vector<class_rep::base_info>::const_iterator i = from->bases().begin(); i != from->bases().end(); ++i)
			{
				int steps = implicit_cast(i->base, to, offset);
				pointer_offset = offset + i->pointer_offset;
				if (steps >= 0) return steps + 2;
			}
			return -1;
		}

		// the functions dispatcher assumes the following:
		// there is one upvalue that points to the method_rep that this dispatcher is to call
		// the first parameter on the lua stack is an object_rep that points to the object the
		// call is being made on
		static int function_dispatcher(lua_State* L)
		{
			method_rep* rep = static_cast<method_rep*>(lua_touserdata(L, lua_upvalueindex(1)));
			object_rep* obj = reinterpret_cast<object_rep*>(lua_touserdata(L, 1));

#ifndef LUABIND_NO_ERROR_CHECKING

			if (is_class_object(L, 1) == 0)
			{
				{
					string_class msg = "No self reference given as first parameter to member function '";
					msg += rep->crep->name();
					msg += ":";
					msg += rep->name;
					msg += "'. Have you used '.' instead of ':'?";

					lua_pushstring(L, msg.c_str());
				}
				lua_error(L);
			}

			int p;
			if (implicit_cast(obj->crep(), rep->crep, p) < 0)
			{
				{
					string_class msg = "invalid self reference given to '";
					msg += rep->crep->name();
					msg += ":";
					msg += rep->name;
					msg += "'";
					lua_pushstring(L, msg.c_str());
				}
				lua_error(L);
			}

#endif

			bool ambiguous = false;
			int match_index = -1;
			int min_match = std::numeric_limits<int>::max();
			bool found;

#ifdef LUABIND_NO_ERROR_CHECKING
			if (rep->overloads().size() == 1)
			{
				match_index = 0;
			}
			else
			{
#endif

				int num_params = lua_gettop(L) - 1;
				found = find_best_match(L, rep->overloads().begin(), rep->overloads().end(), ambiguous, min_match, match_index, num_params);

#ifdef LUABIND_NO_ERROR_CHECKING

			}

#else

			if (!found)
			{
				{
					string_class msg = "no overload of  '";
					msg += rep->crep->name();
					msg += ":";
					msg += rep->name;
					msg += "' matched the arguments (";
					msg += stack_content_by_name(L, 2);
					msg += ")\ncandidates are:\n";

					string_class function_name;
					function_name += rep->crep->name();
					function_name += ":";
					function_name += rep->name;

					msg += get_overload_signatures(L, rep->overloads().begin(), rep->overloads().end(), function_name);

					lua_pushstring(L, msg.c_str());
				}
				lua_error(L);
			}
			else if (ambiguous)
			{
				{
					string_class msg = "call of overloaded  '";
					msg += rep->crep->name();
					msg += ":";
					msg += rep->name;
					msg += "(";
					msg += stack_content_by_name(L, 2);
					msg += ")' is ambiguous\nnone of the overloads have a best conversion:\n";

					std::vector<overload_rep> candidates;
					find_exact_match(L, rep->overloads().begin(), rep->overloads().end(), min_match, num_params, candidates);

					string_class function_name;
					function_name += rep->crep->name();
					function_name += ":";
					function_name += rep->name;

					msg += get_overload_signatures(L, candidates.begin(), candidates.end(), function_name);

					lua_pushstring(L, msg.c_str());
				}
				lua_error(L);
			}

#endif

#ifndef LUABIND_NO_EXCEPTIONS

			try
			{

#endif

				const overload_rep& o = rep->overloads()[match_index];
				return o.call(L, *obj);

#ifndef LUABIND_NO_EXCEPTIONS

			}
			catch(const std::exception& e)
			{
				lua_pushstring(L, e.what());
			}
			catch (const char* s)
			{
				lua_pushstring(L, s);
			}
			catch(...)
			{
				string_class msg = rep->crep->name();
				msg += ":";
				msg += rep->name;
				msg += "() threw an exception";
				lua_pushstring(L, msg.c_str());
			}
			// we can only reach this line if an exception was thrown
			lua_error(L);
			return 0; // will never be reached

#endif

		}

		struct base_info
		{
			int pointer_offset; // the offset added to the pointer to obtain a basepointer (due to multiple-inheritance)
			class_rep* base;
		};

		inline void add_base_class(const base_info& binfo)
		{
			// If you hit this assert you are deriving from a type that is not registered
			// in lua. That is, in the class_<> you are giving a baseclass that isn't registered.
			// Please note that if you don't need to have access to the base class or the
			// conversion from the derived class to the base class, you don't need
			// to tell luabind that it derives.
			assert(binfo.base && "You cannot derive from an unregistered type");

			class_rep* bcrep = binfo.base;

			// import all functions from the base
			for (std::map<const char*, method_rep, ltstr>::const_iterator i = bcrep->m_methods.begin(); i != bcrep->m_methods.end(); ++i)
			{
#ifndef LUABIND_DONT_COPY_STRINGS
				m_strings.push_back(dup_string(i->first));
				method_rep& m = m_methods[m_strings.back()];
#else
				method_rep& m = m_methods[i->first];
#endif
				m.name = i->first;
				m.crep = this;

				for (std::vector<overload_rep>::const_iterator j = i->second.overloads().begin(); j != i->second.overloads().end(); ++j)
				{
					overload_rep o = *j;
					o.add_offset(binfo.pointer_offset);
					m.add_overload(o);
				}
			}

			// import all getters from the base
			for (std::map<const char*, callback, ltstr>::const_iterator i = bcrep->m_getters.begin(); i != bcrep->m_getters.end(); ++i)
			{
#ifndef LUABIND_DONT_COPY_STRINGS
				m_strings.push_back(dup_string(i->first));
				callback& m = m_getters[m_strings.back()];
#else
				callback& m = m_getters[i->first];
#endif
				m.pointer_offset = i->second.pointer_offset + binfo.pointer_offset;
				m.func = i->second.func;
			}

			// import all setters from the base
			for (std::map<const char*, callback, ltstr>::const_iterator i = bcrep->m_setters.begin(); i != bcrep->m_setters.end(); ++i)
			{
#ifndef LUABIND_DONT_COPY_STRINGS
				// TODO: optimize this by not copying the string if it already exists in m_setters.
				// This goes for m_getters, m_static_constants and m_functions too. Both here
				// in add_base() and in the add_function(), add_getter() ... functions.
				m_strings.push_back(dup_string(i->first));
				callback& m = m_setters[m_strings.back()];
#else
				callback& m = m_setters[i->first];
#endif
				m.pointer_offset = i->second.pointer_offset + binfo.pointer_offset;
				m.func = i->second.func;
			}

			// import all static constants
			for (std::map<const char*, int, ltstr>::const_iterator i = bcrep->m_static_constants.begin(); i != bcrep->m_static_constants.end(); ++i)
			{
#ifndef LUABIND_DONT_COPY_STRINGS
				m_strings.push_back(dup_string(i->first));
				int& v = m_static_constants[m_strings.back()];
#else
				int& v = m_static_constants[i->first];
#endif
				v = i->second;
			}

			// import all operators
			for (int i = 0; i < number_of_operators; ++i)
			{
				for (std::vector<operator_callback>::const_iterator j = bcrep->m_operators[i].begin(); j != bcrep->m_operators[i].end(); ++j)
					m_operators[i].push_back(*j);
			}

			// also, save the baseclass info to be used for typecasts
			m_bases.push_back(binfo);
		}

		inline const std::vector<base_info>& bases() const throw() { return m_bases; }
		inline LUABIND_TYPE_INFO type() const throw() { return m_type; }
		inline void set_type(LUABIND_TYPE_INFO t) { m_type = t; }

		inline void add_function(const char* name, const overload_rep& o)
		{

#ifdef LUABIND_DONT_COPY_STRINGS
			detail::method_rep& method = m_methods[name];
			method.name = name;
#else
			m_strings.push_back(dup_string(name));
			detail::method_rep& method = m_methods[m_strings.back()];
			method.name = m_strings.back();
#endif

			method.add_overload(o);
			method.crep = this;
		}

		inline void add_constructor(const detail::construct_rep::overload_t& o)
		{
			m_constructor.overloads.push_back(o);
		}

		inline void add_wrapped_constructor(const detail::construct_rep::overload_t& o)
		{
			m_wrapped_constructor.overloads.push_back(o);
		}

		inline const char* name() const throw()
		{
#ifdef LUABIND_DONT_COPY_STRINGS
			return m_name;
#else
			return m_name.c_str();
#endif
		}

		inline void add_getter(const char* name, const boost::function2<int, lua_State*, int>& g)
		{
			callback c;
			c.func = g;
			c.pointer_offset = 0;
#ifndef LUABIND_DONT_COPY_STRINGS
			m_strings.push_back(dup_string(name));
			m_getters[m_strings.back()] = c;
#else
			m_getters[name] = c;
#endif
		}

		inline void add_setter(const char* name, const boost::function2<int, lua_State*, int>& s)
		{
			callback c;
			c.func = s;
			c.pointer_offset = 0;
#ifndef LUABIND_DONT_COPY_STRINGS
			m_strings.push_back(dup_string(name));
			m_setters[m_strings.back()] = c;
#else
			m_setters[name] = c;
#endif
		}

#ifndef LUABIND_NO_ERROR_CHECKING
		inline void add_operator(lua_State*, int op_id,  int(*func)(lua_State*), int(*matcher)(lua_State*), void(*sig)(lua_State*, string_class&), int arity)
#else
		inline void add_operator(lua_State*, int op_id,  int(*func)(lua_State*), int(*matcher)(lua_State*), int arity)
#endif
		{
			operator_callback o;
			o.set_fun(func);
			o.set_match_fun(matcher);
			o.set_arity(arity);

#ifndef LUABIND_NO_ERROR_CHECKING

			o.set_sig_fun(sig);

#endif
			m_operators[op_id].push_back(o);
		}

		// the lua reference to this class_rep
		inline int self_ref() const throw() { return m_self_ref; }

		// the lua reference to the metatable for this class' instances
		inline int metatable_ref() const throw() { return m_instance_metatable; }

		inline int table_ref() const { return m_table_ref; }

		inline void(*destructor() const)(void*) { return m_destructor; }

		inline class_type get_class_type() const { return m_class_type; }

		void add_static_constant(const char* name, int val)
		{
#ifndef LUABIND_DONT_COPY_STRINGS
			m_strings.push_back(dup_string(name));
			m_static_constants[m_strings.back()] = val;
#else
			m_static_constants[name] = val;
#endif
		}

	static inline int super_callback(lua_State* L)
	{
		int args = lua_gettop(L);

		object_rep* obj = static_cast<object_rep*>(lua_touserdata(L, lua_upvalueindex(2)));
		class_rep* crep = static_cast<class_rep*>(lua_touserdata(L, lua_upvalueindex(1)));
		class_rep* base = crep->bases()[0].base;

//		std::cout << "__super of " << base->name() << "\n";

		if (base->get_class_type() == class_rep::lua_class)
		{
			if (base->bases().empty())
			{
				obj->set_flags(obj->flags() & ~object_rep::call_super);

				lua_pushstring(L, "super");
				lua_pushnil(L);
				lua_settable(L, LUA_GLOBALSINDEX);
			}
			else
			{
				lua_pushstring(L, "super");
				lua_pushlightuserdata(L, base);
				lua_pushvalue(L, lua_upvalueindex(2));
				lua_pushcclosure(L, super_callback, 2);
				lua_settable(L, LUA_GLOBALSINDEX);
			}

//			std::cout << "  lua_class\n";
			detail::getref(L, base->table_ref());
			lua_pushstring(L, "__init");
			lua_gettable(L, -2);
			lua_insert(L, 1);
			lua_pop(L, 1);

			lua_pushvalue(L, lua_upvalueindex(2));
			lua_insert(L, 2);

			lua_call(L, args + 1, 0);

			// TODO: instead of clearing the global variable "super"
			// store it temporarily in the registry. maybe we should
			// have some kind of warning if the super global is used?
			lua_pushstring(L, "super");
			lua_pushnil(L);
			lua_settable(L, LUA_GLOBALSINDEX);
		}
		else
		{
			obj->set_flags(obj->flags() & ~object_rep::call_super);
//			std::cout << "  cpp_class\n";

			// we need to push some garbage at index 1 to make the construction work
			lua_pushboolean(L, 1);
			lua_insert(L, 1);

			construct_rep* rep = &base->m_constructor;

			bool ambiguous = false;
			int match_index = -1;
			int min_match = std::numeric_limits<int>::max();
			bool found;

#ifdef LUABIND_NO_ERROR_CHECKING

			if (rep->overloads.size() == 1)
			{
				match_index = 0;
			}
			else
			{

#endif

				int num_params = lua_gettop(L) - 1;
				found = find_best_match(L, rep->overloads.begin(), rep->overloads.end(), ambiguous, min_match, match_index, num_params);

#ifdef LUABIND_NO_ERROR_CHECKING

			}

#else

			if (!found)
			{
				{
					string_class msg = "no constructor of '";
					msg += base->m_name;
					msg += "' matched the arguments (";
					msg += stack_content_by_name(L, 2);
					msg += ")";
					lua_pushstring(L, msg.c_str());
				}
				lua_error(L);
			}
			else if (ambiguous)
			{
				{
					string_class msg = "call of overloaded constructor '";
					msg += base->m_name;
					msg +=  "(";
					msg += stack_content_by_name(L, 2);
					msg += ")' is ambiguous";
					lua_pushstring(L, msg.c_str());
				}
				lua_error(L);
			}

			// TODO: should this be a warning or something?
/*
			// since the derived class is a lua class
			// it may have reimplemented virtual functions
			// therefore, we have to instantiate the Basewrapper
			// if there is no basewrapper, throw a run-time error
			if (!rep->overloads[match_index].has_wrapped_construct())
			{
				{
					string_class msg = "Cannot derive from C++ class '";
					msg += base->name();
					msg += "'. It does not have a wrapped type";
					lua_pushstring(L, msg.c_str());
				}
				lua_error(L);
			}
*/
#endif

#ifndef LUABIND_NO_EXCEPTIONS

			try
			{

#endif

				if (!rep->overloads[match_index].has_wrapped_construct())
				{
					// if the type doesn't have a wrapped type, use the ordinary constructor
					obj->set_object(rep->overloads[match_index].construct(L));
				}
				else
				{
					// get reference to lua object
					lua_pushvalue(L, lua_upvalueindex(2));
					int ref = detail::ref(L);
					obj->set_object(rep->overloads[match_index].construct_wrapped(L, ref));
				}
				// TODO: is the wrapped type destructed correctly?
				// it should, since the destructor is either the wrapped type's
				// destructor or the base type's destructor, depending on wether
				// the type has a wrapped type or not.
				obj->set_destructor(base->destructor());
				return 0;

#ifndef LUABIND_NO_EXCEPTIONS

			}
			catch(const std::exception& e)
			{
				lua_pushstring(L, e.what());
			}
			catch(const char* s)
			{
				lua_pushstring(L, s);
			}
			catch(...)
			{
				string_class msg = base->m_name;
				msg += "() threw an exception";
				lua_pushstring(L, msg.c_str());
			}
			// can only be reached if an exception was thrown
			lua_error(L);
#endif
		}

		return 0;

	}

	static int lua_settable_dispatcher(lua_State* L)
	{
		class_rep* crep = static_cast<class_rep*>(lua_touserdata(L, 1));
		detail::getref(L, crep->m_table_ref);
		lua_replace(L, 1);
		lua_rawset(L, -3);
		return 0;
	}

	static int construct_lua_class_callback(lua_State* L)
	{
		class_rep* crep = static_cast<class_rep*>(lua_touserdata(L, 1));

		int args = lua_gettop(L);

		// lua stack: crep <arguments>

		lua_newtable(L);
		int ref = detail::ref(L);

		bool has_bases = !crep->bases().empty();

		if (has_bases)
		{
			lua_pushstring(L, "super");
			lua_pushvalue(L, 1); // crep
		}

		// lua stack: crep <arguments> "super" crep
		// or
		// lua stack: crep <arguments>

		// if we have a baseclass we set the flag to say that the super has not yet been called
		// we will use this flag later to check that it actually was called from __init()
		int flags = object_rep::lua_class | object_rep::owner | (has_bases ? object_rep::call_super : 0);

		void* obj_ptr = lua_newuserdata(L, sizeof(object_rep));
		new(obj_ptr) object_rep(crep, flags, ref);

		detail::getref(L, crep->metatable_ref());
		lua_setmetatable(L, -2);

		// lua stack: crep <arguments> "super" crep obj_ptr
		// or
		// lua stack: crep <arguments> obj_ptr

		if (has_bases)	lua_pushvalue(L, -1); // obj_ptr
		lua_replace(L, 1); // obj_ptr

		// lua stack: obj_ptr <arguments> "super" crep obj_ptr
		// or
		// lua stack: obj_ptr <arguments>

		if (has_bases)
		{
			lua_pushcclosure(L, super_callback, 2);
			// lua stack: crep <arguments> "super" function
			lua_settable(L, LUA_GLOBALSINDEX);
		}

		// lua stack: crep <arguments>

		lua_pushvalue(L, 1);
		lua_insert(L, 1);

		detail::getref(L, crep->table_ref());
		lua_pushstring(L, "__init");
		lua_gettable(L, -2);

#ifndef LUABIND_NO_ERROR_CHECKING

		// TODO: should this be a run-time error?
		// maybe the default behavior should be to just call
		// the base calss' constructor. We should register
		// the super callback funktion as __init
		if (!lua_isfunction(L, -1))
		{
			{
				string_class msg = crep->name();
				msg += ":__init is not defined";
				lua_pushstring(L, msg.c_str());
			}
			lua_error(L);
		}

#endif

		lua_insert(L, 2); // function first on stack
		lua_pop(L, 1);
		// TODO: lua_call may invoke longjump! make sure we don't have any memory leaks!
		// we don't have any stack objects here
		lua_call(L, args, 0);

#ifndef LUABIND_NO_ERROR_CHECKING

		object_rep* obj = static_cast<object_rep*>(obj_ptr);
		if (obj->flags() & object_rep::call_super)
		{
			lua_pushstring(L, "derived class must call super on base");
			lua_error(L);
		}

#endif

		return 1;
	}

	// called from the metamethod for __index
	// obj is the object pointer
	static int lua_class_gettable(lua_State* L)
	{
		object_rep* obj = static_cast<object_rep*>(lua_touserdata(L, 1));
		class_rep* crep = obj->crep();

#ifndef LUABIND_NO_ERROR_CHECKING

		if (obj->flags() & object_rep::call_super)
		{
			lua_pushstring(L, "derived class must call super on base");
			lua_error(L);
		}

#endif

		detail::getref(L, obj->lua_table_ref());
		lua_pushvalue(L, 2);
		lua_gettable(L, -2);

		if (!lua_isnil(L, -1)) return 1;

		lua_pop(L, 2);

		detail::getref(L, crep->table_ref());
		lua_pushvalue(L, 2);
		lua_gettable(L, -2);

		if (!lua_isnil(L, -1)) return 1;

		lua_pop(L, 2);

		if (lua_isnil(L, 2))
		{
			lua_pushnil(L);
			return 1;
		}

		// we have to ignore the first argument since this may point to
		// a method that is not present in this class (but in a subclass)
		const char* key = lua_tostring(L, 2);

		std::map<const char*, method_rep, ltstr>::iterator i = crep->m_methods.find(key);
		if (i != crep->m_methods.end())
		{
			// the name is a method, return it
			lua_pushlightuserdata(L, &i->second);
			lua_pushcclosure(L, class_rep::function_dispatcher, 1);
			return 1;
		}

		std::map<const char*, class_rep::callback, ltstr>::iterator j = crep->m_getters.find(key);
		if (j != crep->m_getters.end())
		{
			// the name is a data member
			return j->second.func(L, j->second.pointer_offset);
		}

		lua_pushnil(L);
		return 1;
	}

	// called from the metamethod for __newindex
	// obj is the object pointer
	static int lua_class_settable(lua_State* L)
	{
		object_rep* obj = static_cast<object_rep*>(lua_touserdata(L, 1));
		class_rep* crep = obj->crep();

#ifndef LUABIND_NO_ERROR_CHECKING

		if (obj->flags() & object_rep::call_super)
		{
			// this block makes sure the string_class is destructed
			// before lua_error is called
			{
				string_class msg = "derived class '";
				msg += crep->name();
				msg += "'must call super on base";
				lua_pushstring(L, msg.c_str());
			}
			lua_error(L);
		}

#endif

		// we have to ignore the first argument since this may point to
		// a method that is not present in this class (but in a subclass)
		const char* key = lua_tostring(L, 2);
		std::map<const char*, class_rep::callback, ltstr>::iterator j = crep->m_setters.find(key);

		if (j == crep->m_setters.end())
		{
			std::map<const char*, class_rep::callback, ltstr>::iterator k = crep->m_getters.find(key);

#ifndef LUABIND_NO_ERROR_CHECKING

			if (k != crep->m_getters.end())
			{
				{
					string_class msg = "cannot set property '";
					msg += crep->name();
					msg += ".";
					msg += key;
					msg += "', because it's read only";
					lua_pushstring(L, msg.c_str());
				}
				lua_error(L);
			}

#endif

			detail::getref(L, obj->lua_table_ref());
			lua_replace(L, 1);
			lua_settable(L, 1);
		}
		else
		{
			// the name is a data member
			j->second.func(L, j->second.pointer_offset);
		}

		return 0;
	}

	static int static_class_gettable(lua_State* L)
	{
		class_rep* crep = static_cast<class_rep*>(lua_touserdata(L, 1));

		if (crep->get_class_type() == class_rep::lua_class)
		{
			detail::getref(L, crep->m_table_ref);
			lua_pushvalue(L, 2);
			lua_gettable(L, -2);
			if (!lua_isnil(L, -1)) return 1;
			else lua_pop(L, 2);
		}

		const char* key = lua_tostring(L, 2);

		std::map<const char*, method_rep, ltstr>::iterator i = crep->m_methods.find(key);
		if (i != crep->m_methods.end())
		{
			// the name is a method, return it
			lua_pushlightuserdata(L, &i->second);
			lua_pushcclosure(L, class_rep::function_dispatcher, 1);
			return 1;
		}

#ifndef LUABIND_NO_ERROR_CHECKING

		std::map<const char*, int, ltstr>::const_iterator j = crep->m_static_constants.find(key);

		if (j != crep->m_static_constants.end())
		{
			lua_pushnumber(L, j->second);
			return 1;
		}

		{
			string_class msg = "no static '";
			msg += key;
			msg += "' in class '";
			msg += crep->name();
			msg += "'";
			lua_pushstring(L, msg.c_str());
		}
		lua_error(L);

#endif

		return 0;
	}

	private:

		// this is a pointer to the type_info structure for
		// this type
		// warning: this may be a problem when using dll:s, since
		// typeid() may actually return different pointers for the same
		// type.
		LUABIND_TYPE_INFO m_type;
		LUABIND_TYPE_INFO m_held_type;

		typedef void*(*extract_ptr_t)(void*);
		extract_ptr_t m_extract_underlying_fun;

		// a list of info for every class this class derives from
		// the information stored here is sufficient to do
		// type casts to the base classes
		std::vector<base_info> m_bases;

		// the class' name (as given when registered to lua with class_)
#ifdef LUABIND_DONT_COPY_STRINGS
		const char* m_name;
#else
		string_class m_name;
#endif

		// contains signatures for all constructors
		construct_rep m_constructor;
		construct_rep m_wrapped_constructor;

		// a reference to this structure itself. Since this struct
		// is kept inside lua (to let lua collect it when lua_close()
		// is called) we need to lock it to prevent collection.
		// the actual reference is not currently used.
		int m_self_ref;

		// a reference to the lua table that represents this class
		// (only used if it is a lua class)
		int m_table_ref;

		// the type of this class.. determines if it's written in c++ or lua
		class_type m_class_type;

		// this is a lua reference that points to the lua table
		// that is to be used as meta table for all instances
		// of this class.
		int m_instance_metatable;

		// ***** the maps below contains all members in this class *****

		// maps method names to a structure with more
		// information about that method.
		// that struct contains the function-signatures
		// for every overload
		std::map<const char*, method_rep, ltstr> m_methods;

#ifndef LUABIND_DONT_COPY_STRINGS
		// this is where the strings that the maps contains
		// pointer to are kept. To make sure they are destructed.
		std::vector<char*> m_strings;
#endif

		struct callback
		{
			boost::function2<int, lua_State*, int> func;
			int pointer_offset;
		};

		// datamembers, some members may be readonly, and
		// only have a getter function
		std::map<const char*, callback, ltstr> m_getters;
		std::map<const char*, callback, ltstr> m_setters;

		struct operator_callback: public overload_rep_base
		{
			inline void set_fun(int (*f)(lua_State*)) { func = f; }
			inline int call(lua_State* L) { return func(L); }
			inline void set_arity(int arity) { m_arity = arity; }

		private:

			int(*func)(lua_State*);
		};

		std::vector<operator_callback> m_operators[number_of_operators]; // the operators in lua

		void(*m_destructor)(void*);

		std::map<const char*, int, ltstr> m_static_constants;
	};

	inline bool is_class_rep(lua_State* L, int index)
	{
		if (lua_getmetatable(L, index) == 0) return false;

		lua_pushstring(L, "__luabind_classrep");
		lua_gettable(L, -2);
		if (lua_toboolean(L, -1))
		{
			lua_pop(L, 2);
			return true;
		}

		lua_pop(L, 2);
		return false;

	}

}}

#endif // LUABIND_CLASS_REP_HPP_INCLUDED


text:
//Copyright (c) 2013 Singapore-MIT Alliance for Research and Technology
//Licensed under the terms of the MIT License, as described in the file:
//   license.txt   (http://opensource.org/licenses/MIT)

#pragma once

#include <string>
#include <sstream>
#include <boost/lexical_cast.hpp>

/*namespace geo {
class Node_t_pimpl;
class intersection_t_pimpl;
class UniNode_t_pimpl;
}*/

namespace sim_mob
{

/**
 * Class to represent data we wish to carry along but not react to. Agents shouldn't ever check these values.
 *
 * \author Seth N. Hetu
 */
template <typename T>
class OpaqueProperty {
private:
    std::string repr_;
    T lastVal;

public:
    void setProps(const std::string& key, const T& value) {
        std::stringstream builder;
        builder <<"\"" <<key <<"\"" <<":"
                <<"\"" <<value <<"\"" <<",";
        builder >>repr_;
        lastVal = value;
    }

    bool isSet() const {
        return !repr_.empty();
    }

    std::string getLogItem() const {
        return repr_;
    }

    unsigned int getLastVal() {
        return lastVal;
    }

    //Allow assigning from a string
    sim_mob::OpaqueProperty<T>& operator=(const std::string& srcStr) {
        this->repr_ = srcStr;
        return *this;
    }
};

}

ext: hpp


text:
// Copyright (C) 2018-2019 Jonathan Müller <jonathanmueller.dev@gmail.com>
// This file is subject to the license terms in the LICENSE file
// found in the top-level directory of this distribution.

#ifndef FOONATHAN_LEX_PRODUCTION_KIND_HPP_INCLUDED
#define FOONATHAN_LEX_PRODUCTION_KIND_HPP_INCLUDED

#include <boost/mp11/algorithm.hpp>

#include <foonathan/lex/detail/select_integer.hpp>
#include <foonathan/lex/grammar.hpp>

namespace foonathan
{
namespace lex
{
    namespace production_kind_detail
    {
        template <class Grammar>
        using id_type
            = detail::select_integer<boost::mp11::mp_size<typename Grammar::productions>::value>;

        template <class Grammar, class Production>
        constexpr id_type<Grammar> get_id() noexcept
        {
            constexpr auto index
                = boost::mp11::mp_find<typename Grammar::productions, Production>::value;
            static_assert(boost::mp11::mp_contains<typename Grammar::productions,
                                                   Production>::value,
                          "not one of the specified productions");
            return static_cast<id_type<Grammar>>(index);
        }
    } // namespace production_kind_detail

    /// Information about the kind of a production.
    template <class Grammar>
    class production_kind
    {
    public:
        /// \effects Creates it from the integral id.
        static constexpr production_kind from_id(std::size_t id) noexcept
        {
            return production_kind(0, static_cast<production_kind_detail::id_type<Grammar>>(id));
        }

        /// \effects Creates it from an incomplete production type.
        /// But otherwise behaves like the constructor.
        template <class Production>
        static constexpr production_kind of() noexcept
        {
            return production_kind(0, production_kind_detail::get_id<Grammar, Production>());
        }

        /// \effects Creates the specified production kind.
        /// \requires The token must be one of the specified productions.
        template <class Production>
        constexpr production_kind(Production) noexcept
        : id_(production_kind_detail::get_id<Grammar, Production>())
        {}

        /// \returns Whether or not it is the specified production kind.
        template <class Production>
        constexpr bool is(Production = {}) const noexcept
        {
            return id_ == production_kind_detail::get_id<Grammar, Production>();
        }

        /// \returns The underlying integer value of the token.
        constexpr production_kind_detail::id_type<Grammar> get() const noexcept
        {
            return id_;
        }

        friend constexpr bool operator==(production_kind lhs, production_kind rhs) noexcept
        {
            return lhs.id_ == rhs.id_;
        }
        friend constexpr bool operator!=(production_kind lhs, production_kind rhs) noexcept
        {
            return !(lhs == rhs);
        }

    private:
        explicit constexpr production_kind(int,
                                           production_kind_detail::id_type<Grammar> id) noexcept
        : id_(id)
        {}

        production_kind_detail::id_type<Grammar> id_;
    };
} // namespace lex
} // namespace foonathan

#endif // FOONATHAN_LEX_PRODUCTION_KIND_HPP_INCLUDED

max_stars_repo_name: foonathan/lex

max_issues_repo_name: foonathan/lex

max_forks_repo_name: foonathan/lex


text:
#ifndef TIKPP_BASIC_API_HPP
#define TIKPP_BASIC_API_HPP

#include "tikpp/detail/async_result.hpp"
#include "tikpp/detail/operations/async_connect.hpp"
#include "tikpp/detail/operations/async_read_response.hpp"
#include "tikpp/detail/type_traits/error_handler.hpp"
#include "tikpp/detail/type_traits/stream.hpp"

#include "tikpp/commands/login.hpp"
#include "tikpp/error_code.hpp"
#include "tikpp/io_context.hpp"
#include "tikpp/request.hpp"
#include "tikpp/response.hpp"

#include <boost/asio/ip/address.hpp>
#include <boost/asio/write.hpp>
#include <boost/system/error_code.hpp>

#include <atomic>
#include <cassert>
#include <deque>
#include <functional>
#include <map>
#include <memory>
#include <string>

namespace tikpp {

enum class api_state { closed, connecting, connected };

/*!
 * \brief A struct to manage RouterOS API connections
 */
template <typename AsyncStream,
          typename ErrorHandler,
          typename = std::enable_if_t<
              tikpp::detail::type_traits::is_async_stream_v<AsyncStream> &&
              tikpp::detail::type_traits::is_error_handler_v<ErrorHandler>>>
struct basic_api
    : std::enable_shared_from_this<basic_api<AsyncStream, ErrorHandler>> {

    /*!
     * \brief The handler that handlers read responses
     */
    using read_handler = std::function<bool(const boost::system::error_code &,
                                            tikpp::response &&)>;

    /*!
     * \brief Asynchronously opens an API connection to the router, then logs
     *        in to the router
     *
     * \param [in]     host     The router host address
     * \param [in]     port     The API listening port
     * \param [in,out] token    The asynchronous operation completion token
     *
     * \return The passed completion token result
     */
    template <typename CompletionToken>
    decltype(auto) async_open(const std::string &host,
                              std::uint16_t      port,
                              CompletionToken && token) {
        GENERATE_COMPLETION_HANDLER(void(const boost::system::error_code &),
                                    token, handler, result);

        if (state_.load() == api_state::connecting) {
            io_.post([handler {std::move(handler)}]() mutable {
                handler(boost::asio::error::make_error_code(
                    boost::asio::error::in_progress));
            });
            return result.get();
        }

        assert(state_.load() == api_state::closed);
        state_.store(api_state::connecting);

        tikpp::detail::operations::async_connect(
            sock_, host, port,
            [self = this->shared_from_this(),
             handler {std::move(handler)}](const auto &err) mutable {
                assert(self->state_.load() == api_state::connecting);

                if (err) {
                    self->state_.store(api_state::closed);
                    return handler(err);
                }

                self->state_.store(api_state::connected);
                handler(err);

                self->read_next_response();
            });

        return result.get();
    }

    /*!
     * \brief Asynchronously opens an API connection to the router, then logs
     *        in to the router
     *
     * \param [in]     host     The router host address
     * \param [in]     port     The API listening port
     * \param [in]     name     The name used to login after successfully
     *                          connecting
     * \param [in]     password The password used to login after successfully
     *                          connecting
     * \param [in,out] token    The asynchronous operation completion token
     *
     * \return The passed completion token result
     */
    template <typename CompletionToken>
    decltype(auto) async_open(const std::string &host,
                              std::uint16_t      port,
                              const std::string &name,
                              const std::string &password,
                              CompletionToken && token) {
        GENERATE_COMPLETION_HANDLER(void(const boost::system::error_code &),
                                    token, handler, result);

        async_open(host, port,
                   [this, handler {std::move(handler)}, name,
                    password](const auto &err) mutable {
                       if (err) {
                           return handler(err);
                       }

                       async_login(name, password,
                                   [this, handler {std::move(handler)}](
                                       const auto &err) mutable {
                                       if (err) {
                                           if (is_open()) {
                                               close();
                                           }

                                           handler(err);
                                       } else {
                                           handler(
                                               boost::system::error_code {});
                                       }
                                   });
                   });

        return result.get();
    }

    //! \brief Closes an already-opened connection to the router
    inline void close() {
        assert(is_open());
        sock_.close();
        state_.store(api_state::closed);
        logged_in_.store(false);
    }

    /*!
     * \brief Creates a request from a command request type
     *
     * \param [in] args The arguments used to construct the command request
     *
     * \return The created command request
     */
    template <
        typename Command,
        typename... Args,
        typename = std::enable_if_t<std::is_base_of_v<tikpp::request, Command>>>
    [[nodiscard]] inline auto make_request(Args &&... args)
        -> std::shared_ptr<tikpp::request> {
        return std::make_shared<Command>(aquire_unique_tag(),
                                         std::forward<Args>(args)...);
    }

    /*!
     * \brief Creates a request from a command string
     *
     * \param [in] command The command string to be used to construct the
     *                     request
     *
     * \return The created request
     */
    [[nodiscard]] inline auto make_request(std::string command)
        -> std::shared_ptr<tikpp::request> {
        return std::make_shared<tikpp::request>(std::move(command),
                                                aquire_unique_tag());
    }

    /*!
     * \brief Asynchronously sends a request to the router
     *
     * \param [in]      req   The request to the best
     * \param [in, out] token The asynchronous operation completion token
     *
     * \return The passed completion token result
     */
    template <typename CompletionToken>
    void async_send(std::shared_ptr<request> req, CompletionToken &&token) {
        assert(req != nullptr);

        GENERATE_COMPLETION_HANDLER(
            void(const boost::system::error_code &, tikpp::response &&), token,
            handler, result);

        io_.post([self = this->shared_from_this(), req {std::move(req)},
                  handler {std::move(handler)}]() mutable {
            self->send_queue_.emplace_back(
                std::make_pair(std::move(req), std::move(handler)));
            self->send_next();
        });

        return result.get();
    }

    /*!
     * \brief Asynchronously logs in to the router
     *
     * \param [in]      name     The user name which to be used to login to the
     *                           router
     * \param [in]      password The password which to be used to login
     *                           to the router
     * \param [in, out] token    The asynchronous operation
     *                           completion token
     *
     * \return The passed completion token result
     */
    template <typename CompletionToken>
    decltype(auto) async_login(const std::string &name,
                               const std::string &password,
                               CompletionToken && token) {
        GENERATE_COMPLETION_HANDLER(void(const boost::system::error_code &),
                                    token, handler, result);

        async_send(
            make_request<tikpp::commands::v2::login>(name, password),
            [this, name, password, handler {std::move(handler)}](
                const auto &err, auto &&resp) mutable {
                if (err) {
                    handler(err);
                } else if (resp.error()) {
                    handler(resp.error());
                } else if (resp.contains(
                               tikpp::commands::v1::login::challenge_param)) {
                    auto req = make_request<tikpp::commands::v1::login>(
                        name, password,
                        resp[tikpp::commands::v1::login::challenge_param]);
                    async_send(std::move(req),
                               [this, handler {std::move(handler)}](
                                   const auto &err, auto &&resp) mutable {
                                   if (err) {
                                       handler(err);
                                   } else if (resp.error()) {
                                       handler(resp.error());
                                   } else {
                                       logged_in_.store(true);
                                       handler(boost::system::error_code {});
                                   }

                                   return false;
                               });
                } else {
                    handler(boost::system::error_code {});
                }
                return false;
            });

        return result.get();
    }

    /*!
     * \brief Gets the current request tag that the next request will have
     *
     * \return The next request tag
     */
    [[nodiscard]] inline auto current_tag() const noexcept -> std::uint32_t {
        return current_tag_.load();
    }

    /*!
     * \brief Gets a unique tag to be used for a request
     *
     * \return A unique request tag
     */
    [[nodiscard]] inline auto aquire_unique_tag() noexcept -> std::uint32_t {
        return current_tag_.fetch_add(1);
    }

    /*!
     * \brief Gets the API connection socket
     *
     * \return The connection socket
     */
    [[nodiscard]] inline auto socket() noexcept -> AsyncStream & {
        return sock_;
    }

    /*!
     * \brief Gets whether the API connection is open or not
     *
     * \return The connection open status
     */
    [[nodiscard]] inline auto is_open() const noexcept -> bool {
        return state_.load() == api_state::connected && sock_.is_open();
    }

    /*!
     * \brief Gets whether the API connection is authenticated or not
     *
     * \return The connection authentication status
     */
    [[nodiscard]] inline auto is_logged_in() const noexcept -> bool {
        return logged_in_.load();
    }

  protected:
    explicit basic_api(tikpp::io_context &io, ErrorHandler &&handler)
        : io_ {io},
          sock_ {io},
          error_handler_ {std::move(handler)},
          state_ {api_state::closed},
          current_tag_ {0},
          logged_in_ {false} {
    }

  private:
    inline void send_next() {
        assert(!send_queue_.empty());

        auto [req, cb] = std::move(send_queue_.front());
        send_queue_.pop_front();

        if (!is_open()) {
            cb(boost::asio::error::not_connected, {});
            return;
        }

        auto buf = std::make_shared<std::vector<std::uint8_t>>();
        req->encode(*buf);

        boost::asio::async_write(
            sock_, boost::asio::buffer(*buf),
            [self = this->shared_from_this(), buf, req {std::move(req)},
             cb {std::move(cb)}](const auto &err, const auto &sent) mutable {
                if (!self->is_open()) {
                    cb(boost::asio::error::not_connected, {});
                    return;
                }

                if (err) {
                    self->close();
                    cb(err, {});
                } else {
                    self->read_cbs_.emplace(
                        std::make_pair(req->tag(), std::move(cb)));
                }

                if (!self->send_queue_.empty()) {
                    self->send_next();
                }
            });
    }

    inline void read_next_response() {
        if (!is_open()) {
            return;
        }

        tikpp::detail::operations::async_read_response(
            sock_, [self = this->shared_from_this()](const auto &err,
                                                     auto &&     resp) mutable {
                if (!self->is_open()) {
                    return;
                }

                if (err) {
                    return self->on_error(err);
                }

                self->on_response(std::move(resp));
            });
    }

    inline void on_response(tikpp::response &&resp) {
        if (auto itr = read_cbs_.find(resp.tag().value());
            itr != read_cbs_.end()) {
            if (!itr->second({}, std::move(resp))) {
                read_cbs_.erase(itr);
            }
        }

        read_next_response();
    }

    inline void on_error(const boost::system::error_code &err) {
        close();
        error_handler_(err);
    }

    tikpp ::io_context &io_;
    AsyncStream         sock_;
    ErrorHandler        error_handler_;

    std::atomic<api_state> state_;
    std::atomic_uint32_t   current_tag_;
    std::atomic_bool       logged_in_;

    std::deque<std::pair<std::shared_ptr<request>, read_handler>> send_queue_;
    std::map<std::uint32_t, read_handler>                         read_cbs_;
};

//! A type-erased alias for \see basic_api struct
template <typename AsyncStream>
using basic_api_te =
    basic_api<AsyncStream,
              std::function<void(const boost::system::error_code &)>>;

namespace detail {

/*!
 * \brief A wrapper class to enable the use of \see std::make_shared function
 *        on \see basic_api struct
 */
template <typename AsyncStream, typename ErrorHandler>
struct basic_api_creator : tikpp::basic_api<AsyncStream, ErrorHandler> {
    template <typename... Arg>
    basic_api_creator(Arg &&... args)
        : tikpp::basic_api<AsyncStream, ErrorHandler> {
              std::forward<Arg>(args)...} {
    }
};

} // namespace detail

/*!
 * \brief Creates a new instance of \see basic_api struct
 *
 * \param [in] io      The IO object to be used by the API connection
 * \param [in] handler A callable object to be called on fatal errors
 *
 * \return The create \see basic_api instance
 */
template <typename AsyncStream, typename ErrorHandler>
[[nodiscard]] inline auto make_basic_api(tikpp::io_context &io,
                                         ErrorHandler &&    handler)
    -> std::shared_ptr<tikpp::basic_api<AsyncStream, ErrorHandler>> {
    return std::make_shared<
        tikpp::detail::basic_api_creator<AsyncStream, ErrorHandler>>(
        io, std::forward<ErrorHandler>(handler));
}

}; // namespace tikpp

#endif

max_stars_repo_name: aymanalqadhi/tikpp


text:
/*
 * Copyright 2017 MapD Technologies, 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.
 */

/**
 * @file        GlobalFileMgr.cpp
 * @author      Norair Khachiyan <norair@map-d.com>
 * @author      Todd Mostak <todd@map-d.com>
 */

#include "DataMgr/FileMgr/GlobalFileMgr.h"

#include <fcntl.h>
#include <algorithm>
#include <boost/filesystem.hpp>
#include <boost/lexical_cast.hpp>
#include <string>
#include <thread>
#include <utility>
#include <vector>

#include "DataMgr/ForeignStorage/ArrowForeignStorage.h"
#include "DataMgr/ForeignStorage/ForeignStorageInterface.h"
#include "Shared/File.h"

using namespace std;

namespace File_Namespace {

GlobalFileMgr::GlobalFileMgr(const int32_t deviceId,
                             std::shared_ptr<ForeignStorageInterface> fsi,
                             std::string basePath,
                             const size_t num_reader_threads,
                             const size_t defaultPageSize)
    : AbstractBufferMgr(deviceId)
    , basePath_(basePath)
    , num_reader_threads_(num_reader_threads)
    , epoch_(-1)
    ,  // set the default epoch for all tables corresponding to the time of
       // last checkpoint
    defaultPageSize_(defaultPageSize)
    , fsi_(fsi) {
  omnisci_db_version_ = 2;
  // DS changes also triggered by individual FileMgr per table project (release 2.1.0)
  dbConvert_ = false;
  init();
}

void GlobalFileMgr::init() {
  // check if basePath_ already exists, and if not create one
  boost::filesystem::path path(basePath_);
  if (basePath_.size() > 0 && basePath_[basePath_.size() - 1] != '/') {
    basePath_.push_back('/');
  }
  if (boost::filesystem::exists(path)) {
    if (!boost::filesystem::is_directory(path)) {
      LOG(FATAL) << "Specified path is not a directory.";
    }
  } else {  // data directory does not exist
    if (!boost::filesystem::create_directory(path)) {
      LOG(FATAL) << "Could not create data directory";
    }
  }
}

void GlobalFileMgr::checkpoint() {
  mapd_unique_lock<mapd_shared_mutex> write_lock(fileMgrs_mutex_);
  for (auto fileMgrsIt = allFileMgrs_.begin(); fileMgrsIt != allFileMgrs_.end();
       ++fileMgrsIt) {
    fileMgrsIt->second->checkpoint();
  }
}

void GlobalFileMgr::checkpoint(const int32_t db_id, const int32_t tb_id) {
  getFileMgr(db_id, tb_id)->checkpoint();
}

size_t GlobalFileMgr::getNumChunks() {
  mapd_shared_lock<mapd_shared_mutex> read_lock(fileMgrs_mutex_);
  size_t num_chunks = 0;
  for (auto fileMgrsIt = allFileMgrs_.begin(); fileMgrsIt != allFileMgrs_.end();
       ++fileMgrsIt) {
    num_chunks += fileMgrsIt->second->getNumChunks();
  }

  return num_chunks;
}

void GlobalFileMgr::deleteBuffersWithPrefix(const ChunkKey& keyPrefix, const bool purge) {
  /* keyPrefix[0] can be -1 only for gpu or cpu buffers but not for FileMgr.
   * There is no assert here, as GlobalFileMgr is being called with -1 value as well in
   * the same loop with other buffers. So the case of -1 will just be ignored, as nothing
   * needs to be done.
   */
  if (keyPrefix[0] != -1) {
    return getFileMgr(keyPrefix)->deleteBuffersWithPrefix(keyPrefix, purge);
  }
}

AbstractBufferMgr* GlobalFileMgr::findFileMgrUnlocked(const int32_t db_id,
                                                      const int32_t tb_id) {
  // NOTE: only call this private function after locking is already in place
  AbstractBufferMgr* fm = nullptr;
  const auto file_mgr_key = std::make_pair(db_id, tb_id);
  if (auto it = allFileMgrs_.find(file_mgr_key); it != allFileMgrs_.end()) {
    fm = it->second;
  }
  return fm;
}

void GlobalFileMgr::deleteFileMgr(const int32_t db_id, const int32_t tb_id) {
  // NOTE: only call this private function after locking is already in place
  const auto file_mgr_key = std::make_pair(db_id, tb_id);
  if (auto it = ownedFileMgrs_.find(file_mgr_key); it != ownedFileMgrs_.end()) {
    ownedFileMgrs_.erase(it);
  }
  if (auto it = allFileMgrs_.find(file_mgr_key); it != allFileMgrs_.end()) {
    allFileMgrs_.erase(it);
  }
}

void GlobalFileMgr::closeFileMgr(const int32_t db_id, const int32_t tb_id) {
  mapd_unique_lock<mapd_shared_mutex> write_lock(fileMgrs_mutex_);
  deleteFileMgr(db_id, tb_id);
}

bool GlobalFileMgr::existsDiffBetweenFileMgrParamsAndFileMgr(
    FileMgr* file_mgr,
    const FileMgrParams& file_mgr_params) const {
  if (file_mgr_params.epoch != -1 &&
      file_mgr_params.epoch != file_mgr->lastCheckpointedEpoch()) {
    return true;
  }
  if (file_mgr_params.max_rollback_epochs != -1 &&
      file_mgr_params.max_rollback_epochs != file_mgr->maxRollbackEpochs()) {
    return true;
  }
  return false;
}

void GlobalFileMgr::setFileMgrParams(const int32_t db_id,
                                     const int32_t tb_id,
                                     const FileMgrParams& file_mgr_params) {
  auto fm = dynamic_cast<File_Namespace::FileMgr*>(findFileMgr(db_id, tb_id));
  mapd_unique_lock<mapd_shared_mutex> write_lock(fileMgrs_mutex_);
  if (fm) {
    deleteFileMgr(db_id, tb_id);
  }
  const auto file_mgr_key = std::make_pair(db_id, tb_id);
  auto max_rollback_epochs =
      (file_mgr_params.max_rollback_epochs >= 0 ? file_mgr_params.max_rollback_epochs
                                                : -1);
  auto s = std::make_shared<FileMgr>(
      0,
      this,
      file_mgr_key,
      max_rollback_epochs,
      num_reader_threads_,
      file_mgr_params.epoch != -1 ? file_mgr_params.epoch : epoch_,
      defaultPageSize_);
  CHECK(ownedFileMgrs_.insert(std::make_pair(file_mgr_key, s)).second);
  CHECK(allFileMgrs_.insert(std::make_pair(file_mgr_key, s.get())).second);
  max_rollback_epochs_per_table_[{db_id, tb_id}] = max_rollback_epochs;
  return;
}

AbstractBufferMgr* GlobalFileMgr::getFileMgr(const int32_t db_id, const int32_t tb_id) {
  {  // check if FileMgr already exists for (db_id, tb_id)
    mapd_shared_lock<mapd_shared_mutex> read_lock(fileMgrs_mutex_);
    AbstractBufferMgr* fm = findFileMgrUnlocked(db_id, tb_id);
    if (fm) {
      return fm;
    }
  }

  {  // create new FileMgr for (db_id, tb_id)
    mapd_unique_lock<mapd_shared_mutex> write_lock(fileMgrs_mutex_);
    AbstractBufferMgr* fm = findFileMgrUnlocked(db_id, tb_id);
    if (fm) {
      return fm;  // mgr was added between the read lock and the write lock
    }
    const auto file_mgr_key = std::make_pair(db_id, tb_id);
    const auto foreign_buffer_manager = fsi_->lookupBufferManager(db_id, tb_id);
    if (foreign_buffer_manager) {
      CHECK(allFileMgrs_.insert(std::make_pair(file_mgr_key, foreign_buffer_manager))
                .second);
      return foreign_buffer_manager;
    } else {
      int32_t max_rollback_epochs{-1};
      if (max_rollback_epochs_per_table_.find(file_mgr_key) !=
          max_rollback_epochs_per_table_.end()) {
        max_rollback_epochs = max_rollback_epochs_per_table_[file_mgr_key];
      }
      auto s = std::make_shared<FileMgr>(0,
                                         this,
                                         file_mgr_key,
                                         max_rollback_epochs,
                                         num_reader_threads_,
                                         epoch_,
                                         defaultPageSize_);
      CHECK(ownedFileMgrs_.insert(std::make_pair(file_mgr_key, s)).second);
      CHECK(allFileMgrs_.insert(std::make_pair(file_mgr_key, s.get())).second);
      return s.get();
    }
  }
}

// For testing purposes only
std::shared_ptr<FileMgr> GlobalFileMgr::getSharedFileMgr(const int db_id,
                                                         const int table_id) {
  const auto table_key = std::make_pair(db_id, table_id);
  if (ownedFileMgrs_.find(table_key) == ownedFileMgrs_.end()) {
    return nullptr;
  }
  return ownedFileMgrs_[table_key];
}

// For testing purposes only
void GlobalFileMgr::setFileMgr(const int db_id,
                               const int table_id,
                               std::shared_ptr<FileMgr> file_mgr) {
  allFileMgrs_[{db_id, table_id}] = file_mgr.get();
  ownedFileMgrs_[{db_id, table_id}] = file_mgr;
}

void GlobalFileMgr::writeFileMgrData(
    FileMgr* fileMgr) {  // this function is not used, keep it for now for future needs
  mapd_shared_lock<mapd_shared_mutex> read_lock(fileMgrs_mutex_);
  for (auto fileMgrIt = allFileMgrs_.begin(); fileMgrIt != allFileMgrs_.end();
       fileMgrIt++) {
    FileMgr* fm = dynamic_cast<FileMgr*>(fileMgrIt->second);
    CHECK(fm);
    if ((fileMgr != 0) && (fileMgr != fm)) {
      continue;
    }
    for (auto chunkIt = fm->chunkIndex_.begin(); chunkIt != fm->chunkIndex_.end();
         chunkIt++) {
      chunkIt->second->write((int8_t*)chunkIt->second, chunkIt->second->size(), 0);
    }
  }
}

void GlobalFileMgr::removeTableRelatedDS(const int32_t db_id, const int32_t tb_id) {
  mapd_unique_lock<mapd_shared_mutex> write_lock(fileMgrs_mutex_);
  auto fm = dynamic_cast<File_Namespace::FileMgr*>(findFileMgrUnlocked(db_id, tb_id));
  if (fm) {
    fm->closeRemovePhysical();
  } else {
    // fileMgr has not been initialized so there is no need to
    // spend the time initializing
    // initialize just enough to have to rename
    const auto file_mgr_key = std::make_pair(db_id, tb_id);
    auto u = std::make_unique<FileMgr>(0, this, file_mgr_key, defaultPageSize_, true);
    u->closeRemovePhysical();
  }
  // remove table related in-memory DS only if directory was removed successfully

  deleteFileMgr(db_id, tb_id);
  max_rollback_epochs_per_table_.erase({db_id, tb_id});
}

void GlobalFileMgr::setTableEpoch(const int32_t db_id,
                                  const int32_t tb_id,
                                  const int32_t start_epoch) {
  AbstractBufferMgr* opened_fm = findFileMgr(db_id, tb_id);
  if (opened_fm) {
    // Delete this FileMgr to ensure epoch change occurs in constructor with other
    // reads/writes locked out
    deleteFileMgr(db_id, tb_id);
  }
  const auto file_mgr_key = std::make_pair(db_id, tb_id);
  // this is where the real rollback of any data ahead of the currently set epoch is
  // performed
  // Will call set_epoch with start_epoch internally
  auto u = std::make_unique<FileMgr>(
      0, this, file_mgr_key, -1, num_reader_threads_, start_epoch, defaultPageSize_);
  // remove the dummy one we built
  u.reset();
}

size_t GlobalFileMgr::getTableEpoch(const int32_t db_id, const int32_t tb_id) {
  // UX change was made to this function Oct 2020 to return checkpointed epoch. In turn,
  // setTableEpoch was changed to set the epoch at the user's input, instead of input - 1
  mapd_shared_lock<mapd_shared_mutex> read_lock(fileMgrs_mutex_);
  AbstractBufferMgr* opened_fm = findFileMgr(db_id, tb_id);
  if (opened_fm) {
    return dynamic_cast<FileMgr*>(opened_fm)->lastCheckpointedEpoch();
  }
  // Do not do full init of table just to get table epoch, just check file instead
  const auto file_mgr_key = std::make_pair(db_id, tb_id);
  auto u = std::make_unique<FileMgr>(0, this, file_mgr_key, defaultPageSize_, true);
  const auto epoch = u->lastCheckpointedEpoch();
  u.reset();
  return epoch;
}

StorageStats GlobalFileMgr::getStorageStats(const int32_t db_id, const int32_t tb_id) {
  mapd_shared_lock<mapd_shared_mutex> read_lock(fileMgrs_mutex_);
  AbstractBufferMgr* opened_fm = findFileMgr(db_id, tb_id);
  if (opened_fm) {
    return dynamic_cast<FileMgr*>(opened_fm)->getStorageStats();
  }
  // Do not do full init of table just to get storage stats, just check file instead
  const auto file_mgr_key = std::make_pair(db_id, tb_id);
  auto u = std::make_unique<FileMgr>(0, this, file_mgr_key, defaultPageSize_, true);
  const auto basic_storage_stats = u->getStorageStats();
  u.reset();
  return basic_storage_stats;
}

void GlobalFileMgr::compactDataFiles(const int32_t db_id, const int32_t tb_id) {
  auto file_mgr = dynamic_cast<File_Namespace::FileMgr*>(findFileMgr(db_id, tb_id));
  {
    mapd_unique_lock<mapd_shared_mutex> write_lock(fileMgrs_mutex_);
    if (file_mgr) {
      file_mgr->compactFiles();
      deleteFileMgr(db_id, tb_id);
    }
  }

  // Re-initialize file manager
  getFileMgr(db_id, tb_id);
}
}  // namespace File_Namespace

ext: cpp

max_stars_repo_name: gshimansky/omniscidb

max_issues_repo_name: gshimansky/omniscidb

max_forks_repo_name: gshimansky/omniscidb


text:
#include <iostream>
#include <sstream>
#include <fstream>

#include <Eigen/Core>
#include <Eigen/Dense>
#include <opencv2/core/eigen.hpp>
#include <opencv2/opencv.hpp>
#include <glog/logging.h>
#include <pcl/io/ply_io.h>
#include <pcl/common/transforms.h>

#include "localization/IOUtils.h"
#include "datastruct/Lidar3DStruct.h"
#include "param_config/ParamConfig.h"
#include "sensor_geometry/MultiRayLidar.h"
#include "sensor_geometry/PanoAxis.h"
#include "sensor_geometry/PinholeCamera.h"
#include "sensor_geometry/SensorFactory.h"
#include "util/FileSystemTools.h"
#include "util/LabelmeUtils.h"
#include "Utils.h"

bool projectLaserScan2Camera(const common::PinholeCameraPtr &cam_ptr,
                             const sensorhandler::PointCloudPtr &laser_scan_ptr,
                             const Eigen::Matrix4d &T_c_l, cv::Mat &out_img) {
  if (cam_ptr == nullptr || laser_scan_ptr == nullptr) {
    LOG(ERROR) << "Invalid input pointer!";
    return false;
  }
  if (T_c_l.hasNaN()) {
    LOG(ERROR) << "Invalid transformation matrix!";
    return false;
  }

  int img_width = cam_ptr->resolution().width;
  int img_height = cam_ptr->resolution().height;
  int point_num = laser_scan_ptr->points.size();
  // LOG(INFO) << "Process " << point_num << " laser points";

  cv::Scalar color_start(0, 255, 0);
  cv::Scalar color_end(0,0,255);
  const double max_distant = 10.0;
  double weight_b = (color_end[0] - color_start[0]) / max_distant;
  double weight_g = (color_end[1] - color_start[1]) / max_distant;
  double weight_r = (color_end[2] - color_start[2]) / max_distant;

  int cnt = 0;
  for (int i = 0; i < point_num; ++i) {
    Eigen::Vector3d p_l(laser_scan_ptr->points[i].x,
                        laser_scan_ptr->points[i].y,
                        laser_scan_ptr->points[i].z);

    Eigen::Vector3d p_c = (T_c_l * p_l.homogeneous()).hnormalized();
    if (p_c[2] < 0)
        continue;

    Eigen::Vector2d p_img;
    cam_ptr->project(p_c, &p_img);
    if (p_img[0] < 0 || p_img[0] >= img_width || p_img[1] < 0 || p_img[1] >= img_height)
      continue;

    // draw color square as projected laser point
    {
      double color_scale = p_c[2];
      cv::Scalar color(0, 255 + weight_g*color_scale , weight_r * color_scale);
      cv::Point p(p_img[0], p_img[1]);
      cv::circle(out_img, p, 1, color, -1);
      cnt ++;
    }
  }

  LOG(INFO) << "Project " << cnt << " laser points into camera.";
  return true;
}

// this exe visualize lidar2cam extrinsic by backprojecting laser point cloud into image plane

int main(int argc, char **argv) {
  if (argc < 3) {
    LOG(ERROR)
        << "Usage: ./test_lidar2tehce_evaluation [config.yaml] [data_folder] \n \
    \t [config.yaml] is backpack configuration file. \n \
    \t [data_folder] is dataset fodler for evaluation.  \n";
    return -1;
  }

  std::string config_file(argv[1]);
  std::string data_folder(argv[2]);
  std::string lidar_scan_folder = common::concatenateFolderAndFileName(data_folder, "scans");
  std::string teche_image_folder = common::concatenateFolderAndFileName(data_folder, "undist_pano_images");

  if (!common::fileExists(config_file)) {
    LOG(ERROR) << " Configuration file does not exit, quit...\n";
    return -1;
  }
  if (!common::pathExists(lidar_scan_folder)) {
    LOG(ERROR) << " Lidar folder does not exit, quit...\n";
    return -1;
  }
  if (!common::pathExists(teche_image_folder)) {
    LOG(ERROR) << " Teche image folder does not exit, quit...\n";
    return -1;
  }

  common::ParamConfig::setParameterFile(config_file);

  // teche cameras
  std::vector<common::PinholeCameraPtr> v_teche_cameras_ptr;
  for (size_t i = 0; i < 4; ++i) {
    common::PinholeCameraPtr cam_ptr = std::make_shared<common::PinholeCamera>("teche_" + std::to_string(i));
    if (cam_ptr != nullptr) {
      v_teche_cameras_ptr.push_back(cam_ptr);
    } else {
      LOG(ERROR) << "FAIL to construct teche camera from configuration file!";
      return -1;
    }
  }

  common::MultiRayLidarPtr vertical_lidar_ptr = common::SensorFactory::createMultiRayLidar("vertical_lidar");
  common::MultiRayLidarPtr horizontal_lidar_ptr = common::SensorFactory::createMultiRayLidar("horizon_lidar");

  // pano
  common::PanoAxisPtr pano_axis_ptr = common::SensorFactory::createPanoAxis("teche_pano_axis");

  Eigen::Matrix4d T_base_l0 = horizontal_lidar_ptr->extrinsics();
  Eigen::Matrix4d T_base_l1 = vertical_lidar_ptr->extrinsics();
  Eigen::Matrix4d T_base_pano_axis = pano_axis_ptr->extrinsics();
  std::string horizon_pc_filepath = common::concatenateFolderAndFileName(lidar_scan_folder, "0_0.ply");
  std::string vertical_pc_filepath = common::concatenateFolderAndFileName(lidar_scan_folder, "1_0.ply");

  PointCloudPtr vertical_sweep_cloud_ptr(new PointCloud);
  PointCloudPtr horizon_sweep_cloud_ptr(new PointCloud);

  if (!common::fileExists(vertical_pc_filepath)) {
    LOG(ERROR) << "cannot find pc file: " << vertical_pc_filepath;
    return -1;
  }
  if (!common::fileExists(horizon_pc_filepath)) {
    LOG(ERROR) << "cannot find pc file: " << vertical_pc_filepath;
    return -1;
  }

  pcl::io::loadPLYFile(vertical_pc_filepath, *vertical_sweep_cloud_ptr);
  pcl::io::loadPLYFile(horizon_pc_filepath, *horizon_sweep_cloud_ptr);

  double perpendicular_angle = 0.0;
  Eigen::Vector3d lidar0_corner_point = calcCornerPoint(lidar_scan_folder, "lidar0", perpendicular_angle);
  Eigen::Vector3d lidar1_corner_point = calcCornerPoint(lidar_scan_folder, "lidar1", perpendicular_angle);
  if(lidar0_corner_point.norm() > 1e3 && lidar1_corner_point.norm() > 1e3){
    LOG(ERROR) << "Invalid corner points! Please check input plane cloud";
    return -1;
  }

  std::vector<std::string> v_img_paths;
  std::vector<std::string> paths;
  paths.push_back(teche_image_folder);
  common::getFileLists(paths, true, "jpg", &v_img_paths);

  int img_num = v_img_paths.size();
  for (int i = 0; i < img_num; ++i) {
    std::string &img_path = v_img_paths[i];
    std::string img_folder, img_name;
    common::splitPathAndFilename(img_path, &img_folder, &img_name);

    int cam_index = img_name[0] - 48;
    if (cam_index < 1 || cam_index > 4) {
      LOG(ERROR) << "Invalid teche images!";
      continue;
    }

    // read corner coordinates on image
    std::string corner_file_name = img_name.substr(0, img_name.size()-4) + ".json";
    std::string corner_file_path = common::concatenateFolderAndFileName(teche_image_folder, corner_file_name);
    // skip images that corner is unsivisable
    if (!common::fileExists(corner_file_path)) {
      LOG(WARNING) << "cannot find labelme file: " << corner_file_path;
      continue;
    }
    std::vector<Eigen::Vector2d> v_corners;
    common::readLabelMeResult(corner_file_path, v_corners);

    cv::Mat out_img = cv::imread(img_path, cv::IMREAD_UNCHANGED);
    if(out_img.empty()){
        LOG(ERROR) << "Fail to read image  " << img_path;
        return -1;
    }

    common::PinholeCameraPtr teche_cam_ptr = v_teche_cameras_ptr[cam_index - 1];
    Eigen::Matrix4d T_pano_axis_c = teche_cam_ptr->extrinsics();
    Eigen::Matrix3d intrinsic = teche_cam_ptr->cameraMatrix();

    // project horizontal sweeps into camera
    // Eigen::Matrix4d T_l0_c = (T_base_l0.inverse()) * T_base_pano_axis * T_pano_axis_c;
    Eigen::Matrix4d T_l0_c = (T_base_l0.inverse()) * T_pano_axis_c;
    std::cout << "T_l0_c" << cam_index-1 << " : " << T_l0_c << "\n";
    Eigen::Matrix4d T_c_l0 = T_l0_c.inverse();
    bool sts = projectLaserScan2Camera(teche_cam_ptr, horizon_sweep_cloud_ptr,
                                       T_c_l0, out_img);
    if (!sts) {
      LOG(ERROR) << "Fail to project laser point into image!";
      return -1;
    }

    double reproject_err = calcCornerPointReprojectError(lidar0_corner_point, T_c_l0, intrinsic, v_corners[0], out_img);
    LOG(INFO) << "Reproject error of Corner extract from lidar0 sweeps : " << reproject_err;
    std::string save_img_path = common::concatenateFolderAndFileName(img_folder, "eva_lidar0_" + img_name);
    cv::imwrite(save_img_path, out_img);

    if(lidar1_corner_point.norm() > 1e6){
      LOG(WARNING) << " Cannot find corner point in Lidara1";
      continue;
    }
    out_img = cv::imread(img_path, cv::IMREAD_UNCHANGED);
    // project vertical sweeps into camera
    // Eigen::Matrix4d T_l1_c = (T_base_l1.inverse()) * T_base_pano_axis * T_pano_axis_c;
    Eigen::Matrix4d T_l1_c = (T_base_l1.inverse()) * T_pano_axis_c;
    // T_l1_c << -0.305399684008826,  -0.951924037185201,  0.0239094214973372,   0.640044537317772,
    // -0.0215547405557131, -0.0181916807166895,  -0.999602148813356,  -0.075209496121445,
    //   0.951980265639412,  -0.305793541759355, -0.0149627421078072,  -0.039993200341565,
    //   0, 0, 0, 1;
    // T_l1_c <<  0.298707809405327,  -0.953858732908545, -0.0304493391451621,   0.662864589002141,
    // 0.0389234600194619, -0.0197027160624481,   0.999047930401678,  0.0639108552539182,
    // -0.953550527691314,  -0.299608612416047,  0.0312421271002314, -0.0762731696475622,
    // 0, 0, 0, 1;
    std::cout << "T_l1_c" << cam_index-1 << " : " << T_l1_c << "\n";
    Eigen::Matrix4d T_c_l1 = T_l1_c.inverse();
    sts = projectLaserScan2Camera(teche_cam_ptr, vertical_sweep_cloud_ptr,
                                  T_c_l1, out_img);
    if (!sts) {
      LOG(ERROR) << "Fail to project laser point into image!";
      return -1;
    }

    reproject_err = calcCornerPointReprojectError(lidar1_corner_point, T_c_l1, intrinsic, v_corners[0], out_img);
    LOG(INFO) << "Reproject error of Corner extract from lidar1 sweeps : " << reproject_err;
    save_img_path = common::concatenateFolderAndFileName(img_folder, "eva_lidar1_" + img_name);
    cv::imwrite(save_img_path, out_img);

    Eigen::Matrix4d T_l0_l1 = Eigen::Matrix4d::Identity();
    T_l0_l1 = T_l0_c * T_l1_c.inverse();
    std::cout << T_l0_l1(0,0) << ", " << T_l0_l1(0,1) << ", " << T_l0_l1(0,2) << ", " << T_l0_l1(0,3) << "\n";
    std::cout << T_l0_l1(1,0) << ", " << T_l0_l1(1,1) << ", " << T_l0_l1(1,2) << ", " << T_l0_l1(1,3) << "\n";
    std::cout << T_l0_l1(2,0) << ", " << T_l0_l1(2,1) << ", " << T_l0_l1(2,2) << ", " << T_l0_l1(2,3) << "\n";
    std::cout << T_l0_l1(3,0) << ", " << T_l0_l1(3,1) << ", " << T_l0_l1(3,2) << ", " << T_l0_l1(3,3) << "\n";
  }

  return 0;
}


text:
//
// Copyright Jason Rice 2016
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//

#ifndef NBDL_TEST_ASSETS_TEST_STATE_CONSUMER_HPP
#define NBDL_TEST_ASSETS_TEST_STATE_CONSUMER_HPP

#include <nbdl/concept/StateConsumer.hpp>

#include <boost/hana.hpp>
#include <utility>

namespace nbdl_test
{
  struct state_consumer;

  template <typename Context>
  struct state_consumer_impl
  {
    using hana_tag = state_consumer;
    Context context;

    template <typename T>
    state_consumer_impl(nbdl::actor_initializer<Context, T>&& a)
     : context(a.context)
    { }
  };

  struct state_consumer
  {
    template <typename Context>
    using actor_impl = state_consumer_impl<Context>;
  };

}

namespace nbdl
{
  template <>
  struct notify_state_change_impl<nbdl_test::state_consumer>
  {
    template <typename StateConsumer, typename Path>
    static void apply(StateConsumer&&, Path&&)
    {
      // ???
    }
  };
}

#endif

max_stars_repo_name: ricejasonf/nbdl

max_issues_repo_name: ricejasonf/nbdl

max_forks_repo_name: ricejasonf/nbdl


text:
#include "stdafx.h"

#include <boost/python.hpp>
#include "PyBaseObject.h"
#include "strconv.h"
#include "GripData.h"

std::wstring str_for_base_object;
HeeksColor color_for_base_object;

bool BaseObject::NeverDelete(){ return true; }

int BaseObject::GetType()const{
	//return m_type;
	std::pair<bool, int> result = CallReturnInt("GetType");
	if (result.first)
		return result.second;
	return 0;
}

bool BaseObject::UsesID()
{
	std::pair<bool, bool> result = CallReturnBool("UsesID");
	if (result.first)
		return result.second;
	return ObjList::UsesID();
}

const wchar_t* BaseObject::GetIconFilePath()
{
	std::pair<bool, std::string> result = CallReturnString("GetIconFilePath");
	if (result.first)
		return Ctt(result.second.c_str());
	return ObjList::GetIconFilePath();
}

const wchar_t* BaseObject::GetShortString()const
{
	std::pair<bool, std::string> result = CallReturnString("GetTitle");
	if (result.first)
		return Ctt(result.second.c_str());
	return ObjList::GetShortString();
}

bool  BaseObject::CanEditString(void)const
{
	std::pair<bool, bool> result = CallReturnBool("CanEditString");
	if (result.first)
		return result.second;
	return ObjList::CanEditString();
}

void BaseObject::OnEditString(const wchar_t* str)
{
	if (!CallVoidReturn("OnEditString", std::wstring(str)))
		ObjList::OnEditString(str);
}

const wchar_t* BaseObject::GetTypeString()const
{
	std::pair<bool, std::string> result = CallReturnString("GetTypeString");
	if (result.first)
		return Ctt(result.second.c_str());
	return ObjList::GetTypeString();
}

const HeeksColor* BaseObject::GetColor()const
{
	std::pair<bool, bool> result = CallReturnBool("HasColor");
	if (result.first && result.second)
	{
		// HasColor exists and HasColor returns True
		std::pair<bool, HeeksColor> result2 = CallReturnColor("GetColor");
		if (result2.first)
		{
			color_for_base_object = result2.second;
			return &color_for_base_object;
		}
	}
	return ObjList::GetColor();
}

void BaseObject::SetColor(const HeeksColor &col)
{
	CallVoidReturn("SetColor", col);
}

void BaseObject::glCommands(bool select, bool marked, bool no_color)
{
	m_no_colour = no_color;
	m_marked = marked;
	m_select = select;

	if (!CallVoidReturn("OnGlCommands", select, marked, no_color))
		ObjList::glCommands(select, marked, no_color);
}

extern std::list<Property *> *property_list;

void BaseObject::GetProperties(std::list<Property *> *list)
{
	property_list = list;
	if (!CallVoidReturn("GetProperties"))
		ObjList::GetProperties(list);
}

static std::list<GripData>* gripper_list;

void BaseObject::GetGripperPositionsTransformed(std::list<GripData> *list, bool just_for_endof)
{
	gripper_list = list;
	if (!CallVoidReturn("GetGrippers", just_for_endof))
		ObjList::GetGripperPositionsTransformed(list, just_for_endof);
}

Point3d Stretch_point;
Point3d Stretch_shift;

Point3d GetStretchPoint()
{
	return Stretch_point;
}

Point3d GetStretchShift()
{
	return Stretch_shift;

}

bool BaseObject::Stretch(const Point3d &p, const Point3d &shift, void* data)
{
	Stretch_point = p;
	Stretch_shift = shift;
	if (!CallVoidReturn("Stretch"))
		return ObjList::Stretch(p, shift, data);
	return false;
}

void BaseObject::Transform(const Matrix &m)
{
	if (!CallVoidReturn("Transform", m))
		ObjList::Transform(m);
}

void AddGripper(GripData& gripper)
{
	gripper_list->push_back(gripper);
}

void BaseObject::GetBox(CBox &box)
{
	std::pair<bool, CBox> result2 = CallReturnBox("GetBox");
	if (result2.first)
	{
		box.Insert(result2.second);
	}
}

void BaseObject::KillGLLists()
{
	if (!CallVoidReturn("KillGLLists"))
		ObjList::KillGLLists();
}

void BaseObject::WriteToXML(TiXmlElement *element)
{
	theApp->m_cur_xml_element = element;
	CallVoidReturn("WriteXml");
}

void BaseObject::ReadFromXML(TiXmlElement *element)
{
	theApp->m_cur_xml_element = element;
	CallVoidReturn("ReadXml");
}

const wchar_t* BaseObject::GetXMLTypeString()const
{
	std::pair<bool, std::string> result = CallReturnString("GetXMLTypeString");
	if (result.first)
		return Ctt(result.second.c_str());
	return ObjList::GetXMLTypeString();
}

HeeksObj* BaseObject::MakeACopy()const
{
	std::pair<bool, HeeksObj*> result = CallReturnHeeksObj("MakeACopy");
	if (result.first)
		return result.second;
	return NULL;
}

void BaseObject::CopyFrom(const HeeksObj* object)
{
	copy_from_object = object;
	CallVoidReturn("CopyFrom", object);
}

void BaseObject::ReloadPointers()
{
	if (!CallVoidReturn("ReloadPointers"))
		ObjList::ReloadPointers();
}

bool BaseObject::OneOfAKind()
{
	std::pair<bool, bool> result = CallReturnBool("OneOfAKind");
	if (result.first)
		return result.second;
	return ObjList::OneOfAKind();
}

bool BaseObject::OneOfAKind_default(){
	return ObjList::OneOfAKind();
}

void BaseObject::OnAdd()
{
	CallVoidReturn("OnAdd");
}

void BaseObject::OnRemove()
{
	CallVoidReturn("OnRemove");
}

bool BaseObject::SetClickMarkPoint(const Point3d &ray_start, const Point3d &ray_direction)
{
	std::pair<bool, bool> result = CallReturnBool("SetClickMarkPoint", ray_start, ray_direction);
	if (result.first)
		return result.second;
	return ObjList::SetClickMarkPoint(ray_start, ray_direction);
}

static void(*callback_for_GetTriangles)(const double*, const double*) = NULL;
static double cusp_for_GetTriangles = 0.0;
static bool just_one_average_normal_for_GetTriangles = false;

void BaseObject::GetTriangles(void(*callbackfunc)(const double* x, const double* n), double cusp, bool just_one_average_normal)
{
	callback_for_GetTriangles = callbackfunc;
	cusp_for_GetTriangles = cusp;
	just_one_average_normal_for_GetTriangles = just_one_average_normal;
	CallVoidReturn("GetTriangles");
}

void BaseObject::AddTriangle(double x0, double y0, double z0, double x1, double y1, double z1, double x2, double y2, double z2)
{
	static double x[9];
	static double n[9];

	x[0] = x0;
	x[1] = y0;
	x[2] = z0;
	x[3] = x1;
	x[4] = y1;
	x[5] = z1;
	x[6] = x2;
	x[7] = y2;
	x[8] = z2;
	Point3d p0(&x[0]);
	Point3d p1(&x[1]);
	Point3d p2(&x[2]);
	Point3d v1(p0, p1);
	Point3d v2(p0, p2);
	try
	{
		Point3d norm = (v1 ^ v2).Normalized();
		n[0] = norm.x;
		n[1] = norm.y;
		n[2] = norm.z;
		if (!just_one_average_normal_for_GetTriangles)
		{
			n[3] = n[0];
			n[4] = n[1];
			n[5] = n[2];
			n[6] = n[0];
			n[7] = n[1];
			n[8] = n[2];
		}
		(*callback_for_GetTriangles)(x, n);
	}
	catch (...)
	{
	}
}

boost::python::override BaseObject::get_override(char const* name) const
{
	boost::python::override result = boost::python::wrapper<ObjList>::get_override(name);
	if (result != NULL)
		return result;
	PyErr_Clear();
	return result;
}

// static definitions
bool BaseObject::in_glCommands = false;
bool BaseObject::triangles_begun = false;
bool BaseObject::lines_begun = false;
bool BaseObject::m_no_colour = false;
bool BaseObject::m_marked = false;
bool BaseObject::m_select = false;
const HeeksObj* BaseObject::copy_from_object = NULL;

max_stars_repo_name: danheeks/PyCAD

max_issues_repo_name: danheeks/PyCAD

max_forks_repo_name: danheeks/PyCAD