ohex.hpp

Go to the documentation of this file.
00001 #ifndef S11N_NET_S11N_1_3_CPPX0_HPP_INCLUDED
00002 #define S11N_NET_S11N_1_3_CPPX0_HPP_INCLUDED 1
00003 
00004 #include <algorithm>
00005 #include <iterator>
00006 #include <tuple>
00007 #include <s11n.net/s11n/algo.hpp> // serialize_subnode()
00008 #include <s11n.net/s11n/variant.hpp>
00009 #include <s11n.net/s11n/s11n_config.hpp>
00010 #if ! s11n_CONFIG_HAVE_CPP0X
00011 #error "s11n_CONFIG_HAVE_CPP0X is not set, which means this code probably won't compile (it needs C++0x support)"
00012 #endif
00013 
00014 namespace s11n {
00015 /**
00016 
00017 EXPERIMENTAL code based on C++0x features.
00018 
00019 Code in this namespace uses C++0x features, as currently supported by
00020 gcc 4.3 (at the time of this writing). It won't compile on any older
00021 compilers.
00022 
00023 */
00024 namespace cpp0x {
00025 
00026     /**
00027        count<> is a variadic template metafunction to count variadic
00028        template lists.  Used like: count<int,double,char>::value (==3)
00029     */
00030     template <typename ... Args> struct count;
00031     template <typename T,typename ... Args>
00032     struct count<T,Args...> {
00033     static const int value = 1 + count<Args...>::value;
00034     };
00035     template <> struct count<> { static const int value = 0; };
00036 
00037     namespace Detail {
00038     /** 
00039         Does nothing and returns true. Exists to give the variadic overload a stopping point.
00040     */
00041     template <typename NodeT>
00042     inline bool serialize_group_impl( const size_t, NodeT & )
00043     {
00044         return true;
00045     }
00046 
00047     /**
00048        Internal implementation of serialize_group().
00049     */
00050     template <typename NodeT, typename SerT, typename ... SerList>
00051     inline bool serialize_group_impl( const size_t high, NodeT & dest, SerT const &src, SerList && ... srcN )
00052     {
00053         typedef s11n::s11n_traits<SerT> ST;
00054         return s11n::serialize_subnode( dest,
00055                         s11n::format_string( "i%d", high - s11n::cpp0x::count<SerList...>::value ),
00056                         src )
00057         && serialize_group_impl( high, dest, srcN... );
00058     }
00059     }
00060 
00061 
00062     /**
00063        serialize_group() works similarly to s11n::serialize_subnode(), except
00064        that it can be passed one or more Serializables. A child node is added
00065        to dest, named groupName, and each serializable is serialized as a child
00066        of that "group node".
00067 
00068        Quite Significant Points of Interest:
00069 
00070        (Please do refrain from failing to read these notes!)
00071 
00072        #1:
00073 
00074        SerT and all of SerList must be Serializable types. NodeT must
00075        conform to s11n::node_traits<NodeT> conventions.
00076 
00077        #2:
00078 
00079        To deserialize items call deserialize_group() with the EXACT
00080        same group name and the same types of arguments (but non-const)
00081        in the EXACT same order as were passed to the corresponding
00082        serialize_group() call. Changing the types or order of the
00083        SerT+SerList list will likely lead to deserialization errors
00084        when reading data saved using previous calls of
00085        serialize_group().
00086 
00087        The reason for #2 is because this routine has to synthesize
00088        node-name-compatible name tokens for each Serializable. The only
00089        halfway reasonable thing it can do is name them numerically. This
00090        number, in turn, is used as a lookup key when deserializing, so
00091        the object in that position in the deser call needs to be the
00092        same (or s11n-compatible) type as the one passed at that arg position
00093        to serialize_group().
00094 
00095        #3:
00096 
00097        The string passed for the groupName parameter should be a unique
00098        name amongst the children of the dest node. If it is not unique
00099        then deserialization is likely to fail because it might get the
00100        wrong child node.
00101 
00102 
00103        Added in version 1.3.1.
00104     */
00105     template <typename NodeT, typename SerT, typename ... SerList>
00106     inline bool serialize_group( NodeT & dest, std::string const & groupName, SerT const &src, SerList && ... srcN )
00107     {
00108     typedef s11n::s11n_traits<SerT> ST;
00109     NodeT & tgt( s11n::create_child( dest, groupName ) );
00110     s11n::node_traits<NodeT>::class_name(tgt, "serialize_group");
00111     return Detail::serialize_group_impl( 1+count<SerList...>::value, tgt, src, std::forward<SerList>(srcN)... );
00112     }
00113 
00114     namespace Detail {
00115     /** 
00116         Does nothing and returns true. Exists to give the variadic overload a stopping point.
00117     */
00118     template <typename NodeT>
00119     inline bool deserialize_group_impl( size_t const, NodeT const & )
00120     {
00121         return true;
00122     }
00123     /**
00124        Internal implementation of deserialize_group().
00125     */
00126     template <typename NodeT, typename SerT, typename ... SerList>
00127     inline bool deserialize_group_impl( size_t const high, NodeT const & src, SerT & dest, SerList && ... destN )
00128     {
00129         typedef s11n::s11n_traits<SerT> ST;
00130         typedef s11n::node_traits<NodeT> NTR;
00131         return s11n::deserialize_subnode( src,
00132                           s11n::format_string( "i%d", high - count<SerList...>::value ),
00133                           dest )
00134         && deserialize_group_impl( high, src, std::forward<SerList>(destN)... );
00135     }
00136     }
00137 
00138     /**
00139        deserialize_group() is the counterpart to serialize_group(). See that
00140        function for important caveats.
00141 
00142        If src contains no child node named groupName then this function
00143        will throw and s11n_exception, otherwise it will return the
00144        cumulative success/fail value of deserialization on each item
00145        in the list [SerT,SerList]. It will propagate any exceptions
00146        throws by the underlying deserialize() calls.
00147     */
00148     template <typename NodeT, typename SerT, typename ... SerList>
00149     inline bool deserialize_group( NodeT const & src, std::string const & groupName, SerT & dest, SerList && ... destN )
00150     {
00151     if( NodeT const * ch = s11n::find_child_by_name( src, groupName ) )
00152     {
00153         return Detail::deserialize_group_impl( 1 + count<SerList...>::value, *ch, dest, std::forward<SerList>(destN)... );
00154     }
00155     throw s11n::s11n_exception(S11N_SOURCEINFO,"deserialize_group(node,'%s',...): child node not found.", groupName.c_str() );
00156     }
00157 
00158 
00159     namespace Detail {
00160     /** 
00161         Does nothing and returns true. Exists to give the variadic overload a stopping point.
00162     */
00163     template <typename NodeT>
00164     inline bool serialize_subnodes( NodeT & ) throw()
00165     {
00166         return true;
00167     }
00168     /** 
00169         Does nothing and returns true. Exists to give the variadic overload a stopping point.
00170     */
00171     template <typename NodeT>
00172     inline bool deserialize_subnodes( NodeT const & ) throw()
00173     {
00174         return true;
00175     }
00176     }
00177 
00178     /**
00179        A variadic form of s11n::serialize_subnode(), it takes pairs of
00180        (string,Serializable) and calls serialize_subnode() for each
00181        one. If the argument list has an odd number of elements then
00182        this function will not compile (a static assertion fails).
00183     */
00184     template <typename NodeT, typename SerT, typename ... SerList>
00185     inline bool serialize_subnodes( NodeT & dest, std::string const & name, SerT const & src, SerList && ... srcN )
00186     {
00187     static_assert( 0 == (count<SerList...>::value % 2),
00188                "Wrong number of template args passed to serialize_subnodes(): args must be passed in pairs of (string,Serializable)");
00189     using namespace Detail;
00190     return s11n::serialize_subnode( dest, name, src )
00191         && serialize_subnodes( dest, std::forward<SerList>(srcN)... );
00192     }
00193 
00194     /**
00195        The counterpart to serialize_subnodes(). See that function for
00196        how it works.  Unlike serialize_group(), this function does not
00197        care about the order of the (string,Serializable) pairs because
00198        they are looked up by name instead of position. (OTOH, this
00199        function is slightly slower because of that.)
00200     */
00201     template <typename NodeT, typename SerT, typename ... SerList>
00202     inline bool deserialize_subnodes( NodeT const & src, std::string const & name, SerT & dest, SerList && ... destN )
00203     {
00204     static_assert( 0 == (count<SerList...>::value % 2),
00205                "Wrong number of template args passed to deserialize_subnodes(): args must be passed in pairs of (string,Serializable)");
00206     using namespace Detail;
00207     return s11n::deserialize_subnode( src, name, dest )
00208         && deserialize_subnodes( src, destN... );
00209     }
00210 
00211     /**
00212        A variadic form of s11n::serialize_versioned(), except that it
00213        bundles multiple Serializables with a single version.
00214 
00215        This function has one notable caveat: it uses serialize_group() to
00216        do the leg-work, which means that when you call
00217        deserialize_versioned() to fetch the data the arguments passed
00218        to it must be of the same type and in the same order as those
00219        passed to serialized_versioned(). See serialize_group() for
00220        more information on that requirement.
00221 
00222        TODO: try to re-implement in terms of the non-variadic form to avoid
00223        duplicate code/key names.
00224     */
00225     template <typename NodeT, typename VersionT, typename SerT, typename ... SerList>
00226     inline bool serialize_versioned( NodeT & dest, VersionT ver, SerT const & src, SerList && ... srcN )
00227     {
00228     typedef s11n::node_traits<NodeT> NTR;
00229     NTR::set( dest, "version", ver );
00230     return serialize_group( dest, "vdata", src, srcN... );
00231     }
00232 
00233     /**
00234        A variadic form of s11n::deserialize_versioned(). See the variadic form
00235        of serialize_version() for important information.
00236 
00237        TODO: try to re-implement in terms of the non-variadic form, to avoid
00238        duplicate code/key names.
00239     */
00240     template <typename NodeT, typename VersionT, typename SerT, typename ... SerList>
00241     bool deserialize_versioned( NodeT & src, VersionT ver, SerT & dest, SerList && ... destN )
00242     {
00243     typedef s11n::node_traits<NodeT> NTR;
00244     VersionT gotver( NTR::get( src, "version", VersionT() ) );
00245     if( ver !=  gotver )
00246     {
00247         using s11n::Detail::variant;
00248         variant v1( ver );
00249         variant v2( gotver );
00250         throw s11n_exception( S11N_SOURCEINFO, "Version mismatch. Expected '%s' but got '%s'.",
00251                   v1.str().c_str(),
00252                   v2.str().c_str() );
00253     }
00254     return deserialize_group( src, "vdata", dest, destN... );
00255     }
00256 
00257 
00258 } } // namespaces
00259 
00260 #endif // S11N_NET_S11N_1_3_CPPX0_HPP_INCLUDED

Generated on Wed Jun 4 21:45:18 2008 for libs11n by  doxygen 1.5.3