Algorithm.h 14 KB

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