The Gaudi Framework  master (e68eea06)
Loading...
Searching...
No Matches
StreamBuffer.h
Go to the documentation of this file.
1/***********************************************************************************\
2* (c) Copyright 1998-2025 CERN for the benefit of the LHCb and ATLAS collaborations *
3* *
4* This software is distributed under the terms of the Apache version 2 licence, *
5* copied verbatim in the file "LICENSE". *
6* *
7* In applying this licence, CERN does not waive the privileges and immunities *
8* granted to it by virtue of its status as an Intergovernmental Organization *
9* or submit itself to any jurisdiction. *
10\***********************************************************************************/
11#pragma once
12
13#include <GaudiKernel/Kernel.h>
14#include <algorithm>
15#include <cstdlib>
16#include <cstring>
17#include <iostream>
18#include <list>
19#include <string>
20#include <typeinfo>
21#include <unistd.h>
22#include <vector>
23
24class StreamBuffer;
25class DataObject;
26class ContainedObject;
27
47class StreamBuffer /* : public std::string */
48{
49public:
51 class DataIO {
52 public:
54 DataIO() = default;
56 virtual ~DataIO() = default;
58 void badStreamMode() { throw( "Not acceptable stream mode!" ); }
60 virtual void serialize( StreamBuffer& stream ) {
61 if ( stream.isReading() )
62 load( stream );
63 else if ( stream.isWriting() )
64 dump( stream );
65 else
67 }
68
69 virtual void load( StreamBuffer& ) { badStreamMode(); }
71 virtual void dump( StreamBuffer& ) { badStreamMode(); }
72 };
73
75 class Istream : public DataIO {
77 std::istream* m_stream;
78
79 public:
81 Istream( std::istream& str ) : m_stream( &str ) {}
82
84 void load( StreamBuffer& stream ) override {
85 // Generic implementation for istreams:
86 int len;
87 ( *m_stream ) >> len;
88 stream.erase();
89 stream.reserve( len );
90 m_stream->read( stream.data(), len );
91 }
92 };
93
94 class Ostream : public DataIO {
95 std::ostream* m_stream;
96
97 public:
99 Ostream( std::ostream& str ) : m_stream( &str ) {}
101 virtual ~Ostream() = default;
102
104 void dump( StreamBuffer& stream ) override {
105 // Generic implementation for ostreams:
106 ( *m_stream ) << stream.buffPointer();
107 m_stream->write( stream.data(), stream.buffPointer() );
108 }
109 };
110
111public:
117 enum State { INVALID = -1, VALID };
120 public:
124 ContainedLink() = default;
125 ContainedLink( ContainedObject* pObj, long hint, long link ) : first( pObj ), second( hint ), third( link ) {}
126 ContainedLink( const ContainedLink& copy ) = default;
127 ContainedLink& operator=( const ContainedLink& copy ) = default;
128 };
129
131 public:
132 DataObject* first = nullptr;
134 IdentifiedLink() = default;
135 IdentifiedLink( DataObject* pObj, long hint ) : first( pObj ), second( hint ) {}
136 IdentifiedLink( const IdentifiedLink& copy ) = default;
137 IdentifiedLink& operator=( const IdentifiedLink& copy ) = default;
138 };
139
140 typedef std::vector<ContainedLink> ContainedLinks;
142 typedef std::vector<IdentifiedLink> IdentifiedLinks;
144 typedef void ( *AnalyzeFunction )( const void* data, int siz, const std::type_info& type );
146 friend class DataObject;
147
148protected:
151
153 mutable long m_pointer = 0;
154
156 mutable long m_length = 0;
157
159 mutable char* m_buffer = nullptr;
160
162 bool m_swapEnabled = true;
163
166
169
172
174 SwapAction swapBuffer( int siz ) const;
175
179 template <class TYPE>
180 StreamBuffer& getObjectPointer( const DataObject* /*pObject*/, TYPE*& refpObject ) {
181 IdentifiedLink& link = m_identifiedLinks.back();
182 DataObject* pObj = link.first;
183 m_identifiedLinks.pop_back();
184 refpObject = dynamic_cast<TYPE*>( pObj );
185 return *this;
186 }
187
190 template <class TYPE>
191 StreamBuffer& getObjectPointer( const ContainedObject* /*pObject*/, TYPE*& refpObject ) {
192 ContainedLink& link = m_containedLinks.back();
193 ContainedObject* pObj = link.first;
194 m_containedLinks.pop_back();
195 refpObject = dynamic_cast<TYPE*>( pObj );
196 return *this;
197 }
198
199public:
201 StreamBuffer( bool do_swap = true ) : m_swapEnabled( do_swap ) {}
203 virtual ~StreamBuffer() { ::free( m_buffer ); }
205 StreamBuffer( const StreamBuffer& ) = delete;
209 const char* data() const { return m_buffer; }
211 char* data() { return m_buffer; }
213 void erase() { m_pointer = 0; }
215 char* adopt() const {
216 char* ptr = m_buffer;
217 m_containedLinks.erase( m_containedLinks.begin(), m_containedLinks.end() );
219 m_buffer = NULL; // char *
220 m_pointer = 0; // long
221 m_length = 0; // long
222 return ptr;
223 }
224
225 void reserve( long len ) {
226 if ( len > m_length ) {
227 m_length = ( len < 16384 ) ? 16384 : len;
228 m_buffer = (char*)::realloc( m_buffer, m_length );
229 }
230 }
231
232 void extend( long len ) {
233 if ( len + m_pointer > m_length ) {
234 // We have to be a bit generous here in order not to run too often
235 // into ::realloc().
236 long new_len = ( m_length < 16384 ) ? 16384 : 2 * m_length;
237 if ( m_length < len ) new_len += len;
238 reserve( new_len );
239 }
240 }
241
242 long size() const { return m_length; }
247
252
254 void setMode( Mode m ) {
255 m_mode = m;
256 m_pointer = 0;
257 m_containedLinks.erase( m_containedLinks.begin(), m_containedLinks.end() );
259 }
260
262 bool isReading() const { return m_mode == READING; }
263
265 bool isWriting() const { return m_mode == WRITING; }
267 long buffPointer() const { return m_pointer; }
269 void setBuffPointer( long ptr ) { m_pointer = ptr; }
271 void setAnalyzer( AnalyzeFunction fun = nullptr ) { m_analyzer = fun; }
273 void swapToBuffer( const void* source, int siz );
274
276 void swapFromBuffer( void* target, int siz );
277
279 StreamBuffer& writeBytes( const char* str, long len ) {
280 extend( m_pointer + len + 4 );
281 *this << len;
282 std::copy_n( str, len, data() + buffPointer() );
283 m_pointer += len;
284 return *this;
285 }
286
287 void getIdentifiedLink( DataObject*& pObject, long& hint ) {
289 pObject = l.first;
290 hint = l.second;
291 m_identifiedLinks.pop_back();
292 }
293 void addIdentifiedLink( const DataObject* pObject, long hint ) {
294 m_identifiedLinks.push_back( IdentifiedLink( const_cast<DataObject*>( pObject ), hint ) );
295 }
296
297 void getContainedLink( ContainedObject*& pObject, long& hint, long& link ) {
299 pObject = l.first;
300 hint = l.second;
301 link = l.third;
302 m_containedLinks.pop_back();
303 }
304 void addContainedLink( const ContainedObject* pObject, long hint, long link ) {
305 m_containedLinks.push_back( ContainedLink( const_cast<ContainedObject*>( pObject ), hint, link ) );
306 }
307
308#ifdef USE_STREAM_ANALYSER
309# define STREAM_ANALYSE( data, len ) \
310 if ( 0 != m_analyzer ) m_analyzer( &data, len, typeid( data ) )
311#else
312# define STREAM_ANALYSE( data, len )
313#endif
314
315// Implement streamer macros for primivive data types.
316#define IMPLEMENT_STREAMER( TYPE ) \
317 /* Output Streamer */ \
318 StreamBuffer& operator<<( TYPE data ) { \
319 swapToBuffer( &data, sizeof( data ) ); \
320 STREAM_ANALYSE( data, sizeof( data ) ); \
321 return *this; \
322 } \
323 /* Input Streamer */ \
324 StreamBuffer& operator>>( TYPE& data ) { \
325 swapFromBuffer( &data, sizeof( data ) ); \
326 return *this; \
327 }
328// RootCint does not understand this macro....
329// But we can easily live without it!
330#undef IMPLEMENT_STREAMER
331
334 swapToBuffer( &data, sizeof( data ) );
335 STREAM_ANALYSE( data, sizeof( data ) );
336 return *this;
337 }
338
339 StreamBuffer& operator>>( long long& data ) {
340 swapFromBuffer( &data, sizeof( data ) );
341 return *this;
342 }
343
345 swapToBuffer( &data, sizeof( data ) );
346 STREAM_ANALYSE( data, sizeof( data ) );
347 return *this;
348 }
349
351 swapFromBuffer( &data, sizeof( data ) );
352 return *this;
353 }
354
355 StreamBuffer& operator<<( unsigned int data ) {
356 swapToBuffer( &data, sizeof( data ) );
357 STREAM_ANALYSE( data, sizeof( data ) );
358 return *this;
359 }
360
361 StreamBuffer& operator>>( unsigned int& data ) {
362 swapFromBuffer( &data, sizeof( data ) );
363 return *this;
364 }
365
367 swapToBuffer( &data, sizeof( data ) );
368 STREAM_ANALYSE( data, sizeof( data ) );
369 return *this;
370 }
371
373 swapFromBuffer( &data, sizeof( data ) );
374 return *this;
375 }
376
377 StreamBuffer& operator<<( unsigned long data ) {
378 swapToBuffer( &data, sizeof( data ) );
379 STREAM_ANALYSE( data, sizeof( data ) );
380 return *this;
381 }
382
383 StreamBuffer& operator>>( unsigned long& data ) {
384 swapFromBuffer( &data, sizeof( data ) );
385 return *this;
386 }
387
389 swapToBuffer( &data, sizeof( data ) );
390 STREAM_ANALYSE( data, sizeof( data ) );
391 return *this;
392 }
393
395 swapFromBuffer( &data, sizeof( data ) );
396 return *this;
397 }
398
399 StreamBuffer& operator<<( unsigned short data ) {
400 swapToBuffer( &data, sizeof( data ) );
401 STREAM_ANALYSE( data, sizeof( data ) );
402 return *this;
403 }
404
405 StreamBuffer& operator>>( unsigned short& data ) {
406 swapFromBuffer( &data, sizeof( data ) );
407 return *this;
408 }
409
411 swapToBuffer( &data, sizeof( data ) );
412 STREAM_ANALYSE( data, sizeof( data ) );
413 return *this;
414 }
415
417 swapFromBuffer( &data, sizeof( data ) );
418 return *this;
419 }
420
421 StreamBuffer& operator<<( unsigned char data ) {
422 swapToBuffer( &data, sizeof( data ) );
423 STREAM_ANALYSE( data, sizeof( data ) );
424 return *this;
425 }
426
427 StreamBuffer& operator>>( unsigned char& data ) {
428 swapFromBuffer( &data, sizeof( data ) );
429 return *this;
430 }
431
433 swapToBuffer( &data, sizeof( data ) );
434 STREAM_ANALYSE( data, sizeof( data ) );
435 return *this;
436 }
437
439 swapFromBuffer( &data, sizeof( data ) );
440 return *this;
441 }
442
444 swapToBuffer( &data, sizeof( data ) );
445 STREAM_ANALYSE( data, sizeof( data ) );
446 return *this;
447 }
448
450 swapFromBuffer( &data, sizeof( data ) );
451 return *this;
452 }
453
455 long i, len;
456 *this >> len;
457 for ( i = 0, data[0] = 0; i < len; i++ ) { data[i] = m_buffer[m_pointer++]; }
458 return *this;
459 }
460
461 StreamBuffer& operator<<( const char* data ) {
462 const char* ptr = 0 == data ? "" : data;
463 size_t len = strlen( ptr ) + 1;
464 if ( 0 == m_analyzer )
465 writeBytes( ptr, len );
466 else { STREAM_ANALYSE( data, len ); }
467 return *this;
468 }
469
470 StreamBuffer& operator>>( std::string& data ) {
471 long i, len;
472 *this >> len;
473 for ( i = 0, data = ""; i < len; i++ ) { data.append( 1, m_buffer[m_pointer++] ); }
474 return *this;
475 }
476
477 StreamBuffer& operator<<( const std::string& data ) {
478 if ( 0 == m_analyzer ) {
479 const char* ptr = data.c_str();
480 long len = data.length();
481 writeBytes( ptr, len );
482 } else {
483 STREAM_ANALYSE( data, sizeof( data ) );
484 }
485 return *this;
486 }
487
493 template <class TYPE>
494 StreamBuffer& operator>>( TYPE*& refpObject ) {
495 return getObjectPointer( refpObject, refpObject );
496 }
497
505 STREAM_ANALYSE( pObject, sizeof( pObject ) );
506 addContainedLink( pObject, INVALID, INVALID );
507 return *this;
508 }
509
516 StreamBuffer& operator<<( const DataObject* pObject ) {
517 STREAM_ANALYSE( pObject, sizeof( pObject ) );
518 addIdentifiedLink( pObject, INVALID );
519 return *this;
520 }
521
528 void serialize( DataIO& ioObject ) {
529 ioObject.serialize( *this );
530 m_pointer = 0;
531 }
532};
533
534#undef STREAM_ANALYSE
535
538 switch ( siz ) {
539 case 1:
540 return SINGLE_BYTE;
541 default:
542#if defined( __alpha ) && !defined( __VMS )
543 // return m_swapEnabled ? SWAP : NOSWAP;
544 return NOSWAP;
545#elif defined( __sun ) && defined( __SVR4 ) && defined( __i386 )
546 // return m_swapEnabled ? SWAP : NOSWAP;
547 return NOSWAP;
548#elif defined( __APPLE__ )
549 // return m_swapEnabled ? SWAP : NOSWAP;
550 return SWAP;
551#elif defined( __linux ) && !defined( __powerpc )
552 // return m_swapEnabled ? SWAP : NOSWAP;
553 return NOSWAP;
554#else
555 return m_swapEnabled ? SWAP : NOSWAP;
556// return NOSWAP;
557#endif
558 }
559}
560
562inline void StreamBuffer::swapToBuffer( const void* source, int siz ) {
563 char buff[8], *tar, *src = (char*)source;
564 extend( m_pointer + siz );
565 tar = m_buffer + m_pointer;
566 switch ( swapBuffer( siz ) ) {
567 case SINGLE_BYTE:
568 *tar = *src;
569 break;
570 case SWAP:
571#ifdef __APPLE__
572 for ( int i = 0, j = siz - 1; i < siz; i++, j-- ) tar[j] = src[i];
573#else
574 ::swab( src, buff, siz );
575#endif
576 src = buff;
577 [[fallthrough]];
578 case NOSWAP:
579 std::copy_n( src, siz, tar );
580 break;
581 default:
582 break;
583 }
584 m_pointer += siz;
585}
586
588inline void StreamBuffer::swapFromBuffer( void* target, int siz ) {
589 char* tar = (char*)target;
590 char* src = m_buffer + m_pointer;
591 switch ( swapBuffer( siz ) ) {
592 case SINGLE_BYTE:
593 *tar = *src;
594 break;
595 case SWAP:
596#ifdef __APPLE__
597 for ( int i = 0, j = siz - 1; i < siz; i++, j-- ) tar[j] = src[i];
598#else
599 ::swab( src, tar, siz );
600#endif
601 break;
602 case NOSWAP:
603 std::copy_n( src, siz, tar );
604 break;
605 default:
606 break;
607 }
608 m_pointer += siz;
609}
610
611// Output serialize a vector of items
612template <class T>
613inline StreamBuffer& operator<<( StreamBuffer& s, const std::vector<T>& v ) {
614 s << v.size();
615 for ( const auto& i : v ) s << i;
616 return s;
617}
618
619// Input serialize a vector of items
620template <class T>
621inline StreamBuffer& operator>>( StreamBuffer& s, std::vector<T>& v ) {
622 long i, len;
623 s >> len;
624 v.clear();
625 for ( i = 0; i < len; i++ ) {
626 T temp;
627 s >> temp;
628 v.push_back( temp );
629 }
630 return s;
631}
632
633// Output serialize a list of items
634template <class T>
635inline StreamBuffer& operator<<( StreamBuffer& s, const std::list<T>& l ) {
636 s << l.size();
637 for ( const auto& i : l ) s << i;
638 return s;
639}
640
641// Input serialize a list of items
642template <class T>
643inline StreamBuffer& operator>>( StreamBuffer& s, std::list<T>& l ) {
644 long len;
645 s >> len;
646 l.clear();
647 for ( long i = 0; i < len; i++ ) {
648 T temp;
649 s >> temp;
650 l.push_back( temp );
651 }
652 return s;
653}
StreamBuffer & operator>>(StreamBuffer &s, std::vector< T > &v)
StreamBuffer & operator<<(StreamBuffer &s, const std::vector< T > &v)
#define STREAM_ANALYSE(data, len)
All classes that their objects may be contained in an LHCb ObjectContainer (e.g.
A DataObject is the base class of any identifiable object on any data store.
Definition DataObject.h:37
A small base class to handle generic data streaming.
void badStreamMode()
Throw Exception.
DataIO()=default
Standard constructor.
virtual ~DataIO()=default
Standard destructor.
virtual void dump(StreamBuffer &)
Template function to save stream data.
virtual void serialize(StreamBuffer &stream)
Serialization method: loads/dumps streambuffer content.
virtual void load(StreamBuffer &)
Template function to load stream data.
Istream(std::istream &str)
Constructor.
std::istream * m_stream
Reference to input stream.
void load(StreamBuffer &stream) override
Data load method.
virtual ~Ostream()=default
Standard Destructor.
Ostream(std::ostream &str)
Standard constructor: pass reference to stream object.
void dump(StreamBuffer &stream) override
Output dumper.
std::ostream * m_stream
The stream buffer is a small object collecting object data.
char * data()
write access to data buffer
virtual ~StreamBuffer()
Standard destructor.
StreamBuffer(bool do_swap=true)
Standard constructor.
IdentifiedLinks & identifiedLinks()
Access to identified links.
StreamBuffer & operator<<(short data)
Output Streamer.
StreamBuffer & operator>>(char &data)
Input Streamer.
StreamBuffer & operator<<(char data)
Output Streamer.
void erase()
Reset the buffer.
long m_pointer
Current buffer pointer.
StreamBuffer & operator>>(char *data)
Streamer to read strings in (char*) format.
const ContainedLinks & containedLinks() const
CONST Access to contained links.
StreamBuffer & operator>>(std::string &data)
Streamer to read strings in (std::string) format.
void setAnalyzer(AnalyzeFunction fun=nullptr)
Enable user analysis function.
void getIdentifiedLink(DataObject *&pObject, long &hint)
std::vector< ContainedLink > ContainedLinks
StreamBuffer & operator<<(int data)
Output Streamer.
StreamBuffer & operator>>(float &data)
Input Streamer.
StreamBuffer & getObjectPointer(const ContainedObject *, TYPE *&refpObject)
Helper to distinguish between identified pointers and contained pointers.
bool m_swapEnabled
Flag indicating swapping.
long size() const
Total buffer size.
SwapAction
Data Sawp actions.
char * adopt() const
Remove the data buffer and pass it to client. It's the client responsability to free the memory.
IdentifiedLinks m_identifiedLinks
Container with links to contained objects.
StreamBuffer & operator>>(short &data)
Input Streamer.
Mode
Streamer mode.
StreamBuffer & operator>>(unsigned short &data)
Input Streamer.
void serialize(DataIO &ioObject)
Serialize the buffer using an IO object.
StreamBuffer & operator<<(const DataObject *pObject)
Streamer to write links to identified objects.
long buffPointer() const
Retrieve current buffer pointer.
StreamBuffer(const StreamBuffer &)=delete
No copy.
StreamBuffer & operator<<(const std::string &data)
Streamer to write strings in (std::string) format.
const char * data() const
Read access to data buffer.
StreamBuffer & operator>>(long long &data)
Input Streamer.
void addIdentifiedLink(const DataObject *pObject, long hint)
void setMode(Mode m)
Set mode of the stream and allocate buffer.
StreamBuffer & operator<<(unsigned int data)
Output Streamer.
SwapAction swapBuffer(int siz) const
Check for byte swapping.
StreamBuffer & operator>>(long &data)
Input Streamer.
void extend(long len)
Extend the buffer.
std::vector< IdentifiedLink > IdentifiedLinks
Definition of the identifiable link set.
StreamBuffer & operator<<(const ContainedObject *pObject)
Streamer to write links to contained objects.
void(* AnalyzeFunction)(const void *data, int siz, const std::type_info &type)
Definition of the buffer analyzer.
bool isReading() const
Get stream buffer state.
StreamBuffer & operator>>(unsigned long &data)
Input Streamer.
StreamBuffer & getObjectPointer(const DataObject *, TYPE *&refpObject)
Helper to distinguish between identified pointers and contained pointers.
StreamBuffer & operator<<(unsigned char data)
Output Streamer.
StreamBuffer & operator>>(unsigned int &data)
Input Streamer.
AnalyzeFunction m_analyzer
Hook function for analysis of data to the stream.
StreamBuffer & operator>>(unsigned char &data)
Input Streamer.
void getContainedLink(ContainedObject *&pObject, long &hint, long &link)
void swapToBuffer(const void *source, int siz)
Swap buffers: int, long, short, float and double.
void reserve(long len)
Reserve buffer space; Default: 16 k buffer size.
StreamBuffer & operator<<(double data)
Output Streamer.
const IdentifiedLinks & identifiedLinks() const
CONST Access to identified links.
void setBuffPointer(long ptr)
Retrieve current buffer pointer.
StreamBuffer & operator<<(const char *data)
Streamer to write strings in (char*) format.
StreamBuffer & operator=(const StreamBuffer &)=delete
No assignment.
StreamBuffer & writeBytes(const char *str, long len)
Write string to output stream.
StreamBuffer & operator>>(double &data)
Input Streamer.
State
Link state defintions.
bool isWriting() const
Get stream buffer state.
void swapFromBuffer(void *target, int siz)
Swap buffers: int, long, short, float and double.
StreamBuffer & operator<<(long long data)
Output Streamer.
ContainedLinks m_containedLinks
Container with links to contained objects.
StreamBuffer & operator<<(long data)
Output Streamer.
ContainedLinks & containedLinks()
Access to contained links.
StreamBuffer & operator<<(unsigned short data)
Output Streamer.
char * m_buffer
Pointer to heap buffer.
StreamBuffer & operator<<(float data)
Output Streamer.
long m_length
Total buffer length.
void addContainedLink(const ContainedObject *pObject, long hint, long link)
StreamBuffer & operator>>(TYPE *&refpObject)
Streamer to read links to contained or identified objects.
StreamBuffer & operator>>(int &data)
Input Streamer.
StreamBuffer & operator<<(unsigned long data)
Output Streamer.
friend class DataObject
DataObject is friend.
Mode m_mode
Boolean indicating wether the stream is in read or write mode.