PVData C++  8.0.5
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 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 
160 #ifdef _ARCH_PPC
161 
162 template<typename T>
163 union alignu {
164  T val;
165  char bytes[sizeof(T)];
166 };
167 
168 template<typename T>
169 EPICS_ALWAYS_INLINE void store_unaligned(char *buf, T val)
170 {
171  alignu<T> A;
172  A.val = val;
173  for(unsigned i=0, N=sizeof(T); i<N; i++) {
174  buf[i] = A.bytes[i];
175  }
176 }
177 
178 template<typename T>
179 EPICS_ALWAYS_INLINE T load_unaligned(const char *buf)
180 {
181  alignu<T> A;
182  for(unsigned i=0, N=sizeof(T); i<N; i++) {
183  A.bytes[i] = buf[i];
184  }
185  return A.val;
186 }
187 
188 #else /* alignement */
189 
190 template<typename T>
191 EPICS_ALWAYS_INLINE void store_unaligned(char *buf, T val)
192 {
193  *reinterpret_cast<T*>(buf) = val;
194 }
195 
196 template<typename T>
197 EPICS_ALWAYS_INLINE T load_unaligned(const char *buf)
198 {
199  return *reinterpret_cast<const T*>(buf);
200 }
201 
202 #endif /* alignement */
203 
204 } // namespace detail
205 
206 //! Unconditional byte order swap.
207 //! defined for integer and floating point types
208 template<typename T>
210 {
211  return detail::asInt<T>::from(
212  detail::swap<sizeof(T)>::op(
213  detail::asInt<T>::to(val)));
214 }
215 
216 #define is_aligned(POINTER, BYTE_COUNT)
217  (((std::size_t)(POINTER)) % (BYTE_COUNT) == 0)
218 
219 #if defined (__GNUC__) && (__GNUC__ < 3)
220 #define GET(T) get((T*)0)
221 #else
222 #define GET(T) get<T>()
223 #endif
224 
225 /**
226  * @brief This class implements a Bytebuffer that is like the java.nio.ByteBuffer.
227  *
228  * <p>A @c BitSet is not safe for multithreaded use without
229  * external synchronization.
230  *
231  * Based on Java implementation.
232  */
233 class ByteBuffer
234 {
235 public:
236  /**
237  * Constructor.
238  *
239  * @param size The number of bytes.
240  * @param byteOrder The byte order.
241  * Must be one of EPICS_BYTE_ORDER,EPICS_ENDIAN_LITTLE,EPICS_ENDIAN_BIG.
242  */
243  ByteBuffer(std::size_t size, int byteOrder = EPICS_BYTE_ORDER) :
244  _buffer((char*)std::malloc(size)), _size(size),
247  _wrapped(false)
248  {
249  if(!_buffer)
250  throw std::bad_alloc();
251  clear();
252  }
253 
254  /**
255  * Constructor for wrapping an existing buffer.
256  * Given buffer will not be released by the ByteBuffer instance.
257  * @param buffer Existing buffer. May not be NULL.
258  * @param size The number of bytes.
259  * @param byteOrder The byte order.
260  * Must be one of EPICS_BYTE_ORDER,EPICS_ENDIAN_LITTLE,EPICS_ENDIAN_BIG.
261  */
262  ByteBuffer(char* buffer, std::size_t size, int byteOrder = EPICS_BYTE_ORDER) :
263  _buffer(buffer), _size(size),
266  _wrapped(true)
267  {
268  if(!_buffer)
269  throw std::invalid_argument("ByteBuffer can't be constructed with NULL");
270  clear();
271  }
272  /**
273  * Destructor
274  */
276  {
277  if (_buffer && !_wrapped) std::free(_buffer);
278  }
279  /**
280  * Set the byte order.
281  *
282  * @param byteOrder The byte order.
283  * Must be one of EPICS_BYTE_ORDER,EPICS_ENDIAN_LITTLE,EPICS_ENDIAN_BIG,
284  */
285  inline void setEndianess(int byteOrder)
286  {
287  _reverseEndianess = (byteOrder != EPICS_BYTE_ORDER);
288  _reverseFloatEndianess = (byteOrder != EPICS_FLOAT_WORD_ORDER);
289  }
290  /**
291  * Get the raw buffer data.
292  * @return the raw buffer data.
293  */
294  inline const char* getBuffer() const
295  {
296  return _buffer;
297  }
298  /**
299  * Makes a buffer ready for a new sequence of channel-read or relative put operations:
300  * It sets the limit to the capacity and the position to zero.
301  */
302  inline void clear()
303  {
304  _position = _buffer;
305  _limit = _buffer + _size;
306  }
307  /**
308  * Makes a buffer ready to read out previously written values.
309  *
310  * Typically _limit==_buffer+_size is the initial state, but this is not
311  * required.
312  *
313  * V _buffer V _position V _limit V _buffer+_size
314  * |_______written_______|____uninitialized___|____allocated___|
315  *
316  * becomes
317  *
318  * V _buffer/_position V _limit V _buffer+size
319  * |_______written_______|________________allocated____________|
320  */
321  inline void flip() {
322  _limit = _position;
323  _position = _buffer;
324  }
325  /**
326  * Makes a buffer ready for re-reading the data that it already contains:
327  * It leaves the limit unchanged and sets the position to zero.
328  *
329  * Note that this may allow reading of uninitialized values. flip() should be considered
330  *
331  * V _buffer V _position V _limit V _buffer+_size
332  * |_______written_______|____uninitialized___|____allocated___|
333  *
334  * becomes
335  *
336  * V _buffer/_position V _limit V _buffer+size
337  * |_______written_______|____uninitialized___|____allocated___|
338  */
339  inline void rewind() {
340  _position = _buffer;
341  }
342  /**
343  * Returns the current position.
344  * @return The current position in the raw data.
345  */
346  inline std::size_t getPosition() const
347  {
348  return _position - _buffer;
349  }
350  /**
351  * Sets the buffer position.
352  * If the mark is defined and larger than the new position then it is discarded.
353  *
354  * @param pos The offset into the raw buffer.
355  * The new position value; must be no larger than the current limit
356  */
357  inline void setPosition(std::size_t pos)
358  {
359  assert(pos<=_size);
360  _position = _buffer + pos;
361  assert(_position<=_limit);
362  }
363  /**
364  * Returns this buffer's limit.
365  *
366  * @return The offset into the raw buffer.
367  */
368  inline std::size_t getLimit() const
369  {
370  return _limit - _buffer;
371  }
372  /**
373  * Sets this buffer's limit.
374  * If the position is larger than the new limit then it is set to the new limit.s
375  * If the mark is defined and larger than the new limit then it is discarded.
376  *
377  * @param limit The new position value;
378  * must be no larger than the current limit
379  */
380  inline void setLimit(std::size_t limit)
381  {
382  assert(limit<=_size);
383  _limit = _buffer + limit;
384  assert(_position<=_limit);
385  }
386  /**
387  * Returns the number of elements between the current position and the limit.
388  *
389  * @return The number of elements remaining in this buffer.
390  */
391  inline std::size_t getRemaining() const
392  {
393  return _limit - _position;
394  }
395  /**
396  * Returns The size, i.e. capacity of the raw data buffer in bytes.
397  *
398  * @return The size of the raw data buffer.
399  */
400  EPICS_ALWAYS_INLINE std::size_t getSize() const
401  {
402  return _size;
403  }
404  /**
405  * Put the value into the raw buffer as a byte stream in the current byte order.
406  *
407  * @param value The value to be put into the byte buffer.
408  */
409  template<typename T>
410  inline void put(T value);
411  /**
412  * Put the value into the raw buffer at the specified index as a byte stream in the current byte order.
413  *
414  * @param index Offset in the byte buffer.
415  * @param value The value to be put into the byte buffer.
416  */
417  template<typename T>
418  inline void put(std::size_t index, T value) const;
419  /**
420  * Get the new object from the byte buffer. The item MUST have type @c T.
421  * The position is adjusted based on the type.
422  *
423  * @return The object.
424  */
425 #if defined (__GNUC__) && (__GNUC__ < 3)
426  template<typename T>
427  inline T get(const T*);
428 #else
429  template<typename T>
430  inline T get();
431 #endif
432  /**
433  * Get the new object from the byte buffer at the specified index.
434  * The item MUST have type @c T.
435  * The position is adjusted based on the type.
436  *
437  * @param index The location in the byte buffer.
438  * @return The object.
439  */
440  template<typename T>
441  inline T get(std::size_t index) const;
442  /**
443  * Put a sub-array of bytes into the byte buffer.
444  * The position is increased by the count.
445  *
446  * @param src The source array.
447  * @param src_offset The starting position within src.
448  * @param count The number of bytes to put into the byte buffer.
449  * Must be less than getRemaining()
450  */
451  inline void put(const char* src, std::size_t src_offset, std::size_t count) {
452  assert(count<=getRemaining());
453  memcpy(_position, src + src_offset, count);
454  _position += count;
455  }
456  /**
457  * Get a sub-array of bytes from the byte buffer.
458  * The position is increased by the count.
459  *
460  * @param dest The destination array.
461  * @param dest_offset The starting position within src.
462  * @param count The number of bytes to put into the byte buffer.
463  * Must be less than getRemaining()
464  */
465  inline void get(char* dest, std::size_t dest_offset, std::size_t count) {
466  assert(count<=getRemaining());
467  memcpy(dest + dest_offset, _position, count);
468  _position += count;
469  }
470  /**
471  * Put an array of type @c T into the byte buffer.
472  * The position is adjusted.
473  *
474  * @param values The input array.
475  * @param count The number of elements.
476  */
477  template<typename T>
478  inline void putArray(const T* values, std::size_t count);
479  /**
480  * Get an array of type @c T from the byte buffer.
481  * The position is adjusted.
482  *
483  * @param values The destination array.
484  * @param count The number of elements.
485  */
486  template<typename T>
487  inline void getArray(T* values, std::size_t count);
488  /**
489  * Is the byte order the EPICS_BYTE_ORDER
490  * @return (false,true) if (is, is not) the EPICS_BYTE_ORDER
491  */
492  template<typename T>
494  {
495  return sizeof(T)>1 && _reverseEndianess;
496  }
497  /**
498  * Put a boolean value into the byte buffer.
499  *
500  * @param value The value.
501  */
502  EPICS_ALWAYS_INLINE void putBoolean( bool value) { put< int8>(value ? 1 : 0); }
503  /**
504  * Put a byte value into the byte buffer.
505  *
506  * @param value The value.
507  */
508  EPICS_ALWAYS_INLINE void putByte ( int8 value) { put< int8>(value); }
509  /**
510  * Put a short value into the byte buffer.
511  *
512  * @param value The value.
513  */
514  EPICS_ALWAYS_INLINE void putShort ( int16 value) { put< int16>(value); }
515  /**
516  * Put an int value into the byte buffer.
517  *
518  * @param value The value.
519  */
520  EPICS_ALWAYS_INLINE void putInt ( int32 value) { put< int32>(value); }
521  /**
522  * Put a long value into the byte buffer.
523  *
524  * @param value The value.
525  */
526  EPICS_ALWAYS_INLINE void putLong ( int64 value) { put< int64>(value); }
527  /**
528  * Put a float value into the byte buffer.
529  *
530  * @param value The value.
531  */
532  EPICS_ALWAYS_INLINE void putFloat ( float value) { put< float>(value); }
533  /**
534  * Put a double value into the byte buffer.
535  *
536  * @param value The value.
537  */
538  EPICS_ALWAYS_INLINE void putDouble (double value) { put<double>(value); }
539 
540  /**
541  * Put a boolean value into the byte buffer at the specified index.
542  *
543  * @param index The offset in the byte buffer,
544  * @param value The value.
545  */
546  EPICS_ALWAYS_INLINE void putBoolean(std::size_t index, bool value) { put< int8>(index, value); }
547  /**
548  * Put a byte value into the byte buffer at the specified index.
549  *
550  * @param index The offset in the byte buffer,
551  * @param value The value.
552  */
553  EPICS_ALWAYS_INLINE void putByte (std::size_t index, int8 value) { put< int8>(index, value); }
554  /**
555  * Put a short value into the byte buffer at the specified index.
556  *
557  * @param index The offset in the byte buffer,
558  * @param value The value.
559  */
560  EPICS_ALWAYS_INLINE void putShort (std::size_t index, int16 value) { put< int16>(index, value); }
561  /**
562  * Put an int value into the byte buffer at the specified index.
563  *
564  * @param index The offset in the byte buffer,
565  * @param value The value.
566  */
567  EPICS_ALWAYS_INLINE void putInt (std::size_t index, int32 value) { put< int32>(index, value); }
568  /**
569  * Put a long value into the byte buffer at the specified index.
570  *
571  * @param index The offset in the byte buffer,
572  * @param value The value.
573  */
574  EPICS_ALWAYS_INLINE void putLong (std::size_t index, int64 value) { put< int64>(index, value); }
575  /**
576  * Put a float value into the byte buffer at the specified index.
577  *
578  * @param index The offset in the byte buffer,
579  * @param value The value.
580  */
581  EPICS_ALWAYS_INLINE void putFloat (std::size_t index, float value) { put< float>(index, value); }
582  /**
583  * Put a double value into the byte buffer at the specified index.
584  *
585  * @param index The offset in the byte buffer,
586  * @param value The value.
587  */
588  EPICS_ALWAYS_INLINE void putDouble (std::size_t index, double value) { put<double>(index, value); }
589  /**
590  * Get a boolean value from the byte buffer.
591  *
592  * @return The value.
593  */
594  EPICS_ALWAYS_INLINE bool getBoolean() { return GET( int8) != 0; }
595  /**
596  * Get a byte value from the byte buffer.
597  *
598  * @return The value.
599  */
600  EPICS_ALWAYS_INLINE int8 getByte () { return GET( int8); }
601  /**
602  * Get a short value from the byte buffer.
603  *
604  * @return The value.
605  */
606  EPICS_ALWAYS_INLINE int16 getShort () { return GET( int16); }
607  /**
608  * Get a int value from the byte buffer.
609  *
610  * @return The value.
611  */
612  EPICS_ALWAYS_INLINE int32 getInt () { return GET( int32); }
613  /**
614  * Get a long value from the byte buffer.
615  *
616  * @return The value.
617  */
618  EPICS_ALWAYS_INLINE int64 getLong () { return GET( int64); }
619  /**
620  * Get a float value from the byte buffer.
621  *
622  * @return The value.
623  */
624  EPICS_ALWAYS_INLINE float getFloat () { return GET( float); }
625  /**
626  * Get a double value from the byte buffer.
627  *
628  * @return The value.
629  */
630  EPICS_ALWAYS_INLINE double getDouble () { return GET(double); }
631  /**
632  * Get a boolean value from the byte buffer at the specified index.
633  *
634  * @param index The offset in the byte buffer.
635  * @return The value.
636  */
637  EPICS_ALWAYS_INLINE bool getBoolean(std::size_t index) { return get< int8>(index) != 0; }
638  /**
639  * Get a byte value from the byte buffer at the specified index.
640  *
641  * @param index The offset in the byte buffer.
642  * @return The value.
643  */
644  EPICS_ALWAYS_INLINE int8 getByte (std::size_t index) { return get< int8>(index); }
645  /**
646  * Get a short value from the byte buffer at the specified index.
647  *
648  * @param index The offset in the byte buffer.
649  * @return The value.
650  */
651  EPICS_ALWAYS_INLINE int16 getShort (std::size_t index) { return get< int16>(index); }
652  /**
653  * Get an int value from the byte buffer at the specified index.
654  *
655  * @param index The offset in the byte buffer.
656  * @return The value.
657  */
658  EPICS_ALWAYS_INLINE int32 getInt (std::size_t index) { return get< int32>(index); }
659  /**
660  * Get a long value from the byte buffer at the specified index.
661  *
662  * @param index The offset in the byte buffer.
663  * @return The value.
664  */
665  EPICS_ALWAYS_INLINE int64 getLong (std::size_t index) { return get< int64>(index); }
666  /**
667  * Get a float value from the byte buffer at the specified index.
668  *
669  * @param index The offset in the byte buffer.
670  * @return The value.
671  */
672  EPICS_ALWAYS_INLINE float getFloat (std::size_t index) { return get< float>(index); }
673  /**
674  * Get a boolean value from the byte buffer at the specified index.
675  *
676  * @param index The offset in the byte buffer.
677  * @return The value.
678  */
679  EPICS_ALWAYS_INLINE double getDouble (std::size_t index) { return get<double>(index); }
680 
681  // TODO remove
682  EPICS_ALWAYS_INLINE const char* getArray() const EPICS_DEPRECATED
683  {
684  return _buffer;
685  }
686 
687 
688 private:
689  char* const _buffer;
690  char* _position;
691  char* _limit;
692  const std::size_t _size;
693  bool _reverseEndianess;
694  bool _reverseFloatEndianess;
695  const bool _wrapped;
696 };
697 
698  template<>
699  EPICS_ALWAYS_INLINE bool ByteBuffer::reverse<bool>() const
700  {
701  return false;
702  }
703 
704  template<>
705  EPICS_ALWAYS_INLINE bool ByteBuffer::reverse<int8>() const
706  {
707  return false;
708  }
709 
710  template<>
711  EPICS_ALWAYS_INLINE bool ByteBuffer::reverse<uint8>() const
712  {
713  return false;
714  }
715 
716  template<>
717  EPICS_ALWAYS_INLINE bool ByteBuffer::reverse<float>() const
718  {
719  return _reverseFloatEndianess;
720  }
721 
722  template<>
723  EPICS_ALWAYS_INLINE bool ByteBuffer::reverse<double>() const
724  {
725  return _reverseFloatEndianess;
726  }
727 
728  // the following methods must come after the specialized reverse<>() methods to make pre-gcc3 happy
729 
730  template<typename T>
731  inline void ByteBuffer::put(T value)
732  {
733  assert(sizeof(T)<=getRemaining());
734 
735  if(reverse<T>())
736  value = swap<T>(value);
737 
738  detail::store_unaligned(_position, value);
739  _position += sizeof(T);
740  }
741 
742  template<typename T>
743  inline void ByteBuffer::put(std::size_t index, T value) const
744  {
745  assert(_buffer+index<=_limit);
746 
747  if(reverse<T>())
748  value = swap<T>(value);
749 
750  detail::store_unaligned(_buffer+index, value);
751  }
752 
753 #if defined (__GNUC__) && (__GNUC__ < 3)
754  template<typename T>
755  inline T ByteBuffer::get(const T*)
756 #else
757  template<typename T>
758  inline T ByteBuffer::get()
759 #endif
760  {
761  assert(sizeof(T)<=getRemaining());
762 
763  T value = detail::load_unaligned<T>(_position);
764  _position += sizeof(T);
765 
766  if(reverse<T>())
767  value = swap<T>(value);
768  return value;
769  }
770 
771  template<typename T>
772  inline T ByteBuffer::get(std::size_t index) const
773  {
774  assert(_buffer+index<=_limit);
775 
776  T value = detail::load_unaligned<T>(_buffer + index);
777 
778  if(reverse<T>())
779  value = swap<T>(value);
780  return value;
781  }
782 
783  template<typename T>
784  inline void ByteBuffer::putArray(const T* values, std::size_t count)
785  {
786  size_t n = sizeof(T)*count; // bytes
787  assert(n<=getRemaining());
788 
789  if (reverse<T>()) {
790  for(std::size_t i=0; i<count; i++) {
791  detail::store_unaligned(_position+i*sizeof(T), swap<T>(values[i]));
792  }
793  } else {
794  memcpy(_position, values, n);
795  }
796  _position += n;
797  }
798 
799  template<typename T>
800  inline void ByteBuffer::getArray(T* values, std::size_t count)
801  {
802  size_t n = sizeof(T)*count; // bytes
803  assert(n<=getRemaining());
804 
805  if (reverse<T>()) {
806  for(std::size_t i=0; i<count; i++) {
807  values[i] = swap<T>(detail::load_unaligned<T>(_position+i*sizeof(T)));
808  }
809  } else {
810  memcpy(values, _position, n);
811  }
812  _position += n;
813  }
814 
815 }}
816 #endif /* BYTEBUFFER_H */
void putShort(std::size_t index, int16 value)
Definition: byteBuffer.h:560
void putDouble(double value)
Definition: byteBuffer.h:538
void putByte(std::size_t index, int8 value)
Definition: byteBuffer.h:553
int8 getByte(std::size_t index)
Definition: byteBuffer.h:644
T get(std::size_t index) const
Definition: byteBuffer.h:772
void putInt(int32 value)
Definition: byteBuffer.h:520
void putFloat(std::size_t index, float value)
Definition: byteBuffer.h:581
void putInt(std::size_t index, int32 value)
Definition: byteBuffer.h:567
void put(std::size_t index, T value) const
Definition: byteBuffer.h:743
void getArray(T *values, std::size_t count)
Definition: byteBuffer.h:800
ByteBuffer(char *buffer, std::size_t size, int byteOrder=EPICS_BYTE_ORDER)
Definition: byteBuffer.h:262
float getFloat(std::size_t index)
Definition: byteBuffer.h:672
double getDouble(std::size_t index)
Definition: byteBuffer.h:679
void putArray(const T *values, std::size_t count)
Definition: byteBuffer.h:784
uint32_t uint32
Definition: pvType.h:99
void setLimit(std::size_t limit)
Definition: byteBuffer.h:380
uint8_t uint8
Definition: pvType.h:91
int16_t int16
Definition: pvType.h:79
void setEndianess(int byteOrder)
Definition: byteBuffer.h:285
std::size_t getRemaining() const
Definition: byteBuffer.h:391
T swap(T val)
Definition: byteBuffer.h:209
std::size_t getLimit() const
Definition: byteBuffer.h:368
void putDouble(std::size_t index, double value)
Definition: byteBuffer.h:588
bool getBoolean(std::size_t index)
Definition: byteBuffer.h:637
void putLong(std::size_t index, int64 value)
Definition: byteBuffer.h:574
std::size_t getPosition() const
Definition: byteBuffer.h:346
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:400
#define EPICS_ALWAYS_INLINE
Definition: byteBuffer.h:27
void putByte(int8 value)
Definition: byteBuffer.h:508
int64_t int64
Definition: pvType.h:87
void putShort(int16 value)
Definition: byteBuffer.h:514
void setPosition(std::size_t pos)
Definition: byteBuffer.h:357
const char * getBuffer() const
Definition: byteBuffer.h:294
int32_t int32
Definition: pvType.h:83
void putBoolean(bool value)
Definition: byteBuffer.h:502
int32 getInt(std::size_t index)
Definition: byteBuffer.h:658
ByteBuffer(std::size_t size, int byteOrder=EPICS_BYTE_ORDER)
Definition: byteBuffer.h:243
uint16_t uint16
Definition: pvType.h:95
#define GET(T)
Definition: byteBuffer.h:222
int8_t int8
Definition: pvType.h:75
void putLong(int64 value)
Definition: byteBuffer.h:526
int16 getShort(std::size_t index)
Definition: byteBuffer.h:651
void get(char *dest, std::size_t dest_offset, std::size_t count)
Definition: byteBuffer.h:465
void putFloat(float value)
Definition: byteBuffer.h:532
uint64_t uint64
Definition: pvType.h:103
void putBoolean(std::size_t index, bool value)
Definition: byteBuffer.h:546
int64 getLong(std::size_t index)
Definition: byteBuffer.h:665
void put(const char *src, std::size_t src_offset, std::size_t count)
Definition: byteBuffer.h:451