BitHacks.h 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. // David Eberly, Geometric Tools, Redmond WA 98052
  2. // Copyright (c) 1998-2020
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // https://www.boost.org/LICENSE_1_0.txt
  5. // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
  6. // Version: 4.0.2019.08.13
  7. #pragma once
  8. #include <Mathematics/Logger.h>
  9. #include <array>
  10. #include <cstdint>
  11. // The leadingBit table in GetLeadingBit and the trailingBit table in
  12. // GetTrailingBit are based on De Bruijn sequences. The leadingBit table
  13. // is taken from
  14. // https://stackoverflow.com/questions/17027878/algorithm-to-find-the-most-significant-bit
  15. // The trailingBit table is taken from
  16. // https://www.dotnetperls.com/trailing-bits
  17. // The int32_t inputs to the bit-hack functions are required to be
  18. // nonnegative. Expose this if you want exceptions thrown when the
  19. // int32_t inputs are negative.
  20. #define GTE_THROW_ON_BITHACKS_ERROR
  21. namespace WwiseGTE
  22. {
  23. class BitHacks
  24. {
  25. public:
  26. static bool IsPowerOfTwo(uint32_t value)
  27. {
  28. return (value > 0) && ((value & (value - 1)) == 0);
  29. }
  30. static bool IsPowerOfTwo(int32_t value)
  31. {
  32. #if defined(GTE_THROW_ON_BITHACKS_ERROR)
  33. LogAssert(value >= 0, "Invalid input.");
  34. #endif
  35. return IsPowerOfTwo(static_cast<int32_t>(value));
  36. }
  37. static uint32_t Log2OfPowerOfTwo(uint32_t powerOfTwo)
  38. {
  39. uint32_t log2 = (powerOfTwo & 0xAAAAAAAAu) != 0;
  40. log2 |= ((powerOfTwo & 0xFFFF0000u) != 0) << 4;
  41. log2 |= ((powerOfTwo & 0xFF00FF00u) != 0) << 3;
  42. log2 |= ((powerOfTwo & 0xF0F0F0F0u) != 0) << 2;
  43. log2 |= ((powerOfTwo & 0xCCCCCCCCu) != 0) << 1;
  44. return log2;
  45. }
  46. static int32_t Log2OfPowerOfTwo(int32_t powerOfTwo)
  47. {
  48. #if defined(GTE_THROW_ON_BITHACKS_ERROR)
  49. LogAssert(powerOfTwo >= 0, "Invalid input.");
  50. #endif
  51. return static_cast<int32_t>(Log2OfPowerOfTwo(static_cast<uint32_t>(powerOfTwo)));
  52. }
  53. // The return value of the function is the index into the 32-bit value.
  54. // For example, GetLeadingBit(10) = 3 and GetTrailingBit(10) = 2. The
  55. // value in binary is 0x0000000000001010. The bit locations start at 0
  56. // on the right of the pattern and end at 31 on the left of the pattern.
  57. // If the input value is zero, there is no leading bit and no trailing
  58. // bit. However, the functions return 0, which is considered invalid.
  59. // Try to call these functions only for positive inputs.
  60. static int32_t GetLeadingBit(uint32_t value)
  61. {
  62. static std::array<int32_t, 32> const leadingBitTable =
  63. {
  64. 0, 9, 1, 10, 13, 21, 2, 29,
  65. 11, 14, 16, 18, 22, 25, 3, 30,
  66. 8, 12, 20, 28, 15, 17, 24, 7,
  67. 19, 27, 23, 6, 26, 5, 4, 31
  68. };
  69. value |= value >> 1;
  70. value |= value >> 2;
  71. value |= value >> 4;
  72. value |= value >> 8;
  73. value |= value >> 16;
  74. uint32_t key = (value * 0x07C4ACDDu) >> 27;
  75. return leadingBitTable[key];
  76. }
  77. static int32_t GetLeadingBit(int32_t value)
  78. {
  79. #if defined(GTE_THROW_ON_BITHACKS_ERROR)
  80. LogAssert(value != 0, "Invalid input.");
  81. #endif
  82. return GetLeadingBit(static_cast<uint32_t>(value));
  83. }
  84. static int32_t GetLeadingBit(uint64_t value)
  85. {
  86. uint32_t v1 = static_cast<uint32_t>((value >> 32) & 0x00000000FFFFFFFFull);
  87. if (v1 != 0)
  88. {
  89. return GetLeadingBit(v1) + 32;
  90. }
  91. uint32_t v0 = static_cast<uint32_t>(value & 0x00000000FFFFFFFFull);
  92. return GetLeadingBit(v0);
  93. }
  94. static int32_t GetLeadingBit(int64_t value)
  95. {
  96. #if defined(GTE_THROW_ON_BITHACKS_ERROR)
  97. LogAssert(value != 0, "Invalid input.");
  98. #endif
  99. return GetLeadingBit(static_cast<uint64_t>(value));
  100. }
  101. static int32_t GetTrailingBit(int32_t value)
  102. {
  103. static std::array<int32_t, 32> const trailingBitTable =
  104. {
  105. 0, 1, 28, 2, 29, 14, 24, 3,
  106. 30, 22, 20, 15, 25, 17, 4, 8,
  107. 31, 27, 13, 23, 21, 19, 16, 7,
  108. 26, 12, 18, 6, 11, 5, 10, 9
  109. };
  110. #if defined(GTE_THROW_ON_BITHACKS_ERROR)
  111. LogAssert(value != 0, "Invalid input.");
  112. #endif
  113. uint32_t key = (static_cast<uint32_t>((value & -value) * 0x077CB531u)) >> 27;
  114. return trailingBitTable[key];
  115. }
  116. static int32_t GetTrailingBit(uint32_t value)
  117. {
  118. // The GetTrailingBit(int32_t) function contains the actual
  119. // implementation. If the uint32_t-based function were to be
  120. // implemented, the (value & -value) statement generates a compiler
  121. // warning about negating an unsigned integer, which requires
  122. // additional logic to avoid.
  123. return GetTrailingBit(static_cast<int32_t>(value));
  124. }
  125. static int32_t GetTrailingBit(uint64_t value)
  126. {
  127. uint32_t v0 = static_cast<uint32_t>(value & 0x00000000FFFFFFFFull);
  128. if (v0 != 0)
  129. {
  130. return GetTrailingBit(v0);
  131. }
  132. uint32_t v1 = static_cast<uint32_t>((value >> 32) & 0x00000000FFFFFFFFull);
  133. if (v1 != 0)
  134. {
  135. return GetTrailingBit(v1) + 32;
  136. }
  137. return 0;
  138. }
  139. static int32_t GetTrailingBit(int64_t value)
  140. {
  141. #if defined(GTE_THROW_ON_BITHACKS_ERROR)
  142. LogAssert(value != 0, "Invalid input.");
  143. #endif
  144. return GetTrailingBit(static_cast<uint64_t>(value));
  145. }
  146. // Round up to a power of two. If input is zero, the return is 1. If
  147. // input is larger than 2^{31}, the return is 2^{32}.
  148. static uint64_t RoundUpToPowerOfTwo(uint32_t value)
  149. {
  150. if (value > 0)
  151. {
  152. int32_t leading = GetLeadingBit(value);
  153. uint32_t mask = (1 << leading);
  154. if ((value & ~mask) == 0)
  155. {
  156. // value is a power of two
  157. return static_cast<uint64_t>(value);
  158. }
  159. else
  160. {
  161. // round up to a power of two
  162. return (static_cast<uint64_t>(mask) << 1);
  163. }
  164. }
  165. else
  166. {
  167. return 1ull;
  168. }
  169. }
  170. // Round down to a power of two. If input is zero, the return is 0.
  171. static uint32_t RoundDownToPowerOfTwo(uint32_t value)
  172. {
  173. if (value > 0)
  174. {
  175. int32_t leading = GetLeadingBit(value);
  176. uint32_t mask = (1 << leading);
  177. return mask;
  178. }
  179. else
  180. {
  181. return 0;
  182. }
  183. }
  184. };
  185. }