CARMA C++
Serializable.h
Go to the documentation of this file.
1 #ifndef SERIALIZABLE_H
2 #define SERIALIZABLE_H
3 
4 #include <netinet/in.h>
5 #include <iostream>
6 #include <vector>
7 #include <complex>
8 #include <iostream>
9 #include <string.h>
10 
11 #include "carma/util/ByteBuffer.h"
12 #include "carma/correlator/lib/CorrelatorPolarization.h"
13 
19 namespace carma {
20  namespace util {
21 
32  class Serializable {
33  public:
34  explicit Serializable( ) { }
35  virtual ~Serializable( ) { }
36 
42  void serialIntoByteVec( ::std::vector< char > & byteVec ) const;
43 
44  void serialIntoByteBuffer( ByteBuffer & byteBuffer ) const;
45 
46  void serialIntoByteArray( char * byteArray,
47  int byteArraySize,
48  int * totalSerialBytes ) const;
49 
50  int getTotalSerialBytes( ) const;
51 
57  void deserial( const char * byteArray, int byteArraySize );
58  void deserial( const ::std::vector< char > & byteVec );
59  void deserial( const ByteBuffer & byteBuffer );
60 
64  void serialize( char * const byteArray,
65  int * const offset ) const;
66 
67  protected:
68 
72  virtual int getSizeInBytes( ) const = 0;
73 
78  virtual void mySerialize( char * byteArray,
79  int * offset ) const = 0;
80 
89  virtual void deserializeVer0( const char * byteArray,
90  int * offset,
91  int byteArraySize ) = 0;
92 
93  virtual void deserializeVer1( const char * byteArray,
94  int * offset,
95  int byteArraySize ) = 0;
96 
105  virtual void deserializeSwapVer0( const char * byteArray,
106  int * offset,
107  int byteArraySize ) = 0;
108 
109  virtual void deserializeSwapVer1( const char * byteArray,
110  int * offset,
111  int byteArraySize ) = 0;
112 
113  template < typename T >
114  static void pack( const ::std::vector< T > & tmpv,
115  char * byteArray,
116  int * offset );
117 
118  template < typename T >
119  static void pack( const T tmp,
120  char * byteArray,
121  int * offset );
122 
123  template < typename T >
124  static void unpack( T & val,
125  const char * byteArray,
126  int * offset,
127  int byteArraySize );
128 
129  template < typename T >
130  static void unpack( ::std::vector< T > & tmpv,
131  const char * byteArray,
132  int * offset,
133  int byteArraySize );
134 
135  static void unpackSwap(char& val,
136  const char * byteArray,
137  int* offset,
138  int byteArraySize );
139 
140  static void unpackSwap(bool& val,
141  const char * byteArray,
142  int* offset,
143  int byteArraySize );
144 
145  static void unpackSwap(short& val,
146  const char * byteArray,
147  int* offset,
148  int byteArraySize );
149 
150  static void unpackSwap(int& val,
151  const char * byteArray,
152  int* offset,
153  int byteArraySize );
154 
155  static void unpackSwap(long& val,
156  const char * byteArray,
157  int* offset,
158  int byteArraySize );
159 
160  static void unpackSwap(float& val,
161  const char * byteArray,
162  int* offset,
163  int byteArraySize );
164 
165  static void unpackSwap(double& val,
166  const char * byteArray,
167  int* offset,
168  int byteArraySize );
169 
170  static void unpackSwap( ::std::complex< float > & tmpv,
171  const char * byteArray,
172  int * offset,
173  int byteArraySize );
174 
175  static void unpackSwap( ::std::vector< short > & tmpv,
176  const char * byteArray,
177  int * offset,
178  int byteArraySize );
179 
180  static void unpackSwap( ::std::vector< int > & tmpv,
181  const char * byteArray,
182  int * offset,
183  int byteArraySize );
184 
185  static void unpackSwap( ::std::vector< float > & tmpv,
186  const char * byteArray,
187  int * offset,
188  int byteArraySize );
189 
190  static void unpackSwap( ::std::vector< ::std::complex< float > > & tmpv,
191  const char * byteArray,
192  int * offset,
193  int byteArraySize );
194 
195  static void unpackSwap( unsigned int & tmpv, const char * byteArray,
196  int* offset,
197  int byteArraySize );
198 
199  static void unpackSwap( carma::correlator::lib::Polarization & val,
200  const char * byteArray,
201  int* offset,
202  int byteArraySize );
203 
204  static int32_t getVersion();
205 
206  static int32_t version_;
207  // These methods convert floats and doubles to network byte order.
208  // It's required that the sizeof(float) = sizeof(long) and
209  // sizeof(double) = 2 * sizeof(long); I didn't put check's in these
210  // routines as I wanted to maximize speed for now.
211  private:
212 
217  static bool isLittleEndian( );
218 
219  static void swapAnyBytes( void * in, size_t size );
220 
221  template < typename T >
222  static T swapBytes( T val );
223 
224  static void throwByteArrayTooSmallError( int neededBytes,
225  int availBytes );
226 
227  static void throwByteArrayOverrunError( int bufferSize,
228  int finalOffset );
229 
230  static void preemptivelyCheckForByteArrayOverrun( int maxBufferSize,
231  int futureOffset );
232 
233  }; // class Serializable
234  } // End namespace util
235 } // End namespace carma
236 
237 inline bool
238 carma::util::Serializable::isLittleEndian( )
239 {
240  const int a = 5;
241  const int b = htonl(a);
242  if (a == b) // big-endian
243  return false;
244  else // little-endian
245  return true;
246 }
247 
248 
249 inline void
250 carma::util::Serializable::swapAnyBytes( void * const in,
251  const size_t size )
252 {
253  char * const tmp = static_cast< char * >( in );
254  const size_t halfSize = (size >> 1);
255  for ( size_t i = 0; i < halfSize; ++i ) {
256  const size_t j = size - 1 - i;
257  const char t = tmp[i];
258  tmp[i] = tmp[j];
259  tmp[j] = t;
260  }
261 }
262 
263 
264 template < typename T >
265 inline T
266 carma::util::Serializable::swapBytes( T val )
267 {
268  T tmp = val; // Make a copy so we don't overwrite original
269  swapAnyBytes( static_cast< void * >( &tmp ), sizeof( T ) );
270 
271  return tmp;
272 }
273 
274 
275 template < typename T >
276 inline void
277 carma::util::Serializable::pack( const ::std::vector< T > & tmpv,
278  char * const byteArray,
279  int * offset )
280 {
281  const size_t size = tmpv.size() * sizeof( T );
282  memcpy(&(byteArray[*offset]), &tmpv[0], size);
283  *offset += size;
284 }
285 
286 
287 template < typename T >
288 inline void
289 carma::util::Serializable::pack( const T tmp,
290  char * const byteArray,
291  int * const offset )
292 {
293  const size_t size = sizeof( T );
294  memcpy( &(byteArray[*offset]), &tmp, size );
295  *offset += size;
296 }
297 
298 
299 template < typename T >
300 inline void
301 carma::util::Serializable::unpack( T & val,
302  const char * const byteArray,
303  int * const offset,
304  const int byteArraySize )
305 {
306  const int size = sizeof( val );
307  preemptivelyCheckForByteArrayOverrun( byteArraySize, *offset + size );
308  memcpy( &val, &(byteArray[*offset]), size );
309  *offset += size;
310 }
311 
312 
313 template < typename T >
314 inline void
315 carma::util::Serializable::unpack( ::std::vector< T > & tmpv,
316  const char * const byteArray,
317  int * const offset,
318  const int byteArraySize )
319 {
320  const int size = tmpv.size() * sizeof( T );
321  preemptivelyCheckForByteArrayOverrun( byteArraySize, *offset + size );
322  memcpy(&tmpv[0], &(byteArray[*offset]), size);
323  *offset += size;
324 }
325 
326 
327 inline void
328 carma::util::Serializable::unpackSwap( char& val,
329  const char * const byteArray,
330  int * const offset,
331  const int byteArraySize )
332 {
333  unpack(val, byteArray, offset, byteArraySize );
334 }
335 
336 
337 inline void
338 carma::util::Serializable::unpackSwap(bool& val,
339  const char * const byteArray,
340  int * const offset,
341  const int byteArraySize )
342 {
343  unpack(val, byteArray, offset, byteArraySize );
344 }
345 
346 
347 inline void
348 carma::util::Serializable::unpackSwap(short& val,
349  const char * const byteArray,
350  int * const offset,
351  const int byteArraySize )
352 {
353  preemptivelyCheckForByteArrayOverrun( byteArraySize, *offset + sizeof(val) );
354  memcpy(&val, &(byteArray[*offset]), sizeof(val));
355  val = swapBytes(val);
356  *offset += sizeof(val);
357 }
358 
359 
360 inline void
361 carma::util::Serializable::unpackSwap(int& val,
362  const char * const byteArray,
363  int * const offset,
364  const int byteArraySize )
365 {
366  long lval = static_cast< long >(val);
367  preemptivelyCheckForByteArrayOverrun( byteArraySize, *offset + sizeof(lval));
368  memcpy(&lval, &(byteArray[*offset]), sizeof(lval));
369  lval = swapBytes(lval);
370  val = static_cast< int >(lval);
371  *offset += sizeof(lval);
372 }
373 
374 inline void
375 carma::util::Serializable::unpackSwap(unsigned int& val,
376  const char * const byteArray,
377  int * const offset,
378  const int byteArraySize )
379 {
380  long lval = static_cast< long >(val);
381  preemptivelyCheckForByteArrayOverrun( byteArraySize, *offset + sizeof(lval));
382  memcpy(&lval, &(byteArray[*offset]), sizeof(lval));
383  lval = swapBytes(lval);
384  val = static_cast< int >(lval);
385  *offset += sizeof(lval);
386 }
387 
388 inline void
389 carma::util::Serializable::unpackSwap(long& val,
390  const char * const byteArray,
391  int * const offset,
392  const int byteArraySize )
393 {
394  preemptivelyCheckForByteArrayOverrun( byteArraySize, *offset + sizeof(val));
395  memcpy(&val, &(byteArray[*offset]), sizeof(val));
396  val = swapBytes(val);
397  *offset += sizeof(val);
398 }
399 
400 
401 inline void
402 carma::util::Serializable::unpackSwap(float& val,
403  const char * const byteArray,
404  int * const offset,
405  const int byteArraySize )
406 {
407  preemptivelyCheckForByteArrayOverrun( byteArraySize, *offset + sizeof(val));
408  memcpy(&val, &(byteArray[*offset]), sizeof(val));
409  val = swapBytes(val);
410  *offset += sizeof(val);
411 }
412 
413 inline void
414 carma::util::Serializable::unpackSwap(double& val,
415  const char * const byteArray,
416  int * const offset,
417  const int byteArraySize )
418 {
419  preemptivelyCheckForByteArrayOverrun( byteArraySize, *offset + sizeof(val));
420  memcpy(&val, &(byteArray[*offset]), sizeof(val));
421  val = swapBytes(val);
422  *offset += sizeof(val);
423 }
424 
425 
426 inline void
427 carma::util::Serializable::unpackSwap(std::complex<float>& tmpv,
428  const char * const byteArray,
429  int * const offset,
430  const int byteArraySize )
431 {
432  int size = sizeof(std::complex<float>);
433  int size2 = static_cast< int >(size * .5);
434 
435  float real;
436  float imag;
437 
438  preemptivelyCheckForByteArrayOverrun( byteArraySize, *offset + size );
439 
440  memcpy(&real, &(byteArray[*offset]), size2);
441  real = swapBytes(real);
442  *offset += size2;
443  memcpy(&imag, &(byteArray[*offset]), size2);
444  imag = swapBytes(imag);
445  *offset += size2;
446 
447  tmpv = std::complex<float>(real, imag);
448 }
449 
450 
451 inline void
452 carma::util::Serializable::unpackSwap(std::vector<short>& tmpv,
453  const char * const byteArray,
454  int * const offset,
455  const int byteArraySize )
456 {
457  int size = tmpv.size() * sizeof(short);
458  preemptivelyCheckForByteArrayOverrun( byteArraySize, *offset + size );
459  memcpy(&tmpv[0], &(byteArray[*offset]), size);
460  for (unsigned int idx = 0; idx < tmpv.size(); ++idx)
461  tmpv[idx] = swapBytes(tmpv[idx]);
462  *offset += size;
463 }
464 
465 
466 inline void
467 carma::util::Serializable::unpackSwap(std::vector<int>& tmpv,
468  const char * const byteArray,
469  int * const offset,
470  const int byteArraySize )
471 {
472  int size = tmpv.size() * sizeof(int);
473  preemptivelyCheckForByteArrayOverrun( byteArraySize, *offset + size );
474  memcpy(&tmpv[0], &(byteArray[*offset]), size);
475  for (unsigned int idx = 0; idx < tmpv.size(); ++idx)
476  tmpv[idx] = swapBytes(tmpv[idx]);
477  *offset += size;
478 }
479 
480 
481 inline void
482 carma::util::Serializable::unpackSwap(std::vector<float>& tmpv,
483  const char * const byteArray,
484  int * const offset,
485  const int byteArraySize )
486 {
487  int size = tmpv.size() * sizeof(float);
488  preemptivelyCheckForByteArrayOverrun( byteArraySize, *offset + size );
489  memcpy(&tmpv[0], &(byteArray[*offset]), size);
490  for (unsigned int idx = 0; idx < tmpv.size(); ++idx)
491  tmpv[idx] = swapBytes(tmpv[idx]);
492  *offset += size;
493 }
494 
495 
496 inline void
497 carma::util::Serializable::unpackSwap(std::vector<std::complex<float> >& tmpv,
498  const char * const byteArray,
499  int * const offset,
500  const int byteArraySize )
501 {
502  int length = tmpv.size();
503  int size = length * sizeof( std::complex<float> );
504  int size2 = sizeof(float);
505 
506  preemptivelyCheckForByteArrayOverrun( byteArraySize, *offset + size );
507 
508  float real;
509  float imag;
510  for (int idx = 0; idx < length; ++idx) {
511  memcpy(&real, &(byteArray[*offset]), size2);
512  real = swapBytes(real);
513  *offset += size2;
514  memcpy(&imag, &(byteArray[*offset]), size2);
515  imag = swapBytes(imag);
516  *offset += size2;
517  tmpv[idx] = std::complex<float>(real, imag);
518  }
519 }
520 
521 
522 inline void
523 carma::util::Serializable::unpackSwap( carma::correlator::lib::Polarization& val,
524  const char * const byteArray,
525  int * const offset,
526  const int byteArraySize )
527 {
528  unpack(val, byteArray, offset, byteArraySize );
529 }
530 
531 
532 inline void
533 carma::util::Serializable::deserial( const char * const byteArray,
534  const int byteArraySize )
535 {
536  if ( byteArraySize == 0 )
537  throwByteArrayOverrunError( byteArraySize, 1 );
538 
539  int offset = 1;
540  if ( byteArray[0] == isLittleEndian() ) {
541  unpack( version_, byteArray, &offset, byteArraySize );
542  switch ( version_ ) {
543  case 0:
544  deserializeVer0( byteArray, &offset, byteArraySize );
545  break;
546  case 1:
547  case 2:
548  deserializeVer1( byteArray, &offset, byteArraySize );
549  break;
550  }
551  } else {
552  unpackSwap( version_, byteArray, &offset, byteArraySize );
553  switch ( version_ ) {
554  case 0:
555  deserializeSwapVer0( byteArray, &offset, byteArraySize );
556  break;
557  case 1:
558  case 2:
559  deserializeSwapVer1( byteArray, &offset, byteArraySize );
560  break;
561  }
562  }
563 }
564 
565 inline void
566 carma::util::Serializable::deserial( const ::std::vector< char > & byteVec )
567 {
568  deserial( &(byteVec[0]), byteVec.size() );
569 }
570 
571 
572 inline void
573 carma::util::Serializable::deserial( const ByteBuffer & byteBuffer )
574 {
575  deserial( byteBuffer.get(), byteBuffer.size() );
576 }
577 
578 
579 inline int
580 carma::util::Serializable::getTotalSerialBytes( ) const
581 {
582  return (1 + sizeof( long ) + getSizeInBytes());
583 }
584 
585 
586 inline void
588  ::std::vector< char > & byteVec ) const
589 {
590  byteVec.resize( getTotalSerialBytes() );
591 
592  char * const byteArray = &(byteVec[0]);
593 
594  // first byte = true if data is in little endian
595  byteArray[0] = isLittleEndian();
596 
597  int offset = 1;
598 
599  // next comes the version tag
600  const int32_t version = 2;
601  pack( version, byteArray, &offset );
602 
603  // finally the data
604  mySerialize( byteArray, &offset );
605 }
606 
607 
608 inline void
609 carma::util::Serializable::serialIntoByteBuffer(
610  ByteBuffer & byteBuffer ) const
611 {
612  byteBuffer.destructiveResize( getTotalSerialBytes() );
613 
614  char * const byteArray = byteBuffer.get();
615 
616  // first byte = true if data is in little endian
617  byteArray[0] = isLittleEndian();
618 
619  int offset = 1;
620 
621  // next comes the version tag
622  const int32_t version = 2;
623  pack( version, byteArray, &offset );
624 
625  // finally the data
626  mySerialize( byteArray, &offset );
627 }
628 
629 
630 inline void
631 carma::util::Serializable::serialIntoByteArray(
632  char * const byteArray,
633  const int byteArraySize,
634  int * const totalSerialBytes ) const
635 {
636  const int totalNeededBytes = getTotalSerialBytes();
637 
638  if ( totalNeededBytes > byteArraySize ) {
639  throwByteArrayTooSmallError( totalNeededBytes, byteArraySize );
640  } else {
641  // first byte = true if data is in little endian
642  byteArray[0] = isLittleEndian();
643 
644  int offset = 1;
645 
646  // next comes the version tag
647  const int32_t version = 2;
648  pack( version, byteArray, &offset );
649 
650  // finally the data
651  mySerialize( byteArray, &offset );
652 
653  if ( totalSerialBytes != 0 )
654  *totalSerialBytes = totalNeededBytes;
655  }
656 }
657 
658 
659 inline void
660 carma::util::Serializable::serialize( char * const byteArray,
661  int * const offset ) const
662 {
663  mySerialize( byteArray, offset );
664 }
665 
666 
667 inline void
668 carma::util::Serializable::preemptivelyCheckForByteArrayOverrun(
669  const int maxBufferSize,
670  const int futureOffset )
671 {
672  if ( futureOffset > maxBufferSize )
673  throwByteArrayOverrunError( maxBufferSize,
674  futureOffset );
675 }
676 
677 #endif
char * get() const
Get the present pointer to the buffer.
Definition: ByteBuffer.h:95
Abstract Class used to allow object to serialize themselves into a byte array.
Definition: Serializable.h:32
void serialize(char *const byteArray, int *const offset) const
Write objects data members into a byte array.
Definition: Serializable.h:660
virtual void deserializeSwapVer0(const char *byteArray, int *offset, int byteArraySize)=0
Called to continue the reconstruction of member objects from the byte Array.
virtual int getSizeInBytes() const =0
Return size in bytes of object.
virtual void deserializeVer0(const char *byteArray, int *offset, int byteArraySize)=0
Called to continue the reconstruction of member objects from the byte Array.
void destructiveResize(size_t count)
Resize the buffer.
Definition: ByteBuffer.h:124
void serialIntoByteVec(::std::vector< char > &byteVec) const
Write objects data members into a byte vector.
Definition: Serializable.h:587
void deserial(const char *byteArray, int byteArraySize)
Call to initiate the reconstruction of the object from the byte Array.
Definition: Serializable.h:533
virtual void mySerialize(char *byteArray, int *offset) const =0
Called by serialize().
Manages a (possibly destructively) resizable buffer of raw bytes.
Definition: ByteBuffer.h:16