/* * StringApi.hpp * * Created on: Apr 1, 2013 * Author: Jan Travnicek */ #ifndef STRING_API_HPP_ #define STRING_API_HPP_ #include <alib/functional> #include <alib/deque> #include <alib/map> #include <alib/string> #include <alib/memory> #include <alib/algorithm> #include <object/Object.h> #include "exception/CommonException.h" namespace core { template < typename T, typename Enable = void > struct stringApi { }; template < > struct stringApi < object::Object > { private: class GroupReader { public: virtual object::Object parse ( std::istream & input ) = 0; virtual ~GroupReader ( ) { } }; static ext::deque < std::pair < std::function < bool ( std::istream & ) >, std::unique_ptr < GroupReader > > > & parseFunctions ( ) { static ext::deque < std::pair < std::function < bool ( std::istream & ) >, std::unique_ptr < GroupReader > > > res; return res; } template < class Type > class ReaderRegister : public GroupReader { std::function < Type ( std::istream & ) > parseFunction; public: ReaderRegister( ) : parseFunction ( stringApi < Type >::parse ) { } virtual ~ReaderRegister ( ) { } virtual object::Object parse ( std::istream & input ) { return object::Object ( parseFunction ( input ) ); } }; class GroupWriter { public: virtual void compose ( std::ostream & output, const object::Object & group ) = 0; virtual ~GroupWriter ( ) { } }; static ext::map < std::string, std::unique_ptr < GroupWriter > > & composeFunctions ( ) { static ext::map < std::string, std::unique_ptr < GroupWriter > > res; return res; } template < class Type > class WriterRegister : public GroupWriter { std::function < void ( std::ostream &, const Type & ) > composeFunction; public: WriterRegister( ) : composeFunction ( stringApi < Type >::compose ) { } virtual ~WriterRegister ( ) { } virtual void compose ( std::ostream & output, const object::Object & group ) { composeFunction ( output, static_cast < const Type & > ( group.getData ( ) ) ); } }; public: template < class Type > static void registerStringReader ( ) { parseFunctions ( ).push_back ( std::make_pair ( stringApi < Type >::first, std::unique_ptr < GroupReader > ( new ReaderRegister < Type > ( ) ) ) ); } template < class Type > static void registerStringWriter ( ) { bool res = composeFunctions ( ).insert ( std::make_pair ( ext::to_string < Type > ( ), std::unique_ptr < GroupWriter > ( new WriterRegister < Type > ( ) ) ) ).second; if ( ! res ) { std::string groupName = ext::to_string < object::Object > ( ); std::string typeName = ext::to_string < Type > ( ); throw::exception::CommonException ( "Parse callback of " + typeName + " already registered in group " + groupName + "." ); } } static object::Object parse ( std::istream & input ) { auto lambda = [ & ] ( const std::pair < std::function < bool ( std::istream & ) >, std::unique_ptr < GroupReader > > & entry ) { return entry.first ( input ); }; int pos = input.tellg(); auto callback = find_if ( parseFunctions ( ).begin ( ), parseFunctions ( ).end ( ), lambda ); if ( callback == parseFunctions ( ).end ( ) ) throw exception::CommonException ( "Parse callback not registered." ); if ( pos != input.tellg ( ) ) throw exception::CommonException ( "First function of registered callback moved the stream" ); return callback->second->parse ( input ); } static bool first ( std::istream & input ) { auto lambda = [ & ] ( const std::pair < std::function < bool ( std::istream & ) >, std::unique_ptr < GroupReader > > & entry ) { return entry.first ( input ); }; return std::any_of ( parseFunctions ( ).begin ( ), parseFunctions ( ).end ( ), lambda ); } static void compose ( std::ostream & output, const object::Object & data ) { const auto & content = data.getData ( ); std::string type = ext::to_string ( ext::type_index ( typeid ( content ) ) ); auto callback = composeFunctions ( ).find ( type ); if ( callback == composeFunctions ( ).end ( ) ) throw exception::CommonException ( "Compose callback for " + type + " tag not registered." ); callback->second->compose ( output, data ); } }; } /* namespace core */ #endif /* STRING_API_HPP_ */