#ifndef s11n_SERIALIZE_TPP_INCLUDED #define s11n_SERIALIZE_TPP_INCLUDED // this is the implementation file for the code declared in serialize.hpp /** ******************************************************************** General API Conventions: NodeType should conform to the conventions laid out by s11n::s11n_node. SerializableTypes/BaseTypes: - BaseT must have the following in it's interface: - bool SerializeFunction( NodeType & dest ) const; - bool DeserializeFunction( const NodeType & dest ); SerializeFunction/DeserializeFunction need not be virtual, though they may be. Proxy functors: Serialization functor must have: bool operator()( NodeType & dest, const BaseT & src ) const; Deserialization functor must have: bool operator()( const NodeType & src, BaseT & dest ) const; They may be the same functor type - const resolution will determine which s11n uses. Sometimes this might cause an ambiguity, and may require 2 functors. These signatures apply for all functors designed to work as de/serialization proxies. ********************************************************************* */ #include #include // auto_ptr #include // COUT/CERR #include // classload() #include // s11n_traits #include // type_traits #include // s11n_exception and friends //////////////////////////////////////////////////////////////////////////////// // NO DEPS ON s11n_node.hpp ALLOWED! //////////////////////////////////////////////////////////////////////////////// template void s11n::cleanup_serializable( SerializableType & s ) throw() { try { typename s11n::s11n_traits::cleanup_functor cf; cf(s); } catch(...) { using namespace ::s11n::debug; S11N_TRACE(TRACE_ERROR) << "Exception thrown during cleanup! INGORING IT! This might mean a mem leak has occurred!\n"; } } template void s11n::cleanup_serializable( SerializableType * & s ) throw() { using namespace ::s11n::debug; S11N_TRACE(TRACE_CLEANUP) << "cleanup_serializable(*&): @ " << std::hex << s << ", s11n_class="<::class_name(s)<<"\n"; if( s ) { s11n::cleanup_serializable( *s ); delete s; s = 0; } } template bool s11n::Detail::s11n_api_marshaler::serialize( NodeType &dest, const SerializableType & src ) { typedef ::s11n::node_traits NTR; typedef ::s11n::s11n_traits STR; NTR::class_name( dest, STR::class_name(&src) ); typename STR::serialize_functor sf; return sf( dest, src ); } template bool s11n::Detail::s11n_api_marshaler::deserialize( const NodeType & src, SerializableType & dest ) { typedef ::s11n::s11n_traits STR; typename STR::deserialize_functor df; return df( src, dest ); } template bool s11n::Detail::s11n_api_marshaler::serialize( NodeType &dest, const SerializableType * const & src ) { if( ! src ) { return false; } return parent_type::serialize( dest, *src ); } template bool s11n::Detail::s11n_api_marshaler::deserialize( const NodeType & src, SerializableType * & dest ) { if( ! dest ) { return false; } return parent_type::deserialize( src, *dest ); } template bool s11n::serialize( DataNodeType & target, const SerializableType & src ) { return s11n::Detail::s11n_api_marshaler::serialize( target, src ); } template bool s11n::deserialize( const DataNodeType & src, DeserializableT & target ) { return s11n::Detail::s11n_api_marshaler::deserialize( src, target ); } template bool s11n::deserialize( const DataNodeType & src, DeserializableT * & target ) { using namespace ::s11n::debug; S11N_TRACE(TRACE_INFO) << "using experimental deserialize(const node &, DeserT * &)\n"; typedef s11n::node_traits NTR; typedef s11n::s11n_traits STR; if( target ) { return s11n::Detail::s11n_api_marshaler::deserialize( src, *target ); } // We want to destroy the obj we allocate if deser fails: typedef s11n::cleanup_ptr CP; CP x( ::s11n::cl::classload( NTR::class_name( src ) ) ); if( ! x.get() ) // try harder... { // S11N_TRACE(TRACE_FACTORY_LOOKUP) << "Trying to dyn-load obj of class '"<( STR::class_name( target /** 0 ?? **/ ) ) ); } if( ! x.get() ) // give up :( { S11N_TRACE(TRACE_ERROR) << "deserialize(const NT &, ST * &): dyn-load failed for class '"<::deserialize( src, *x ) ) { return false; } target = x.release(); return true; } template bool s11n::deserialize( const DataNodeType & src, s11n::cleanup_ptr & target ) { DeserializableT * d = target.get(); if( deserialize( src, d ) ) { target.take(d); // ^^^^^^^^ We actually only have to take(d) only if d // started out as 0, but why bother with a flag? // Remeber also that take() explicitely does nothing // if (get()==d), which means we don't need to // duplicate that check here. The case that take(d) is // passed 0 AND (d != 0) at call time cannot happen // here, so we need not worry about stomping an // existing object with take(d). return true; } return false; } template DeserializableT * s11n::deserialize( const DataNodeType & src ) { typedef ::s11n::s11n_traits STR; typedef ::s11n::node_traits NTR; typename STR::factory_type fac; typedef typename s11n::type_traits::type base_type; s11n::cleanup_ptr obj( fac( NTR::class_name( src ) ) ); if( ! obj.get() ) { using namespace ::s11n::debug; S11N_TRACE(TRACE_ERROR) << "deserialize<>(DataNode): classload failed for class '" << NTR::class_name( src )<<"'." << " It is probably not registered with its base-most classloader."; return 0; } try { if( s11n::deserialize( src, *obj ) ) // might throw { return obj.release(); // take over ownership. } } catch( ... ) { using namespace ::s11n::debug; S11N_TRACE(TRACE_ERROR) << "deserialize(const NT&) failed deser'ing child and is using cleanup_serializable() on it.\n"; throw; } return 0; } template SerializableType * s11n::s11n_clone( const SerializableType & tocp ) { DataNodeType node; return ::s11n::serialize( node, tocp ) ? ::s11n::deserialize( node ) : 0; } template bool s11n::s11n_cast( const Type1 & t1, Type2 & t2 ) { NodeType n; return ::s11n::serialize( n, t1 ) && ::s11n::deserialize( n, t2 ); } #endif // s11n_SERIALIZE_TPP_INCLUDED