1 | // =============================================================== // |
---|
2 | // // |
---|
3 | // File : PT_tools.h // |
---|
4 | // Purpose : // |
---|
5 | // // |
---|
6 | // Coded by Ralf Westram (coder@reallysoft.de) in October 2012 // |
---|
7 | // Institute of Microbiology (Technical University Munich) // |
---|
8 | // http://www.arb-home.de/ // |
---|
9 | // // |
---|
10 | // =============================================================== // |
---|
11 | |
---|
12 | #ifndef PT_TOOLS_H |
---|
13 | #define PT_TOOLS_H |
---|
14 | |
---|
15 | #ifndef STATIC_ASSERT_H |
---|
16 | #include <static_assert.h> |
---|
17 | #endif |
---|
18 | #ifndef ARB_ASSERT_H |
---|
19 | #include <arb_assert.h> |
---|
20 | #endif |
---|
21 | |
---|
22 | #define pt_assert(bed) arb_assert(bed) |
---|
23 | |
---|
24 | typedef void * PT_PNTR; |
---|
25 | |
---|
26 | typedef unsigned char uint_8; // @@@ use uint8_t, uint16_t, uint32_t, uint64_t here |
---|
27 | typedef unsigned short uint_16; |
---|
28 | typedef unsigned int uint_32; |
---|
29 | typedef unsigned long uint_64; |
---|
30 | |
---|
31 | #if defined(ARB_64) |
---|
32 | typedef uint_64 uint_big; |
---|
33 | #else |
---|
34 | typedef uint_32 uint_big; |
---|
35 | #endif |
---|
36 | |
---|
37 | // ---------------------- |
---|
38 | // bswap for OSX |
---|
39 | |
---|
40 | #if defined(DARWIN) |
---|
41 | |
---|
42 | static inline unsigned short bswap_16(unsigned short x) { |
---|
43 | return (x>>8) | (x<<8); |
---|
44 | } |
---|
45 | |
---|
46 | static inline unsigned int bswap_32(unsigned int x) { |
---|
47 | return (bswap_16(x&0xffff)<<16) | bswap_16(x>>16); |
---|
48 | } |
---|
49 | |
---|
50 | static inline unsigned long long bswap_64(unsigned long long x) { |
---|
51 | return (((unsigned long long)bswap_32(x&0xffffffffull))<<32) | bswap_32(x>>32); |
---|
52 | } |
---|
53 | |
---|
54 | #else |
---|
55 | #include <byteswap.h> |
---|
56 | #endif // DARWIN |
---|
57 | |
---|
58 | // ------------------------------------------------------------ |
---|
59 | // Note about bswap as used here: |
---|
60 | // |
---|
61 | // * MSB has to be at start of written byte-chain, cause the most significant bit is used to separate |
---|
62 | // between INT and SHORT |
---|
63 | // |
---|
64 | // * To use PT-server on a big-endian system it has to be skipped |
---|
65 | // ------------------------------------------------------------ |
---|
66 | |
---|
67 | |
---|
68 | // ---------------------------- |
---|
69 | // read/write numbers |
---|
70 | |
---|
71 | inline uint_8 PT_read_char (const void *fromMem) { return *(uint_8*)fromMem; } |
---|
72 | inline uint_16 PT_read_short(const void *fromMem) { return bswap_16(*(uint_16*)fromMem); } |
---|
73 | inline uint_32 PT_read_int (const void *fromMem) { return bswap_32(*(uint_32*)fromMem); } |
---|
74 | #if defined(ARB_64) |
---|
75 | inline uint_64 PT_read_long (const void *fromMem) { return bswap_64(*(uint_64*)fromMem); } |
---|
76 | inline uint_big PT_read_big (const void *fromMem) { return PT_read_long(fromMem); } |
---|
77 | #else |
---|
78 | inline uint_big PT_read_big (const void *fromMem) { return PT_read_int(fromMem); } |
---|
79 | #endif |
---|
80 | |
---|
81 | inline void PT_write_char (void *toMem, uint_8 i) { *(uint_8*) toMem = i; } |
---|
82 | inline void PT_write_short(void *toMem, uint_16 i) { *(uint_16*)toMem = bswap_16(i); } |
---|
83 | inline void PT_write_int (void *toMem, uint_32 i) { *(uint_32*)toMem = bswap_32(i); } |
---|
84 | #if defined(ARB_64) |
---|
85 | inline void PT_write_long (void *toMem, uint_64 i) { *(uint_64*)toMem = bswap_64(i); } |
---|
86 | inline void PT_write_big (void *toMem, uint_big i) { PT_write_long(toMem, i); } |
---|
87 | #else |
---|
88 | inline void PT_write_big (void *toMem, uint_big i) { PT_write_int(toMem, i); } |
---|
89 | #endif |
---|
90 | |
---|
91 | // ------------------------------------------------ |
---|
92 | // compressed read/write positive numbers |
---|
93 | |
---|
94 | // Note: number of least significant bit is 0 (in template parameters) |
---|
95 | |
---|
96 | // compile-time generation of mask-values for bit B = [0..31] |
---|
97 | template <int B> struct BitMask { enum { value = (1<<B) }; }; |
---|
98 | |
---|
99 | // compile-time generation of mask-values for all bits below bit B = [0..32] |
---|
100 | template <int B> struct BitsBelowBit { enum { value = (BitMask<B>::value-1) }; }; |
---|
101 | template <> struct BitsBelowBit<32> { enum { value = 0xffffffff }; }; // avoid shift overflow |
---|
102 | template <> struct BitsBelowBit<31> { enum { value = 0x7fffffff }; }; // avoid int overflow |
---|
103 | |
---|
104 | // compile-time generation of mask-values for all bits in range [LB..HB] |
---|
105 | // |
---|
106 | template <int HB, int LB> struct BitRange { enum { value = (BitsBelowBit<HB+1>::value-BitsBelowBit<LB>::value) }; }; |
---|
107 | |
---|
108 | |
---|
109 | template <int R> // R is number of reserved bits |
---|
110 | inline void write_nat_with_reserved_bits(char*& toMem, uint_32 nat, uint_8 reserved_bits) { |
---|
111 | pt_assert((reserved_bits&BitsBelowBit<R>::value) == reserved_bits); // reserved_bits exceed allowed value-range |
---|
112 | reserved_bits = reserved_bits << (8-R); |
---|
113 | if (nat < BitMask<7-R>::value) { |
---|
114 | PT_write_char(toMem, nat|reserved_bits); |
---|
115 | toMem += 1; |
---|
116 | } |
---|
117 | else { |
---|
118 | nat -= BitMask<7-R>::value; |
---|
119 | if (nat < BitMask<6-R+8>::value) { |
---|
120 | PT_write_short(toMem, nat|BitMask<7-R+8>::value|(reserved_bits<<8)); |
---|
121 | toMem += 2; |
---|
122 | } |
---|
123 | else { |
---|
124 | nat -= BitMask<6-R+8>::value; |
---|
125 | if (nat < BitMask<5-R+16>::value) { |
---|
126 | PT_write_char(toMem, (nat>>16)|BitRange<7-R,6-R>::value|reserved_bits); |
---|
127 | PT_write_short(toMem+1, nat&0xffff); |
---|
128 | toMem += 3; |
---|
129 | } |
---|
130 | else { |
---|
131 | nat -= BitMask<5-R+16>::value; |
---|
132 | if (nat < BitMask<4-R+24>::value) { |
---|
133 | PT_write_int(toMem, nat|BitRange<7-R+24,5-R+24>::value|(reserved_bits<<24)); |
---|
134 | toMem += 4; |
---|
135 | } |
---|
136 | else { |
---|
137 | PT_write_char(toMem, BitRange<7-R,4-R>::value|reserved_bits); |
---|
138 | PT_write_int(toMem+1, nat); |
---|
139 | toMem += 5; |
---|
140 | } |
---|
141 | } |
---|
142 | } |
---|
143 | } |
---|
144 | } |
---|
145 | |
---|
146 | template <int R> // R is number of reserved bits |
---|
147 | inline uint_32 read_nat_with_reserved_bits(const char*& fromMem, uint_8& reserved_bits) { |
---|
148 | uint_32 nat = PT_read_char(fromMem); |
---|
149 | reserved_bits = nat >> (8-R); |
---|
150 | nat = nat & BitsBelowBit<8-R>::value; |
---|
151 | |
---|
152 | if (nat & BitMask<7-R>::value) { |
---|
153 | if (nat & BitMask<6-R>::value) { |
---|
154 | if (nat & BitMask<5-R>::value) { |
---|
155 | if (nat & BitMask<4-R>::value) { // 5 bytes |
---|
156 | nat = PT_read_int(fromMem+1); |
---|
157 | fromMem += 5; |
---|
158 | } |
---|
159 | else { // 4 bytes |
---|
160 | nat = PT_read_int(fromMem) & (BitMask<4-R+24>::value-1); |
---|
161 | fromMem += 4; |
---|
162 | } |
---|
163 | nat += BitMask<5-R+16>::value; |
---|
164 | } |
---|
165 | else { // 3 bytes |
---|
166 | nat = ((nat&(BitMask<6-R>::value-1))<<16)|PT_read_short(fromMem+1); |
---|
167 | fromMem += 3; |
---|
168 | } |
---|
169 | nat += BitMask<6-R+8>::value; |
---|
170 | } |
---|
171 | else { // 2 bytes |
---|
172 | nat = PT_read_short(fromMem) & (BitMask<7-R+8>::value-1); |
---|
173 | fromMem += 2; |
---|
174 | } |
---|
175 | nat += BitMask<7-R>::value; |
---|
176 | } |
---|
177 | else { // 1 byte |
---|
178 | ++fromMem; |
---|
179 | } |
---|
180 | return nat; |
---|
181 | } |
---|
182 | |
---|
183 | template <int R> |
---|
184 | inline void write_int_with_reserved_bits(char*& toMem, int32_t i, uint_8 reserved_bits) { |
---|
185 | write_nat_with_reserved_bits<R+1>(toMem, i<0 ? -i-1 : i, (reserved_bits<<1)|(i<0)); |
---|
186 | } |
---|
187 | template <int R> |
---|
188 | inline int32_t read_int_with_reserved_bits(const char*& fromMem, uint_8& reserved_bits) { |
---|
189 | uint_32 nat = read_nat_with_reserved_bits<R+1>(fromMem, reserved_bits); |
---|
190 | bool isNeg = reserved_bits&1; |
---|
191 | reserved_bits = reserved_bits>>1; |
---|
192 | return isNeg ? -nat-1 : nat; |
---|
193 | } |
---|
194 | |
---|
195 | // read/write uint_32 using variable amount of mem (small numbers use less space than big numbers) |
---|
196 | inline uint_32 PT_read_compact_nat(const char*& fromMem) { uint_8 nothing; return read_nat_with_reserved_bits<0>(fromMem, nothing); } |
---|
197 | inline void PT_write_compact_nat(char*& toMem, uint_32 nat) { write_nat_with_reserved_bits<0>(toMem, nat, 0); } |
---|
198 | |
---|
199 | // ----------------------------- |
---|
200 | // read/write pointers |
---|
201 | |
---|
202 | |
---|
203 | STATIC_ASSERT(sizeof(void*) == sizeof(uint_big)); |
---|
204 | |
---|
205 | inline void *PT_read_void_pointer(const void *fromMem) { return (void*)PT_read_big(fromMem); } |
---|
206 | inline void PT_write_pointer(void *toMem, const void *thePtr) { PT_write_big(toMem, (uint_big)thePtr); } |
---|
207 | |
---|
208 | template<typename POINTED> |
---|
209 | inline POINTED* PT_read_pointer(const void *fromMem) { return (POINTED*)PT_read_void_pointer(fromMem); } |
---|
210 | |
---|
211 | inline void fflush_all() { |
---|
212 | fflush(stderr); |
---|
213 | fflush(stdout); |
---|
214 | } |
---|
215 | |
---|
216 | #else |
---|
217 | #error PT_tools.h included twice |
---|
218 | #endif // PT_TOOLS_H |
---|