00001 #ifndef s11n_SERIALIZERS_HPP_INCLUDED 00002 #define s11n_SERIALIZERS_HPP_INCLUDED 1 00003 00004 //////////////////////////////////////////////////////////////////////////////// 00005 // serializers.hpp: Some utility code for working with 00006 // s11n::io Serializer types. 00007 // 00008 // License: Public Domain 00009 // Author: stephan@s11n.net 00010 //////////////////////////////////////////////////////////////////////////////// 00011 00012 #include <s11n.net/s11n/classload.hpp> // factory fucntions 00013 #include <s11n.net/s11n/io/data_node_io.hpp> // data_node_serializer<> class. 00014 #include <s11n.net/s11n/s11n_config.hpp> 00015 00016 namespace s11n { 00017 namespace io { 00018 00019 /** 00020 Intended mainly as a convenience for client 00021 applications, serializer_list() populates the 00022 target list with the names of registered 00023 Serializers. 00024 00025 ListT must support push_back(std::string). 00026 00027 If onlyShortNames is true (the default) then only 00028 "simple" names (only alphanumeric or underscore 00029 characters) are put into target, not the "full" 00030 names of the classes. This is to make the data more 00031 useful in the context of client applications as, 00032 e.g., a list of choices for users. 00033 00034 When onlyShortNames is false then the list may contain 00035 some unsightly magic cookie strings. 00036 00037 In either case, the list may very well contain 00038 different names for the same underlying Serializer, 00039 as most are registered with several aliases. 00040 00041 Note that only serializers extending from 00042 s11n::io::data_node_serializer<NodeT> are returned. 00043 */ 00044 template <typename NodeT, typename ListT> 00045 void serializer_list( ListT & target, bool onlyShortNames = true ) 00046 { 00047 typedef ::s11n::io::data_node_serializer<NodeT> BaseSerT; 00048 /** 00049 Maintenance note: i don't encourage the 00050 direc use of s11n::fac here, but that is 00051 currently the only way to get the list of 00052 class names from the factory layer. 00053 */ 00054 typedef ::s11n::fac::factory_mgr< BaseSerT > SerCL; 00055 typedef typename SerCL::aliaser_type::alias_map_type AMap; 00056 SerCL const & cl = ::s11n::fac::factory< BaseSerT >(); 00057 typename AMap::const_iterator cit = cl.aliases().begin(), 00058 cet = cl.aliases().end(); 00059 std::string alias; 00060 static const std::string nonspecial = 00061 "_0123456789abcdefghijklmnopqrstuvwqxyzABCDEFGHIJKLMNOPQRSTUVWQXYZ"; 00062 for( ; cet != cit; ++cit ) 00063 { 00064 alias = (*cit).first; 00065 if( onlyShortNames ) 00066 { // filter out all but "simple" names: 00067 if( std::string::npos != 00068 alias.find_first_not_of( nonspecial ) 00069 ) 00070 { 00071 continue; 00072 } 00073 } 00074 target.push_back( alias ); 00075 } 00076 } 00077 00078 00079 /** 00080 Registers a Serializer type with the s11n::io layer. It must: 00081 00082 - be templatized on a DataNodeType 00083 00084 - subclass 00085 s11n::io::data_node_serializer<DataNodeType> 00086 00087 - provide a node_type typedef which is the same as 00088 DataNodeType 00089 00090 - Be a complete type at the time this function is 00091 called. 00092 00093 i.e., the conventions of all of the Serializers 00094 included with libs11n. 00095 00096 00097 Registering makes the type available to the 00098 data_node_serializer classloader. 00099 00100 Arguments: 00101 00102 - classname = SerializerT's stringified class name, 00103 minus any template parts. e.g. my_serializer. 00104 00105 - alias = a "friendly" name for the SerializerT. By 00106 convention this is the Serializer's class name 00107 stripped of namespace and any trailing 00108 "_serializer" part. The alias should, by 00109 convention, be suitable to use via, e.g. entry as a 00110 command-line argument. 00111 00112 SerializeT's magic_cookie() function is called to 00113 alias the cookie as an alias for classname. Thus, a 00114 SerializerT object is (briefly) instantiated. 00115 00116 Node that this function essentially performs the 00117 same operations as the reg_serializer.hpp 00118 supermacro, and the two should be equivalent 00119 (though this seems easier to use). 00120 */ 00121 template <typename SerializerT> 00122 void register_serializer( const std::string & classname, const std::string & alias ) 00123 { 00124 //CERR << "register_serializer(" << classname << ","<<alias<<")\n"; 00125 typedef SerializerT ST; 00126 typedef typename ST::node_type NT; 00127 typedef s11n::io::data_node_serializer<NT> BaseST; 00128 ::s11n::cl::classloader_register_subtype< BaseST, ST >( classname ); 00129 ::s11n::cl::classloader_alias< BaseST >( alias, classname ); 00130 ::s11n::cl::classloader_alias< BaseST >( ST().magic_cookie(), classname ); 00131 // ^^^ i don't LIKE having to instantiate ST here, but i don't see an 00132 // easy way around it. 00133 } 00134 00135 /** 00136 Returns a Serializer object, which must have been registered with 00137 the s11n::cl/s11n::fac classloading API, using an interface type 00138 of s11n::io::data_node_serializer<NodeT>. e.g., register_serializer() 00139 will do the trick. 00140 00141 If no serializer for classname is found and 00142 classname does not contain the string 00143 "_serializer", then then (classname+"_serializer") 00144 is tried. This is intended to ease DLL lookups for 00145 the conventional abbreviations for the Serializer 00146 classes (i.e., my_serializer). 00147 00148 The caller owns the returned pointer, which may be 0. 00149 */ 00150 template <typename NodeT> 00151 s11n::io::data_node_serializer<NodeT> * 00152 create_serializer( const std::string & classname ) 00153 { 00154 typedef s11n::io::data_node_serializer<NodeT> BaseSerT; 00155 BaseSerT * s = 0; 00156 // todo: consider using try/catch and return 0, to allow for 00157 // more transparency when swapping out the core's factory layer. 00158 // Some factories may throw on load errors. 00159 if( 0 != ( s = s11n::cl::classload< BaseSerT >( classname ) ) ) 00160 { 00161 return s; 00162 } 00163 static const char * addon = "_serializer"; 00164 if( (std::string::npos == classname.find(addon)) ) // try harder! 00165 { 00166 std::string harder = classname + addon; 00167 // CERR << "Trying harder for " << classname << " --> " << harder << "!\n"; 00168 s = create_serializer<NodeT>( harder ); 00169 } 00170 return s; 00171 } 00172 00173 } // namespace io 00174 } // namespace s11n 00175 00176 00177 #endif // s11n_SERIALIZERS_HPP_INCLUDED