Cogs.Core
PowerOfTwo.h
1#pragma once
2#ifdef _MSC_VER
3#include <intrin.h>
4#endif
5#include <cassert>
6#include <cstdint>
7#include <type_traits>
8
9namespace Cogs
10{
11
14 template<typename T>
15 inline bool isPowerOfTwo(T x)
16 {
17 static_assert(std::is_integral<T>::value, "Integer required.");
18 // x-1 inverts all bits from the lowest set bit and down inclusive,
19 // while everything above remains unchanged. Thus, the expression
20 // removes the lowest set bit. If the number is a power of two, then
21 // the number consists of a single bit set, the lowest bit set.
22 return (x & (x-1)) == 0;
23 }
24
25
28 inline uint8_t roundUpToPowerOfTwo(uint8_t x)
29 {
30#if defined(_MSC_VER)
31 unsigned long index;
32 if (_BitScanReverse(&index, x)) {
33 return (uint8_t)1 << (((x & (x - 1)) == 0) ? index : index + 1);
34 }
35 return 0;
36#else
37#ifdef _DEBUG
38 uint16_t o = x;
39#endif
40 x--; // If we are a power-of-two, this will pop one leading bit. Otherwise leading bit will remain.
41 x |= x >> 1u; // Make leading bit a pair of leading bits.
42 x |= x >> 2u; // And than in turn into a quadruplet of leading bits.
43 x |= x >> 4u; // And now all bits below the leading bit are set.
44 x++; // The next number is a power of two, equal or larger than the input.
45
46 // Also note that if x was zero, first instruction sets all bits, then already set bits
47 // gets propagated down with no effect, and the last add flips everything back to zero.
48#ifdef _DEBUG
49 assert(o <= x);
50 assert((o == 0) || (o / 2 < x));
51#endif
52 return x;
53#endif
54 }
55
58 inline uint16_t roundUpToPowerOfTwo(uint16_t x)
59 {
60#if defined(_MSC_VER)
61 unsigned long index;
62 if (_BitScanReverse(&index, x)) {
63 return (uint16_t)1 << (((x & (x - 1)) == 0) ? index : index + 1);
64 }
65 return 0;
66#else
67#ifdef _DEBUG
68 uint16_t o = x;
69#endif
70 x--;
71 x |= x >> 1u;
72 x |= x >> 2u;
73 x |= x >> 4u;
74 x |= x >> 8u;
75 x++;
76#ifdef _DEBUG
77 assert(o <= x);
78 assert((o == 0) || (o/2 < x));
79#endif
80 return x;
81#endif
82 }
83
84 inline uint16_t roundDownToPowerOfTwo(uint16_t x)
85 {
86#if defined(_MSC_VER)
87 unsigned long index;
88 if (_BitScanReverse(&index, x)) {
89 return (uint16_t)(1 << index);
90 }
91 return 0;
92#else
93#ifdef _DEBUG
94 uint16_t o = x;
95#endif
96 x |= x >> 1u; // Make leading bit a pair of leading bits.
97 x |= x >> 2u;
98 x |= x >> 4u;
99 x |= x >> 8u;
100 x = x - (x >> 1);
101#ifdef _DEBUG
102 assert(x <= o);
103#endif
104 return x;
105#endif
106 }
107
108
111 inline uint32_t roundUpToPowerOfTwo(uint32_t x)
112 {
113#if defined(_MSC_VER)
114 unsigned long index;
115 if (_BitScanReverse(&index, x)) {
116 return (uint32_t)1 << (((x & (x - 1)) == 0) ? index : index + 1);
117 }
118 return 0;
119#else
120#ifdef _DEBUG
121 uint32_t o = x;
122#endif
123 x--;
124 x |= x >> 1u;
125 x |= x >> 2u;
126 x |= x >> 4u;
127 x |= x >> 8u;
128 x |= x >> 16u;
129 x++;
130#ifdef _DEBUG
131 assert(o <= x);
132 assert((o == 0) || (o / 2 < x));
133#endif
134 return x;
135#endif
136 }
137
140 inline uint64_t roundUpToPowerOfTwo(uint64_t x)
141 {
142#if defined(_MSC_VER) && defined(_WIN64)
143 unsigned long index;
144 if (_BitScanReverse64(&index, x)) {
145 return (uint64_t)1 << (((x & (x - 1)) == 0) ? index : index + 1);
146 }
147 return 0;
148#else
149#ifdef _DEBUG
150 uint64_t o = x;
151#endif
152 x--;
153 x |= x >> 1u;
154 x |= x >> 2u;
155 x |= x >> 4u;
156 x |= x >> 8u;
157 x |= x >> 16u;
158 x |= x >> 32u;
159 x++;
160#ifdef _DEBUG
161 assert(o <= x);
162 assert((o == 0) || (o / 2 < x));
163#endif
164 return x;
165#endif
166 }
167
170 inline uint8_t roundUpToPowerOfTwoShift(uint8_t x)
171 {
172#ifdef _MSC_VER
173 unsigned long index;
174 if (_BitScanReverse(&index, x)) {
175 return (uint8_t)(((x & (x - 1)) == 0) ? index : index + 1);
176 }
177 return 0;
178#else
179 uint8_t t = roundUpToPowerOfTwo(x);
180
181 // Find shift of most significant bit (i.e. only bit).
182 uint8_t s = 0;
183 if (t & 0xF0u) s += 4; // If any bits in 1111 0000, shift is at least 4
184 if (t & 0xCCu) s += 2; // If any bits in 1100 1100, shift is at least 2, plus previous.
185 if (t & 0xAAu) s += 1; // If any bits in 1010 1010, shift is at least 1, plus previous.
186
187#ifdef _DEBUG
188 assert(x <= (1u << s));
189 assert((s == 0u) || ((1u << (s - 1u) < x)));
190#endif
191 return s;
192#endif
193 }
194
197 inline uint16_t roundUpToPowerOfTwoShift(uint16_t x)
198 {
199#ifdef _MSC_VER
200 unsigned long index;
201 if (_BitScanReverse(&index, x)) {
202 return (uint16_t)(((x & (x - 1)) == 0) ? index : index + 1);
203 }
204 return 0;
205#else
206 uint16_t t = roundUpToPowerOfTwo(x);
207
208 uint16_t s = 0;
209 if (t & 0xFF00u) s += 8;
210 if (t & 0xF0F0u) s += 4;
211 if (t & 0xCCCCu) s += 2;
212 if (t & 0xAAAAu) s += 1;
213
214#ifdef _DEBUG
215 assert(x <= (1u << s));
216 assert((s == 0u) || ((1u << (s - 1u) < x)));
217#endif
218 return s;
219#endif
220 }
221
224 inline uint32_t roundUpToPowerOfTwoShift(uint32_t x)
225 {
226#ifdef _MSC_VER
227 unsigned long index;
228 if (_BitScanReverse(&index, x)) {
229 return (uint32_t)(((x & (x - 1)) == 0) ? index : index + 1);
230 }
231 return 0;
232#else
233 uint32_t t = roundUpToPowerOfTwo(x);
234
235 uint32_t s = 0;
236 if (t & 0xFFFF0000u) s += 16;
237 if (t & 0xFF00FF00u) s += 8;
238 if (t & 0xF0F0F0F0u) s += 4;
239 if (t & 0xCCCCCCCCu) s += 2;
240 if (t & 0xAAAAAAAAu) s += 1;
241
242#ifdef _DEBUG
243 assert(x <= (1u << s));
244 assert((s == 0u) || ((1u << (s - 1u) < x)));
245#endif
246 return s;
247#endif
248 }
249
252 inline uint64_t roundUpToPowerOfTwoShift(uint64_t x)
253 {
254#if defined(_MSC_VER) && defined(_WIN64)
255 unsigned long index;
256 if (_BitScanReverse64(&index, x)) {
257 return ((x & (x - 1)) == 0) ? index : index + 1;
258 }
259 return 0;
260#else
261 uint64_t t = roundUpToPowerOfTwo(x);
262
263 uint64_t s = 0;
264 if (t & 0xFFFFFFFF00000000u) s += 32;
265 if (t & 0xFFFF0000FFFF0000u) s += 16;
266 if (t & 0xFF00FF00FF00FF00u) s += 8;
267 if (t & 0xF0F0F0F0F0F0F0F0u) s += 4;
268 if (t & 0xCCCCCCCCCCCCCCCCu) s += 2;
269 if (t & 0xAAAAAAAAAAAAAAAAu) s += 1;
270
271#ifdef _DEBUG
272 assert(x <= (1ull << s));
273 assert((s == 0u) || ((1ull << (s - 1u) < x)));
274#endif
275 return s;
276#endif
277 }
278
279}
Contains all Cogs related functionality.
Definition: FieldSetter.h:23
uint8_t roundUpToPowerOfTwo(uint8_t x)
Definition: PowerOfTwo.h:28
bool isPowerOfTwo(T x)
Definition: PowerOfTwo.h:15
uint8_t roundUpToPowerOfTwoShift(uint8_t x)
Definition: PowerOfTwo.h:170