Antkeeper  0.0.1
bit-math.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2023 Christopher J. Howard
3  *
4  * This file is part of Antkeeper source code.
5  *
6  * Antkeeper source code is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Antkeeper source code is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef ANTKEEPER_BIT_MATH_HPP
21 #define ANTKEEPER_BIT_MATH_HPP
22 
23 #include <stdint.h>
24 
26 namespace bit {
27 
34 template <class T>
35 constexpr T compress(T x) noexcept;
36 
43 template <class T>
44 constexpr int count(T x) noexcept;
45 
54 template <class T>
55 constexpr T crossover(T a, T b, int i) noexcept;
56 
65 template <class T>
66 constexpr T crossover_n(T a, T b, T mask) noexcept;
67 
75 template <class T>
76 constexpr T deposit(T x, T mask) noexcept;
77 
84 template <class T>
85 constexpr T desegregate(T x) noexcept;
86 
94 template <class T>
95 constexpr int difference(T x, T y) noexcept;
96 
103 template <class T>
104 constexpr T expand(T x) noexcept;
105 
113 template <class T>
114 constexpr T extract(T x, T mask) noexcept;
115 
123 template <class T>
124 constexpr T flip(T x, int i) noexcept;
125 
133 template <class T, class U = T>
134 constexpr U interleave(T a, T b) noexcept;
135 
144 template <class T>
145 constexpr T merge(T a, T b, T mask) noexcept;
146 
153 template <class T>
154 constexpr T parity(T x) noexcept;
155 
162 template <class T>
163 constexpr T segregate(T x) noexcept;
164 
171 template <class T>
172 constexpr T swap_adjacent(T x) noexcept;
173 
175 std::uint16_t swap16(std::uint16_t x) noexcept;
176 
178 std::int16_t swap16(std::int16_t x) noexcept;
179 
181 std::uint32_t swap32(std::uint32_t x) noexcept;
182 
184 std::int32_t swap32(std::int32_t x) noexcept;
185 
187 std::uint64_t swap64(std::uint64_t x) noexcept;
188 
190 std::int64_t swap64(std::int64_t x) noexcept;
191 
192 template <class T>
193 constexpr T compress(T x) noexcept
194 {
195  x &= T(0x5555555555555555);
196 
197  x = (x ^ (x >> 1)) & T(0x3333333333333333);
198  x = (x ^ (x >> 2)) & T(0x0f0f0f0f0f0f0f0f);
199 
200  if constexpr(sizeof(T) >= 2)
201  x = (x ^ (x >> 4)) & T(0x00ff00ff00ff00ff);
202  if constexpr(sizeof(T) >= 4)
203  x = (x ^ (x >> 8)) & T(0x0000ffff0000ffff);
204  if constexpr(sizeof(T) >= 8)
205  x = (x ^ (x >> 16)) & T(0x00000000ffffffff);
206 
207  return x;
208 }
209 
210 template <class T>
211 constexpr int count(T x) noexcept
212 {
213  int n = 0;
214  for (; x; ++n)
215  x &= x - 1;
216  return n;
217 }
218 
219 template <class T>
220 inline constexpr T crossover(T a, T b, int i) noexcept
221 {
222  T mask = (T(1) << i) - 1;
223  return merge(b, a, mask);
224 }
225 
226 template <class T>
227 constexpr T crossover_n(T a, T b, T mask) noexcept
228 {
229  T merge = ~T(0) * parity(mask);
230 
231  while (mask)
232  {
233  merge ^= (mask ^ (mask - 1)) >> 1;
234  mask &= mask - 1;
235  }
236 
237  return merge(a, b, merge);
238 }
239 
240 template <class T>
241 inline constexpr T desegregate(T x) noexcept
242 {
243  return interleave<T>(x, x >> (sizeof(T) << 2));
244 }
245 
246 template <class T>
247 constexpr T expand(T x) noexcept
248 {
249  x &= (1 << (sizeof(T) << 2)) - 1;
250 
251  if constexpr(sizeof(T) >= 8)
252  x = (x ^ (x << 16)) & T(0x0000ffff0000ffff);
253  if constexpr(sizeof(T) >= 4)
254  x = (x ^ (x << 8)) & T(0x00ff00ff00ff00ff);
255  if constexpr(sizeof(T) >= 2)
256  x = (x ^ (x << 4)) & T(0x0f0f0f0f0f0f0f0f);
257 
258  x = (x ^ (x << 2)) & T(0x3333333333333333);
259  x = (x ^ (x << 1)) & T(0x5555555555555555);
260 
261  return x;
262 }
263 
264 template <class T>
265 constexpr T deposit(T x, T mask) noexcept
266 {
267  T result = 0;
268 
269  for (T i = 1; mask; i <<= 1)
270  {
271  if (x & i)
272  result |= mask & -mask;
273  mask &= mask - 1;
274  }
275 
276  return result;
277 }
278 
279 template <class T>
280 inline constexpr int difference(T x, T y) noexcept
281 {
282  return count(x ^ y);
283 }
284 
285 template <class T>
286 constexpr T extract(T x, T mask) noexcept
287 {
288  T result = 0;
289 
290  for (T i = 1; mask; i <<= 1)
291  {
292  if (x & mask & -mask)
293  result |= i;
294  mask &= mask - 1;
295  }
296 
297  return result;
298 }
299 
300 template <class T>
301 inline constexpr T flip(T x, int i) noexcept
302 {
303  return x ^ (T(1) << i);
304 }
305 
306 template <class T, class U>
307 inline constexpr U interleave(T a, T b) noexcept
308 {
309  return expand<U>(a) | (expand<U>(b) << 1);
310 }
311 
312 template <class T>
313 inline constexpr T merge(T a, T b, T mask) noexcept
314 {
315  return a ^ ((a ^ b) & mask);
316 }
317 
318 template <class T>
319 constexpr T parity(T x) noexcept
320 {
321  if constexpr(sizeof(T) >= 8)
322  x ^= x >> 32;
323  if constexpr(sizeof(T) >= 4)
324  x ^= x >> 16;
325  if constexpr(sizeof(T) >= 2)
326  x ^= x >> 8;
327 
328  x ^= x >> 4;
329 
330  return (0x6996 >> (x & 0xf)) & 1;
331 }
332 
333 template <class T>
334 constexpr T segregate(T x) noexcept
335 {
336  T odd = compress(x);
337  T even = compress(x >> 1);
338 
339  return odd | (even << (sizeof(T) << 2));
340 }
341 
342 template <class T>
343 constexpr T swap_adjacent(T x) noexcept
344 {
345  return ((x & T(0xaaaaaaaaaaaaaaaa)) >> 1) | ((x & T(0x5555555555555555)) << 1);
346 }
347 
348 std::uint16_t swap16(std::uint16_t x) noexcept
349 {
350  return (x << 8) | (x >> 8);
351 }
352 
353 std::int16_t swap16(std::int16_t x) noexcept
354 {
355  return (x << 8) | ((x >> 8) & 0xFF);
356 }
357 
358 std::uint32_t swap32(std::uint32_t x) noexcept
359 {
360  x = ((x << 8) & 0xFF00FF00) | ((x >> 8) & 0xFF00FF);
361  return (x << 16) | (x >> 16);
362 }
363 
364 std::int32_t swap32(std::int32_t x) noexcept
365 {
366  x = ((x << 8) & 0xFF00FF00) | ((x >> 8) & 0xFF00FF);
367  return (x << 16) | ((x >> 16) & 0xFFFF);
368 }
369 
370 std::uint64_t swap64(std::uint64_t x) noexcept
371 {
372  x = ((x << 8) & 0xFF00FF00FF00FF00) | ((x >> 8) & 0x00FF00FF00FF00FF);
373  x = ((x << 16) & 0xFFFF0000FFFF0000) | ((x >> 16) & 0x0000FFFF0000FFFF);
374  return (x << 32) | (x >> 32);
375 }
376 
377 std::int64_t swap64(std::int64_t x) noexcept
378 {
379  x = ((x << 8) & 0xFF00FF00FF00FF00) | ((x >> 8) & 0x00FF00FF00FF00FF);
380  x = ((x << 16) & 0xFFFF0000FFFF0000) | ((x >> 16) & 0x0000FFFF0000FFFF);
381  return (x << 32) | ((x >> 32) & 0xFFFFFFFF);
382 }
383 
384 } // namespace bit
385 
386 #endif // ANTKEEPER_BIT_MATH_HPP
Bitwise math.
Definition: bit-math.hpp:26
constexpr T swap_adjacent(T x) noexcept
Swaps the each odd bit with its following even bit.
Definition: bit-math.hpp:343
constexpr T compress(T x) noexcept
Compresses the even bits of a value into the lower half, then clears the upper half.
Definition: bit-math.hpp:193
std::uint32_t swap32(std::uint32_t x) noexcept
Swaps the byte order of an unsigned 32-bit number.
Definition: bit-math.hpp:358
constexpr T crossover(T a, T b, int i) noexcept
Performs a single-point crossover between two values.
Definition: bit-math.hpp:220
constexpr T merge(T a, T b, T mask) noexcept
Merges the bits of two values using a bit mask.
Definition: bit-math.hpp:313
constexpr T flip(T x, int i) noexcept
Flips a single bit in a value.
Definition: bit-math.hpp:301
constexpr T segregate(T x) noexcept
Segregates the odd and even bits of a value.
Definition: bit-math.hpp:334
constexpr U interleave(T a, T b) noexcept
Returns a value with even bits containing the first value's lower half, and odd bits containing the s...
Definition: bit-math.hpp:307
constexpr T crossover_n(T a, T b, T mask) noexcept
Performs an n-point crossover between two values.
Definition: bit-math.hpp:227
constexpr int difference(T x, T y) noexcept
Returns the number of differing bits between two values, known as Hamming distance.
Definition: bit-math.hpp:280
std::uint16_t swap16(std::uint16_t x) noexcept
Swaps the byte order of an unsigned 16-bit number.
Definition: bit-math.hpp:348
constexpr int count(T x) noexcept
Returns the number of set bits in a value, known as a population count or Hamming weight.
Definition: bit-math.hpp:211
constexpr T desegregate(T x) noexcept
Interleaves bits of the lower and upper halves of a value.
Definition: bit-math.hpp:241
constexpr T parity(T x) noexcept
Returns the parity of a value.
Definition: bit-math.hpp:319
std::uint64_t swap64(std::uint64_t x) noexcept
Swaps the byte order of an unsigned 64-bit number.
Definition: bit-math.hpp:370
constexpr T deposit(T x, T mask) noexcept
Reads bits from the least significant bits of a value and returns them in the positions marked by a m...
Definition: bit-math.hpp:265
constexpr T expand(T x) noexcept
Moves bits from the lower half of a value to occupy all even bits, and clears all odd bits.
Definition: bit-math.hpp:247
constexpr T extract(T x, T mask) noexcept
Reads bits from a value in the positions marked by a mask and returns them in the least significant b...
Definition: bit-math.hpp:286