algo.hpp

Go to the documentation of this file.
00001 #ifndef s11n_net_s11n_v1_1_ALGO_HPP_INCLUDED
00002 #define s11n_net_s11n_v1_1_ALGO_HPP_INCLUDED 1
00003 /////////////////////////////////////////////////////////////////////////
00004 // algo.hpp: generic functors and algos for use with libs11n.
00005 // Author: stephan beal <stephan@s11n.net>
00006 // License: Public Domain
00007 /////////////////////////////////////////////////////////////////////////
00008 
00009 #include <string>
00010 #include <algorithm>
00011 
00012 #include <s11n.net/s11n/s11n_debuggering_macros.hpp> // COUT/CERR
00013 #include <s11n.net/s11n/serialize.hpp> // core de/serialize interface
00014 #include <s11n.net/s11n/traits.hpp> // node_traits
00015 #include <s11n.net/s11n/type_traits.hpp> // type_traits<>
00016 
00017 namespace s11n
00018 {
00019 
00020         /**
00021            Serializes src to as a subnode of target, named
00022            nodename. Except for the addition of a subnode, it is
00023            identical to serialize( target, src ).
00024 
00025        If serialization into the subnode throws the subnode is not
00026        added to target (it is destroyed) and any exception is
00027        propagated back to the caller.
00028 
00029            This is a convenience function: not part of the s11n kernel.
00030 
00031 
00032        Changed in 1.1.3:
00033 
00034        - Moved to algo.hpp to be symetric with deserialize_subnode().
00035 
00036         */
00037         template <typename DataNodeType, typename SerializableT >
00038         bool serialize_subnode( DataNodeType & target,
00039                                 const std::string & nodename,
00040                                 const SerializableT & src );
00041 
00042 
00043         /**
00044            If a child named subnodename is found in src then this function
00045            returns deserialize( child, target ) and returns it's result, otherwise
00046            it returns 0.
00047 
00048        The function might throw, as it uses the two-arg form of
00049        deserialize().
00050 
00051            This is a convenience function: not part of the s11n
00052            kernel.
00053 
00054 
00055        Changed in 1.1.3:
00056 
00057        - Moved to algo.hpp to avoid a circular dependency on
00058        s11n::find_child_by_name().
00059 
00060         */
00061         template <typename DataNodeType, typename DeserializableT>
00062         bool deserialize_subnode( const DataNodeType & src,
00063                                   const std::string & subnodename,
00064                                   DeserializableT & target );
00065 
00066         /**
00067            If a child named subnodename is found in src then this function
00068            returns the result of deserialize(child), otherwise
00069            it returns 0.
00070 
00071        The function might throw, as it uses the two-arg form of
00072        deserialize().
00073 
00074            This is a convenience function: not part of the s11n kernel.
00075 
00076        Changed in 1.1.3:
00077 
00078        - Moved to algo.hpp to avoid a circular dependency on
00079        s11n::find_child_by_name().
00080 
00081         */
00082         template <typename DataNodeType, typename DeserializableT>
00083         DeserializableT * deserialize_subnode( const DataNodeType & src,
00084                                                const std::string & subnodename );
00085 
00086 
00087 
00088         /**
00089            For each item in [first,last), copies the item to OutputIt
00090            if pred(*item) returns true.
00091 
00092            Code copied from:
00093 
00094            http://www.bauklimatik-dresden.de/privat/nicolai/html/en/cpp.html
00095         */
00096 
00097         template <typename InputIt, typename OutputIt, typename UnaryPredicate>
00098         OutputIt copy_if (InputIt first,
00099                           InputIt last,
00100                           OutputIt result,
00101                           UnaryPredicate pred) 
00102         {
00103                 while (first != last)
00104                 {
00105                         if (pred(*first)) *result++ = *first;
00106                         ++first;
00107                 }
00108                 return result;
00109         }
00110 
00111  
00112 
00113         /**
00114            Deletes an object passed to it.
00115 
00116            This type accepts non-pointer types for "destruction." This
00117            is a non-operation, and is supported to allow other
00118            template code to generically free objects without needing
00119            to know if they are pointers. This allows some
00120            formerly-non-consolidatable reference-vs-pointer-type code to
00121            share a single implementation, as "delete(myobj)" is not
00122            valid for non-pointer types, but object_deleter()(myobj)
00123            is.
00124 
00125        DEPRECATED: this will be removed in favor of
00126        cleanup_serializable().
00127 
00128        @deprecated
00129         */
00130         struct object_deleter
00131         {
00132                 /**
00133                    Deletes t.
00134                 */
00135                 template <typename T>
00136                 void operator()( T * t ) const
00137                 {
00138                         // ACH!!!! If we use (const T *) for the arguments
00139                         // then the (const T &) version is called
00140                         // even when a pointer type is passed in!!!!
00141 
00142                         // i don't fully understand why
00143                         // delete( const T * ) is legal, 
00144                         // considering that it triggers a dtor,
00145                         // and dtors are non-const.
00146                         //CERR << "object_deleter deleting "<< std::hex<<t<<"\n";
00147                         delete( t );
00148                 }
00149                 /**
00150                    Does nothing: is here to allow some
00151                    reference-vs-pointer-type transparency.
00152                 */
00153                 template <typename T>
00154                 void operator()( const T & t ) const
00155                 {
00156                         //CERR << "object_deleter no-op\n";
00157                 }
00158         };
00159 
00160 
00161 
00162         /**
00163            For each item in [begin,end) object_deleter()(*item) is called.
00164 
00165            After this call the container from which the iterators come
00166            still contains the items but they are invalid - deleted
00167            pointers. The client should call erase(begin,end) to delete
00168            the entries, or use convenience function
00169            free_list_entries(), which accepts a list-style
00170            container and empties the list.
00171 
00172        DEPRECATED: this will be removed in favor of
00173        cleanup_serializable().
00174 
00175        @deprecated
00176         */
00177         template <typename IterT>
00178         void delete_objects( IterT begin, IterT end )
00179         {
00180                 std::for_each( begin, end, object_deleter() );
00181         }
00182 
00183 
00184 
00185         /**
00186            object_reference_wrapper is a type for giving access
00187            to T objects via their dot operator, regardless of whether
00188            they are pointers or not.
00189 
00190            Intended for use with value_types which come from, e.g.,
00191            std::list, so objects of those types can be called using
00192            the same syntax regardless of whether they are pointer
00193            types or not.
00194 
00195            e.g., assuming MyType might be a pointer or a reference,
00196            we can ignore that difference for call-syntax purposes
00197            with:
00198 
00199 <pre>           
00200 object_reference_wrapper<MyType> wrap;
00201 wrap(myobj).memberfunc();
00202 </pre>
00203 
00204 or:
00205 
00206 <pre>
00207 object_reference_wrapper<MyType> wrap(myobj);
00208 wrap().memberfunc();           
00209 </pre>
00210         */
00211         template <typename T>
00212         struct object_reference_wrapper
00213         {
00214                 typedef T value_type;
00215                 typedef T base_value_type;
00216 //                 object_reference_wrapper() : m_ptr(0) {}
00217                 object_reference_wrapper( value_type &obj ) : m_ptr(&obj) {};
00218                 /**
00219                    Sets this object's proxy object to t and returns t.
00220                  */
00221                 base_value_type & operator()( value_type & t )
00222                 {
00223                         return this->m_ptr = &t;
00224                         return t;
00225                 }
00226                 /**
00227                    Returns this object's wrapped object.
00228                  */
00229                 base_value_type & operator()() const { return *(this->m_ptr); }
00230 
00231                 /**
00232                    Returns true if this object is wrapping a non-0 object, else
00233                    false.
00234                 */
00235                 bool good() const
00236                 {
00237                         return 0 != this->m_ptr;
00238                 }
00239 
00240         private:
00241                 value_type * m_ptr;
00242         };
00243 
00244         /**
00245            A specialization to wrap pointers to (T *) such that they
00246            can be accessed, via this wrapper, using a dot instead of
00247            <tt>-></tt>.
00248         */
00249         template <typename T>
00250         struct object_reference_wrapper<T *>
00251         {
00252                 typedef T * value_type;
00253                 typedef T base_value_type;
00254 //                 object_reference_wrapper() : m_ptr(0) {}
00255                 object_reference_wrapper( value_type & obj ) : m_ptr(obj) {};
00256                 /** Sets this object's proxied object to t and Returns t. */
00257                 base_value_type & operator()( value_type & t )
00258                 {
00259                         this->m_ptr = &t;
00260                         return *t;
00261                 }
00262                 /** Returns this object's wrapped object.
00263                 */
00264                 base_value_type & operator()() const { return *(this->m_ptr); }
00265         private:
00266                 base_value_type * m_ptr;
00267         };
00268 
00269 
00270         /**
00271            const_object_reference_wrapper is identical in usage to
00272            object_reference_wrapper, except that it deals with const
00273            objects. It is a separate functor to avoid ambiguity and
00274            some impossible overloads.
00275         */
00276         template <typename T>
00277         struct const_object_reference_wrapper
00278         {
00279                 typedef T value_type;
00280                 typedef T base_value_type;
00281 //                 const_object_reference_wrapper() : m_ptr(0) {}
00282                 const_object_reference_wrapper( const value_type &obj ) : m_ptr(&obj) {};
00283                 /**
00284                    Sets this object's proxied obj to t and returns t.
00285                  */
00286                 const base_value_type & operator()( const value_type & t )
00287                 {
00288                         this->m_ptr = &t;
00289                         return t;
00290                 }
00291                 /**
00292                    Returns this object's wrapped object.
00293                  */
00294                 const base_value_type & operator()() const { return *this->m_ptr; }
00295         private:
00296                 const value_type * m_ptr;
00297         };
00298 
00299         /**
00300            A specialization to wrap pointers to (T *) such that they
00301            can be accessed, via this wrapper, using a dot instead of
00302            <tt>-></tt>.
00303         */
00304         template <typename T>
00305         struct const_object_reference_wrapper<T *>
00306         {
00307                 typedef T * value_type;
00308                 typedef T base_value_type;
00309 //                 const_object_reference_wrapper() : m_ptr(0) {}
00310                 explicit const_object_reference_wrapper( const value_type & obj ) : m_ptr(obj) {};
00311                 /** Returns (*t). */
00312                 inline const base_value_type & operator()( value_type & t )
00313                 { 
00314                         this->m_ptr = &t;
00315             return t;
00316                 }
00317                 /** Returns this object's wrapped object. It does not check for validity.*/
00318                 inline const base_value_type & operator()() const { return *(this->m_ptr); }
00319         private:
00320                 const base_value_type * m_ptr;
00321         };
00322 
00323 
00324     namespace Detail {
00325         /**
00326            child_pointer_deep_copier is a functor to deep-copy
00327            a list of pointers into another list. Designed for
00328            use with std::for_each and the like.
00329            
00330            Assuming T is the type contained in ListType, stripped
00331            of any pointer part, then the following must hold:
00332            
00333 
00334            - List must support <code>push_back( T * )</code>.
00335 
00336            - This must be a valid expression:
00337 
00338            <code>T * t = new T( *p );</code>
00339        
00340            Where p is a passed to this type's operator().
00341 
00342            ACHTUNG: This is only useful for non-polymorphic
00343            copying.
00344 
00345            It might be interesting to note that copying
00346            monomorphic s11n::s11n_node objects this way is
00347            "pseudo-polymorphic" - the copy itself is
00348            monomorphic but the data needed to deserialize the
00349            proper type from the node is maintained.
00350         */
00351         template <typename ListType>
00352         class child_pointer_deep_copier
00353         {
00354         public:
00355             typedef ListType list_type;
00356             typedef typename ListType::value_type full_value_type;
00357             typedef typename ::s11n::type_traits<full_value_type>::type value_type; // list_type::value_type minus any pointer part.
00358             /**
00359                Target list must outlive this object.
00360             */
00361             child_pointer_deep_copier( list_type & target ) : m_childs(&target)
00362             {}
00363             
00364             /**
00365                Inserts a copy of p into this object's list and returns true.
00366                
00367                Returns true if p is successfully copied.
00368                
00369                If an exception thrown while copying, this function
00370                will catch it and not modify the underlying
00371                container. In that case, false is returned.
00372                
00373                The target list takes ownership of the new copy of p.
00374             */
00375             bool operator()( const value_type * p ) throw()
00376             {
00377                 if( ! this->m_childs || ! p ) return false;
00378                 value_type * cp = 0;
00379                 try
00380                 {
00381                     cp = new value_type( *p );
00382                     if( ! cp ) return false;
00383                 }
00384                 catch(...)
00385                 {
00386                     delete( cp ); // not necessary
00387                     return false;
00388                 }
00389                 this->m_childs->push_back( cp );
00390                 return true;
00391             }
00392         private:
00393             list_type * m_childs;
00394         };
00395 
00396 
00397         /**
00398            Functor to return true if given NodeT objects match
00399            a certain name. NodeT must be compatible with
00400            node_traits<NodeT>.
00401 
00402            This class is admittedly to avoid the use of bind1st/bind2nd
00403            :/.
00404         */
00405         template <typename NodeT>
00406         struct same_name
00407         {
00408             typedef NodeT node_type;
00409             typedef ::s11n::node_traits< NodeT > traits_t;
00410             explicit same_name( const std::string & n ) : m_name(n)
00411             {}
00412             
00413             inline bool operator()( const node_type * x ) const
00414             {
00415                 return ( ! x  )
00416                     ? this->m_name.empty()
00417                     : (traits_t::name( *x ) == this->m_name);
00418             }
00419         private:
00420             std::string m_name;
00421         };
00422 
00423     } // namespace Detail
00424 
00425 
00426 
00427         /**
00428            A helper functor to loop over serializable
00429            children.
00430 
00431            Designed for use with std::for_each().
00432 
00433            NodeType must be compatible with s11n node conventions.
00434 
00435            Please see the operator() docs for important usage
00436            information, especially if you want to use this
00437            object outside the context of for_each().
00438         */
00439         template <typename NodeType>
00440         struct subnode_serializer_f
00441         {
00442                 typedef NodeType node_type;
00443                 /**
00444                    Creates an object for serializing
00445 
00446                    Preconditions:
00447 
00448                    - dest must outlive this object.
00449                    More correctly, this object's
00450                    operator() must not be called after
00451                    dest is destroyed.
00452 
00453                 */
00454                 subnode_serializer_f( node_type & dest, const std::string & subname )
00455                         : result(true), m_root(&dest), m_name(subname)
00456                 {
00457                 }
00458  
00459                 /**
00460                    Serializes src into a subnode of dest using the
00461                    name given in this object's ctor.
00462 
00463                    Note that during an, e.g., for_each() this object
00464                    will return false on a failed serialize, and will
00465                    CONTINUE to return false on additional serializations.
00466                    This is to avoid the possibility that for_each()
00467                    fails on the first item of a list, handles 3000 items,
00468                    and then the whole thing fails because of the first one.
00469                    Thus, this operator will never process another request
00470                    once it has returned false ONCE.
00471 
00472            Versions prior to 1.1.3 always dereferenced src,
00473            without checking for a null pointer. As of 1.1.3,
00474            false is returned if (!src).
00475                 */
00476                 template <typename SerializableT>
00477                 inline bool operator()( const SerializableT * src )
00478                 {
00479                         return (src && this->result)
00480                 ? (this->result = ::s11n::serialize_subnode( *this->m_root,
00481                                           this->m_name,
00482                                           *src ))
00483                 : false;
00484                 }
00485                 template <typename SerializableT>
00486                 inline bool operator()( const SerializableT & src )
00487                 {
00488                         return this->operator()( &src );
00489                 }
00490 
00491                 /**
00492                    For use as a "return value catcher" for std::for_each().
00493                    See operator() for how it is set. The starting value
00494                    is true, which means that looping over an empty list
00495                    with this object will return a true result (which is
00496                    the convention in s11n).
00497                 */
00498                 bool result;
00499         private:
00500                 node_type * m_root;
00501                 std::string m_name;
00502         };
00503 
00504 
00505 
00506 
00507         /**
00508            A Serializable Proxy for streamable types. It "should" work
00509            with any type which meets these conditions:
00510 
00511            - complementary i/ostream operators are implemented (as
00512            member or free functions).
00513 
00514            - supports a copy ctor (for deserialization).
00515 
00516 
00517        The class name of serialized objects will be taken
00518        from s11n_traits<>::class_name(), which isn't truly
00519        valid because most streamable types are never registed
00520        via s11n_traits. Hmmm.
00521 
00522            Its output is significantly bigger than using, e.g. node
00523            properties to store them, but with this proxy any
00524            streamable can be treated as a full-fledged Serializable,
00525            which allows some generic container-based serialization to
00526            be done regardless of the underlying types (see the various
00527            standard container algos for examples).
00528 
00529        ACHTUNG: never pass the same Serializable to the
00530        operators more than once or you will get duplicate and/or
00531        incorrect data.
00532         */
00533         struct streamable_type_serialization_proxy
00534         {
00535                 /**
00536                 */
00537                 streamable_type_serialization_proxy()
00538                 {}
00539 
00540                 /**
00541                    Creates a property in dest, called 'v', and sets
00542                    its value to src using node_traits<NodeType>::set(dest,"v",src).
00543 
00544                    Always returns true unless no class name can be found
00545            for src, in which case it returns false to avoid inserting
00546            a non-name node into the data tree (which might
00547            result in unreadable data later).
00548                 */
00549                 template <typename NodeType, typename SerType>
00550                 bool operator()( NodeType & dest, const SerType & src ) const
00551                 {
00552                         typedef node_traits<NodeType> NTR;
00553             typedef s11n_traits<SerType> STR;
00554                         NTR::class_name( dest, STR::class_name(&src) );
00555                         NTR::set( dest, "v", src );
00556                         return true;
00557                 }
00558 
00559                 /**
00560                    Looks for a property set by the serialize operator and sets
00561                    dest to its value. The default for dest, in the case
00562                    of a missing property or nonconvertable value is
00563                    dest itself.
00564 
00565                    If the property is missing this function throws an
00566                    s11n_exception. [Design note: this seems a bit
00567                    harsh.]
00568 
00569                    On success dest gets assigned the property's value
00570                    and true is returned. This function cannot catch a
00571                    case of inability to convert the value into a
00572                    SerType: client code interested in doing so should
00573                    compare dest's value to a known error value after
00574                    this function returns or throw from that type's
00575                    istream operator on error.
00576                 */
00577                 template <typename NodeType, typename SerType>
00578                 bool operator()( const NodeType & src, SerType & dest ) const
00579                 {
00580                         typedef node_traits<NodeType> NTR;
00581                         if( ! NTR::is_set( src, "v" ) )
00582                         {
00583                 throw s11n_exception( "streamable_serializable_proxy: deser failed: property 'v' missing!" );
00584                         }
00585                         dest = NTR::get( src, "v", SerType() /* should never happen */ );
00586                         return true;
00587                 }
00588         };
00589 
00590 
00591         /**
00592            Adds ch as a child of parent. Parent takes over ownership
00593            of ch.
00594 
00595            NodeType must have a node_traits<> specialization.
00596         */
00597         template <typename NodeType, typename ChildType>
00598         inline void add_child( NodeType & parent, ChildType * ch )
00599         {
00600                 typedef ::s11n::node_traits<NodeType> NTR;
00601                 NTR::children( parent ).push_back( ch );
00602         }
00603 
00604 
00605         /**
00606            Creates a new node, named nodename, as a child of parent.
00607 
00608            Returns a reference to the new child, which parent now
00609            owns.
00610 
00611            NodeType must have a node_traits<> specialization or work
00612            using the default.
00613 
00614        Development tip: this function often comes in handy
00615        during serialization.
00616         */
00617         template <typename NodeType>
00618         NodeType & create_child( NodeType & parent, const std::string nodename );
00619 
00620 
00621         /**
00622            Each child in parent.children() which has the given name is
00623            copied into the target container.
00624 
00625            Returns the number of items added to target.
00626 
00627            DestContainerT must support an insert iterator which will
00628            insert the pointer type contained in the list returned by
00629            parent.children(). i.e., it must hold (const
00630            NodeT *).
00631 
00632            Ownership of the children do not change by calling this
00633            function. Normally they are owned by the parent node
00634            (unless the client explicitely does something to change
00635            that).
00636         */
00637         template <typename NodeT, typename DestContainerT>
00638         size_t find_children_by_name( const NodeT & parent, const std::string & name, DestContainerT & target );
00639 
00640         /**
00641            Finds the FIRST child in parent with the given name and
00642            returns a pointer to it, or 0 if no such child is found.
00643 
00644            Ownership of the child does not change by calling this
00645            function: parent still owns it.
00646 
00647        Complexity is linear.
00648         */
00649         template <typename NodeT>
00650         const NodeT *
00651         find_child_by_name( const NodeT & parent, const std::string & name );
00652 
00653         /**
00654            A non-const overload of find_child_by_name(). Functionally
00655            identical to the const form, except for the constness of
00656            the parent argument and return value.
00657 
00658            Ownership of the returned pointer is not changed by calling
00659            this function (normally parent owns it, but clients may
00660            change that without affecting this function). When in
00661            doubt, i.e. during "normal usage", do NOT delete the returned
00662            pointer, because the parent node owns it. This function can
00663        be used to find a child for manual removal from parent via
00664        the API for the node_traits<NodeT>::children(parent) object.
00665         */
00666         template <typename NodeT>
00667         NodeT *
00668         find_child_by_name( NodeT & parent, const std::string & name );
00669 
00670     namespace debug {
00671 
00672         /**
00673            Dumps a tree-like view of n's structure, excluding properties,
00674            to cerr. The second parameter is for use by this function
00675            in recursion: do not pass a value for it.
00676         */
00677         template <typename NodeT>
00678         void dump_node_structure( const NodeT & n, int indentlv = 0 );
00679 
00680     } // namespace
00681 
00682 
00683 
00684 
00685     /**
00686        A functor which simply forwards its arguments to
00687        s11n::serialize_subnode().
00688 
00689        Added in 1.1.3.
00690     */
00691     struct serialize_subnode_f
00692     {
00693         template <typename NT, typename ST>
00694         inline bool operator()( NT & dest, const std::string & subname, const ST & src ) const
00695         {
00696             return serialize_subnode<NT,ST>( dest, subname, src );
00697         }
00698     };
00699 
00700     /**
00701        A functor which simply forwards its arguments to
00702        s11n::deserialize_subnode().
00703 
00704        Added in 1.1.3.
00705     */
00706     struct deserialize_subnode_f
00707     {
00708         template <typename NT, typename ST>
00709         inline bool operator()( NT & dest, const std::string & subname, const ST & src ) const
00710         {
00711             return deserialize_subnode<NT,ST>( dest, subname, src );
00712         }
00713     };
00714 
00715 
00716 } // namespace
00717 
00718 
00719 #include <s11n.net/s11n/algo.tpp> // implementations
00720 #endif // s11n_net_s11n_v1_1_ALGO_HPP_INCLUDED

Generated on Sun Apr 27 11:48:19 2008 for libs11n-1.2.6 by  doxygen 1.5.3