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 The exact values returned by this function may 00045 change in the future. e.g., at the moment it does 00046 not return the "real" classnames, only registered 00047 aliases, but this is arguable behaviour and may 00048 change. 00049 */ 00050 template <typename NodeT, typename ListT> 00051 void serializer_list( ListT & target, bool onlyShortNames = true ) 00052 { 00053 typedef ::s11n::io::data_node_serializer<NodeT> BaseSerT; 00054 /** 00055 Maintenance note: i don't encourage the 00056 direc use of s11n::fac here, but that is 00057 currently the only way to get the list of 00058 class names from the factory layer. 00059 */ 00060 typedef ::s11n::fac::factory_mgr< BaseSerT > SerCL; 00061 typedef typename SerCL::aliaser_type::alias_map_type AMap; 00062 SerCL & cl = ::s11n::fac::factory< BaseSerT >(); 00063 typename AMap::const_iterator cit = cl.aliases().begin(), 00064 cet = cl.aliases().end(); 00065 std::string alias; 00066 static const std::string nonspecial = 00067 "_0123456789abcdefghijklmnopqrstuvwqxyzABCDEFGHIJKLMNOPQRSTUVWQXYZ"; 00068 for( ; cet != cit; ++cit ) 00069 { 00070 alias = (*cit).first; 00071 if( onlyShortNames ) 00072 { // filter out all but "simple" names: 00073 if( std::string::npos != 00074 alias.find_first_not_of( nonspecial ) 00075 ) 00076 { 00077 continue; 00078 } 00079 } 00080 target.push_back( alias ); 00081 } 00082 } 00083 00084 00085 /** 00086 Registers a Serializer type with the s11n::io layer. It must: 00087 00088 - be templatized on a DataNodeType 00089 00090 - subclass 00091 s11n::io::data_node_serializer<DataNodeType> 00092 00093 - provide a node_type typedef which is the same as 00094 DataNodeType 00095 00096 - Be a complete type at the time this function is 00097 called. 00098 00099 i.e., the conventions of all of the Serializers 00100 included with libs11n. 00101 00102 00103 Registering makes the type available to the 00104 data_node_serializer classloader. 00105 00106 Arguments: 00107 00108 - classname = SerializerT's stringified class name, 00109 minus any template parts. e.g. my_serializer. 00110 00111 - alias = a "friendly" name for the SerializerT. By 00112 convention this is the Serializer's class name 00113 stripped of namespace and any trailing 00114 "_serializer" part. The alias should, by 00115 convention, be suitable to use via, e.g. entry as a 00116 command-line argument. 00117 00118 SerializeT's magic_cookie() function is called to 00119 alias the cookie as an alias for classname. Thus, a 00120 SerializerT object is (briefly) instantiated. 00121 00122 Node that this function essentially performs the 00123 same operations as the reg_serializer.hpp 00124 supermacro, and the two should be equivalent 00125 (though this seems easier to use). 00126 */ 00127 template <typename SerializerT> 00128 void register_serializer( const std::string & classname, const std::string & alias ) 00129 { 00130 //CERR << "register_serializer(" << classname << ","<<alias<<")\n"; 00131 typedef SerializerT ST; 00132 typedef typename ST::node_type NT; 00133 typedef s11n::io::data_node_serializer<NT> BaseST; 00134 ::s11n::cl::classloader_register_subtype< BaseST, ST >( classname ); 00135 ::s11n::cl::classloader_alias< BaseST >( alias, classname ); 00136 ::s11n::cl::classloader_alias< BaseST >( ST().magic_cookie(), classname ); 00137 // ^^^ i don't LIKE having to instantiate ST here, but i don't see an 00138 // easy way around it. 00139 } 00140 00141 /** 00142 Returns a Serializer object, which must have been registered with 00143 the s11n::cl/s11n::fac classloading API, using an interface type 00144 of s11n::io::data_node_serializer<NodeT>. e.g., register_serializer() 00145 will do the trick. 00146 00147 If no serializer for classname is found and 00148 classname does not contain the string 00149 "_serializer", then then (classname+"_serializer") 00150 is tried. This is intended to ease DLL lookups for 00151 the conventional abbreviations for the Serializer 00152 classes (i.e., my_serializer). 00153 00154 The caller owns the returned pointer, which may be 0. 00155 */ 00156 template <typename NodeT> 00157 s11n::io::data_node_serializer<NodeT> * 00158 create_serializer( const std::string & classname ) 00159 { 00160 typedef s11n::io::data_node_serializer<NodeT> BaseSerT; 00161 BaseSerT * s = 0; 00162 // todo: consider using try/catch and return 0, to allow for 00163 // more transparency when swapping out the core's factory layer. 00164 // Some factories may throw on load errors. 00165 if( 0 != ( s = s11n::cl::classload< BaseSerT >( classname ) ) ) 00166 { 00167 return s; 00168 } 00169 static const char * addon = "_serializer"; 00170 if( (std::string::npos == classname.find(addon)) ) // try harder! 00171 { 00172 std::string harder = classname + addon; 00173 // CERR << "Trying harder for " << classname << " --> " << harder << "!\n"; 00174 s = create_serializer<NodeT>( harder ); 00175 } 00176 return s; 00177 } 00178 00179 } // namespace io 00180 } // namespace s11n 00181 00182 00183 #endif // s11n_SERIALIZERS_HPP_INCLUDED