PVData C++  8.0.6-dev
byteBuffer.h
1 /* byteBuffer.h */
2 /*
3  * Copyright information and license terms for this software can be
4  * found in the file LICENSE that is included with the distribution
5  */
6 /**
7  * @author mse
8  */
9 #ifndef BYTEBUFFER_H
10 #define BYTEBUFFER_H
11 
12 #include <string>
13 #include <cstring>
14 #include <cstdlib>
15 
16 #include <epicsEndian.h>
17 #include <shareLib.h>
18 #include <epicsAssert.h>
19 #include <compilerDependencies.h>
20 
21 #include <pv/templateMeta.h>
22 #include <pv/pvType.h>
23 #include <pv/epicsException.h>
24 
25 
26 #ifndef EPICS_ALWAYS_INLINE
27 # define EPICS_ALWAYS_INLINE inline
28 #endif
29 
30 /* various compilers provide builtins for byte order swaps.
31  * conditions based on boost endian library
32  */
33 #if defined(__clang__)
34 
35 #if __has_builtin(__builtin_bswap16)
36 #define _PVA_swap16(X) __builtin_bswap16(X)
37 #endif
38 #if __has_builtin(__builtin_bswap32)
39 #define _PVA_swap32(X) __builtin_bswap32(X)
40 #endif
41 #if __has_builtin(__builtin_bswap64)
42 #define _PVA_swap64(X) __builtin_bswap64(X)
43 #endif
44 
45 #elif defined(__GNUC__) && ((__GNUC__>4) || (__GNUC__==4 && __GNUC_MINOR__>=3))
46 
47 #if (__GNUC__>4) || (__GNUC__==4 && __GNUC_MINOR__>=8)
48 #define _PVA_swap16(X) __builtin_bswap16(X)
49 #endif
50 
51 #define _PVA_swap32(X) __builtin_bswap32(X)
52 #define _PVA_swap64(X) __builtin_bswap64(X)
53 
54 #elif defined(_MSC_VER)
55 
56 #define _PVA_swap16(X) _byteswap_ushort(X)
57 #define _PVA_swap32(X) _byteswap_ulong(X)
58 #define _PVA_swap64(X) _byteswap_uint64(X)
59 
60 #endif
61 
62 namespace epics {namespace pvData {
63 
64 namespace detail {
65 template<typename T>
66 struct asInt {
67  static EPICS_ALWAYS_INLINE T from(T v) { return v; }
68  static EPICS_ALWAYS_INLINE T to(T v) { return v; }
69 };
70 template<>
71 struct asInt<float> {
72  union pun {float f; uint32 i;};
73  static EPICS_ALWAYS_INLINE float from(uint32 v) {
74  pun P;
75  P.i = v;
76  return P.f;
77  }
78  static EPICS_ALWAYS_INLINE uint32 to(float v) {
79  pun P;
80  P.f = v;
81  return P.i;
82  }
83 };
84 template<>
85 struct asInt<double> {
86  union pun {double f; uint64 i;};
87  static EPICS_ALWAYS_INLINE double from(uint64 v) {
88  pun P;
89  P.i = v;
90  return P.f;
91  }
92  static EPICS_ALWAYS_INLINE uint64 to(double v) {
93  pun P;
94  P.f = v;
95  return P.i;
96  }
97 };
98 
99 template<int N>
100 struct swap; // no default
101 template<>
102 struct swap<1> {
103  static EPICS_ALWAYS_INLINE uint8 op(uint8 v) { return v; }
104 };
105 template<>
106 struct swap<2> {
107  static EPICS_ALWAYS_INLINE uint16 op(uint16 v) {
108 #ifdef _PVA_swap16
109  return _PVA_swap16(v);
110 #else
111  return (((v) >> 8) | ((v) << 8));
112 #endif
113  }
114 };
115 template<>
116 struct swap<4> {
117  static EPICS_ALWAYS_INLINE uint32 op(uint32 v) {
118 #ifdef _PVA_swap32
119  return _PVA_swap32(v);
120 #else
121  return ((((v) & 0xff000000) >> 24) |
122  (((v) & 0x00ff0000) >> 8) |
123  (((v) & 0x0000ff00) << 8) |
124  (((v) & 0x000000ff) << 24));
125 #endif
126  }
127 };
128 template<>
129 struct swap<8> {
130 #ifdef _PVA_swap64
131  static EPICS_ALWAYS_INLINE uint64 op(uint64 v) {
132  return _PVA_swap64(v);
133  }
134 #else
135  static inline uint64 op(uint64 v) {
136  return (((v) >> 56) |
137  (((v) >> 40) & 0x0000ff00) |
138  (((v) >> 24) & 0x00ff0000) |
139  (((v) >> 8) & 0xff000000) |
140  (((v) << 8) & ((uint64_t)0xff << 32)) |
141  (((v) << 24) & ((uint64_t)0xff << 40)) |
142  (((v) << 40) & ((uint64_t)0xff << 48)) |
143  (((v) << 56)));
144  }
145 #endif
146 };
147 
148 #undef _PVA_swap16
149 #undef _PVA_swap32
150 #undef _PVA_swap64
151 
152 /* PVD serialization doesn't pay attention to alignement,
153  * which some targets (ARM and powerpc) really care about and treat unaligned
154  * access as a fault, or with a heavy penalty (~= to a syscall).
155  *
156  * For those targets,, we will have to live with the increase
157  * in execution time and/or object code size of byte-wise copy.
158  *
159  * Treat x86 32/64 as an outlier, and assume all other targets
160  * need, or greatly benefit, from aligned access.
161  */
162 
163 #if !(defined(__x86_64__) || defined(_M_AMD64) || defined(__i386__) || defined(_M_IX86))
164 
165 template<typename T>
166 union alignu {
167  T val;
168  char bytes[sizeof(T)];
169 };
170 
171 template<typename T>
172 EPICS_ALWAYS_INLINE void store_unaligned(char *buf, T val)
173 {
174  alignu<T> A;
175  A.val = val;
176  for(unsigned i=0, N=sizeof(T); i<N; i++) {
177  buf[i] = A.bytes[i];
178  }
179 }
180 
181 template<typename T>
182 EPICS_ALWAYS_INLINE T load_unaligned(const char *buf)
183 {
184  alignu<T> A;
185  for(unsigned i=0, N=sizeof(T); i<N; i++) {
186  A.bytes[i] = buf[i];
187  }
188  return A.val;
189 }
190 
191 #else /* alignement */
192 
193 template<typename T>
194 EPICS_ALWAYS_INLINE void store_unaligned(char *buf, T val)
195 {
196  *reinterpret_cast<T*>(buf) = val;
197 }
198 
199 template<typename T>
200 EPICS_ALWAYS_INLINE T load_unaligned(const char *buf)
201 {
202  return *reinterpret_cast<const T*>(buf);
203 }
204 
205 #endif /* alignement */
206 
207 } // namespace detail
208 
209 //! Unconditional byte order swap.
210 //! defined for integer and floating point types
211 template<typename T>
213 {
214  return detail::asInt<T>::from(
215  detail::swap<sizeof(T)>::op(
216  detail::asInt<T>::to(val)));
217 }
218 
219 #define is_aligned(POINTER, BYTE_COUNT)
220  (((std::size_t)(POINTER)) % (BYTE_COUNT) == 0)
221 
222 #if defined (__GNUC__) && (__GNUC__ < 3)
223 #define GET(T) get((T*)0)
224 #else
225 #define GET(T) get<T>()
226 #endif
227 
228 /**
229  * @brief This class implements a Bytebuffer that is like the java.nio.ByteBuffer.
230  *
231  * <p>A @c BitSet is not safe for multithreaded use without
232  * external synchronization.
233  *
234  * Based on Java implementation.
235  */
236 class ByteBuffer
237 {
238 public:
239  /**
240  * Constructor.
241  *
242  * @param size The number of bytes.
243  * @param byteOrder The byte order.
244  * Must be one of EPICS_BYTE_ORDER,EPICS_ENDIAN_LITTLE,EPICS_ENDIAN_BIG.
245  */
246  ByteBuffer(std::size_t size, int byteOrder = EPICS_BYTE_ORDER) :
247  _buffer((char*)std::malloc(size)), _size(size),
250  _wrapped(false)
251  {
252  if(!_buffer)
253  throw std::bad_alloc();
254  clear();
255  }
256 
257  /**
258  * Constructor for wrapping an existing buffer.
259  * Given buffer will not be released by the ByteBuffer instance.
260  * @param buffer Existing buffer. May not be NULL.
261  * @param size The number of bytes.
262  * @param byteOrder The byte order.
263  * Must be one of EPICS_BYTE_ORDER,EPICS_ENDIAN_LITTLE,EPICS_ENDIAN_BIG.
264  */
265  ByteBuffer(char* buffer, std::size_t size, int byteOrder = EPICS_BYTE_ORDER) :
266  _buffer(buffer), _size(size),
269  _wrapped(true)
270  {
271  if(!_buffer)
272  throw std::invalid_argument("ByteBuffer can't be constructed with NULL");
273  clear();
274  }
275  /**
276  * Destructor
277  */
279  {
280  if (_buffer && !_wrapped) std::free(_buffer);
281  }
282  /**
283  * Set the byte order.
284  *
285  * @param byteOrder The byte order.
286  * Must be one of EPICS_BYTE_ORDER,EPICS_ENDIAN_LITTLE,EPICS_ENDIAN_BIG,
287  */
288  inline void setEndianess(int byteOrder)
289  {
290  _reverseEndianess = (byteOrder != EPICS_BYTE_ORDER);
291  _reverseFloatEndianess = (byteOrder != EPICS_FLOAT_WORD_ORDER);
292  }
293  /**
294  * Get the raw buffer data.
295  * @return the raw buffer data.
296  */
297  inline const char* getBuffer() const
298  {
299  return _buffer;
300  }
301  /**
302  * Makes a buffer ready for a new sequence of channel-read or relative put operations:
303  * It sets the limit to the capacity and the position to zero.
304  */
305  inline void clear()
306  {
307  _position = _buffer;
308  _limit = _buffer + _size;
309  }
310  /**
311  * Makes a buffer ready to read out previously written values.
312  *
313  * Typically _limit==_buffer+_size is the initial state, but this is not
314  * required.
315  *
316  * V _buffer V _position V _limit V _buffer+_size
317  * |_______written_______|____uninitialized___|____allocated___|
318  *
319  * becomes
320  *
321  * V _buffer/_position V _limit V _buffer+size
322  * |_______written_______|________________allocated____________|
323  */
324  inline void flip() {
325  _limit = _position;
326  _position = _buffer;
327  }
328  /**
329  * Makes a buffer ready for re-reading the data that it already contains:
330  * It leaves the limit unchanged and sets the position to zero.
331  *
332  * Note that this may allow reading of uninitialized values. flip() should be considered
333  *
334  * V _buffer V _position V _limit V _buffer+_size
335  * |_______written_______|____uninitialized___|____allocated___|
336  *
337  * becomes
338  *
339  * V _buffer/_position V _limit V _buffer+size
340  * |_______written_______|____uninitialized___|____allocated___|
341  */
342  inline void rewind() {
343  _position = _buffer;
344  }
345  /**
346  * Returns the current position.
347  * @return The current position in the raw data.
348  */
349  inline std::size_t getPosition() const
350  {
351  return _position - _buffer;
352  }
353  /**
354  * Sets the buffer position.
355  * If the mark is defined and larger than the new position then it is discarded.
356  *
357  * @param pos The offset into the raw buffer.
358  * The new position value; must be no larger than the current limit
359  */
360  inline void setPosition(std::size_t pos)
361  {
362  assert(pos<=_size);
363  _position = _buffer + pos;
364  assert(_position<=_limit);
365  }
366  /**
367  * Returns this buffer's limit.
368  *
369  * @return The offset into the raw buffer.
370  */
371  inline std::size_t getLimit() const
372  {
373  return _limit - _buffer;
374  }
375  /**
376  * Sets this buffer's limit.
377  * If the position is larger than the new limit then it is set to the new limit.s
378  * If the mark is defined and larger than the new limit then it is discarded.
379  *
380  * @param limit The new position value;
381  * must be no larger than the current limit
382  */
383  inline void setLimit(std::size_t limit)
384  {
385  assert(limit<=_size);
386  _limit = _buffer + limit;
387  assert(_position<=_limit);
388  }
389  /**
390  * Returns the number of elements between the current position and the limit.
391  *
392  * @return The number of elements remaining in this buffer.
393  */
394  inline std::size_t getRemaining() const
395  {
396  return _limit - _position;
397  }
398  /**
399  * Returns The size, i.e. capacity of the raw data buffer in bytes.
400  *
401  * @return The size of the raw data buffer.
402  */
403  EPICS_ALWAYS_INLINE std::size_t getSize() const
404  {
405  return _size;
406  }
407  /**
408  * Put the value into the raw buffer as a byte stream in the current byte order.
409  *
410  * @param value The value to be put into the byte buffer.
411  */
412  template<typename T>
413  inline void put(T value);
414  /**
415  * Put the value into the raw buffer at the specified index as a byte stream in the current byte order.
416  *
417  * @param index Offset in the byte buffer.
418  * @param value The value to be put into the byte buffer.
419  */
420  template<typename T>
421  inline void put(std::size_t index, T value) const;
422  /**
423  * Get the new object from the byte buffer. The item MUST have type @c T.
424  * The position is adjusted based on the type.
425  *
426  * @return The object.
427  */
428 #if defined (__GNUC__) && (__GNUC__ < 3)
429  template<typename T>
430  inline T get(const T*);
431 #else
432  template<typename T>
433  inline T get();
434 #endif
435  /**
436  * Get the new object from the byte buffer at the specified index.
437  * The item MUST have type @c T.
438  * The position is adjusted based on the type.
439  *
440  * @param index The location in the byte buffer.
441  * @return The object.
442  */
443  template<typename T>
444  inline T get(std::size_t index) const;
445  /**
446  * Put a sub-array of bytes into the byte buffer.
447  * The position is increased by the count.
448  *
449  * @param src The source array.
450  * @param src_offset The starting position within src.
451  * @param count The number of bytes to put into the byte buffer.
452  * Must be less than getRemaining()
453  */
454  inline void put(const char* src, std::size_t src_offset, std::size_t count) {
455  assert(count<=getRemaining());
456  memcpy(_position, src + src_offset, count);
457  _position += count;
458  }
459  /**
460  * Get a sub-array of bytes from the byte buffer.
461  * The position is increased by the count.
462  *
463  * @param dest The destination array.
464  * @param dest_offset The starting position within src.
465  * @param count The number of bytes to put into the byte buffer.
466  * Must be less than getRemaining()
467  */
468  inline void get(char* dest, std::size_t dest_offset, std::size_t count) {
469  assert(count<=getRemaining());
470  memcpy(dest + dest_offset, _position, count);
471  _position += count;
472  }
473  /**
474  * Put an array of type @c T into the byte buffer.
475  * The position is adjusted.
476  *
477  * @param values The input array.
478  * @param count The number of elements.
479  */
480  template<typename T>
481  inline void putArray(const T* values, std::size_t count);
482  /**
483  * Get an array of type @c T from the byte buffer.
484  * The position is adjusted.
485  *
486  * @param values The destination array.
487  * @param count The number of elements.
488  */
489  template<typename T>
490  inline void getArray(T* values, std::size_t count);
491  /**
492  * Is the byte order the EPICS_BYTE_ORDER
493  * @return (false,true) if (is, is not) the EPICS_BYTE_ORDER
494  */
495  template<typename T>
497  {
498  return sizeof(T)>1 && _reverseEndianess;
499  }
500  /**
501  * Put a boolean value into the byte buffer.
502  *
503  * @param value The value.
504  */
505  EPICS_ALWAYS_INLINE void putBoolean( bool value) { put< int8>(value ? 1 : 0); }
506  /**
507  * Put a byte value into the byte buffer.
508  *
509  * @param value The value.
510  */
511  EPICS_ALWAYS_INLINE void putByte ( int8 value) { put< int8>(value); }
512  /**
513  * Put a short value into the byte buffer.
514  *
515  * @param value The value.
516  */
517  EPICS_ALWAYS_INLINE void putShort ( int16 value) { put< int16>(value); }
518  /**
519  * Put an int value into the byte buffer.
520  *
521  * @param value The value.
522  */
523  EPICS_ALWAYS_INLINE void putInt ( int32 value) { put< int32>(value); }
524  /**
525  * Put a long value into the byte buffer.
526  *
527  * @param value The value.
528  */
529  EPICS_ALWAYS_INLINE void putLong ( int64 value) { put< int64>(value); }
530  /**
531  * Put a float value into the byte buffer.
532  *
533  * @param value The value.
534  */
535  EPICS_ALWAYS_INLINE void putFloat ( float value) { put< float>(value); }
536  /**
537  * Put a double value into the byte buffer.
538  *
539  * @param value The value.
540  */
541  EPICS_ALWAYS_INLINE void putDouble (double value) { put<double>(value); }
542 
543  /**
544  * Put a boolean value into the byte buffer at the specified index.
545  *
546  * @param index The offset in the byte buffer,
547  * @param value The value.
548  */
549  EPICS_ALWAYS_INLINE void putBoolean(std::size_t index, bool value) { put< int8>(index, value); }
550  /**
551  * Put a byte value into the byte buffer at the specified index.
552  *
553  * @param index The offset in the byte buffer,
554  * @param value The value.
555  */
556  EPICS_ALWAYS_INLINE void putByte (std::size_t index, int8 value) { put< int8>(index, value); }
557  /**
558  * Put a short value into the byte buffer at the specified index.
559  *
560  * @param index The offset in the byte buffer,
561  * @param value The value.
562  */
563  EPICS_ALWAYS_INLINE void putShort (std::size_t index, int16 value) { put< int16>(index, value); }
564  /**
565  * Put an int value into the byte buffer at the specified index.
566  *
567  * @param index The offset in the byte buffer,
568  * @param value The value.
569  */
570  EPICS_ALWAYS_INLINE void putInt (std::size_t index, int32 value) { put< int32>(index, value); }
571  /**
572  * Put a long value into the byte buffer at the specified index.
573  *
574  * @param index The offset in the byte buffer,
575  * @param value The value.
576  */
577  EPICS_ALWAYS_INLINE void putLong (std::size_t index, int64 value) { put< int64>(index, value); }
578  /**
579  * Put a float value into the byte buffer at the specified index.
580  *
581  * @param index The offset in the byte buffer,
582  * @param value The value.
583  */
584  EPICS_ALWAYS_INLINE void putFloat (std::size_t index, float value) { put< float>(index, value); }
585  /**
586  * Put a double value into the byte buffer at the specified index.
587  *
588  * @param index The offset in the byte buffer,
589  * @param value The value.
590  */
591  EPICS_ALWAYS_INLINE void putDouble (std::size_t index, double value) { put<double>(index, value); }
592  /**
593  * Get a boolean value from the byte buffer.
594  *
595  * @return The value.
596  */
597  EPICS_ALWAYS_INLINE bool getBoolean() { return GET( int8) != 0; }
598  /**
599  * Get a byte value from the byte buffer.
600  *
601  * @return The value.
602  */
603  EPICS_ALWAYS_INLINE int8 getByte () { return GET( int8); }
604  /**
605  * Get a short value from the byte buffer.
606  *
607  * @return The value.
608  */
609  EPICS_ALWAYS_INLINE int16 getShort () { return GET( int16); }
610  /**
611  * Get a int value from the byte buffer.
612  *
613  * @return The value.
614  */
615  EPICS_ALWAYS_INLINE int32 getInt () { return GET( int32); }
616  /**
617  * Get a long value from the byte buffer.
618  *
619  * @return The value.
620  */
621  EPICS_ALWAYS_INLINE int64 getLong () { return GET( int64); }
622  /**
623  * Get a float value from the byte buffer.
624  *
625  * @return The value.
626  */
627  EPICS_ALWAYS_INLINE float getFloat () { return GET( float); }
628  /**
629  * Get a double value from the byte buffer.
630  *
631  * @return The value.
632  */
633  EPICS_ALWAYS_INLINE double getDouble () { return GET(double); }
634  /**
635  * Get a boolean value from the byte buffer at the specified index.
636  *
637  * @param index The offset in the byte buffer.
638  * @return The value.
639  */
640  EPICS_ALWAYS_INLINE bool getBoolean(std::size_t index) { return get< int8>(index) != 0; }
641  /**
642  * Get a byte value from the byte buffer at the specified index.
643  *
644  * @param index The offset in the byte buffer.
645  * @return The value.
646  */
647  EPICS_ALWAYS_INLINE int8 getByte (std::size_t index) { return get< int8>(index); }
648  /**
649  * Get a short value from the byte buffer at the specified index.
650  *
651  * @param index The offset in the byte buffer.
652  * @return The value.
653  */
654  EPICS_ALWAYS_INLINE int16 getShort (std::size_t index) { return get< int16>(index); }
655  /**
656  * Get an int value from the byte buffer at the specified index.
657  *
658  * @param index The offset in the byte buffer.
659  * @return The value.
660  */
661  EPICS_ALWAYS_INLINE int32 getInt (std::size_t index) { return get< int32>(index); }
662  /**
663  * Get a long value from the byte buffer at the specified index.
664  *
665  * @param index The offset in the byte buffer.
666  * @return The value.
667  */
668  EPICS_ALWAYS_INLINE int64 getLong (std::size_t index) { return get< int64>(index); }
669  /**
670  * Get a float value from the byte buffer at the specified index.
671  *
672  * @param index The offset in the byte buffer.
673  * @return The value.
674  */
675  EPICS_ALWAYS_INLINE float getFloat (std::size_t index) { return get< float>(index); }
676  /**
677  * Get a boolean value from the byte buffer at the specified index.
678  *
679  * @param index The offset in the byte buffer.
680  * @return The value.
681  */
682  EPICS_ALWAYS_INLINE double getDouble (std::size_t index) { return get<double>(index); }
683 
684  // TODO remove
685  EPICS_ALWAYS_INLINE const char* getArray() const EPICS_DEPRECATED
686  {
687  return _buffer;
688  }
689 
690 
691 private:
692  char* const _buffer;
693  char* _position;
694  char* _limit;
695  const std::size_t _size;
696  bool _reverseEndianess;
697  bool _reverseFloatEndianess;
698  const bool _wrapped;
699 };
700 
701  template<>
702  EPICS_ALWAYS_INLINE bool ByteBuffer::reverse<bool>() const
703  {
704  return false;
705  }
706 
707  template<>
708  EPICS_ALWAYS_INLINE bool ByteBuffer::reverse<int8>() const
709  {
710  return false;
711  }
712 
713  template<>
714  EPICS_ALWAYS_INLINE bool ByteBuffer::reverse<uint8>() const
715  {
716  return false;
717  }
718 
719  template<>
720  EPICS_ALWAYS_INLINE bool ByteBuffer::reverse<float>() const
721  {
722  return _reverseFloatEndianess;
723  }
724 
725  template<>
726  EPICS_ALWAYS_INLINE bool ByteBuffer::reverse<double>() const
727  {
728  return _reverseFloatEndianess;
729  }
730 
731  // the following methods must come after the specialized reverse<>() methods to make pre-gcc3 happy
732 
733  template<typename T>
734  inline void ByteBuffer::put(T value)
735  {
736  assert(sizeof(T)<=getRemaining());
737 
738  if(reverse<T>())
739  value = swap<T>(value);
740 
741  detail::store_unaligned(_position, value);
742  _position += sizeof(T);
743  }
744 
745  template<typename T>
746  inline void ByteBuffer::put(std::size_t index, T value) const
747  {
748  assert(_buffer+index<=_limit);
749 
750  if(reverse<T>())
751  value = swap<T>(value);
752 
753  detail::store_unaligned(_buffer+index, value);
754  }
755 
756 #if defined (__GNUC__) && (__GNUC__ < 3)
757  template<typename T>
758  inline T ByteBuffer::get(const T*)
759 #else
760  template<typename T>
761  inline T ByteBuffer::get()
762 #endif
763  {
764  assert(sizeof(T)<=getRemaining());
765 
766  T value = detail::load_unaligned<T>(_position);
767  _position += sizeof(T);
768 
769  if(reverse<T>())
770  value = swap<T>(value);
771  return value;
772  }
773 
774  template<typename T>
775  inline T ByteBuffer::get(std::size_t index) const
776  {
777  assert(_buffer+index<=_limit);
778 
779  T value = detail::load_unaligned<T>(_buffer + index);
780 
781  if(reverse<T>())
782  value = swap<T>(value);
783  return value;
784  }
785 
786  template<typename T>
787  inline void ByteBuffer::putArray(const T* values, std::size_t count)
788  {
789  size_t n = sizeof(T)*count; // bytes
790  assert(n<=getRemaining());
791 
792  if (reverse<T>()) {
793  for(std::size_t i=0; i<count; i++) {
794  detail::store_unaligned(_position+i*sizeof(T), swap<T>(values[i]));
795  }
796  } else {
797  memcpy(_position, values, n);
798  }
799  _position += n;
800  }
801 
802  template<typename T>
803  inline void ByteBuffer::getArray(T* values, std::size_t count)
804  {
805  size_t n = sizeof(T)*count; // bytes
806  assert(n<=getRemaining());
807 
808  if (reverse<T>()) {
809  for(std::size_t i=0; i<count; i++) {
810  values[i] = swap<T>(detail::load_unaligned<T>(_position+i*sizeof(T)));
811  }
812  } else {
813  memcpy(values, _position, n);
814  }
815  _position += n;
816  }
817 
818 }}
819 #endif /* BYTEBUFFER_H */
void putShort(std::size_t index, int16 value)
Definition: byteBuffer.h:563
void putDouble(double value)
Definition: byteBuffer.h:541
void putByte(std::size_t index, int8 value)
Definition: byteBuffer.h:556
int8 getByte(std::size_t index)
Definition: byteBuffer.h:647
T get(std::size_t index) const
Definition: byteBuffer.h:775
void putInt(int32 value)
Definition: byteBuffer.h:523
void putFloat(std::size_t index, float value)
Definition: byteBuffer.h:584
void putInt(std::size_t index, int32 value)
Definition: byteBuffer.h:570
void put(std::size_t index, T value) const
Definition: byteBuffer.h:746
void getArray(T *values, std::size_t count)
Definition: byteBuffer.h:803
ByteBuffer(char *buffer, std::size_t size, int byteOrder=EPICS_BYTE_ORDER)
Definition: byteBuffer.h:265
float getFloat(std::size_t index)
Definition: byteBuffer.h:675
double getDouble(std::size_t index)
Definition: byteBuffer.h:682
void putArray(const T *values, std::size_t count)
Definition: byteBuffer.h:787
uint32_t uint32
Definition: pvType.h:99
void setLimit(std::size_t limit)
Definition: byteBuffer.h:383
uint8_t uint8
Definition: pvType.h:91
int16_t int16
Definition: pvType.h:79
void setEndianess(int byteOrder)
Definition: byteBuffer.h:288
std::size_t getRemaining() const
Definition: byteBuffer.h:394
T swap(T val)
Definition: byteBuffer.h:212
std::size_t getLimit() const
Definition: byteBuffer.h:371
void putDouble(std::size_t index, double value)
Definition: byteBuffer.h:591
bool getBoolean(std::size_t index)
Definition: byteBuffer.h:640
void putLong(std::size_t index, int64 value)
Definition: byteBuffer.h:577
std::size_t getPosition() const
Definition: byteBuffer.h:349
virtual void serialize(ByteBuffer *buffer, SerializableControl *flusher, std::size_t offset, std::size_t count) const =0
std::size_t getSize() const
Definition: byteBuffer.h:403
#define EPICS_ALWAYS_INLINE
Definition: byteBuffer.h:27
void putByte(int8 value)
Definition: byteBuffer.h:511
int64_t int64
Definition: pvType.h:87
void putShort(int16 value)
Definition: byteBuffer.h:517
void setPosition(std::size_t pos)
Definition: byteBuffer.h:360
const char * getBuffer() const
Definition: byteBuffer.h:297
int32_t int32
Definition: pvType.h:83
void putBoolean(bool value)
Definition: byteBuffer.h:505
int32 getInt(std::size_t index)
Definition: byteBuffer.h:661
ByteBuffer(std::size_t size, int byteOrder=EPICS_BYTE_ORDER)
Definition: byteBuffer.h:246
uint16_t uint16
Definition: pvType.h:95
#define GET(T)
Definition: byteBuffer.h:225
int8_t int8
Definition: pvType.h:75
void putLong(int64 value)
Definition: byteBuffer.h:529
int16 getShort(std::size_t index)
Definition: byteBuffer.h:654
void get(char *dest, std::size_t dest_offset, std::size_t count)
Definition: byteBuffer.h:468
void putFloat(float value)
Definition: byteBuffer.h:535
uint64_t uint64
Definition: pvType.h:103
void putBoolean(std::size_t index, bool value)
Definition: byteBuffer.h:549
int64 getLong(std::size_t index)
Definition: byteBuffer.h:668
void put(const char *src, std::size_t src_offset, std::size_t count)
Definition: byteBuffer.h:454