Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
CastApi.hpp 3.58 KiB
/*
 * CastApi.hpp
 *
 * Created on: Apr 1, 2013
 * Author: Jan Travnicek
 */

#ifndef CAST_API_HPP_
#define CAST_API_HPP_

#include <functional>
#include <map>
#include <string>

#include "object/ObjectBase.h"
#include "object/Object.h"

namespace alib {

struct castApi {
	class CastPoolBase {
	protected:
		std::map < std::type_index, std::function < alib::Object ( const alib::ObjectBase & ) > > castFunctions;

	public:
		alib::Object cast ( const alib::ObjectBase & from ) {
			std::map < std::type_index, std::function < alib::Object ( const alib::ObjectBase & ) > >::iterator res = castFunctions.find ( std::type_index ( typeid ( from ) ) );

			if ( res == castFunctions.end ( ) )
				throw std::bad_cast ( );

			return res->second ( from );
		}

		bool castAvailable ( std::type_index from ) {
			return castFunctions.count ( from );
		}

	};

	template < class To >
	class CastPool : public CastPoolBase {
	public:
		template < class From >
		void add ( ) {
			castFunctions.insert ( std::make_pair ( std::type_index ( typeid ( From ) ), [] ( const alib::ObjectBase & from ) { return alib::Object ( To ( ( const From & ) from ) ); } ) );
		}

		template < class From >
		bool test ( ) {
			return castFunctions.count ( std::type_index ( typeid ( From ) ) );
		}

	};

private:
	 // INFO: Function exist to handle static order of initialisation
	static std::map < std::type_index, CastPoolBase * > & castFunctionsById ( ) {
		static std::map < std::type_index, CastPoolBase * > res;

		return res;
	}

	 // INFO: Function exist to handle static order of initialisation
	static std::map < std::string, CastPoolBase * > & castFunctionsByString ( ) {
		static std::map < std::string, CastPoolBase * > res;

		return res;
	}
public:
	template < class To >
	static CastPool < To > & getCastPool ( ) {
		std::map < std::type_index, CastPoolBase * >::iterator res = castFunctionsById ( ).find ( std::type_index ( typeid ( To ) ) );

		if ( res == castFunctionsById ( ).end ( ) ) {
			CastPool < To > * castPool = new CastPool < To > ( );
			castPool->template add < To > ( );
			return * ( CastPool < To > * )( castFunctionsById ( ).insert ( std::make_pair ( std::type_index ( typeid ( To ) ), castPool ) ).first->second );
		} else {
			return * ( CastPool < To > * )res->second;
		}
	}

	static CastPoolBase & getCastPool ( const std::string & tagName ) {
		std::map < std::string, CastPoolBase * >::iterator res = castFunctionsByString ( ).find ( tagName );

		if ( res == castFunctionsByString ( ).end ( ) )
			throw std::invalid_argument ( "Casting to type " + tagName + " not available." );
		else
			return * res->second;
	}

	static CastPoolBase & getCastPool ( std::type_index typeId ) {
		std::map < std::type_index, CastPoolBase * >::iterator res = castFunctionsById ( ).find ( typeId );

		if ( res == castFunctionsById ( ).end ( ) )
			throw std::invalid_argument ( "Casting to type ? not available." );
		else
			return * res->second;
	}

	static bool castAvailable ( std::type_index to, std::type_index from ) {
		std::map < std::type_index, CastPoolBase * >::iterator res = castFunctionsById ( ).find ( to );

		if ( res == castFunctionsById ( ).end ( ) )
			return false;

		return res->second->castAvailable ( from );
	}

	template < class To >
	class CastPoolStringBinder {
	public:
		CastPoolStringBinder ( std::string tagName ) {
			castFunctionsByString ( ).insert ( std::make_pair ( tagName, & getCastPool < To > ( ) ) );
		}

	};

	template < class To, class From >
	class CastRegister {
	public:
		CastRegister ( ) {
			getCastPool < To > ( ).template add < From > ( );
		}

	};

};

} /* namespace alib */

#endif /* CAST_API_HPP_ */