This is Unofficial EPICS BASE Doxygen Site
byteBuffer.h
Go to the documentation of this file.
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  */
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> {
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> {
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>
198 {
199  return *reinterpret_cast<const T*>(buf);
200 }
201 
202 #endif /* alignement */
203 
204 } // namespace detail
205 
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 
234 {
235 public:
243  ByteBuffer(std::size_t size, int byteOrder = EPICS_BYTE_ORDER) :
244  _buffer((char*)std::malloc(size)), _size(size),
245  _reverseEndianess(byteOrder != EPICS_BYTE_ORDER),
246  _reverseFloatEndianess(byteOrder != EPICS_FLOAT_WORD_ORDER),
247  _wrapped(false)
248  {
249  if(!_buffer)
250  throw std::bad_alloc();
251  clear();
252  }
253 
262  ByteBuffer(char* buffer, std::size_t size, int byteOrder = EPICS_BYTE_ORDER) :
263  _buffer(buffer), _size(size),
264  _reverseEndianess(byteOrder != EPICS_BYTE_ORDER),
265  _reverseFloatEndianess(byteOrder != EPICS_FLOAT_WORD_ORDER),
266  _wrapped(true)
267  {
268  if(!_buffer)
269  throw std::invalid_argument("ByteBuffer can't be constructed with NULL");
270  clear();
271  }
276  {
277  if (_buffer && !_wrapped) std::free(_buffer);
278  }
285  inline void setEndianess(int byteOrder)
286  {
287  _reverseEndianess = (byteOrder != EPICS_BYTE_ORDER);
288  _reverseFloatEndianess = (byteOrder != EPICS_FLOAT_WORD_ORDER);
289  }
294  inline const char* getBuffer() const
295  {
296  return _buffer;
297  }
302  inline void clear()
303  {
304  _position = _buffer;
305  _limit = _buffer + _size;
306  }
321  inline void flip() {
322  _limit = _position;
323  _position = _buffer;
324  }
339  inline void rewind() {
340  _position = _buffer;
341  }
346  inline std::size_t getPosition() const
347  {
348  return _position - _buffer;
349  }
357  inline void setPosition(std::size_t pos)
358  {
359  assert(pos<=_size);
360  _position = _buffer + pos;
361  assert(_position<=_limit);
362  }
368  inline std::size_t getLimit() const
369  {
370  return _limit - _buffer;
371  }
380  inline void setLimit(std::size_t limit)
381  {
382  assert(limit<=_size);
383  _limit = _buffer + limit;
384  assert(_position<=_limit);
385  }
391  inline std::size_t getRemaining() const
392  {
393  return _limit - _position;
394  }
400  EPICS_ALWAYS_INLINE std::size_t getSize() const
401  {
402  return _size;
403  }
409  template<typename T>
410  inline void put(T value);
417  template<typename T>
418  inline void put(std::size_t index, T value) const;
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 
440  template<typename T>
441  inline T get(std::size_t index) const;
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  }
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  }
477  template<typename T>
478  inline void putArray(const T* values, std::size_t count);
486  template<typename T>
487  inline void getArray(T* values, std::size_t count);
492  template<typename T>
494  {
495  return sizeof(T)>1 && _reverseEndianess;
496  }
504  inline void align(std::size_t size, char fill='\0')
505  {
506  const std::size_t k = size - 1, bufidx = (std::size_t)_position;
507  if(bufidx&k) {
508  std::size_t npad = size-(bufidx&k);
509  assert(npad<=getRemaining());
510  std::fill(_position, _position+npad, fill);
511  _position += npad;
512  }
513  }
519  EPICS_ALWAYS_INLINE void putBoolean( bool value) { put< int8>(value ? 1 : 0); }
525  EPICS_ALWAYS_INLINE void putByte ( int8 value) { put< int8>(value); }
531  EPICS_ALWAYS_INLINE void putShort ( int16 value) { put< int16>(value); }
537  EPICS_ALWAYS_INLINE void putInt ( int32 value) { put< int32>(value); }
543  EPICS_ALWAYS_INLINE void putLong ( int64 value) { put< int64>(value); }
549  EPICS_ALWAYS_INLINE void putFloat ( float value) { put< float>(value); }
555  EPICS_ALWAYS_INLINE void putDouble (double value) { put<double>(value); }
556 
563  EPICS_ALWAYS_INLINE void putBoolean(std::size_t index, bool value) { put< int8>(index, value); }
570  EPICS_ALWAYS_INLINE void putByte (std::size_t index, int8 value) { put< int8>(index, value); }
577  EPICS_ALWAYS_INLINE void putShort (std::size_t index, int16 value) { put< int16>(index, value); }
584  EPICS_ALWAYS_INLINE void putInt (std::size_t index, int32 value) { put< int32>(index, value); }
591  EPICS_ALWAYS_INLINE void putLong (std::size_t index, int64 value) { put< int64>(index, value); }
598  EPICS_ALWAYS_INLINE void putFloat (std::size_t index, float value) { put< float>(index, value); }
605  EPICS_ALWAYS_INLINE void putDouble (std::size_t index, double value) { put<double>(index, value); }
611  EPICS_ALWAYS_INLINE bool getBoolean() { return GET( int8) != 0; }
641  EPICS_ALWAYS_INLINE float getFloat () { return GET( float); }
647  EPICS_ALWAYS_INLINE double getDouble () { return GET(double); }
654  EPICS_ALWAYS_INLINE bool getBoolean(std::size_t index) { return get< int8>(index) != 0; }
661  EPICS_ALWAYS_INLINE int8 getByte (std::size_t index) { return get< int8>(index); }
668  EPICS_ALWAYS_INLINE int16 getShort (std::size_t index) { return get< int16>(index); }
675  EPICS_ALWAYS_INLINE int32 getInt (std::size_t index) { return get< int32>(index); }
682  EPICS_ALWAYS_INLINE int64 getLong (std::size_t index) { return get< int64>(index); }
689  EPICS_ALWAYS_INLINE float getFloat (std::size_t index) { return get< float>(index); }
696  EPICS_ALWAYS_INLINE double getDouble (std::size_t index) { return get<double>(index); }
697 
698  // TODO remove
700  {
701  return _buffer;
702  }
703 
704 
705 private:
706  char* const _buffer;
707  char* _position;
708  char* _limit;
709  const std::size_t _size;
710  bool _reverseEndianess;
711  bool _reverseFloatEndianess;
712  const bool _wrapped;
713 };
714 
715  template<>
716  EPICS_ALWAYS_INLINE bool ByteBuffer::reverse<bool>() const
717  {
718  return false;
719  }
720 
721  template<>
722  EPICS_ALWAYS_INLINE bool ByteBuffer::reverse<int8>() const
723  {
724  return false;
725  }
726 
727  template<>
728  EPICS_ALWAYS_INLINE bool ByteBuffer::reverse<uint8>() const
729  {
730  return false;
731  }
732 
733  template<>
734  EPICS_ALWAYS_INLINE bool ByteBuffer::reverse<float>() const
735  {
736  return _reverseFloatEndianess;
737  }
738 
739  template<>
740  EPICS_ALWAYS_INLINE bool ByteBuffer::reverse<double>() const
741  {
742  return _reverseFloatEndianess;
743  }
744 
745  // the following methods must come after the specialized reverse<>() methods to make pre-gcc3 happy
746 
747  template<typename T>
748  inline void ByteBuffer::put(T value)
749  {
750  assert(sizeof(T)<=getRemaining());
751 
752  if(reverse<T>())
753  value = swap<T>(value);
754 
755  detail::store_unaligned(_position, value);
756  _position += sizeof(T);
757  }
758 
759  template<typename T>
760  inline void ByteBuffer::put(std::size_t index, T value) const
761  {
762  assert(_buffer+index<=_limit);
763 
764  if(reverse<T>())
765  value = swap<T>(value);
766 
767  detail::store_unaligned(_buffer+index, value);
768  }
769 
770 #if defined (__GNUC__) && (__GNUC__ < 3)
771  template<typename T>
772  inline T ByteBuffer::get(const T*)
773 #else
774  template<typename T>
775  inline T ByteBuffer::get()
776 #endif
777  {
778  assert(sizeof(T)<=getRemaining());
779 
780  T value = detail::load_unaligned<T>(_position);
781  _position += sizeof(T);
782 
783  if(reverse<T>())
784  value = swap<T>(value);
785  return value;
786  }
787 
788  template<typename T>
789  inline T ByteBuffer::get(std::size_t index) const
790  {
791  assert(_buffer+index<=_limit);
792 
793  T value = detail::load_unaligned<T>(_buffer + index);
794 
795  if(reverse<T>())
796  value = swap<T>(value);
797  return value;
798  }
799 
800  template<typename T>
801  inline void ByteBuffer::putArray(const T* values, std::size_t count)
802  {
803  size_t n = sizeof(T)*count; // bytes
804  assert(n<=getRemaining());
805 
806  if (reverse<T>()) {
807  for(std::size_t i=0; i<count; i++) {
808  detail::store_unaligned(_position+i*sizeof(T), swap<T>(values[i]));
809  }
810  } else {
811  memcpy(_position, values, n);
812  }
813  _position += n;
814  }
815 
816  template<typename T>
817  inline void ByteBuffer::getArray(T* values, std::size_t count)
818  {
819  size_t n = sizeof(T)*count; // bytes
820  assert(n<=getRemaining());
821 
822  if (reverse<T>()) {
823  for(std::size_t i=0; i<count; i++) {
824  values[i] = swap<T>(detail::load_unaligned<T>(_position+i*sizeof(T)));
825  }
826  } else {
827  memcpy(values, _position, n);
828  }
829  _position += n;
830  }
831 
832 }}
833 #endif /* BYTEBUFFER_H */
int8_t int8
Definition: pvType.h:75
EPICS_ALWAYS_INLINE bool getBoolean(std::size_t index)
Definition: byteBuffer.h:654
Definition: link.h:174
#define EPICS_FLOAT_WORD_ORDER
Definition: osdWireConfig.h:60
#define assert(exp)
Declare that a condition should be true.
Definition: epicsAssert.h:70
EPICS_ALWAYS_INLINE void store_unaligned(char *buf, T val)
Definition: byteBuffer.h:191
std::tr1::shared_ptr< detail::SharedPut > put
EPICS_ALWAYS_INLINE int32 getInt(std::size_t index)
Definition: byteBuffer.h:675
static EPICS_ALWAYS_INLINE double from(uint64 v)
Definition: byteBuffer.h:87
EPICS_ALWAYS_INLINE int8 getByte()
Definition: byteBuffer.h:617
EPICS_ALWAYS_INLINE T swap(T val)
Definition: byteBuffer.h:209
EPICS_ALWAYS_INLINE float getFloat(std::size_t index)
Definition: byteBuffer.h:689
An EPICS-specific replacement for ANSI C&#39;s assert.
#define true
Definition: flexdef.h:84
ByteBuffer(char *buffer, std::size_t size, int byteOrder=EPICS_BYTE_ORDER)
Definition: byteBuffer.h:262
uint16_t uint16
Definition: pvType.h:95
int i
Definition: scan.c:967
EPICS_ALWAYS_INLINE void putInt(int32 value)
Definition: byteBuffer.h:537
const char * getBuffer() const
Definition: byteBuffer.h:294
#define GET(T)
Definition: byteBuffer.h:222
std::size_t getLimit() const
Definition: byteBuffer.h:368
EPICS_ALWAYS_INLINE void putDouble(std::size_t index, double value)
Definition: byteBuffer.h:605
Definition: memory.hpp:41
EPICS_ALWAYS_INLINE int8 getByte(std::size_t index)
Definition: byteBuffer.h:661
TODO only here because of the Lockable.
Definition: ntaggregate.cpp:16
EPICS_ALWAYS_INLINE void putBoolean(std::size_t index, bool value)
Definition: byteBuffer.h:563
Mark external symbols and entry points for shared libraries.
EPICS_ALWAYS_INLINE std::size_t getSize() const
Definition: byteBuffer.h:400
EPICS_ALWAYS_INLINE double getDouble(std::size_t index)
Definition: byteBuffer.h:696
void align(std::size_t size, char fill='\0')
Definition: byteBuffer.h:504
std::size_t getPosition() const
Definition: byteBuffer.h:346
static EPICS_ALWAYS_INLINE float from(uint32 v)
Definition: byteBuffer.h:73
static EPICS_ALWAYS_INLINE uint32 to(float v)
Definition: byteBuffer.h:78
void putArray(const T *values, std::size_t count)
Definition: byteBuffer.h:801
EPICS_ALWAYS_INLINE int32 getInt()
Definition: byteBuffer.h:629
uint64_t uint64
Definition: pvType.h:103
ByteBuffer(std::size_t size, int byteOrder=EPICS_BYTE_ORDER)
Definition: byteBuffer.h:243
void setPosition(std::size_t pos)
Definition: byteBuffer.h:357
EPICS_ALWAYS_INLINE T load_unaligned(const char *buf)
Definition: byteBuffer.h:197
EPICS_ALWAYS_INLINE void putFloat(float value)
Definition: byteBuffer.h:549
EPICS_ALWAYS_INLINE double getDouble()
Definition: byteBuffer.h:647
EPICS_ALWAYS_INLINE int16 getShort(std::size_t index)
Definition: byteBuffer.h:668
EPICS_ALWAYS_INLINE int64 getLong(std::size_t index)
Definition: byteBuffer.h:682
EPICS_ALWAYS_INLINE void putByte(int8 value)
Definition: byteBuffer.h:525
This class implements a Bytebuffer that is like the java.nio.ByteBuffer.
Definition: byteBuffer.h:233
EPICS_ALWAYS_INLINE int16 getShort()
Definition: byteBuffer.h:623
static EPICS_ALWAYS_INLINE uint16 op(uint16 v)
Definition: byteBuffer.h:107
EPICS_ALWAYS_INLINE void putInt(std::size_t index, int32 value)
Definition: byteBuffer.h:584
std::size_t getRemaining() const
Definition: byteBuffer.h:391
EPICS_ALWAYS_INLINE const char * getArray() const EPICS_DEPRECATED
Definition: byteBuffer.h:699
static uint64 op(uint64 v)
Definition: byteBuffer.h:135
int64_t int64
Definition: pvType.h:87
::epics::pvAccess::Destroyable Destroyable EPICS_DEPRECATED
Definition: destroyable.h:61
EPICS_ALWAYS_INLINE void putByte(std::size_t index, int8 value)
Definition: byteBuffer.h:570
static EPICS_ALWAYS_INLINE uint64 to(double v)
Definition: byteBuffer.h:92
EPICS_ALWAYS_INLINE void putFloat(std::size_t index, float value)
Definition: byteBuffer.h:598
EPICS_ALWAYS_INLINE bool getBoolean()
Definition: byteBuffer.h:611
void setEndianess(int byteOrder)
Definition: byteBuffer.h:285
EPICS_ALWAYS_INLINE int64 getLong()
Definition: byteBuffer.h:635
EPICS_ALWAYS_INLINE void putDouble(double value)
Definition: byteBuffer.h:555
static EPICS_ALWAYS_INLINE T to(T v)
Definition: byteBuffer.h:68
int16_t int16
Definition: pvType.h:79
void put(const char *src, std::size_t src_offset, std::size_t count)
Definition: byteBuffer.h:451
ChannelPut::shared_pointer op
Definition: pvAccess.cpp:132
EPICS_ALWAYS_INLINE void putBoolean(bool value)
Definition: byteBuffer.h:519
Compiler specific declarations.
#define EPICS_BYTE_ORDER
Definition: osdWireConfig.h:16
EPICS_ALWAYS_INLINE bool reverse() const
Definition: byteBuffer.h:493
void setLimit(std::size_t limit)
Definition: byteBuffer.h:380
EPICS_ALWAYS_INLINE void putLong(int64 value)
Definition: byteBuffer.h:543
#define EPICS_ALWAYS_INLINE
Definition: byteBuffer.h:27
EPICS_ALWAYS_INLINE void putShort(int16 value)
Definition: byteBuffer.h:531
EPICS_ALWAYS_INLINE float getFloat()
Definition: byteBuffer.h:641
#define false
Definition: flexdef.h:85
int32_t int32
Definition: pvType.h:83
static EPICS_ALWAYS_INLINE T from(T v)
Definition: byteBuffer.h:67
static EPICS_ALWAYS_INLINE uint32 op(uint32 v)
Definition: byteBuffer.h:117
static EPICS_ALWAYS_INLINE uint8 op(uint8 v)
Definition: byteBuffer.h:103
uint8_t uint8
Definition: pvType.h:91
EPICS_ALWAYS_INLINE void putShort(std::size_t index, int16 value)
Definition: byteBuffer.h:577
uint32_t uint32
Definition: pvType.h:99
EPICS_ALWAYS_INLINE void putLong(std::size_t index, int64 value)
Definition: byteBuffer.h:591