-
Jan Trávníček authoredJan Trávníček authored
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_ */