Functions.h 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. // Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. /// @file
  6. /// Contains misc functions
  7. #pragma once
  8. #include <AnKi/Util/StdTypes.h>
  9. #include <AnKi/Util/Assert.h>
  10. #include <cmath>
  11. #include <utility>
  12. #include <new>
  13. #include <cstring>
  14. #include <algorithm>
  15. #include <functional>
  16. namespace anki
  17. {
  18. /// @addtogroup util_other
  19. /// @{
  20. #define _ANKI_CONCATENATE(a, b) a##b
  21. /// Concatenate 2 preprocessor tokens.
  22. #define ANKI_CONCATENATE(a, b) _ANKI_CONCATENATE(a, b)
  23. #define _ANKI_STRINGIZE(a) #a
  24. /// Make a preprocessor token a string.
  25. #define ANKI_STRINGIZE(a) _ANKI_STRINGIZE(a)
  26. /// Format to print bits
  27. #define ANKI_PRIb8 "c%c%c%c%c%c%c%c"
  28. #define ANKI_PRIb16 ANKI_PRIb8 "%c%c%c%c%c%c%c%c"
  29. #define ANKI_PRIb32 ANKI_PRIb16 "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c"
  30. #define ANKI_PRIb64 ANKI_PRIb32 "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c"
  31. #define _ANKI_FORMAT_HELPER(byte, bit) (U64(byte) & (U64(1) << U64(bit))) ? '1' : '0'
  32. #define ANKI_FORMAT_U8(byte) \
  33. _ANKI_FORMAT_HELPER((byte), 7), _ANKI_FORMAT_HELPER((byte), 6), _ANKI_FORMAT_HELPER((byte), 5), \
  34. _ANKI_FORMAT_HELPER((byte), 4), _ANKI_FORMAT_HELPER((byte), 3), _ANKI_FORMAT_HELPER((byte), 2), \
  35. _ANKI_FORMAT_HELPER((byte), 1), _ANKI_FORMAT_HELPER((byte), 0)
  36. #define ANKI_FORMAT_U16(u16) ANKI_FORMAT_U8(u16 >> 8), ANKI_FORMAT_U8(u16)
  37. #define ANKI_FORMAT_U32(u32) ANKI_FORMAT_U16(u32 >> 16), ANKI_FORMAT_U16(u32)
  38. #define ANKI_FORMAT_U64(u64) ANKI_FORMAT_U32(u64 >> 32), ANKI_FORMAT_U32(u64)
  39. // ANKI_ENABLE_METHOD & ANKI_ENABLE_ARG trickery copied from Tick library
  40. template<typename T, int N>
  41. struct DummyType
  42. {
  43. };
  44. #if defined(_MSC_VER)
  45. template<bool B>
  46. struct RequiresBool
  47. {
  48. static constexpr bool VALUE = B;
  49. };
  50. template<typename T, int N>
  51. struct RequiresUnwrap : T
  52. {
  53. };
  54. template<int N>
  55. struct PrivateEnum
  56. {
  57. enum class Type
  58. {
  59. NA
  60. };
  61. };
  62. # define ANKI_REQUIRES_BOOL(line, ...) RequiresUnwrap<decltype(RequiresBool<(__VA_ARGS__)>{}), line>::VALUE
  63. # define ANKI_ENABLE_INTERNAL(line, ...) \
  64. typename PrivateEnum<line>::Type ANKI_CONCATENATE( \
  65. privateEnum, line) = PrivateEnum<line>::Type::NA, \
  66. bool ANKI_CONCATENATE(privateBool, line) = true, \
  67. typename = typename std::enable_if_t<(ANKI_CONCATENATE(privateBool, line) \
  68. && ANKI_REQUIRES_BOOL(line, __VA_ARGS__))>
  69. #else
  70. # define ANKI_ENABLE_INTERNAL(line, ...) \
  71. bool privateBool##line = true, typename std::enable_if_t<(privateBool##line && __VA_ARGS__), int> = 0
  72. #endif
  73. /// Use it to enable a method based on a constant expression.
  74. /// @code
  75. /// template<int N> class Foo {
  76. /// ANKI_ENABLE_METHOD(N == 10)
  77. /// void foo() {}
  78. /// };
  79. /// @endcode
  80. #define ANKI_ENABLE_METHOD(...) template<ANKI_ENABLE_INTERNAL(__LINE__, __VA_ARGS__)>
  81. /// Use it to enable a method based on a constant expression.
  82. /// @code
  83. /// class Foo {
  84. /// void foo(ANKI_ENABLE_ARG(Boo, expr) b) {}
  85. /// };
  86. /// @endcode
  87. #define ANKI_ENABLE_ARG(type_, expression) \
  88. typename std::conditional<(expression), type_, DummyType<type_, __LINE__>>::type
  89. /// Use it to enable a method based on a constant expression.
  90. /// @code
  91. /// template<typename T, ANKI_ENABLE(std::is_whatever<T>::value)>
  92. /// void foo(T x) {}
  93. /// @endcode
  94. #define ANKI_ENABLE(...) ANKI_ENABLE_INTERNAL(__LINE__, __VA_ARGS__)
  95. /// OS specific debug breakpoint
  96. #if ANKI_OS_WINDOWS
  97. # define ANKI_DEBUG_BREAK() __debugbreak()
  98. #else
  99. # define ANKI_DEBUG_BREAK() abort()
  100. #endif
  101. /// Get a pseudo random number.
  102. U64 getRandom();
  103. /// Pick a random number from min to max
  104. template<typename T, ANKI_ENABLE(std::is_floating_point<T>::value)>
  105. T getRandomRange(T min, T max)
  106. {
  107. ANKI_ASSERT(min <= max);
  108. const F64 r = F64(getRandom()) / F64(MAX_U64);
  109. return T(min + r * (max - min));
  110. }
  111. template<typename T, ANKI_ENABLE(std::is_integral<T>::value)>
  112. T getRandomRange(T min, T max)
  113. {
  114. ANKI_ASSERT(min <= max);
  115. const U64 r = getRandom();
  116. return T(r % U64(max - min + 1)) + min;
  117. }
  118. /// Get min of two values.
  119. template<typename T>
  120. inline constexpr T min(T a, T b)
  121. {
  122. return (a < b) ? a : b;
  123. }
  124. /// Get max of two values.
  125. template<typename T>
  126. inline constexpr T max(T a, T b)
  127. {
  128. return (a > b) ? a : b;
  129. }
  130. /// Check if a number is a power of 2
  131. template<typename Int, ANKI_ENABLE(std::is_integral<Int>::value)>
  132. inline constexpr Bool isPowerOfTwo(Int x)
  133. {
  134. return !(x == 0) && !(x & (x - 1));
  135. }
  136. /// Get the next power of two number. For example if x is 130 this will return 256.
  137. template<typename Int, ANKI_ENABLE(std::is_integral<Int>::value)>
  138. inline constexpr Int nextPowerOfTwo(Int x)
  139. {
  140. const F64 d = F64(x);
  141. const F64 res = pow(2.0, ceil(log(d) / log(2.0)));
  142. return Int(res);
  143. }
  144. /// Get the aligned number rounded up.
  145. /// @param alignment The bytes of alignment
  146. /// @param value The value to align
  147. template<typename TInt, ANKI_ENABLE(std::is_integral<TInt>::value)>
  148. inline constexpr TInt getAlignedRoundUp(PtrSize alignment, TInt value)
  149. {
  150. ANKI_ASSERT(alignment > 0);
  151. PtrSize v = PtrSize(value);
  152. v = ((v + alignment - 1) / alignment) * alignment;
  153. return TInt(v);
  154. }
  155. /// Get the aligned number rounded up.
  156. /// @param alignment The bytes of alignment
  157. /// @param value The value to align
  158. template<typename TFloat, ANKI_ENABLE(std::is_floating_point<TFloat>::value)>
  159. inline constexpr TFloat getAlignedRoundUp(TFloat alignment, TFloat value)
  160. {
  161. ANKI_ASSERT(alignment > TFloat(0.0));
  162. return ceil(value / alignment) * alignment;
  163. }
  164. /// Align number
  165. /// @param alignment The bytes of alignment
  166. /// @param value The value to align
  167. template<typename TAlignment, typename TValue>
  168. inline void alignRoundUp(TAlignment alignment, TValue& value)
  169. {
  170. value = getAlignedRoundUp(alignment, value);
  171. }
  172. /// Get the aligned number rounded down.
  173. /// @param alignment The bytes of alignment
  174. /// @param value The value to align
  175. template<typename TInt, ANKI_ENABLE(std::is_integral<TInt>::value)>
  176. inline constexpr TInt getAlignedRoundDown(PtrSize alignment, TInt value)
  177. {
  178. ANKI_ASSERT(alignment > 0);
  179. PtrSize v = PtrSize(value);
  180. v = (v / alignment) * alignment;
  181. return TInt(v);
  182. }
  183. /// Get the aligned number rounded down.
  184. /// @param alignment The bytes of alignment
  185. /// @param value The value to align
  186. template<typename TFloat, ANKI_ENABLE(std::is_floating_point<TFloat>::value)>
  187. inline constexpr TFloat getAlignedRoundDown(TFloat alignment, TFloat value)
  188. {
  189. ANKI_ASSERT(alignment > TFloat(0.0));
  190. return floor(value / alignment) * alignment;
  191. }
  192. /// Align number
  193. /// @param alignment The bytes of alignment
  194. /// @param value The value to align
  195. template<typename TAlignment, typename TValue>
  196. inline void alignRoundDown(TAlignment alignment, TValue& value)
  197. {
  198. value = getAlignedRoundDown(alignment, value);
  199. }
  200. /// Check if a number is aligned
  201. template<typename Type>
  202. inline constexpr Bool isAligned(PtrSize alignment, Type value)
  203. {
  204. return (PtrSize(value) % alignment) == 0;
  205. }
  206. template<typename T>
  207. inline void swapValues(T& a, T& b)
  208. {
  209. const T tmp = b;
  210. b = a;
  211. a = tmp;
  212. }
  213. /// Convert any pointer to a number.
  214. template<typename TPtr>
  215. inline PtrSize ptrToNumber(TPtr ptr)
  216. {
  217. const uintptr_t i = reinterpret_cast<uintptr_t>(ptr);
  218. const PtrSize size = i;
  219. return size;
  220. }
  221. /// Convert a number to a pointer.
  222. template<typename TPtr>
  223. inline constexpr TPtr numberToPtr(PtrSize num)
  224. {
  225. uintptr_t i = static_cast<uintptr_t>(num);
  226. TPtr ptr = reinterpret_cast<TPtr>(i);
  227. return ptr;
  228. }
  229. /// A simple template trick to remove the pointer from one type
  230. ///
  231. /// Example:
  232. /// @code
  233. /// using Ptr = double*;
  234. /// RemovePointer<Ptr>::Type b = 666.0;
  235. /// @endcode
  236. /// The b is of type double
  237. template<typename T>
  238. struct RemovePointer;
  239. template<typename T>
  240. struct RemovePointer<T*>
  241. {
  242. using Type = T;
  243. };
  244. /// Zero memory of an object
  245. template<typename T>
  246. void zeroMemory(T& x)
  247. {
  248. memset(&x, 0, sizeof(T));
  249. }
  250. /// Find a value in a shorted container.
  251. template<class TForwardIterator, class T, class TCompare = std::less<>>
  252. TForwardIterator binarySearch(TForwardIterator first, TForwardIterator last, const T& value, TCompare comp = {})
  253. {
  254. first = std::lower_bound(first, last, value, comp);
  255. return (first != last && !comp(value, *first)) ? first : last;
  256. }
  257. /// Individual classes should specialize that function if they are packed. If a class is packed it can be used as
  258. /// whole in hashing.
  259. template<typename T>
  260. constexpr Bool isPacked()
  261. {
  262. return false;
  263. }
  264. /// Unflatten 3D array index.
  265. /// Imagine an array [sizeA][sizeB][sizeC] and a flat index in that array. Then this function will compute the unflatten
  266. /// indices.
  267. template<typename T, typename TI, typename TOut>
  268. inline void unflatten3dArrayIndex(const T sizeA, const T sizeB, const T sizeC, const TI flatIdx, TOut& a, TOut& b,
  269. TOut& c)
  270. {
  271. ANKI_ASSERT(flatIdx < (sizeA * sizeB * sizeC));
  272. a = (flatIdx / (sizeB * sizeC)) % sizeA;
  273. b = (flatIdx / sizeC) % sizeB;
  274. c = flatIdx % sizeC;
  275. }
  276. /// Given a threaded problem split it into smaller ones. This function accepts the number of threads and the size of
  277. /// the threaded problem. Then given a thread index it chooses a range that the thread can operate into. That range is
  278. /// supposed to be as evenly split as possible across threads.
  279. inline void splitThreadedProblem(U32 threadId, U32 threadCount, U32 problemSize, U32& start, U32& end)
  280. {
  281. ANKI_ASSERT(threadCount > 0 && threadId < threadCount);
  282. const U32 div = problemSize / threadCount;
  283. start = threadId * div;
  284. end = (threadId == threadCount - 1) ? problemSize : (threadId + 1u) * div;
  285. ANKI_ASSERT(!(threadId == threadCount - 1 && end != problemSize));
  286. }
  287. /// @}
  288. } // end namespace anki