PVData C++ 8.0.7
Loading...
Searching...
No Matches
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 */
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
62namespace epics {namespace pvData {
63
64namespace detail {
65template<typename T>
66struct asInt {
67 static EPICS_ALWAYS_INLINE T from(T v) { return v; }
68 static EPICS_ALWAYS_INLINE T to(T v) { return v; }
69};
70template<>
71struct 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};
84template<>
85struct 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
99template<int N>
100struct swap; // no default
101template<>
102struct swap<1> {
103 static EPICS_ALWAYS_INLINE uint8 op(uint8 v) { return v; }
104};
105template<>
106struct 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};
115template<>
116struct 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};
128template<>
129struct 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
165template<typename T>
166union alignu {
167 T val;
168 char bytes[sizeof(T)];
169};
170
171template<typename T>
172EPICS_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
181template<typename T>
182EPICS_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
193template<typename T>
194EPICS_ALWAYS_INLINE void store_unaligned(char *buf, T val)
195{
196 *reinterpret_cast<T*>(buf) = val;
197}
198
199template<typename T>
200EPICS_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
211template<typename T>
212EPICS_ALWAYS_INLINE T swap(T val)
213{
215 detail::swap<sizeof(T)>::op(
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
237{
238public:
246 ByteBuffer(std::size_t size, int byteOrder = EPICS_BYTE_ORDER) :
247 _buffer((char*)std::malloc(size)), _size(size),
248 _reverseEndianess(byteOrder != EPICS_BYTE_ORDER),
249 _reverseFloatEndianess(byteOrder != EPICS_FLOAT_WORD_ORDER),
250 _wrapped(false)
251 {
252 if(!_buffer)
253 throw std::bad_alloc();
254 clear();
255 }
256
265 ByteBuffer(char* buffer, std::size_t size, int byteOrder = EPICS_BYTE_ORDER) :
266 _buffer(buffer), _size(size),
267 _reverseEndianess(byteOrder != EPICS_BYTE_ORDER),
268 _reverseFloatEndianess(byteOrder != EPICS_FLOAT_WORD_ORDER),
269 _wrapped(true)
270 {
271 if(!_buffer)
272 throw std::invalid_argument("ByteBuffer can't be constructed with NULL");
273 clear();
274 }
279 {
280 if (_buffer && !_wrapped) std::free(_buffer);
281 }
288 inline void setEndianess(int byteOrder)
289 {
290 _reverseEndianess = (byteOrder != EPICS_BYTE_ORDER);
291 _reverseFloatEndianess = (byteOrder != EPICS_FLOAT_WORD_ORDER);
292 }
297 inline const char* getBuffer() const
298 {
299 return _buffer;
300 }
305 inline void clear()
306 {
307 _position = _buffer;
308 _limit = _buffer + _size;
309 }
324 inline void flip() {
325 _limit = _position;
326 _position = _buffer;
327 }
342 inline void rewind() {
343 _position = _buffer;
344 }
349 inline std::size_t getPosition() const
350 {
351 return _position - _buffer;
352 }
360 inline void setPosition(std::size_t pos)
361 {
362 assert(pos<=_size);
363 _position = _buffer + pos;
364 assert(_position<=_limit);
365 }
371 inline std::size_t getLimit() const
372 {
373 return _limit - _buffer;
374 }
383 inline void setLimit(std::size_t limit)
384 {
385 assert(limit<=_size);
386 _limit = _buffer + limit;
387 assert(_position<=_limit);
388 }
394 inline std::size_t getRemaining() const
395 {
396 return _limit - _position;
397 }
403 EPICS_ALWAYS_INLINE std::size_t getSize() const
404 {
405 return _size;
406 }
412 template<typename T>
413 inline void put(T value);
420 template<typename T>
421 inline void put(std::size_t index, T value) const;
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
443 template<typename T>
444 inline T get(std::size_t index) const;
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 }
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 }
480 template<typename T>
481 inline void putArray(const T* values, std::size_t count);
489 template<typename T>
490 inline void getArray(T* values, std::size_t count);
495 template<typename T>
496 EPICS_ALWAYS_INLINE bool reverse() const
497 {
498 return sizeof(T)>1 && _reverseEndianess;
499 }
505 EPICS_ALWAYS_INLINE void putBoolean( bool value) { put< int8>(value ? 1 : 0); }
511 EPICS_ALWAYS_INLINE void putByte ( int8 value) { put< int8>(value); }
517 EPICS_ALWAYS_INLINE void putShort ( int16 value) { put< int16>(value); }
523 EPICS_ALWAYS_INLINE void putInt ( int32 value) { put< int32>(value); }
529 EPICS_ALWAYS_INLINE void putLong ( int64 value) { put< int64>(value); }
535 EPICS_ALWAYS_INLINE void putFloat ( float value) { put< float>(value); }
541 EPICS_ALWAYS_INLINE void putDouble (double value) { put<double>(value); }
542
549 EPICS_ALWAYS_INLINE void putBoolean(std::size_t index, bool value) { put< int8>(index, value); }
556 EPICS_ALWAYS_INLINE void putByte (std::size_t index, int8 value) { put< int8>(index, value); }
563 EPICS_ALWAYS_INLINE void putShort (std::size_t index, int16 value) { put< int16>(index, value); }
570 EPICS_ALWAYS_INLINE void putInt (std::size_t index, int32 value) { put< int32>(index, value); }
577 EPICS_ALWAYS_INLINE void putLong (std::size_t index, int64 value) { put< int64>(index, value); }
584 EPICS_ALWAYS_INLINE void putFloat (std::size_t index, float value) { put< float>(index, value); }
591 EPICS_ALWAYS_INLINE void putDouble (std::size_t index, double value) { put<double>(index, value); }
597 EPICS_ALWAYS_INLINE bool getBoolean() { return GET( int8) != 0; }
603 EPICS_ALWAYS_INLINE int8 getByte () { return GET( int8); }
609 EPICS_ALWAYS_INLINE int16 getShort () { return GET( int16); }
615 EPICS_ALWAYS_INLINE int32 getInt () { return GET( int32); }
621 EPICS_ALWAYS_INLINE int64 getLong () { return GET( int64); }
627 EPICS_ALWAYS_INLINE float getFloat () { return GET( float); }
633 EPICS_ALWAYS_INLINE double getDouble () { return GET(double); }
640 EPICS_ALWAYS_INLINE bool getBoolean(std::size_t index) { return get< int8>(index) != 0; }
647 EPICS_ALWAYS_INLINE int8 getByte (std::size_t index) { return get< int8>(index); }
654 EPICS_ALWAYS_INLINE int16 getShort (std::size_t index) { return get< int16>(index); }
661 EPICS_ALWAYS_INLINE int32 getInt (std::size_t index) { return get< int32>(index); }
668 EPICS_ALWAYS_INLINE int64 getLong (std::size_t index) { return get< int64>(index); }
675 EPICS_ALWAYS_INLINE float getFloat (std::size_t index) { return get< float>(index); }
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
691private:
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>
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 */
valarray< size_t > size() const
constexpr iterator_traits< _InputIterator >::difference_type count(_InputIterator __first, _InputIterator __last, const _Tp &__value)
This class implements a Bytebuffer that is like the java.nio.ByteBuffer.
Definition byteBuffer.h:237
void put(const char *src, std::size_t src_offset, std::size_t count)
Definition byteBuffer.h:454
void setLimit(std::size_t limit)
Definition byteBuffer.h:383
void setPosition(std::size_t pos)
Definition byteBuffer.h:360
double getDouble(std::size_t index)
Definition byteBuffer.h:682
void putShort(std::size_t index, int16 value)
Definition byteBuffer.h:563
void putDouble(std::size_t index, double value)
Definition byteBuffer.h:591
void putFloat(float value)
Definition byteBuffer.h:535
float getFloat(std::size_t index)
Definition byteBuffer.h:675
void setEndianess(int byteOrder)
Definition byteBuffer.h:288
int16 getShort(std::size_t index)
Definition byteBuffer.h:654
ByteBuffer(std::size_t size, int byteOrder=EPICS_BYTE_ORDER)
Definition byteBuffer.h:246
ByteBuffer(char *buffer, std::size_t size, int byteOrder=EPICS_BYTE_ORDER)
Definition byteBuffer.h:265
std::size_t getSize() const
Definition byteBuffer.h:403
int64 getLong(std::size_t index)
Definition byteBuffer.h:668
void putDouble(double value)
Definition byteBuffer.h:541
void putBoolean(std::size_t index, bool value)
Definition byteBuffer.h:549
void get(char *dest, std::size_t dest_offset, std::size_t count)
Definition byteBuffer.h:468
const char * getBuffer() const
Definition byteBuffer.h:297
void putLong(std::size_t index, int64 value)
Definition byteBuffer.h:577
void putByte(int8 value)
Definition byteBuffer.h:511
int8 getByte(std::size_t index)
Definition byteBuffer.h:647
void putByte(std::size_t index, int8 value)
Definition byteBuffer.h:556
void putShort(int16 value)
Definition byteBuffer.h:517
void putInt(int32 value)
Definition byteBuffer.h:523
void putInt(std::size_t index, int32 value)
Definition byteBuffer.h:570
void putFloat(std::size_t index, float value)
Definition byteBuffer.h:584
std::size_t getPosition() const
Definition byteBuffer.h:349
std::size_t getLimit() const
Definition byteBuffer.h:371
bool getBoolean(std::size_t index)
Definition byteBuffer.h:640
int32 getInt(std::size_t index)
Definition byteBuffer.h:661
void putBoolean(bool value)
Definition byteBuffer.h:505
void putArray(const T *values, std::size_t count)
Definition byteBuffer.h:787
std::size_t getRemaining() const
Definition byteBuffer.h:394
void putLong(int64 value)
Definition byteBuffer.h:529
uint32_t uint32
Definition pvType.h:99
int32_t int32
Definition pvType.h:83
int16_t int16
Definition pvType.h:79
uint64_t uint64
Definition pvType.h:103
int8_t int8
Definition pvType.h:75
int64_t int64
Definition pvType.h:87
T swap(T val)
Definition byteBuffer.h:212
uint16_t uint16
Definition pvType.h:95
uint8_t uint8
Definition pvType.h:91
epics
Definition convert.h:21