💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

331 lines
7.6 KiB

  1. /*
  2. * Copyright (C) 2021 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. #ifndef ANTKEEPER_BIT_MATH_HPP
  20. #define ANTKEEPER_BIT_MATH_HPP
  21. /// Bitwise math
  22. namespace bit {
  23. /**
  24. * Compresses the even bits of a value into the lower half, then clears the upper half.
  25. *
  26. * @param x Value to compress.
  27. * @return Compressed value.
  28. */
  29. template <class T>
  30. constexpr T compress(T x) noexcept;
  31. /**
  32. * Returns the number of set bits in a value, known as a *population count* or *Hamming weight*.
  33. *
  34. * @param x Value to count.
  35. * @return Number of set bits in @p x.
  36. */
  37. template <class T>
  38. constexpr int count(T x) noexcept;
  39. /**
  40. * Performs a single-point crossover between two values.
  41. *
  42. * @param a First value.
  43. * @param b Second value.
  44. * @param i Index of the crossover point.
  45. * @return Crossed over value.
  46. */
  47. template <class T>
  48. constexpr T crossover(T a, T b, int i) noexcept;
  49. /**
  50. * Performs an n-point crossover between two values.
  51. *
  52. * @param a First value.
  53. * @param b Second value.
  54. * @param mask Bit mask with set bits marking crossover points.
  55. * @return Crossed over value.
  56. */
  57. template <class T>
  58. constexpr T crossover_n(T a, T b, T mask) noexcept;
  59. /**
  60. * Reads bits from the least significant bits of a value and returns them in the positions marked by a mask.
  61. *
  62. * @param x Value from which bits should be read.
  63. * @param mask Bit mask indicating where bits should be deposited.
  64. * @return Bits from the least significant bits of @p x in the positions marked by @p mask.
  65. */
  66. template <class T>
  67. constexpr T deposit(T x, T mask) noexcept;
  68. /**
  69. * Interleaves bits of the lower and upper halves of a value.
  70. *
  71. * @param x Value to desegregate.
  72. * @return Value with bits from the upper half of @p x interleaved with bits from the lower half.
  73. */
  74. template <class T>
  75. constexpr T desegregate(T x) noexcept;
  76. /**
  77. * Returns the number of differing bits between two values, known as *Hamming distance*.
  78. *
  79. * @param x First value.
  80. * @param y Second value.
  81. * @return Hamming distance between @px and @p y.
  82. */
  83. template <class T>
  84. constexpr int difference(T x, T y) noexcept;
  85. /**
  86. * Moves bits from the lower half of a value to occupy all even bits, and clears all odd bits.
  87. *
  88. * @param x Value to expand.
  89. * @return Expanded value.
  90. */
  91. template <class T>
  92. constexpr T expand(T x) noexcept;
  93. /**
  94. * Reads bits from a value in the positions marked by a mask and returns them in the least significant bits.
  95. *
  96. * @param x Value from which bits should be read.
  97. * @param mask Bit mask indicating which bits to extract.
  98. * @return Bits of @p x from the positions marked by @p mask in the least significant bits.
  99. */
  100. template <class T>
  101. constexpr T extract(T x, T mask) noexcept;
  102. /**
  103. * Flips a single bit in a value.
  104. *
  105. * @param x Value to modify.
  106. * @param i Index of the bit to flip.
  107. * @return Copy of @p x with one bit flipped.
  108. */
  109. template <class T>
  110. constexpr T flip(T x, int i) noexcept;
  111. /**
  112. * Returns a value with even bits containing the first value's lower half, and odd bits containing the second value's lower half.
  113. *
  114. * @param a First value.
  115. * @param b Second value.
  116. * @return Value with bits from the lower halves of @p a and @p b interleaved.
  117. */
  118. template <class T, class U = T>
  119. constexpr U interleave(T a, T b) noexcept;
  120. /**
  121. * Merges the bits of two values using a bit mask.
  122. *
  123. * @param a First value.
  124. * @param b Second value.
  125. * @param mask Bit mask with zeros where bits from @p a should be used, and ones where bits from @p b should be used.
  126. * @return Merged value.
  127. */
  128. template <class T>
  129. constexpr T merge(T a, T b, T mask) noexcept;
  130. /**
  131. * Returns the parity of a value.
  132. *
  133. * @param x Value to test.
  134. * @return `1` if an odd number of bits are set, `0` otherwise.
  135. */
  136. template <class T>
  137. constexpr T parity(T x) noexcept;
  138. /**
  139. * Segregates the odd and even bits of a value.
  140. *
  141. * @param x Value to segregate.
  142. * @return Value with even bits of @p x in the lower half, and odd bits in the upper half.
  143. */
  144. template <class T>
  145. constexpr T segregate(T x) noexcept;
  146. /**
  147. * Swaps the each odd bit with its following even bit.
  148. *
  149. * @param x Value in which adjacent bits should be swap.
  150. * @return Copy of @p x with adjacent bits swapped.
  151. */
  152. template <class T>
  153. constexpr T swap_adjacent(T x) noexcept;
  154. template <class T>
  155. constexpr T compress(T x) noexcept
  156. {
  157. x &= T(0x5555555555555555);
  158. x = (x ^ (x >> 1)) & T(0x3333333333333333);
  159. x = (x ^ (x >> 2)) & T(0x0f0f0f0f0f0f0f0f);
  160. if constexpr(sizeof(T) >= 2)
  161. x = (x ^ (x >> 4)) & T(0x00ff00ff00ff00ff);
  162. if constexpr(sizeof(T) >= 4)
  163. x = (x ^ (x >> 8)) & T(0x0000ffff0000ffff);
  164. if constexpr(sizeof(T) >= 8)
  165. x = (x ^ (x >> 16)) & T(0x00000000ffffffff);
  166. return x;
  167. }
  168. template <class T>
  169. constexpr int count(T x) noexcept
  170. {
  171. int n = 0;
  172. for (; x; ++n)
  173. x &= x - 1;
  174. return n;
  175. }
  176. template <class T>
  177. inline constexpr T crossover(T a, T b, int i) noexcept
  178. {
  179. T mask = (T(1) << i) - 1;
  180. return merge(b, a, mask);
  181. }
  182. template <class T>
  183. constexpr T crossover_n(T a, T b, T mask) noexcept
  184. {
  185. T merge = ~T(0) * parity(mask);
  186. while (mask)
  187. {
  188. merge ^= (mask ^ (mask - 1)) >> 1;
  189. mask &= mask - 1;
  190. }
  191. return merge(a, b, merge);
  192. }
  193. template <class T>
  194. inline constexpr T desegregate(T x) noexcept
  195. {
  196. return interleave<T>(x, x >> (sizeof(T) << 2));
  197. }
  198. template <class T>
  199. constexpr T expand(T x) noexcept
  200. {
  201. x &= (1 << (sizeof(T) << 2)) - 1;
  202. if constexpr(sizeof(T) >= 8)
  203. x = (x ^ (x << 16)) & T(0x0000ffff0000ffff);
  204. if constexpr(sizeof(T) >= 4)
  205. x = (x ^ (x << 8)) & T(0x00ff00ff00ff00ff);
  206. if constexpr(sizeof(T) >= 2)
  207. x = (x ^ (x << 4)) & T(0x0f0f0f0f0f0f0f0f);
  208. x = (x ^ (x << 2)) & T(0x3333333333333333);
  209. x = (x ^ (x << 1)) & T(0x5555555555555555);
  210. return x;
  211. }
  212. template <class T>
  213. constexpr T deposit(T x, T mask) noexcept
  214. {
  215. T result = 0;
  216. for (T i = 1; mask; i <<= 1)
  217. {
  218. if (x & i)
  219. result |= mask & -mask;
  220. mask &= mask - 1;
  221. }
  222. return result;
  223. }
  224. template <class T>
  225. inline constexpr int difference(T x, T y) noexcept
  226. {
  227. return count(x ^ y);
  228. }
  229. template <class T>
  230. constexpr T extract(T x, T mask) noexcept
  231. {
  232. T result = 0;
  233. for (T i = 1; mask; i <<= 1)
  234. {
  235. if (x & mask & -mask)
  236. result |= i;
  237. mask &= mask - 1;
  238. }
  239. return result;
  240. }
  241. template <class T>
  242. inline constexpr T flip(T x, int i) noexcept
  243. {
  244. return x ^ (T(1) << i);
  245. }
  246. template <class T, class U>
  247. inline constexpr U interleave(T a, T b) noexcept
  248. {
  249. return expand<U>(a) | (expand<U>(b) << 1);
  250. }
  251. template <class T>
  252. inline constexpr T merge(T a, T b, T mask) noexcept
  253. {
  254. return a ^ ((a ^ b) & mask);
  255. }
  256. template <class T>
  257. constexpr T parity(T x) noexcept
  258. {
  259. if constexpr(sizeof(T) >= 8)
  260. x ^= x >> 32;
  261. if constexpr(sizeof(T) >= 4)
  262. x ^= x >> 16;
  263. if constexpr(sizeof(T) >= 2)
  264. x ^= x >> 8;
  265. x ^= x >> 4;
  266. return (0x6996 >> (x & 0xf)) & 1;
  267. }
  268. template <class T>
  269. constexpr T segregate(T x) noexcept
  270. {
  271. T odd = compress(x);
  272. T even = compress(x >> 1);
  273. return odd | (even << (sizeof(T) << 2));
  274. }
  275. template <class T>
  276. constexpr T swap_adjacent(T x) noexcept
  277. {
  278. return ((x & T(0xaaaaaaaaaaaaaaaa)) >> 1) | ((x & T(0x5555555555555555)) << 1);
  279. }
  280. } // namespace bit
  281. #endif // ANTKEEPER_BIT_MATH_HPP