| 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 |
|---|