Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:57:43

0001 /***********************************************************************************\
0002 * (c) Copyright 1998-2021 CERN for the benefit of the LHCb and ATLAS collaborations *
0003 *                                                                                   *
0004 * This software is distributed under the terms of the Apache version 2 licence,     *
0005 * copied verbatim in the file "LICENSE".                                            *
0006 *                                                                                   *
0007 * In applying this licence, CERN does not waive the privileges and immunities       *
0008 * granted to it by virtue of its status as an Intergovernmental Organization        *
0009 * or submit itself to any jurisdiction.                                             *
0010 \***********************************************************************************/
0011 #ifndef GAUDIKERNEL_STREAMBUFFER_H
0012 #define GAUDIKERNEL_STREAMBUFFER_H 1
0013 
0014 // STL include files
0015 #include <algorithm>
0016 #include <cstdlib>
0017 #include <cstring>
0018 #include <iostream>
0019 #include <list>
0020 #include <string>
0021 #include <typeinfo>
0022 #include <vector>
0023 
0024 #include "GaudiKernel/Kernel.h"
0025 #include "GaudiKernel/swab.h"
0026 
0027 // forward declarations
0028 class StreamBuffer;
0029 class DataObject;
0030 class ContainedObject;
0031 
0032 /** @class StreamBuffer StreamBuffer.h GaudiKernel/StreamBuffer.h
0033 
0034     The stream buffer is a small object collecting object data.
0035     The basic idea behind the StreamBuffer is generic object conversion.
0036     The StreamBuffer acts as a byte stream (hence inheriting from a
0037     std::string: DP: this is not true anymore and it is not a bad thing in my
0038     opinion) and stores any information streamed to the buffer.
0039     Since the information must be represented in a generic way
0040     on the fly byte swapping is performed. However, not only primitive
0041     data can be stored in the buffer, but also pointers to DataObjects
0042     (symbolic links) and pointers to contained objects. Automatically during
0043     serialization the persistent references to the corresponding objects
0044     and containers must be stored. These objects are accessible
0045     from the StreamBuffer object.
0046 
0047     "On the fly" data conversion to non persistent
0048 
0049     @author   M.Frank
0050 */
0051 class StreamBuffer /* : public std::string  */
0052 {
0053 public:
0054   /// A small base class to handle generic data streaming
0055   class DataIO {
0056   public:
0057     /// Standard constructor
0058     DataIO() = default;
0059     /// Standard destructor
0060     virtual ~DataIO() = default;
0061     /// Throw Exception
0062     void badStreamMode() { throw( "Not acceptable stream mode!" ); }
0063     /// Serialization method: loads/dumps streambuffer content
0064     virtual void serialize( StreamBuffer& stream ) {
0065       if ( stream.isReading() )
0066         load( stream );
0067       else if ( stream.isWriting() )
0068         dump( stream );
0069       else
0070         badStreamMode();
0071     }
0072     /// Template function to load stream data
0073     virtual void load( StreamBuffer& ) { badStreamMode(); }
0074     /// Template function to save stream data
0075     virtual void dump( StreamBuffer& ) { badStreamMode(); }
0076   };
0077 
0078   /// Reader for standard input streams
0079   class Istream : public DataIO {
0080     /// Reference to input stream
0081     std::istream* m_stream;
0082 
0083   public:
0084     /// Constructor
0085     Istream( std::istream& str ) : m_stream( &str ) {}
0086 
0087     /// Data load method
0088     void load( StreamBuffer& stream ) override {
0089       // Generic implementation for istreams:
0090       int len;
0091       ( *m_stream ) >> len;
0092       stream.erase();
0093       stream.reserve( len );
0094       m_stream->read( stream.data(), len );
0095     }
0096   };
0097   /// Writer for standard output streams
0098   class Ostream : public DataIO {
0099     std::ostream* m_stream;
0100 
0101   public:
0102     /// Standard constructor: pass reference to stream object
0103     Ostream( std::ostream& str ) : m_stream( &str ) {}
0104     /// Standard Destructor
0105     virtual ~Ostream() = default;
0106 
0107     /// Output dumper
0108     void dump( StreamBuffer& stream ) override {
0109       // Generic implementation for ostreams:
0110       ( *m_stream ) << stream.buffPointer();
0111       m_stream->write( stream.data(), stream.buffPointer() );
0112     }
0113   };
0114 
0115 public:
0116   /// Streamer mode
0117   enum Mode { UNINITIALIZED, READING, WRITING };
0118   /// Data Sawp actions
0119   enum SwapAction { SINGLE_BYTE, SWAP, NOSWAP };
0120   /// Link state defintions
0121   enum State { INVALID = -1, VALID };
0122   /// Definition of the contained link set
0123   class ContainedLink {
0124   public:
0125     ContainedObject* first  = nullptr;
0126     long             second = INVALID;
0127     long             third  = INVALID;
0128     ContainedLink()         = default;
0129     ContainedLink( ContainedObject* pObj, long hint, long link ) : first( pObj ), second( hint ), third( link ) {}
0130     ContainedLink( const ContainedLink& copy )            = default;
0131     ContainedLink& operator=( const ContainedLink& copy ) = default;
0132   };
0133   /// Definition of the contained link set
0134   class IdentifiedLink {
0135   public:
0136     DataObject* first  = nullptr;
0137     long        second = INVALID;
0138     IdentifiedLink()   = default;
0139     IdentifiedLink( DataObject* pObj, long hint ) : first( pObj ), second( hint ) {}
0140     IdentifiedLink( const IdentifiedLink& copy )            = default;
0141     IdentifiedLink& operator=( const IdentifiedLink& copy ) = default;
0142   };
0143 
0144   typedef std::vector<ContainedLink> ContainedLinks;
0145   /// Definition of the identifiable link set
0146   typedef std::vector<IdentifiedLink> IdentifiedLinks;
0147   /// Definition of the buffer analyzer
0148   typedef void ( *AnalyzeFunction )( const void* data, int siz, const std::type_info& type );
0149   /// DataObject is friend
0150   friend class DataObject;
0151 
0152 protected:
0153   /// Boolean indicating wether the stream is in read or write mode
0154   Mode m_mode = UNINITIALIZED;
0155 
0156   /// Current buffer pointer
0157   mutable long m_pointer = 0;
0158 
0159   /// Total buffer length
0160   mutable long m_length = 0;
0161 
0162   /// Pointer to heap buffer
0163   mutable char* m_buffer = nullptr;
0164 
0165   /// Flag indicating swapping
0166   bool m_swapEnabled = true;
0167 
0168   /// Container with links to contained objects
0169   mutable ContainedLinks m_containedLinks;
0170 
0171   /// Container with links to contained objects
0172   mutable IdentifiedLinks m_identifiedLinks;
0173 
0174   /// Hook function for analysis of data to the stream
0175   AnalyzeFunction m_analyzer = nullptr;
0176 
0177   /// Check for byte swapping
0178   SwapAction swapBuffer( int siz ) const;
0179 
0180   /** Helper to distinguish between identified pointers and contained pointers.
0181       This entry resolves identified pointers (= Pointers to DataObject instances.)
0182   */
0183   template <class TYPE>
0184   StreamBuffer& getObjectPointer( const DataObject* /*pObject*/, TYPE*& refpObject ) {
0185     IdentifiedLink& link = m_identifiedLinks.back();
0186     DataObject*     pObj = link.first;
0187     m_identifiedLinks.pop_back();
0188     refpObject = dynamic_cast<TYPE*>( pObj );
0189     return *this;
0190   }
0191   /** Helper to distinguish between identified pointers and contained pointers.
0192       This entry resolves contained pointers (= Pointers to ContainedObject instances.)
0193   */
0194   template <class TYPE>
0195   StreamBuffer& getObjectPointer( const ContainedObject* /*pObject*/, TYPE*& refpObject ) {
0196     ContainedLink&   link = m_containedLinks.back();
0197     ContainedObject* pObj = link.first;
0198     m_containedLinks.pop_back();
0199     refpObject = dynamic_cast<TYPE*>( pObj );
0200     return *this;
0201   }
0202 
0203 public:
0204   /// Standard constructor
0205   StreamBuffer( bool do_swap = true ) : m_swapEnabled( do_swap ) {}
0206   /// Standard destructor
0207   virtual ~StreamBuffer() { ::free( m_buffer ); }
0208   /// Read access to data buffer
0209   const char* data() const { return m_buffer; }
0210   /// write access to data buffer
0211   char* data() { return m_buffer; }
0212   /// Reset the buffer
0213   void erase() { m_pointer = 0; }
0214   /// Remove the data buffer and pass it to client. It's the client responsability to free the memory
0215   char* adopt() const {
0216     char* ptr = m_buffer;
0217     m_containedLinks.erase( m_containedLinks.begin(), m_containedLinks.end() );
0218     m_identifiedLinks.erase( m_identifiedLinks.begin(), m_identifiedLinks.end() );
0219     m_buffer  = NULL; // char *
0220     m_pointer = 0;    // long
0221     m_length  = 0;    // long
0222     return ptr;
0223   }
0224   /// Reserve buffer space; Default: 16 k buffer size
0225   void reserve( long len ) {
0226     if ( len > m_length ) {
0227       m_length = ( len < 16384 ) ? 16384 : len;
0228       m_buffer = (char*)::realloc( m_buffer, m_length );
0229     }
0230   }
0231   /// Extend the buffer
0232   void extend( long len ) {
0233     if ( len + m_pointer > m_length ) {
0234       // We have to be a bit generous here in order not to run too often
0235       // into ::realloc().
0236       long new_len = ( m_length < 16384 ) ? 16384 : 2 * m_length;
0237       if ( m_length < len ) new_len += len;
0238       reserve( new_len );
0239     }
0240   }
0241   /// Total buffer size
0242   long size() const { return m_length; }
0243   /// Access to contained links
0244   ContainedLinks& containedLinks() { return m_containedLinks; }
0245   /// CONST Access to contained links
0246   const ContainedLinks& containedLinks() const { return m_containedLinks; }
0247 
0248   /// Access to identified links
0249   IdentifiedLinks& identifiedLinks() { return m_identifiedLinks; }
0250   /// CONST Access to identified links
0251   const IdentifiedLinks& identifiedLinks() const { return m_identifiedLinks; }
0252 
0253   /// Set mode of the stream and allocate buffer
0254   void setMode( Mode m ) {
0255     m_mode    = m;
0256     m_pointer = 0;
0257     m_containedLinks.erase( m_containedLinks.begin(), m_containedLinks.end() );
0258     m_identifiedLinks.erase( m_identifiedLinks.begin(), m_identifiedLinks.end() );
0259   }
0260 
0261   /// Get stream buffer state
0262   bool isReading() const { return m_mode == READING; }
0263 
0264   /// Get stream buffer state
0265   bool isWriting() const { return m_mode == WRITING; }
0266   /// Retrieve current buffer pointer
0267   long buffPointer() const { return m_pointer; }
0268   /// Retrieve current buffer pointer
0269   void setBuffPointer( long ptr ) { m_pointer = ptr; }
0270   /// Enable user analysis function
0271   void setAnalyzer( AnalyzeFunction fun = nullptr ) { m_analyzer = fun; }
0272   /// Swap buffers: int, long, short, float and double
0273   void swapToBuffer( const void* source, int siz );
0274 
0275   /// Swap buffers: int, long, short, float and double
0276   void swapFromBuffer( void* target, int siz );
0277 
0278   /// Write string to output stream
0279   StreamBuffer& writeBytes( const char* str, long len ) {
0280     extend( m_pointer + len + 4 );
0281     *this << len;
0282     std::copy_n( str, len, data() + buffPointer() );
0283     m_pointer += len;
0284     return *this;
0285   }
0286 
0287   void getIdentifiedLink( DataObject*& pObject, long& hint ) {
0288     IdentifiedLink& l = m_identifiedLinks.back();
0289     pObject           = l.first;
0290     hint              = l.second;
0291     m_identifiedLinks.pop_back();
0292   }
0293   void addIdentifiedLink( const DataObject* pObject, long hint ) {
0294     m_identifiedLinks.push_back( IdentifiedLink( (DataObject*)pObject, hint ) );
0295   }
0296 
0297   void getContainedLink( ContainedObject*& pObject, long& hint, long& link ) {
0298     ContainedLink& l = m_containedLinks.back();
0299     pObject          = l.first;
0300     hint             = l.second;
0301     link             = l.third;
0302     m_containedLinks.pop_back();
0303   }
0304   void addContainedLink( const ContainedObject* pObject, long hint, long link ) {
0305     m_containedLinks.push_back( ContainedLink( (ContainedObject*)pObject, hint, link ) );
0306   }
0307 
0308 #ifdef USE_STREAM_ANALYSER
0309 #  define STREAM_ANALYSE( data, len )                                                                                  \
0310     if ( 0 != m_analyzer ) m_analyzer( &data, len, typeid( data ) )
0311 #else
0312 #  define STREAM_ANALYSE( data, len )
0313 #endif
0314 
0315 // Implement streamer macros for primivive data types.
0316 #define IMPLEMENT_STREAMER( TYPE )                                                                                     \
0317   /*  Output Streamer                                   */                                                             \
0318   StreamBuffer& operator<<( TYPE data ) {                                                                              \
0319     swapToBuffer( &data, sizeof( data ) );                                                                             \
0320     STREAM_ANALYSE( data, sizeof( data ) );                                                                            \
0321     return *this;                                                                                                      \
0322   }                                                                                                                    \
0323   /*  Input Streamer                                    */                                                             \
0324   StreamBuffer& operator>>( TYPE& data ) {                                                                             \
0325     swapFromBuffer( &data, sizeof( data ) );                                                                           \
0326     return *this;                                                                                                      \
0327   }
0328 // RootCint does not understand this macro....
0329 // But we can easily live without it!
0330 #undef IMPLEMENT_STREAMER
0331 
0332   ///  Output Streamer
0333   StreamBuffer& operator<<( long long data ) {
0334     swapToBuffer( &data, sizeof( data ) );
0335     STREAM_ANALYSE( data, sizeof( data ) );
0336     return *this;
0337   }
0338   ///  Input Streamer
0339   StreamBuffer& operator>>( long long& data ) {
0340     swapFromBuffer( &data, sizeof( data ) );
0341     return *this;
0342   }
0343   ///  Output Streamer
0344   StreamBuffer& operator<<( int data ) {
0345     swapToBuffer( &data, sizeof( data ) );
0346     STREAM_ANALYSE( data, sizeof( data ) );
0347     return *this;
0348   }
0349   ///  Input Streamer
0350   StreamBuffer& operator>>( int& data ) {
0351     swapFromBuffer( &data, sizeof( data ) );
0352     return *this;
0353   }
0354   ///  Output Streamer
0355   StreamBuffer& operator<<( unsigned int data ) {
0356     swapToBuffer( &data, sizeof( data ) );
0357     STREAM_ANALYSE( data, sizeof( data ) );
0358     return *this;
0359   }
0360   ///  Input Streamer
0361   StreamBuffer& operator>>( unsigned int& data ) {
0362     swapFromBuffer( &data, sizeof( data ) );
0363     return *this;
0364   }
0365   ///  Output Streamer
0366   StreamBuffer& operator<<( long data ) {
0367     swapToBuffer( &data, sizeof( data ) );
0368     STREAM_ANALYSE( data, sizeof( data ) );
0369     return *this;
0370   }
0371   ///  Input Streamer
0372   StreamBuffer& operator>>( long& data ) {
0373     swapFromBuffer( &data, sizeof( data ) );
0374     return *this;
0375   }
0376   ///  Output Streamer
0377   StreamBuffer& operator<<( unsigned long data ) {
0378     swapToBuffer( &data, sizeof( data ) );
0379     STREAM_ANALYSE( data, sizeof( data ) );
0380     return *this;
0381   }
0382   ///  Input Streamer
0383   StreamBuffer& operator>>( unsigned long& data ) {
0384     swapFromBuffer( &data, sizeof( data ) );
0385     return *this;
0386   }
0387   ///  Output Streamer
0388   StreamBuffer& operator<<( short data ) {
0389     swapToBuffer( &data, sizeof( data ) );
0390     STREAM_ANALYSE( data, sizeof( data ) );
0391     return *this;
0392   }
0393   ///  Input Streamer
0394   StreamBuffer& operator>>( short& data ) {
0395     swapFromBuffer( &data, sizeof( data ) );
0396     return *this;
0397   }
0398   ///  Output Streamer
0399   StreamBuffer& operator<<( unsigned short data ) {
0400     swapToBuffer( &data, sizeof( data ) );
0401     STREAM_ANALYSE( data, sizeof( data ) );
0402     return *this;
0403   }
0404   ///  Input Streamer
0405   StreamBuffer& operator>>( unsigned short& data ) {
0406     swapFromBuffer( &data, sizeof( data ) );
0407     return *this;
0408   }
0409   ///  Output Streamer
0410   StreamBuffer& operator<<( char data ) {
0411     swapToBuffer( &data, sizeof( data ) );
0412     STREAM_ANALYSE( data, sizeof( data ) );
0413     return *this;
0414   }
0415   ///  Input Streamer
0416   StreamBuffer& operator>>( char& data ) {
0417     swapFromBuffer( &data, sizeof( data ) );
0418     return *this;
0419   }
0420   ///  Output Streamer
0421   StreamBuffer& operator<<( unsigned char data ) {
0422     swapToBuffer( &data, sizeof( data ) );
0423     STREAM_ANALYSE( data, sizeof( data ) );
0424     return *this;
0425   }
0426   ///  Input Streamer
0427   StreamBuffer& operator>>( unsigned char& data ) {
0428     swapFromBuffer( &data, sizeof( data ) );
0429     return *this;
0430   }
0431   ///  Output Streamer
0432   StreamBuffer& operator<<( float data ) {
0433     swapToBuffer( &data, sizeof( data ) );
0434     STREAM_ANALYSE( data, sizeof( data ) );
0435     return *this;
0436   }
0437   ///  Input Streamer
0438   StreamBuffer& operator>>( float& data ) {
0439     swapFromBuffer( &data, sizeof( data ) );
0440     return *this;
0441   }
0442   ///  Output Streamer
0443   StreamBuffer& operator<<( double data ) {
0444     swapToBuffer( &data, sizeof( data ) );
0445     STREAM_ANALYSE( data, sizeof( data ) );
0446     return *this;
0447   }
0448   ///  Input Streamer
0449   StreamBuffer& operator>>( double& data ) {
0450     swapFromBuffer( &data, sizeof( data ) );
0451     return *this;
0452   }
0453   /// Streamer to read strings in (char*) format
0454   StreamBuffer& operator>>( char* data ) {
0455     long i, len;
0456     *this >> len;
0457     for ( i = 0, data[0] = 0; i < len; i++ ) { data[i] = m_buffer[m_pointer++]; }
0458     return *this;
0459   }
0460   /// Streamer to write strings in (char*) format
0461   StreamBuffer& operator<<( const char* data ) {
0462     const char* ptr = 0 == data ? "" : data;
0463     size_t      len = strlen( ptr ) + 1;
0464     if ( 0 == m_analyzer )
0465       writeBytes( ptr, len );
0466     else { STREAM_ANALYSE( data, len ); }
0467     return *this;
0468   }
0469   /// Streamer to read strings in (std::string) format
0470   StreamBuffer& operator>>( std::string& data ) {
0471     long i, len;
0472     *this >> len;
0473     for ( i = 0, data = ""; i < len; i++ ) { data.append( 1, m_buffer[m_pointer++] ); }
0474     return *this;
0475   }
0476   /// Streamer to write strings in (std::string) format
0477   StreamBuffer& operator<<( const std::string& data ) {
0478     if ( 0 == m_analyzer ) {
0479       const char* ptr = data.c_str();
0480       long        len = data.length();
0481       writeBytes( ptr, len );
0482     } else {
0483       STREAM_ANALYSE( data, sizeof( data ) );
0484     }
0485     return *this;
0486   }
0487   /** Streamer to read links to contained or identified objects.
0488       The specified internal function call distinguishes between
0489       contained and identified objects.
0490       @param    refpObject Reference to pointer to object to be loaded.
0491       @return              Reference to StreamBuffer object
0492   */
0493   template <class TYPE>
0494   StreamBuffer& operator>>( TYPE*& refpObject ) {
0495     return getObjectPointer( refpObject, refpObject );
0496   }
0497 
0498   /** Streamer to write links to contained objects.
0499       Links to contained objects are not stored immediately,
0500       but collected instead and analyzed later.
0501       @param       pObject Pointer to object to be loaded.
0502       @return              Reference to StreamBuffer object
0503   */
0504   StreamBuffer& operator<<( const ContainedObject* pObject ) {
0505     STREAM_ANALYSE( pObject, sizeof( pObject ) );
0506     addContainedLink( pObject, INVALID, INVALID );
0507     return *this;
0508   }
0509 
0510   /** Streamer to write links to identified objects.
0511       Links to identified objects are not stored immediately,
0512       but collected instead and analyzed later.
0513       @param       pObject Pointer to object to be loaded.
0514       @return              Reference to StreamBuffer object
0515   */
0516   StreamBuffer& operator<<( const DataObject* pObject ) {
0517     STREAM_ANALYSE( pObject, sizeof( pObject ) );
0518     addIdentifiedLink( pObject, INVALID );
0519     return *this;
0520   }
0521 
0522   /** Serialize the buffer using an IO object.
0523       The streambuffer object will make use of a DataIO object, which
0524       can be specialized for streaming to any representation like
0525       e.g. disk files, Root files, Objectivity etc.
0526       @param       ioObject Reference to data IO object.
0527   */
0528   void serialize( DataIO& ioObject ) {
0529     ioObject.serialize( *this );
0530     m_pointer = 0;
0531   }
0532 };
0533 
0534 #undef STREAM_ANALYSE
0535 
0536 /// Check for byte swapping
0537 inline StreamBuffer::SwapAction StreamBuffer::swapBuffer( int siz ) const {
0538   switch ( siz ) {
0539   case 1:
0540     return SINGLE_BYTE;
0541   default:
0542 #if defined( __alpha ) && !defined( __VMS )
0543     //    return m_swapEnabled ? SWAP : NOSWAP;
0544     return NOSWAP;
0545 #elif defined( __sun ) && defined( __SVR4 ) && defined( __i386 )
0546     //    return m_swapEnabled ? SWAP : NOSWAP;
0547     return NOSWAP;
0548 #elif defined( __APPLE__ )
0549     //    return m_swapEnabled ? SWAP : NOSWAP;
0550     return SWAP;
0551 #elif defined( __linux ) && !defined( __powerpc )
0552     //    return m_swapEnabled ? SWAP : NOSWAP;
0553     return NOSWAP;
0554 #elif defined( BORLAND ) || defined( _WIN32 ) || defined( WIN32 )
0555     //    return m_swapEnabled ? SWAP : NOSWAP;
0556     return NOSWAP;
0557 #else
0558     return m_swapEnabled ? SWAP : NOSWAP;
0559 //    return NOSWAP;
0560 #endif
0561   }
0562 }
0563 
0564 /// Swap bytes from a source buffer to the stream buffer with arbitray size
0565 inline void StreamBuffer::swapToBuffer( const void* source, int siz ) {
0566   char buff[8], *tar, *src = (char*)source;
0567   extend( m_pointer + siz );
0568   tar = m_buffer + m_pointer;
0569   switch ( swapBuffer( siz ) ) {
0570   case SINGLE_BYTE:
0571     *tar = *src;
0572     break;
0573   case SWAP:
0574 #ifdef __APPLE__
0575     for ( int i = 0, j = siz - 1; i < siz; i++, j-- ) tar[j] = src[i];
0576 #else
0577     ::_swab( src, buff, siz );
0578 #endif
0579     src = buff;
0580     [[fallthrough]];
0581   case NOSWAP:
0582     std::copy_n( src, siz, tar );
0583     break;
0584   default:
0585     break;
0586   }
0587   m_pointer += siz;
0588 }
0589 
0590 /// Swap bytes from the stream buffer to target buffer with arbitray size
0591 inline void StreamBuffer::swapFromBuffer( void* target, int siz ) {
0592   char* tar = (char*)target;
0593   char* src = m_buffer + m_pointer;
0594   switch ( swapBuffer( siz ) ) {
0595   case SINGLE_BYTE:
0596     *tar = *src;
0597     break;
0598   case SWAP:
0599 #ifdef __APPLE__
0600     for ( int i = 0, j = siz - 1; i < siz; i++, j-- ) tar[j] = src[i];
0601 #else
0602     ::_swab( src, tar, siz );
0603 #endif
0604     break;
0605   case NOSWAP:
0606     std::copy_n( src, siz, tar );
0607     break;
0608   default:
0609     break;
0610   }
0611   m_pointer += siz;
0612 }
0613 
0614 // Output serialize a vector of items
0615 template <class T>
0616 inline StreamBuffer& operator<<( StreamBuffer& s, const std::vector<T>& v ) {
0617   s << v.size();
0618   for ( const auto& i : v ) s << i;
0619   return s;
0620 }
0621 
0622 // Input serialize a vector of items
0623 template <class T>
0624 inline StreamBuffer& operator>>( StreamBuffer& s, std::vector<T>& v ) {
0625   long i, len;
0626   s >> len;
0627   v.clear();
0628   for ( i = 0; i < len; i++ ) {
0629     T temp;
0630     s >> temp;
0631     v.push_back( temp );
0632   }
0633   return s;
0634 }
0635 
0636 // Output serialize a list of items
0637 template <class T>
0638 inline StreamBuffer& operator<<( StreamBuffer& s, const std::list<T>& l ) {
0639   s << l.size();
0640   for ( const auto& i : l ) s << i;
0641   return s;
0642 }
0643 
0644 // Input serialize a list of items
0645 template <class T>
0646 inline StreamBuffer& operator>>( StreamBuffer& s, std::list<T>& l ) {
0647   long len;
0648   s >> len;
0649   l.clear();
0650   for ( long i = 0; i < len; i++ ) {
0651     T temp;
0652     s >> temp;
0653     l.push_back( temp );
0654   }
0655   return s;
0656 }
0657 #endif // GAUDIKERNEL_STREAMBUFFER_H