Functions.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. // Copyright (C) 2009-present, 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/Forward.h>
  10. #include <AnKi/Util/Assert.h>
  11. #include <cmath>
  12. #include <utility>
  13. #include <new>
  14. #include <cstring>
  15. #include <algorithm>
  16. #include <functional>
  17. #include <bit>
  18. namespace anki {
  19. /// @addtogroup util_other
  20. /// @{
  21. #define _ANKI_CONCATENATE(a, b) a##b
  22. /// Concatenate 2 preprocessor tokens.
  23. #define ANKI_CONCATENATE(a, b) _ANKI_CONCATENATE(a, b)
  24. #define _ANKI_STRINGIZE(a) #a
  25. /// Make a preprocessor token a string.
  26. #define ANKI_STRINGIZE(a) _ANKI_STRINGIZE(a)
  27. /// Format to print bits
  28. #define ANKI_PRIb8 "c%c%c%c%c%c%c%c"
  29. #define ANKI_PRIb16 ANKI_PRIb8 "%c%c%c%c%c%c%c%c"
  30. #define ANKI_PRIb32 ANKI_PRIb16 "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c"
  31. #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"
  32. #define _ANKI_FORMAT_HELPER(byte, bit) (U64(byte) & (U64(1) << U64(bit))) ? '1' : '0'
  33. #define ANKI_FORMAT_U8(byte) \
  34. _ANKI_FORMAT_HELPER((byte), 7), _ANKI_FORMAT_HELPER((byte), 6), _ANKI_FORMAT_HELPER((byte), 5), _ANKI_FORMAT_HELPER((byte), 4), \
  35. _ANKI_FORMAT_HELPER((byte), 3), _ANKI_FORMAT_HELPER((byte), 2), _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. /// OS specific debug breakpoint
  40. #if ANKI_OS_WINDOWS
  41. # define ANKI_DEBUG_BREAK() __debugbreak()
  42. #else
  43. # define ANKI_DEBUG_BREAK() abort()
  44. #endif
  45. // ANKI_FOREACH
  46. // Stolen from here https://stackoverflow.com/questions/5957679/is-there-a-way-to-use-c-preprocessor-stringification-on-variadic-macro-argumen
  47. #define _ANKI_NUM_ARGS(X100, X99, X98, X97, X96, X95, X94, X93, X92, X91, X90, X89, X88, X87, X86, X85, X84, X83, X82, X81, X80, X79, X78, X77, X76, \
  48. X75, X74, X73, X72, X71, X70, X69, X68, X67, X66, X65, X64, X63, X62, X61, X60, X59, X58, X57, X56, X55, X54, X53, X52, X51, \
  49. X50, X49, X48, X47, X46, X45, X44, X43, X42, X41, X40, X39, X38, X37, X36, X35, X34, X33, X32, X31, X30, X29, X28, X27, X26, \
  50. X25, X24, X23, X22, X21, X20, X19, X18, X17, X16, X15, X14, X13, X12, X11, X10, X9, X8, X7, X6, X5, X4, X3, X2, X1, n, ...) \
  51. n
  52. #define _ANKI_NUM_ARGS2(...) \
  53. _ANKI_NUM_ARGS(__VA_ARGS__, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, \
  54. 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, \
  55. 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, \
  56. 6, 5, 4, 3, 2, 1)
  57. #define _ANKI_EXPAND(x) x
  58. #define _ANKI_FIRSTARG(x, ...) (x)
  59. #define _ANKI_RESTARGS(x, ...) (__VA_ARGS__)
  60. #define ANKI_FOREACH(macro, list) _ANKI_FOREACH_(_ANKI_NUM_ARGS2 list, macro, list)
  61. #define _ANKI_FOREACH_(n, m, list) _ANKI_FOREACH__(n, m, list)
  62. #define _ANKI_FOREACH__(n, m, list) _ANKI_FOREACH_##n(m, list)
  63. #define _ANKI_FOREACH_1(m, list) m list
  64. #define _ANKI_FOREACH_2(m, list) _ANKI_EXPAND(m _ANKI_FIRSTARG list), _ANKI_FOREACH_1(m, _ANKI_RESTARGS list)
  65. #define _ANKI_FOREACH_3(m, list) _ANKI_EXPAND(m _ANKI_FIRSTARG list), _ANKI_FOREACH_2(m, _ANKI_RESTARGS list)
  66. #define _ANKI_FOREACH_4(m, list) _ANKI_EXPAND(m _ANKI_FIRSTARG list), _ANKI_FOREACH_3(m, _ANKI_RESTARGS list)
  67. #define _ANKI_FOREACH_5(m, list) _ANKI_EXPAND(m _ANKI_FIRSTARG list), _ANKI_FOREACH_4(m, _ANKI_RESTARGS list)
  68. #define _ANKI_FOREACH_6(m, list) _ANKI_EXPAND(m _ANKI_FIRSTARG list), _ANKI_FOREACH_5(m, _ANKI_RESTARGS list)
  69. /// Get a pseudo random number.
  70. U64 getRandom();
  71. /// Pick a random number from min to max
  72. template<typename T>
  73. T getRandomRange(T min, T max) requires(std::is_floating_point<T>::value)
  74. {
  75. ANKI_ASSERT(min <= max);
  76. const F64 r = F64(getRandom()) / F64(kMaxU64);
  77. return T(min + r * (max - min));
  78. }
  79. template<typename T>
  80. T getRandomRange(T min, T max) requires(std::is_integral<T>::value)
  81. {
  82. ANKI_ASSERT(min <= max);
  83. const U64 r = getRandom();
  84. return T(r % U64(max - min + 1)) + min;
  85. }
  86. /// Get min of two values.
  87. template<typename T>
  88. inline constexpr T min(T a, T b)
  89. {
  90. return (a < b) ? a : b;
  91. }
  92. /// Get max of two values.
  93. template<typename T>
  94. inline constexpr T max(T a, T b)
  95. {
  96. return (a > b) ? a : b;
  97. }
  98. template<typename T>
  99. inline constexpr T clamp(T v, T minv, T maxv)
  100. {
  101. ANKI_ASSERT(minv <= maxv);
  102. return min<T>(max<T>(minv, v), maxv);
  103. }
  104. /// Check if a number is a power of 2
  105. template<typename Int>
  106. inline constexpr Bool isPowerOfTwo(Int x) requires(std::is_integral<Int>::value)
  107. {
  108. return !(x == 0) && !(x & (x - 1));
  109. }
  110. /// Get the next power of two number. For example if x is 130 this will return 256.
  111. template<typename Int>
  112. inline constexpr Int nextPowerOfTwo(Int x) requires(std::is_integral<Int>::value)
  113. {
  114. const F64 d = F64(x);
  115. const F64 res = pow(2.0, ceil(log(d) / log(2.0)));
  116. return Int(res);
  117. }
  118. /// Get the previous power of two number. For example if x is 130 this will return 128.
  119. template<typename Int>
  120. inline constexpr Int previousPowerOfTwo(Int x) requires(std::is_integral<Int>::value)
  121. {
  122. const U64 out = (x != 0) ? (1_U64 << ((sizeof(U64) * 8 - 1) - std::countl_zero<U64>(x))) : 0;
  123. return Int(out);
  124. }
  125. /// Get the aligned number rounded up.
  126. /// @param alignment The bytes of alignment
  127. /// @param value The value to align
  128. template<typename TInt>
  129. inline constexpr TInt getAlignedRoundUp(PtrSize alignment, TInt value) requires(std::is_integral<TInt>::value)
  130. {
  131. ANKI_ASSERT(alignment > 0);
  132. PtrSize v = PtrSize(value);
  133. v = ((v + alignment - 1) / alignment) * alignment;
  134. return TInt(v);
  135. }
  136. /// Get the aligned number rounded up.
  137. /// @param alignment The bytes of alignment
  138. /// @param value The value to align
  139. template<typename TFloat>
  140. inline constexpr TFloat getAlignedRoundUp(TFloat alignment, TFloat value) requires(std::is_floating_point<TFloat>::value)
  141. {
  142. ANKI_ASSERT(alignment > TFloat(0.0));
  143. return ceil(value / alignment) * alignment;
  144. }
  145. /// Align number
  146. /// @param alignment The bytes of alignment
  147. /// @param value The value to align
  148. template<typename TAlignment, typename TValue>
  149. inline void alignRoundUp(TAlignment alignment, TValue& value)
  150. {
  151. value = getAlignedRoundUp(alignment, value);
  152. }
  153. /// Get the aligned number rounded down.
  154. /// @param alignment The bytes of alignment
  155. /// @param value The value to align
  156. template<typename TInt>
  157. inline constexpr TInt getAlignedRoundDown(PtrSize alignment, TInt value) requires(std::is_integral<TInt>::value)
  158. {
  159. ANKI_ASSERT(alignment > 0);
  160. PtrSize v = PtrSize(value);
  161. v = (v / alignment) * alignment;
  162. return TInt(v);
  163. }
  164. /// Get the aligned number rounded down.
  165. /// @param alignment The bytes of alignment
  166. /// @param value The value to align
  167. template<typename TFloat>
  168. inline constexpr TFloat getAlignedRoundDown(TFloat alignment, TFloat value) requires(std::is_floating_point<TFloat>::value)
  169. {
  170. ANKI_ASSERT(alignment > TFloat(0.0));
  171. return floor(value / alignment) * alignment;
  172. }
  173. /// Align number
  174. /// @param alignment The bytes of alignment
  175. /// @param value The value to align
  176. template<typename TAlignment, typename TValue>
  177. inline void alignRoundDown(TAlignment alignment, TValue& value)
  178. {
  179. value = getAlignedRoundDown(alignment, value);
  180. }
  181. /// Given two alignments compute a new alignment that satisfies both
  182. template<typename T>
  183. T computeCompoundAlignment(const T alignment1, const T alignment2)
  184. {
  185. ANKI_ASSERT(alignment1 && alignment2);
  186. // Compute greatest common divisor
  187. T greatestCommonDivisor = alignment1;
  188. T alignment2_ = alignment2;
  189. while(alignment2_ != 0)
  190. {
  191. const auto temp = alignment2_;
  192. alignment2_ = greatestCommonDivisor % alignment2_;
  193. greatestCommonDivisor = temp;
  194. }
  195. // Calculate the least common multiple (LCM) of the two alignments
  196. const auto lcmAlignment = alignment1 * (alignment2 / greatestCommonDivisor);
  197. return lcmAlignment;
  198. }
  199. /// Check if a number is aligned
  200. template<typename Type>
  201. inline constexpr Bool isAligned(PtrSize alignment, Type value)
  202. {
  203. return (PtrSize(value) % alignment) == 0;
  204. }
  205. template<typename T>
  206. inline void swapValues(T& a, T& b)
  207. {
  208. const T tmp = b;
  209. b = a;
  210. a = tmp;
  211. }
  212. /// Convert any pointer to a number.
  213. template<typename TPtr>
  214. inline PtrSize ptrToNumber(TPtr ptr)
  215. {
  216. const uintptr_t i = reinterpret_cast<uintptr_t>(ptr);
  217. const PtrSize size = i;
  218. return size;
  219. }
  220. /// Convert a number to a pointer.
  221. template<typename TPtr>
  222. inline constexpr TPtr numberToPtr(PtrSize num)
  223. {
  224. uintptr_t i = static_cast<uintptr_t>(num);
  225. TPtr ptr = reinterpret_cast<TPtr>(i);
  226. return ptr;
  227. }
  228. /// A simple template trick to remove the pointer from one type
  229. ///
  230. /// Example:
  231. /// @code
  232. /// using Ptr = double*;
  233. /// RemovePointer<Ptr>::Type b = 666.0;
  234. /// @endcode
  235. /// The b is of type double
  236. template<typename T>
  237. struct RemovePointer;
  238. template<typename T>
  239. struct RemovePointer<T*>
  240. {
  241. using Type = T;
  242. };
  243. template<typename T>
  244. struct RemovePointer<const T*>
  245. {
  246. using Type = T;
  247. };
  248. /// Zero memory of an object
  249. template<typename T>
  250. void zeroMemory(T& x)
  251. {
  252. memset(&x, 0, sizeof(T));
  253. }
  254. /// Find a value in a shorted container.
  255. template<class TForwardIterator, class T, class TCompare = std::less<>>
  256. TForwardIterator binarySearch(TForwardIterator first, TForwardIterator last, const T& value, TCompare comp = {})
  257. {
  258. first = std::lower_bound(first, last, value, comp);
  259. return (first != last && !comp(value, *first)) ? first : last;
  260. }
  261. /// Individual classes should specialize that function if they are packed. If a class is packed it can be used as whole in hashing.
  262. template<typename T>
  263. constexpr Bool isPacked()
  264. {
  265. return false;
  266. }
  267. /// Unflatten 3D array index.
  268. /// Imagine an array [sizeA][sizeB][sizeC] and a flat index in that array. Then this function will compute the unflatten indices.
  269. template<typename T, typename TI, typename TOut>
  270. inline void unflatten3dArrayIndex(const T sizeA, const T sizeB, const T sizeC, const TI flatIdx, TOut& a, TOut& b, TOut& c)
  271. {
  272. ANKI_ASSERT(flatIdx < (sizeA * sizeB * sizeC));
  273. a = (flatIdx / (sizeB * sizeC)) % sizeA;
  274. b = (flatIdx / sizeC) % sizeB;
  275. c = flatIdx % sizeC;
  276. }
  277. /// Given a threaded problem split it into smaller ones. This function accepts the number of threads and the size of
  278. /// the threaded problem. Then given a thread index it chooses a range that the thread can operate into. That range is
  279. /// supposed to be as evenly split as possible across threads.
  280. inline void splitThreadedProblem(U32 threadId, U32 threadCount, U32 problemSize, U32& start, U32& end)
  281. {
  282. ANKI_ASSERT(threadCount > 0 && threadId < threadCount);
  283. const U32 range = problemSize / threadCount;
  284. const U32 remain = problemSize % threadCount;
  285. start = threadId * range + min(remain, threadId);
  286. end = start + range + (threadId < remain);
  287. ANKI_ASSERT(start <= problemSize && end <= end);
  288. ANKI_ASSERT(!(threadId == threadCount - 1 && end != problemSize));
  289. }
  290. /// Just copy the memory of a float to a uint.
  291. inline U64 floatBitsToUint(F64 f)
  292. {
  293. U64 out;
  294. memcpy(&out, &f, sizeof(out));
  295. return out;
  296. }
  297. /// Just copy the memory of a float to a uint.
  298. inline U32 floatBitsToUint(F32 f)
  299. {
  300. U32 out;
  301. memcpy(&out, &f, sizeof(out));
  302. return out;
  303. }
  304. /// Call one of the costructors of an object.
  305. template<typename T, typename... TArgs>
  306. void callConstructor(T& p, TArgs&&... args)
  307. {
  308. ::new(&p) T(std::forward<TArgs>(args)...);
  309. }
  310. /// Call the destructor of an object.
  311. template<typename T>
  312. void callDestructor(T& p)
  313. {
  314. static_assert(sizeof(T) > 0, "Incomplete type");
  315. p.~T();
  316. }
  317. #define ANKI_FRIEND_CALL_CONSTRUCTOR_AND_DESTRUCTOR \
  318. template<typename T, typename... TArgs> \
  319. friend void callConstructor(T& p, TArgs&&... args); \
  320. template<typename T> \
  321. friend void callDestructor(T& p);
  322. /// Allocate a new object and call it's constructor
  323. template<typename T, typename TMemPool, typename... TArgs>
  324. [[nodiscard]] T* newInstance(TMemPool& pool, TArgs&&... args)
  325. {
  326. T* ptr = static_cast<T*>(pool.allocate(sizeof(T), alignof(T)));
  327. if(ptr) [[likely]]
  328. {
  329. callConstructor(*ptr, std::forward<TArgs>(args)...);
  330. }
  331. return ptr;
  332. }
  333. /// Allocate a new array of objects and call their constructor
  334. template<typename T, typename TMemPool>
  335. [[nodiscard]] T* newArray(TMemPool& pool, PtrSize n)
  336. {
  337. T* ptr = static_cast<T*>(pool.allocate(n * sizeof(T), alignof(T)));
  338. if(ptr) [[likely]]
  339. {
  340. for(PtrSize i = 0; i < n; i++)
  341. {
  342. callConstructor(ptr[i]);
  343. }
  344. }
  345. return ptr;
  346. }
  347. /// Allocate a new array of objects and call their constructor
  348. template<typename T, typename TMemPool>
  349. [[nodiscard]] T* newArray(TMemPool& pool, PtrSize n, const T& copy)
  350. {
  351. T* ptr = static_cast<T*>(pool.allocate(n * sizeof(T), alignof(T)));
  352. if(ptr) [[likely]]
  353. {
  354. for(PtrSize i = 0; i < n; i++)
  355. {
  356. callConstructor(ptr[i], copy);
  357. }
  358. }
  359. return ptr;
  360. }
  361. /// Allocate a new array of objects and call their constructor.
  362. /// @note The output is a parameter (instead of a return value) to work with template deduction.
  363. template<typename T, typename TMemPool, typename TSize>
  364. void newArray(TMemPool& pool, PtrSize n, WeakArray<T, TSize>& out)
  365. {
  366. T* arr = newArray<T>(pool, n);
  367. ANKI_ASSERT(n < getMaxNumericLimit<TSize>());
  368. out.setArray(arr, TSize(n));
  369. }
  370. /// Call the destructor and deallocate an object.
  371. template<typename T, typename TMemPool>
  372. void deleteInstance(TMemPool& pool, T* ptr)
  373. {
  374. if(ptr != nullptr) [[likely]]
  375. {
  376. callDestructor(*ptr);
  377. pool.free(ptr);
  378. }
  379. }
  380. /// Call the destructor and deallocate an array of objects.
  381. template<typename T, typename TMemPool>
  382. void deleteArray(TMemPool& pool, T* arr, PtrSize n)
  383. {
  384. if(arr != nullptr) [[likely]]
  385. {
  386. for(PtrSize i = 0; i < n; i++)
  387. {
  388. callDestructor(arr[i]);
  389. }
  390. pool.free(arr);
  391. }
  392. else
  393. {
  394. ANKI_ASSERT(n == 0);
  395. }
  396. }
  397. /// Call the destructor and deallocate an array of objects.
  398. template<typename T, typename TMemPool, typename TSize>
  399. void deleteArray(TMemPool& pool, WeakArray<T, TSize>& arr)
  400. {
  401. deleteArray(pool, arr.getBegin(), arr.getSize());
  402. arr.setArray(nullptr, 0);
  403. }
  404. /// @}
  405. } // end namespace anki