Algorithm.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. #pragma once
  2. #include <type_traits>
  3. #include <limits>
  4. #include "Internal/TypeTraits.h"
  5. namespace baselib
  6. {
  7. BASELIB_CPP_INTERFACE
  8. {
  9. namespace Algorithm
  10. {
  11. // Index of the most significant bit in a 32bit mask. Returns -1 if no bits are set.
  12. inline int HighestBit(uint32_t value);
  13. // Index of the most significant bit in a 32bit mask of size_t value. Returns -1 if no bits are set.
  14. template<typename T, typename std::enable_if<std::is_same<size_t, T>::value && sizeof(T) == 4, bool>::type = 0>
  15. inline int HighestBit(T value) { return HighestBit(static_cast<uint32_t>(value)); }
  16. // Index of the most significant bit in a 64bit mask. Returns -1 if no bits are set.
  17. inline int HighestBit(uint64_t value);
  18. // Index of the most significant bit in a 64bit mask of size_t value. Returns -1 if no bits are set.
  19. template<typename T, typename std::enable_if<std::is_same<size_t, T>::value && sizeof(T) == 8, bool>::type = 0>
  20. inline int HighestBit(T value) { return HighestBit(static_cast<uint64_t>(value)); }
  21. // Index of the most significant bit in a 32bit mask. Unspecified result if no bits are set.
  22. inline int HighestBitNonZero(uint32_t value);
  23. // Index of the most significant bit in a 32bit mask of size_t value. Unspecified result if no bits are set.
  24. template<typename T, typename std::enable_if<std::is_same<size_t, T>::value && sizeof(T) == 4, bool>::type = 0>
  25. inline int HighestBitNonZero(T value) { return HighestBitNonZero(static_cast<uint32_t>(value)); }
  26. // Index of the most significant bit in a 64bit mask. Unspecified result if no bits are set.
  27. inline int HighestBitNonZero(uint64_t value);
  28. // Index of the most significant bit in a 64bit mask of size_t value. Unspecified result if no bits are set.
  29. template<typename T, typename std::enable_if<std::is_same<size_t, T>::value && sizeof(T) == 8, bool>::type = 0>
  30. inline int HighestBitNonZero(T value) { return HighestBitNonZero(static_cast<uint64_t>(value)); }
  31. // Index of the least significant bit in a 32bit mask. Returns -1 if no bits are set.
  32. inline int LowestBit(uint32_t value);
  33. // Index of the least significant bit in a 32bit mask of size_t value. Returns -1 if no bits are set.
  34. template<typename T, typename std::enable_if<std::is_same<size_t, T>::value && sizeof(T) == 4, bool>::type = 0>
  35. inline int LowestBit(T value) { return LowestBit(static_cast<uint32_t>(value)); }
  36. // Index of the least significant bit in a 64bit mask. Returns -1 if no bits are set.
  37. inline int LowestBit(uint64_t value);
  38. // Index of the least significant bit in a 64bit mask of size_t value. Returns -1 if no bits are set.
  39. template<typename T, typename std::enable_if<std::is_same<size_t, T>::value && sizeof(T) == 8, bool>::type = 0>
  40. inline int LowestBit(T value) { return LowestBit(static_cast<uint64_t>(value)); }
  41. // Index of the least significant bit in a 32bit mask. Unspecified result if no bits are set.
  42. inline int LowestBitNonZero(uint32_t value);
  43. // Index of the least significant bit in a 32bit mask of size_t value. Unspecified result if no bits are set.
  44. template<typename T, typename std::enable_if<std::is_same<size_t, T>::value && sizeof(T) == 4, bool>::type = 0>
  45. inline int LowestBitNonZero(T value) { return LowestBitNonZero(static_cast<uint32_t>(value)); }
  46. // Index of the least significant bit in a 64bit mask. Unspecified result if no bits are set.
  47. inline int LowestBitNonZero(uint64_t value);
  48. // Index of the least significant bit in a 64bit mask of size_t value. Unspecified result if no bits are set.
  49. template<typename T, typename std::enable_if<std::is_same<size_t, T>::value && sizeof(T) == 8, bool>::type = 0>
  50. inline int LowestBitNonZero(T value) { return LowestBitNonZero(static_cast<uint64_t>(value)); }
  51. // Returns number of set bits in a 64 bit mask.
  52. inline int BitsInMask(uint64_t mask);
  53. // Returns number of set bits in a 32 bit mask.
  54. inline int BitsInMask(uint32_t mask);
  55. // Returns number of set bits in a 16 bit mask.
  56. inline int BitsInMask(uint16_t mask);
  57. // Returns number os set bits in a 8 bit mask.
  58. inline int BitsInMask(uint8_t mask);
  59. // Number of set bits (population count) in an array of known size.
  60. // Using Robert Harley and David Seal's algorithm from Hacker's Delight,
  61. // variant that does 4 words in a loop iteration.
  62. // http://www.hackersdelight.org/revisions.pdf
  63. // http://www.hackersdelight.org/HDcode/newCode/pop_arrayHS.cc
  64. template<typename WordT, int WordCount>
  65. inline int BitsInArray(const WordT* data)
  66. {
  67. #define HarleySealCSAStep(h, l, a, b, c) {\
  68. WordT u = a ^ b; \
  69. h = (a & b) | (u & c); l = u ^ c; \
  70. }
  71. WordT ones, twos, twosA, twosB, fours;
  72. int i = 0;
  73. int tot = 0;
  74. twos = ones = 0;
  75. for (; i <= WordCount - 4; i = i + 4)
  76. {
  77. HarleySealCSAStep(twosA, ones, ones, data[i], data[i + 1])
  78. HarleySealCSAStep(twosB, ones, ones, data[i + 2], data[i + 3])
  79. HarleySealCSAStep(fours, twos, twos, twosA, twosB)
  80. tot = tot + BitsInMask(fours);
  81. }
  82. tot = 4 * tot + 2 * BitsInMask(twos) + BitsInMask(ones);
  83. for (; i < WordCount; i++) // Simply add in the last
  84. tot = tot + BitsInMask(data[i]); // 0 to 3 elements.
  85. return tot;
  86. #undef HarleySealCSAStep
  87. }
  88. // Checks if one integers is a multiple of another.
  89. template<typename T>
  90. constexpr inline bool AreIntegersMultiple(T a, T b)
  91. {
  92. static_assert(std::is_integral<T>::value, "AreIntegersMultiple requires integral types.");
  93. return a != 0 && b != 0 && // if at least one integer is 0, consider false (avoid div by 0 of the following modulo)
  94. ((a % b) == 0 || (b % a) == 0);
  95. }
  96. // Checks if value is a power-of-two.
  97. template<typename T>
  98. constexpr inline bool IsPowerOfTwo(T value)
  99. {
  100. static_assert(std::is_integral<T>::value, "IsPowerOfTwo works only with an integral type.");
  101. using T_unsigned = typename std::make_unsigned<T>::type;
  102. return (static_cast<T_unsigned>(value) & (static_cast<T_unsigned>(value) - 1)) == 0;
  103. }
  104. // Returns the next power-of-two of a 32bit number or the current value if it is a power two.
  105. inline uint32_t CeilPowerOfTwo(uint32_t value)
  106. {
  107. value -= 1;
  108. value |= value >> 16;
  109. value |= value >> 8;
  110. value |= value >> 4;
  111. value |= value >> 2;
  112. value |= value >> 1;
  113. return value + 1;
  114. }
  115. // Returns the next power-of-two of a 32bit number of size_t value, or the current value if it is a power two.
  116. template<typename T, typename std::enable_if<std::is_same<size_t, T>::value && sizeof(T) == 4, bool>::type = 0>
  117. inline uint32_t CeilPowerOfTwo(T value) { return CeilPowerOfTwo(static_cast<uint32_t>(value)); }
  118. // Returns the next power-of-two of a 64bit number or the current value if it is a power two.
  119. inline uint64_t CeilPowerOfTwo(uint64_t value)
  120. {
  121. value -= 1;
  122. value |= value >> 32;
  123. value |= value >> 16;
  124. value |= value >> 8;
  125. value |= value >> 4;
  126. value |= value >> 2;
  127. value |= value >> 1;
  128. return value + 1;
  129. }
  130. // Returns the next power-of-two of a 64bit number of size_t value, or the current value if it is a power two.
  131. template<typename T, typename std::enable_if<std::is_same<size_t, T>::value && sizeof(T) == 8, bool>::type = 0>
  132. inline uint64_t CeilPowerOfTwo(T value) { return CeilPowerOfTwo(static_cast<uint64_t>(value)); }
  133. // Returns the closest power-of-two of a 32bit number.
  134. template<typename T>
  135. inline T RoundPowerOfTwo(T value)
  136. {
  137. static_assert(std::is_unsigned<T>::value, "RoundPowerOfTwo works only with an unsigned integral type.");
  138. const T nextPower = CeilPowerOfTwo(value);
  139. const T prevPower = nextPower >> 1;
  140. if (value - prevPower < nextPower - value)
  141. return prevPower;
  142. else
  143. return nextPower;
  144. }
  145. // Returns true if addition of two given operands leads to an integer overflow.
  146. template<typename T>
  147. constexpr inline bool DoesAdditionOverflow(T a, T b)
  148. {
  149. static_assert(std::is_unsigned<T>::value, "Overflow checks apply only work on unsigned integral types.");
  150. return std::numeric_limits<T>::max() - a < b;
  151. }
  152. // Returns true if multiplication of two given operands leads to an integer overflow.
  153. template<typename T>
  154. constexpr inline bool DoesMultiplicationOverflow(T a, T b)
  155. {
  156. static_assert(std::is_unsigned<T>::value, "Overflow checks apply only work on unsigned integral types.");
  157. return b != 0 && std::numeric_limits<T>::max() / b < a;
  158. }
  159. // Clamp
  160. //
  161. // This function can be used with different types - `value` vs. `lo`, `hi`.
  162. // If `lo` if larger than `hi` this function has undefined bahavior.
  163. //
  164. // Return: clamped `value` of the same type as `lo`, `hi`.
  165. //
  166. COMPILER_WARNINGS_PUSH
  167. #if COMPILER_MSVC
  168. COMPILER_WARNINGS_DISABLE(4756)
  169. #endif
  170. template<typename RT, typename VT, typename std::enable_if<
  171. baselib::is_of_same_signedness<RT, VT>::value
  172. || !std::is_integral<RT>::value
  173. || !std::is_integral<VT>::value
  174. , bool>::type = 0>
  175. inline RT Clamp(VT value, RT lo, RT hi)
  176. {
  177. if (value < lo) return lo;
  178. if (value > hi) return hi;
  179. return static_cast<RT>(value);
  180. }
  181. COMPILER_WARNINGS_POP
  182. template<typename RT, typename VT, typename std::enable_if<
  183. std::is_integral<RT>::value && std::is_unsigned<RT>::value &&
  184. std::is_integral<VT>::value && std::is_signed<VT>::value
  185. , bool>::type = 0>
  186. inline RT Clamp(VT value, RT lo, RT hi)
  187. {
  188. if (value < 0)
  189. return lo;
  190. using UnsignedVT = typename std::make_unsigned<VT>::type;
  191. return Clamp(static_cast<UnsignedVT>(value), lo, hi);
  192. }
  193. template<typename RT, typename VT, typename std::enable_if<
  194. std::is_integral<RT>::value && std::is_signed<RT>::value &&
  195. std::is_integral<VT>::value && std::is_unsigned<VT>::value
  196. , bool>::type = 0>
  197. inline RT Clamp(VT value, RT lo, RT hi)
  198. {
  199. if (hi < 0)
  200. return hi;
  201. if (lo < 0)
  202. lo = 0;
  203. using UnsignedRT = typename std::make_unsigned<RT>::type;
  204. return static_cast<RT>(Clamp(value, static_cast<UnsignedRT>(lo), static_cast<UnsignedRT>(hi)));
  205. }
  206. // Clamp `value` by lowest and highest value of RT.
  207. //
  208. // Return: clamped `value` of the type RT.
  209. //
  210. template<typename RT, typename VT, typename std::enable_if<
  211. !(std::numeric_limits<RT>::has_infinity && std::numeric_limits<VT>::has_infinity)
  212. , bool>::type = 0>
  213. inline RT ClampToType(VT value)
  214. {
  215. return Clamp(value, std::numeric_limits<RT>::lowest(), std::numeric_limits<RT>::max());
  216. }
  217. // Clamp `value` by lowest and highest value of RT.
  218. //
  219. // This function is guaranteed to only return infinity values if the source value was already an infinity number.
  220. //
  221. // Return: clamped `value` of the type RT.
  222. //
  223. template<typename RT, typename VT, typename std::enable_if<
  224. (std::numeric_limits<RT>::has_infinity && std::numeric_limits<VT>::has_infinity)
  225. , bool>::type = 0>
  226. inline RT ClampToType(VT value)
  227. {
  228. if (value == std::numeric_limits<VT>::infinity() || value == -std::numeric_limits<VT>::infinity())
  229. return static_cast<RT>(value);
  230. return Clamp(value, std::numeric_limits<RT>::lowest(), std::numeric_limits<RT>::max());
  231. }
  232. }
  233. }
  234. }
  235. #if COMPILER_MSVC
  236. #include "Internal/Compiler/Msvc/AlgorithmMsvc.inl.h"
  237. #elif COMPILER_GCC || COMPILER_CLANG
  238. #include "Internal/Compiler/ClangOrGcc/AlgorithmClangOrGcc.inl.h"
  239. #else
  240. #error "Unknown Compiler"
  241. #endif