Honeycomb  0.1
Component-Model Framework
BitOp.h
Go to the documentation of this file.
1 // Honeycomb, Copyright (C) 2015 NewGamePlus Inc. Distributed under the Boost Software License v1.0.
2 #pragma once
3 
4 #include "Honey/Core/Core.h"
5 #include "Honey/Math/Numeral.h"
6 
7 namespace honey
8 {
9 
11 enum class Endian
12 {
13  little,
14  big
15 };
16 
19 {
21  template<class T>
22  static T rotLeft(const T v, const int n)
23  {
24  typedef typename std::make_unsigned<T>::type Unsigned;
25  return (T)(((Unsigned)v << n) | ((Unsigned)v >> (Numeral<T>::sizeBits-n)));
26  }
28  template<class T>
29  static T rotRight(const T v, const int n) { return rotLeft(v, Numeral<T>::sizeBits-n); }
30 
32  static uint8 swap(const uint8 v) { return v; }
33  static uint16 swap(const uint16 v) { return rotLeft(v,8); }
34  static uint32 swap(const uint32 v) { return (rotLeft(v,8) & 0x00FF00FFU) | (rotLeft(v,24) & 0xFF00FF00U); }
35  static uint64 swap(const uint64 v)
36  {
37  return (rotLeft(v, 8) & 0x000000FF000000FFULL) |
38  (rotLeft(v,24) & 0x0000FF000000FF00ULL) |
39  (rotLeft(v,40) & 0x00FF000000FF0000ULL) |
40  (rotLeft(v,56) & 0xFF000000FF000000ULL);
41  }
43  template<class T>
44  static T swap(const T v)
45  {
46  typedef typename std::make_unsigned<T>::type Unsigned;
47  return (T)swap((Unsigned)v);
48  }
49 
51  static uint8 high(const uint16 v) { return v >> 8; }
52  static uint16 high(const uint32 v) { return v >> 16; }
53  static uint32 high(const uint64 v) { return v >> 32; }
54 
56  static uint8 low(const uint16 v) { return (uint8)v; }
57  static uint16 low(const uint32 v) { return (uint16)v; }
58  static uint32 low(const uint64 v) { return (uint32)v; }
59 
61  static uint32 fromParts(const uint16 hi, const uint16 lo) { return (uint32)lo | ((uint32)hi << 16); }
62  static uint64 fromParts(const uint32 hi, const uint32 lo) { return (uint64)lo | ((uint64)hi << 32); }
63 
64  template<class UInt>
65  static UInt fromPartsLittle(const uint8* p) { UInt val = 0; mt::for_<0, sizeof(UInt)>([&](int i) { val |= (UInt)p[i] << i*8; }); return val; }
66  template<class UInt>
67  static UInt fromPartsBig(const uint8* p) { UInt val = 0; mt::for_<0, sizeof(UInt)>([&](int i) { val |= (UInt)p[i] << (sizeof(UInt)-1-i)*8; }); return val; }
68 
69  template<class UInt>
70  static void toPartsLittle(const UInt v, uint8* p) { mt::for_<0, sizeof(UInt)>([&](int i) { p[i] = (uint8)(v >> i*8); }); }
71  template<class UInt>
72  static void toPartsBig(const UInt v, uint8* p) { mt::for_<0, sizeof(UInt)>([&](int i) { p[i] = (uint8)(v >> (sizeof(UInt)-1-i)*8); }); }
73 
75  static int popCount(uint32 x)
76  {
77  x -= (x >> 1) & 0x55555555;
78  x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
79  x = (x + (x >> 4)) & 0x0f0f0f0f;
80  x += x >> 8;
81  x += x >> 16;
82  return x & 0x0000003f;
83  }
84  static int popCount(uint64 x)
85  {
86  x -= (x >> 1) & 0x5555555555555555; //put count of each 2 bits into those 2 bits
87  x = (x & 0x3333333333333333) + ((x >> 2) & 0x3333333333333333); //put count of each 4 bits into those 4 bits
88  x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f; //put count of each 8 bits into those 8 bits
89  x += x >> 8; //put count of each 16 bits into their lowest 8 bits
90  x += x >> 16; //put count of each 32 bits into their lowest 8 bits
91  x += x >> 32; //put count of each 64 bits into their lowest 8 bits
92  return x & 0x7f;
93  }
94 
96  template<class UInt>
97  static bool isPow2(UInt x) { return !((x-1) & x); }
99  template<class UInt>
100  static UInt pow2Floor(UInt x) { return isPow2(x) ? x : pow2Ceil(x) >> 1; }
102  static uint32 pow2Ceil(uint32 x) { --x; x|=x>>1; x|=x>>2; x|=x>>4; x|=x>>8; x|=x>>16; return ++x; }
103  static uint64 pow2Ceil(uint64 x) { --x; x|=x>>1; x|=x>>2; x|=x>>4; x|=x>>8; x|=x>>16; x|=x>>32; return ++x; }
104 
106  static int log2Floor(uint32 x) { x|=(x>>1); x|=(x>>2); x|=(x>>4); x|=(x>>8); x|=(x>>16); return x ? popCount(x>>1) : -1; }
107  static int log2Floor(uint64 x) { x|=(x>>1); x|=(x>>2); x|=(x>>4); x|=(x>>8); x|=(x>>16); x|=(x>>32); return x ? popCount(x>>1) : -1; }
109  static int log2Ceil(uint32 x) { int32 y=(x&(x-1)); y|=-y; y>>=(32-1); x|=(x>>1); x|=(x>>2); x|=(x>>4); x|=(x>>8); x|=(x>>16); return x ? popCount(x>>1)-y : -1; }
110  static int log2Ceil(uint64 x) { int64 y=(x&(x-1)); y|=-y; y>>=(64-1); x|=(x>>1); x|=(x>>2); x|=(x>>4); x|=(x>>8); x|=(x>>16); x|=(x>>32); return x ? popCount(x>>1)-int(y) : -1; }
111 
113  static uint8 reverse(uint8 v)
114  {
115  v = (v & 0xF0) >> 4 | (v & 0x0F) << 4;
116  v = (v & 0xCC) >> 2 | (v & 0x33) << 2;
117  v = (v & 0xAA) >> 1 | (v & 0x55) << 1;
118  return v;
119  }
121  {
122  v = (v & 0xFF00) >> 8 | (v & 0x00FF) << 8;
123  v = (v & 0xF0F0) >> 4 | (v & 0x0F0F) << 4;
124  v = (v & 0xCCCC) >> 2 | (v & 0x3333) << 2;
125  v = (v & 0xAAAA) >> 1 | (v & 0x5555) << 1;
126  return v;
127  }
129  {
130  v = (v & 0xFFFF0000) >> 16 | (v & 0x0000FFFF) << 16;
131  v = (v & 0xFF00FF00) >> 8 | (v & 0x00FF00FF) << 8;
132  v = (v & 0xF0F0F0F0) >> 4 | (v & 0x0F0F0F0F) << 4;
133  v = (v & 0xCCCCCCCC) >> 2 | (v & 0x33333333) << 2;
134  v = (v & 0xAAAAAAAA) >> 1 | (v & 0x55555555) << 1;
135  return v;
136  }
138  {
139  v = (v & 0xFFFFFFFF00000000) >> 32 | (v & 0x00000000FFFFFFFF) << 32;
140  v = (v & 0xFFFF0000FFFF0000) >> 16 | (v & 0x0000FFFF0000FFFF) << 16;
141  v = (v & 0xFF00FF00FF00FF00) >> 8 | (v & 0x00FF00FF00FF00FF) << 8;
142  v = (v & 0xF0F0F0F0F0F0F0F0) >> 4 | (v & 0x0F0F0F0F0F0F0F0F) << 4;
143  v = (v & 0xCCCCCCCCCCCCCCCC) >> 2 | (v & 0x3333333333333333) << 2;
144  v = (v & 0xAAAAAAAAAAAAAAAA) >> 1 | (v & 0x5555555555555555) << 1;
145  return v;
146  }
147 };
148 
150 namespace endian { namespace priv
151 {
152  template<class Float>
153  inline Float fromParts(const uint8* p)
154  {
155  union { Float f; uint8 bytes[sizeof(Float)]; } val;
156  mt::for_<0, sizeof(Float)>([&](int i) { val.bytes[i] = p[i]; });
157  return val.f;
158  }
159 
160  template<class Float>
161  inline Float fromPartsSwap(const uint8* p)
162  {
163  union { Float f; uint8 bytes[sizeof(Float)]; } val;
164  mt::for_<0, sizeof(Float)>([&](int i) { val.bytes[i] = p[sizeof(Float)-1-i]; });
165  return val.f;
166  }
167 
168  template<class Float>
169  inline void toParts(const Float f, uint8* p)
170  {
171  union { Float f; uint8 bytes[sizeof(Float)]; } val;
172  val.f = f;
173  mt::for_<0, sizeof(Float)>([&](int i) { p[i] = val.bytes[i]; });
174  }
175 
176  template<class Float>
177  inline void toPartsSwap(const Float f, uint8* p)
178  {
179  union { Float f; uint8 bytes[sizeof(Float)]; } val;
180  val.f = f;
181  mt::for_<0, sizeof(Float)>([&](int i) { p[i] = val.bytes[sizeof(Float)-1-i]; });
182  }
183 } }
186 template<int Endian> struct BitOpEndian {};
188 
190 template<>
191 struct BitOpEndian<static_cast<int>(Endian::little)> : BitOpCommon
192 {
194  static Endian platformEndian() { return Endian::little; }
195 
197  template<class Int>
198  static Int littleToPlatform(const Int v) { return v; }
200  template<class Int>
201  static Int platformToLittle(const Int v) { return v; }
202 
204  template<class Int>
205  static Int bigToPlatform(const Int v) { return swap(v); }
207  template<class Int>
208  static Int platformToBig(const Int v) { return swap(v); }
209 
213 
215  template<class T, typename std::enable_if<std::is_integral<T>::value, int>::type=0>
216  static T fromPartsLittle(const uint8* p) { return (T)BitOpCommon::fromPartsLittle<typename std::make_unsigned<T>::type>(p); }
217  template<class T, typename std::enable_if<std::is_floating_point<T>::value, int>::type=0>
218  static T fromPartsLittle(const uint8* p) { return endian::priv::fromParts<T>(p); }
219 
221  template<class T, typename std::enable_if<std::is_integral<T>::value, int>::type=0>
222  static T fromPartsBig(const uint8* p) { return (T)BitOpCommon::fromPartsBig<typename std::make_unsigned<T>::type>(p); }
223  template<class T, typename std::enable_if<std::is_floating_point<T>::value, int>::type=0>
224  static T fromPartsBig(const uint8* p) { return endian::priv::fromPartsSwap<T>(p); }
225 
227  template<class T, typename std::enable_if<std::is_integral<T>::value, int>::type=0>
228  static void toPartsLittle(const T v, uint8* p) { BitOpCommon::toPartsLittle((typename std::make_unsigned<T>::type)v, p); }
229  template<class T, typename std::enable_if<std::is_floating_point<T>::value, int>::type=0>
230  static void toPartsLittle(const T v, uint8* p) { endian::priv::toParts(v, p); }
231 
233  template<class T, typename std::enable_if<std::is_integral<T>::value, int>::type=0>
234  static void toPartsBig(const T v, uint8* p) { BitOpCommon::toPartsBig((typename std::make_unsigned<T>::type)v, p); }
235  template<class T, typename std::enable_if<std::is_floating_point<T>::value, int>::type=0>
236  static void toPartsBig(const T v, uint8* p) { endian::priv::toPartsSwap(v, p); }
238 };
239 
241 template<>
242 struct BitOpEndian<static_cast<int>(Endian::big)> : BitOpCommon
243 {
244 public:
245  static Endian platformEndian() { return Endian::big; }
246 
247  template<class Int>
248  static Int littleToPlatform(const Int v) { return swap(v); }
249  template<class Int>
250  static Int platformToLittle(const Int v) { return swap(v); }
251 
252  template<class Int>
253  static Int bigToPlatform(const Int v) { return v; }
254  template<class Int>
255  static Int platformToBig(const Int v) { return v; }
256 
257  template<class T, typename std::enable_if<std::is_integral<T>::value, int>::type=0>
258  static T fromPartsLittle(const uint8* p) { return (T)BitOpCommon::fromPartsLittle<typename std::make_unsigned<T>::type>(p); }
259  template<class T, typename std::enable_if<std::is_floating_point<T>::value, int>::type=0>
260  static T fromPartsLittle(const uint8* p) { return endian::priv::fromPartsSwap<T>(p); }
261 
262  template<class T, typename std::enable_if<std::is_integral<T>::value, int>::type=0>
263  static T fromPartsBig(const uint8* p) { return (T)BitOpCommon::fromPartsBig<typename std::make_unsigned<T>::type>(p); }
264  template<class T, typename std::enable_if<std::is_floating_point<T>::value, int>::type=0>
265  static T fromPartsBig(const uint8* p) { return endian::priv::fromParts<T>(p); }
266 
267  template<class T, typename std::enable_if<std::is_integral<T>::value, int>::type=0>
268  static void toPartsLittle(const T v, uint8* p) { BitOpCommon::toPartsLittle((typename std::make_unsigned<T>::type)v, p); }
269  template<class T, typename std::enable_if<std::is_floating_point<T>::value, int>::type=0>
270  static void toPartsLittle(const T v, uint8* p) { endian::priv::toPartsSwap(v, p); }
271 
272  template<class T, typename std::enable_if<std::is_integral<T>::value, int>::type=0>
273  static void toPartsBig(const T v, uint8* p) { BitOpCommon::toPartsBig((typename std::make_unsigned<T>::type)v, p); }
274  template<class T, typename std::enable_if<std::is_floating_point<T>::value, int>::type=0>
275  static void toPartsBig(const T v, uint8* p) { endian::priv::toParts(v, p); }
276 };
277 
280 
281 };
static uint16 high(const uint32 v)
Definition: BitOp.h:52
static UInt pow2Floor(UInt x)
Calc nearest power of two <= unsigned integer.
Definition: BitOp.h:100
low byte first
static T fromPartsBig(const uint8 *p)
Definition: BitOp.h:263
static void toPartsBig(const T v, uint8 *p)
Definition: BitOp.h:273
static uint64 pow2Ceil(uint64 x)
Definition: BitOp.h:103
static void toPartsLittle(const T v, uint8 *p)
Definition: BitOp.h:268
static uint16 reverse(uint16 v)
Definition: BitOp.h:120
static uint64 swap(const uint64 v)
Definition: BitOp.h:35
static void toPartsLittle(const T v, uint8 *p)
Convert a full number into an array of smaller number parts, where the first index holds the least si...
Definition: BitOp.h:228
Float_::Real Float
float type
Definition: Float.h:61
static Int platformToBig(const Int v)
Convert integer from platform endian to big endian.
Definition: BitOp.h:208
static int log2Ceil(uint64 x)
Definition: BitOp.h:110
Bit util common to any endian type. Use through class BitOp.
Definition: BitOp.h:18
static void toPartsLittle(const UInt v, uint8 *p)
Definition: BitOp.h:70
unsigned int uint32
Definition: Core.h:16
static Int platformToBig(const Int v)
Definition: BitOp.h:255
high byte first
static bool isPow2(UInt x)
Check if unsigned integer is a power of two.
Definition: BitOp.h:97
static uint32 high(const uint64 v)
Definition: BitOp.h:53
static Int bigToPlatform(const Int v)
Definition: BitOp.h:253
static T swap(const T v)
Reverse order of bytes in a signed integer.
Definition: BitOp.h:44
BitOpEndian< ENDIAN > BitOp
Provides methods for manipulating bits.
Definition: BitOp.h:279
static uint64 reverse(uint64 v)
Definition: BitOp.h:137
static uint16 low(const uint32 v)
Definition: BitOp.h:57
static uint8 reverse(uint8 v)
Reverse order of bits in an unsigned integer.
Definition: BitOp.h:113
static UInt fromPartsBig(const uint8 *p)
Definition: BitOp.h:67
Bit util specific to endian type. Use through class BitOp.
Definition: BitOp.h:187
static T fromPartsBig(const uint8 *p)
Convert an array of smaller number parts into a full number, where the first index holds the most sig...
Definition: BitOp.h:222
unsigned long long uint64
Definition: Core.h:22
static int popCount(uint32 x)
Get number of non-zero bits in unsigned integer.
Definition: BitOp.h:75
static void toPartsBig(const T v, uint8 *p)
Convert a full number into an array of smaller number parts, where the first index holds the most sig...
Definition: BitOp.h:234
static Endian platformEndian()
Get platform endian type.
Definition: BitOp.h:194
static uint8 low(const uint16 v)
Retrieve low bytes from integer.
Definition: BitOp.h:56
unsigned char uint8
Definition: Core.h:12
static uint8 swap(const uint8 v)
Reverse order of bytes in an unsigned integer.
Definition: BitOp.h:32
static int log2Floor(uint64 x)
Definition: BitOp.h:107
int int32
Definition: Core.h:15
static T fromPartsLittle(const uint8 *p)
Definition: BitOp.h:258
static uint32 fromParts(const uint16 hi, const uint16 lo)
Convert smaller integer parts into a full integer.
Definition: BitOp.h:61
static Endian platformEndian()
Definition: BitOp.h:245
static Int platformToLittle(const Int v)
Definition: BitOp.h:250
static uint8 high(const uint16 v)
Retrieve high bytes from integer.
Definition: BitOp.h:51
static T rotRight(const T v, const int n)
Rotate integer bits cyclically to the right.
Definition: BitOp.h:29
static uint16 swap(const uint16 v)
Definition: BitOp.h:33
static Int bigToPlatform(const Int v)
Convert integer from big endian to platform endian.
Definition: BitOp.h:205
static void toPartsBig(const UInt v, uint8 *p)
Definition: BitOp.h:72
unsigned short uint16
Definition: Core.h:14
Numeric type information, use numeral() to get instance safely from a static context.
Definition: Numeral.h:17
static uint32 pow2Ceil(uint32 x)
Calc nearest power of two >= unsigned integer.
Definition: BitOp.h:102
static int log2Floor(uint32 x)
Calc log base 2 of unsigned integer, rounded down to nearest integer. Returns -1 if x is zero...
Definition: BitOp.h:106
static UInt fromPartsLittle(const uint8 *p)
Definition: BitOp.h:65
#define swap(a, i, j)
static uint32 reverse(uint32 v)
Definition: BitOp.h:128
static uint32 low(const uint64 v)
Definition: BitOp.h:58
static T fromPartsLittle(const uint8 *p)
Convert an array of smaller number parts into a full number, where the first index holds the least si...
Definition: BitOp.h:216
long long int64
Definition: Core.h:21
static Int littleToPlatform(const Int v)
Definition: BitOp.h:248
static uint32 swap(const uint32 v)
Definition: BitOp.h:34
static uint64 fromParts(const uint32 hi, const uint32 lo)
Definition: BitOp.h:62
Endian
Endian (byte order) types.
Definition: BitOp.h:11
Global Honeycomb namespace.
static int popCount(uint64 x)
Definition: BitOp.h:84
static int log2Ceil(uint32 x)
Calc log base 2 of unsigned integer, rounded up to nearest integer. Returns -1 if x is zero...
Definition: BitOp.h:109
static Int platformToLittle(const Int v)
Convert integer from platform endian to little endian.
Definition: BitOp.h:201
static Int littleToPlatform(const Int v)
Convert integer from little endian to platform endian.
Definition: BitOp.h:198
static T rotLeft(const T v, const int n)
Rotate integer bits cyclically to the left.
Definition: BitOp.h:22