The Gaudi Framework  master (82fdf313)
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 const char* data() const { return m_buffer; }
207 char* data() { return m_buffer; }
209 void erase() { m_pointer = 0; }
211 char* adopt() const {
212 char* ptr = m_buffer;
213 m_containedLinks.erase( m_containedLinks.begin(), m_containedLinks.end() );
215 m_buffer = NULL; // char *
216 m_pointer = 0; // long
217 m_length = 0; // long
218 return ptr;
219 }
220
221 void reserve( long len ) {
222 if ( len > m_length ) {
223 m_length = ( len < 16384 ) ? 16384 : len;
224 m_buffer = (char*)::realloc( m_buffer, m_length );
225 }
226 }
227
228 void extend( long len ) {
229 if ( len + m_pointer > m_length ) {
230 // We have to be a bit generous here in order not to run too often
231 // into ::realloc().
232 long new_len = ( m_length < 16384 ) ? 16384 : 2 * m_length;
233 if ( m_length < len ) new_len += len;
234 reserve( new_len );
235 }
236 }
237
238 long size() const { return m_length; }
243
248
250 void setMode( Mode m ) {
251 m_mode = m;
252 m_pointer = 0;
253 m_containedLinks.erase( m_containedLinks.begin(), m_containedLinks.end() );
255 }
256
258 bool isReading() const { return m_mode == READING; }
259
261 bool isWriting() const { return m_mode == WRITING; }
263 long buffPointer() const { return m_pointer; }
265 void setBuffPointer( long ptr ) { m_pointer = ptr; }
267 void setAnalyzer( AnalyzeFunction fun = nullptr ) { m_analyzer = fun; }
269 void swapToBuffer( const void* source, int siz );
270
272 void swapFromBuffer( void* target, int siz );
273
275 StreamBuffer& writeBytes( const char* str, long len ) {
276 extend( m_pointer + len + 4 );
277 *this << len;
278 std::copy_n( str, len, data() + buffPointer() );
279 m_pointer += len;
280 return *this;
281 }
282
283 void getIdentifiedLink( DataObject*& pObject, long& hint ) {
285 pObject = l.first;
286 hint = l.second;
287 m_identifiedLinks.pop_back();
288 }
289 void addIdentifiedLink( const DataObject* pObject, long hint ) {
290 m_identifiedLinks.push_back( IdentifiedLink( (DataObject*)pObject, hint ) );
291 }
292
293 void getContainedLink( ContainedObject*& pObject, long& hint, long& link ) {
295 pObject = l.first;
296 hint = l.second;
297 link = l.third;
298 m_containedLinks.pop_back();
299 }
300 void addContainedLink( const ContainedObject* pObject, long hint, long link ) {
301 m_containedLinks.push_back( ContainedLink( (ContainedObject*)pObject, hint, link ) );
302 }
303
304#ifdef USE_STREAM_ANALYSER
305# define STREAM_ANALYSE( data, len ) \
306 if ( 0 != m_analyzer ) m_analyzer( &data, len, typeid( data ) )
307#else
308# define STREAM_ANALYSE( data, len )
309#endif
310
311// Implement streamer macros for primivive data types.
312#define IMPLEMENT_STREAMER( TYPE ) \
313 /* Output Streamer */ \
314 StreamBuffer& operator<<( TYPE data ) { \
315 swapToBuffer( &data, sizeof( data ) ); \
316 STREAM_ANALYSE( data, sizeof( data ) ); \
317 return *this; \
318 } \
319 /* Input Streamer */ \
320 StreamBuffer& operator>>( TYPE& data ) { \
321 swapFromBuffer( &data, sizeof( data ) ); \
322 return *this; \
323 }
324// RootCint does not understand this macro....
325// But we can easily live without it!
326#undef IMPLEMENT_STREAMER
327
330 swapToBuffer( &data, sizeof( data ) );
331 STREAM_ANALYSE( data, sizeof( data ) );
332 return *this;
333 }
334
335 StreamBuffer& operator>>( long long& data ) {
336 swapFromBuffer( &data, sizeof( data ) );
337 return *this;
338 }
339
341 swapToBuffer( &data, sizeof( data ) );
342 STREAM_ANALYSE( data, sizeof( data ) );
343 return *this;
344 }
345
347 swapFromBuffer( &data, sizeof( data ) );
348 return *this;
349 }
350
351 StreamBuffer& operator<<( unsigned int data ) {
352 swapToBuffer( &data, sizeof( data ) );
353 STREAM_ANALYSE( data, sizeof( data ) );
354 return *this;
355 }
356
357 StreamBuffer& operator>>( unsigned int& data ) {
358 swapFromBuffer( &data, sizeof( data ) );
359 return *this;
360 }
361
363 swapToBuffer( &data, sizeof( data ) );
364 STREAM_ANALYSE( data, sizeof( data ) );
365 return *this;
366 }
367
369 swapFromBuffer( &data, sizeof( data ) );
370 return *this;
371 }
372
373 StreamBuffer& operator<<( unsigned long data ) {
374 swapToBuffer( &data, sizeof( data ) );
375 STREAM_ANALYSE( data, sizeof( data ) );
376 return *this;
377 }
378
379 StreamBuffer& operator>>( unsigned long& data ) {
380 swapFromBuffer( &data, sizeof( data ) );
381 return *this;
382 }
383
385 swapToBuffer( &data, sizeof( data ) );
386 STREAM_ANALYSE( data, sizeof( data ) );
387 return *this;
388 }
389
391 swapFromBuffer( &data, sizeof( data ) );
392 return *this;
393 }
394
395 StreamBuffer& operator<<( unsigned short data ) {
396 swapToBuffer( &data, sizeof( data ) );
397 STREAM_ANALYSE( data, sizeof( data ) );
398 return *this;
399 }
400
401 StreamBuffer& operator>>( unsigned short& data ) {
402 swapFromBuffer( &data, sizeof( data ) );
403 return *this;
404 }
405
407 swapToBuffer( &data, sizeof( data ) );
408 STREAM_ANALYSE( data, sizeof( data ) );
409 return *this;
410 }
411
413 swapFromBuffer( &data, sizeof( data ) );
414 return *this;
415 }
416
417 StreamBuffer& operator<<( unsigned char data ) {
418 swapToBuffer( &data, sizeof( data ) );
419 STREAM_ANALYSE( data, sizeof( data ) );
420 return *this;
421 }
422
423 StreamBuffer& operator>>( unsigned char& data ) {
424 swapFromBuffer( &data, sizeof( data ) );
425 return *this;
426 }
427
429 swapToBuffer( &data, sizeof( data ) );
430 STREAM_ANALYSE( data, sizeof( data ) );
431 return *this;
432 }
433
435 swapFromBuffer( &data, sizeof( data ) );
436 return *this;
437 }
438
440 swapToBuffer( &data, sizeof( data ) );
441 STREAM_ANALYSE( data, sizeof( data ) );
442 return *this;
443 }
444
446 swapFromBuffer( &data, sizeof( data ) );
447 return *this;
448 }
449
451 long i, len;
452 *this >> len;
453 for ( i = 0, data[0] = 0; i < len; i++ ) { data[i] = m_buffer[m_pointer++]; }
454 return *this;
455 }
456
457 StreamBuffer& operator<<( const char* data ) {
458 const char* ptr = 0 == data ? "" : data;
459 size_t len = strlen( ptr ) + 1;
460 if ( 0 == m_analyzer )
461 writeBytes( ptr, len );
462 else { STREAM_ANALYSE( data, len ); }
463 return *this;
464 }
465
466 StreamBuffer& operator>>( std::string& data ) {
467 long i, len;
468 *this >> len;
469 for ( i = 0, data = ""; i < len; i++ ) { data.append( 1, m_buffer[m_pointer++] ); }
470 return *this;
471 }
472
473 StreamBuffer& operator<<( const std::string& data ) {
474 if ( 0 == m_analyzer ) {
475 const char* ptr = data.c_str();
476 long len = data.length();
477 writeBytes( ptr, len );
478 } else {
479 STREAM_ANALYSE( data, sizeof( data ) );
480 }
481 return *this;
482 }
483
489 template <class TYPE>
490 StreamBuffer& operator>>( TYPE*& refpObject ) {
491 return getObjectPointer( refpObject, refpObject );
492 }
493
501 STREAM_ANALYSE( pObject, sizeof( pObject ) );
502 addContainedLink( pObject, INVALID, INVALID );
503 return *this;
504 }
505
512 StreamBuffer& operator<<( const DataObject* pObject ) {
513 STREAM_ANALYSE( pObject, sizeof( pObject ) );
514 addIdentifiedLink( pObject, INVALID );
515 return *this;
516 }
517
524 void serialize( DataIO& ioObject ) {
525 ioObject.serialize( *this );
526 m_pointer = 0;
527 }
528};
529
530#undef STREAM_ANALYSE
531
534 switch ( siz ) {
535 case 1:
536 return SINGLE_BYTE;
537 default:
538#if defined( __alpha ) && !defined( __VMS )
539 // return m_swapEnabled ? SWAP : NOSWAP;
540 return NOSWAP;
541#elif defined( __sun ) && defined( __SVR4 ) && defined( __i386 )
542 // return m_swapEnabled ? SWAP : NOSWAP;
543 return NOSWAP;
544#elif defined( __APPLE__ )
545 // return m_swapEnabled ? SWAP : NOSWAP;
546 return SWAP;
547#elif defined( __linux ) && !defined( __powerpc )
548 // return m_swapEnabled ? SWAP : NOSWAP;
549 return NOSWAP;
550#else
551 return m_swapEnabled ? SWAP : NOSWAP;
552// return NOSWAP;
553#endif
554 }
555}
556
558inline void StreamBuffer::swapToBuffer( const void* source, int siz ) {
559 char buff[8], *tar, *src = (char*)source;
560 extend( m_pointer + siz );
561 tar = m_buffer + m_pointer;
562 switch ( swapBuffer( siz ) ) {
563 case SINGLE_BYTE:
564 *tar = *src;
565 break;
566 case SWAP:
567#ifdef __APPLE__
568 for ( int i = 0, j = siz - 1; i < siz; i++, j-- ) tar[j] = src[i];
569#else
570 ::swab( src, buff, siz );
571#endif
572 src = buff;
573 [[fallthrough]];
574 case NOSWAP:
575 std::copy_n( src, siz, tar );
576 break;
577 default:
578 break;
579 }
580 m_pointer += siz;
581}
582
584inline void StreamBuffer::swapFromBuffer( void* target, int siz ) {
585 char* tar = (char*)target;
586 char* src = m_buffer + m_pointer;
587 switch ( swapBuffer( siz ) ) {
588 case SINGLE_BYTE:
589 *tar = *src;
590 break;
591 case SWAP:
592#ifdef __APPLE__
593 for ( int i = 0, j = siz - 1; i < siz; i++, j-- ) tar[j] = src[i];
594#else
595 ::swab( src, tar, siz );
596#endif
597 break;
598 case NOSWAP:
599 std::copy_n( src, siz, tar );
600 break;
601 default:
602 break;
603 }
604 m_pointer += siz;
605}
606
607// Output serialize a vector of items
608template <class T>
609inline StreamBuffer& operator<<( StreamBuffer& s, const std::vector<T>& v ) {
610 s << v.size();
611 for ( const auto& i : v ) s << i;
612 return s;
613}
614
615// Input serialize a vector of items
616template <class T>
617inline StreamBuffer& operator>>( StreamBuffer& s, std::vector<T>& v ) {
618 long i, len;
619 s >> len;
620 v.clear();
621 for ( i = 0; i < len; i++ ) {
622 T temp;
623 s >> temp;
624 v.push_back( temp );
625 }
626 return s;
627}
628
629// Output serialize a list of items
630template <class T>
631inline StreamBuffer& operator<<( StreamBuffer& s, const std::list<T>& l ) {
632 s << l.size();
633 for ( const auto& i : l ) s << i;
634 return s;
635}
636
637// Input serialize a list of items
638template <class T>
639inline StreamBuffer& operator>>( StreamBuffer& s, std::list<T>& l ) {
640 long len;
641 s >> len;
642 l.clear();
643 for ( long i = 0; i < len; i++ ) {
644 T temp;
645 s >> temp;
646 l.push_back( temp );
647 }
648 return s;
649}
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 & 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 & 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.