OpenVDB  13.0.0
Util.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: Apache-2.0
3 
4 /*!
5  \file nanovdb/util/Util.h
6 
7  \author Ken Museth
8 
9  \date January 8, 2020
10 
11  \brief Utility functions
12 */
13 
14 #ifndef NANOVDB_UTIL_UTIL_H_HAS_BEEN_INCLUDED
15 #define NANOVDB_UTIL_UTIL_H_HAS_BEEN_INCLUDED
16 
17 #ifdef __CUDACC_RTC__
18 
19 typedef signed char int8_t;
20 typedef short int16_t;
21 typedef int int32_t;
22 typedef long long int64_t;
23 typedef unsigned char uint8_t;
24 typedef unsigned int uint32_t;
25 typedef unsigned short uint16_t;
26 typedef unsigned long long uint64_t;
27 
28 #define NANOVDB_ASSERT(x)
29 
30 #ifndef UINT64_C
31 #define UINT64_C(x) (x ## ULL)
32 #endif
33 
34 #else // !__CUDACC_RTC__
35 
36 #include <stdlib.h> // for abs in clang7
37 #include <stdint.h> // for types like int32_t etc
38 #include <stddef.h> // for size_t type
39 #include <cassert> // for assert
40 #include <cstdio> // for stderr and snprintf
41 #include <cmath> // for sqrt and fma
42 #include <limits> // for numeric_limits
43 #include <utility>// for std::move
44 #ifdef NANOVDB_USE_IOSTREAMS
45 #include <fstream>// for read/writeUncompressedGrids
46 #endif// ifdef NANOVDB_USE_IOSTREAMS
47 
48 // All asserts can be disabled here, even for debug builds
49 #if 1
50 #define NANOVDB_ASSERT(x) assert(x)
51 #else
52 #define NANOVDB_ASSERT(x)
53 #endif
54 
55 #if defined(NANOVDB_USE_INTRINSICS) && defined(_MSC_VER)
56 #include <intrin.h>
57 #pragma intrinsic(_BitScanReverse)
58 #pragma intrinsic(_BitScanForward)
59 #pragma intrinsic(_BitScanReverse64)
60 #pragma intrinsic(_BitScanForward64)
61 #endif
62 
63 #endif // __CUDACC_RTC__
64 
65 #if defined(__CUDACC__) || defined(__HIP__)
66 // Only define __hostdev__ qualifier when using NVIDIA CUDA or HIP compilers
67 #ifndef __hostdev__
68 #define __hostdev__ __host__ __device__ // Runs on the CPU and GPU, called from the CPU or the GPU
69 #endif
70 #else
71 // Dummy definitions of macros only defined by CUDA and HIP compilers
72 #ifndef __hostdev__
73 #define __hostdev__ // Runs on the CPU and GPU, called from the CPU or the GPU
74 #endif
75 #ifndef __global__
76 #define __global__ // Runs on the GPU, called from the CPU or the GPU
77 #endif
78 #ifndef __device__
79 #define __device__ // Runs on the GPU, called from the GPU
80 #endif
81 #ifndef __host__
82 #define __host__ // Runs on the CPU, called from the CPU
83 #endif
84 
85 #endif // if defined(__CUDACC__) || defined(__HIP__)
86 
87 // The following macro will suppress annoying warnings when nvcc
88 // compiles functions that call (host) intrinsics (which is perfectly valid)
89 #if defined(_MSC_VER) && defined(__CUDACC__)
90 #define NANOVDB_HOSTDEV_DISABLE_WARNING __pragma("hd_warning_disable")
91 #elif defined(__GNUC__) && defined(__CUDACC__)
92 #define NANOVDB_HOSTDEV_DISABLE_WARNING _Pragma("hd_warning_disable")
93 #else
94 #define NANOVDB_HOSTDEV_DISABLE_WARNING
95 #endif
96 
97 // Define compiler warnings that work with all compilers
98 //#if defined(_MSC_VER)
99 //#define NANO_WARNING(msg) _pragma("message" #msg)
100 //#else
101 //#define NANO_WARNING(msg) _Pragma("message" #msg)
102 //#endif
103 
104 //==============================================
105 /// @brief Defines macros that issues warnings for deprecated header files
106 /// @details Example:
107 /// @code
108 /// #include <nanovdb/util/Util.h> // for NANOVDB_DEPRECATED_HEADER
109 /// #include <nanovdb/path/Alternative.h>
110 /// NANOVDB_DEPRECATED_HEADER("This header file is deprecated, please use <nanovdb/path/Alternative.h> instead")
111 /// @endcode
112 #ifdef __GNUC__
113 #define NANOVDB_PRAGMA(X) _Pragma(#X)
114 #define NANOVDB_DEPRECATED_HEADER(MSG) NANOVDB_PRAGMA(GCC warning MSG)
115 #elif defined(_MSC_VER)
116 #define NANOVDB_STRINGIZE_(MSG) #MSG
117 #define NANOVDB_STRINGIZE(MSG) NANOVDB_STRINGIZE_(MSG)
118 #define NANOVDB_DEPRECATED_HEADER(MSG) \
119  __pragma(message(__FILE__ "(" NANOVDB_STRINGIZE(__LINE__) ") : Warning: " MSG))
120 #endif
121 
122 // A portable implementation of offsetof - unfortunately it doesn't work with static_assert
123 #define NANOVDB_OFFSETOF(CLASS, MEMBER) ((int)(size_t)((char*)&((CLASS*)0)->MEMBER - (char*)0))
124 
125 namespace nanovdb {// =================================================================
126 
127 namespace util {// ====================================================================
128 
129 /// @brief Minimal implementation of std::declval, which converts any type @c T to
130 //// a reference type, making it possible to use member functions in the operand
131 /// of the decltype specifier without the need to go through constructors.
132 /// @tparam T Template type to be converted to T&&
133 /// @return T&&
134 /// @warning Unlike std::declval, this version does not work when T = void! However,
135 /// NVRTC does not like std::declval, so we provide our own implementation.
136 template<typename T>
137 T&& declval() noexcept;
138 
139 // --------------------------> string utility functions <------------------------------------
140 
141 /// @brief tests if a c-string @c str is empty, that is its first value is '\0'
142 /// @param str c-string to be tested for null termination
143 /// @return true if str[0] = '\0'
144 __hostdev__ inline bool empty(const char* str)
145 {
146  NANOVDB_ASSERT(str != nullptr);
147  return *str == '\0';
148 }// util::empty
149 
150 /// @brief length of a c-sting, excluding '\0'.
151 /// @param str c-string
152 /// @return the number of characters that precede the terminating null character.
153 __hostdev__ inline size_t strlen(const char *str)
154 {
155  NANOVDB_ASSERT(str != nullptr);
156  const char *s = str;
157  while(*s) ++s;
158  return (s - str);
159 }// util::strlen
160 
161 /// @brief Copy characters from @c src to @c dst.
162 /// @param dst pointer to the destination string.
163 /// @param src pointer to the null-terminated source string.
164 /// @return destination string @c dst.
165 /// @note Emulates the behaviour of std::strcpy, except this version also runs on the GPU.
166 __hostdev__ inline char* strcpy(char *dst, const char *src)
167 {
168  NANOVDB_ASSERT(dst != nullptr && src != nullptr);
169  for (char *p = dst; (*p++ = *src) != '\0'; ++src);
170  return dst;
171 }// util::strcpy(char*, const char*)
172 
173 /// @brief Copies the first num characters of @c src to @c dst.
174 /// If the end of the source C string (which is signaled by a
175 /// null-character) is found before @c max characters have been
176 /// copied, @c dst is padded with zeros until a total of @c max
177 /// characters have been written to it.
178 /// @param dst destination string
179 /// @param src source string
180 /// @param max maximum number of character in destination string
181 /// @return destination string @c dst
182 /// @warning if strncpy(dst, src, max)[max-1]!='\0' then @c src has more
183 /// characters than @c max and the return string needs to be
184 /// manually null-terminated, i.e. strncpy(dst, src, max)[max-1]='\0'
185 __hostdev__ inline char* strncpy(char *dst, const char *src, size_t max)
186 {
187  NANOVDB_ASSERT(dst != nullptr && src != nullptr);
188  size_t i = 0;
189  for (; i < max && src[i] != '\0'; ++i) dst[i] = src[i];
190  for (; i < max; ++i) dst[i] = '\0';
191  return dst;
192 }// util::strncpy(char *dst, const char *src, size_t max)
193 
194 /// @brief converts a number to a string using a specific base
195 /// @param dst destination string
196 /// @param num signed number to be concatenated after @c dst
197 /// @param bas base used when converting @c num to a string
198 /// @return destination string @c dst
199 /// @note Emulates the behaviour of itoa, except this verion also works on the GPU.
200 __hostdev__ inline char* strcpy(char* dst, int num, int bas = 10)
201 {
202  NANOVDB_ASSERT(dst != nullptr && bas > 0);
203  int len = 0;// length of number once converted to a string
204  if (num == 0) dst[len++] = '0';
205  for (int abs = num < 0 && bas == 10 ? -num : num; abs; abs /= bas) {
206  const int rem = abs % bas;
207  dst[len++] = rem > 9 ? rem - 10 + 'a' : rem + '0';
208  }
209  if (num < 0) dst[len++] = '-';// append '-' if negative
210  for (char *a = dst, *b = a + len - 1; a < b; ++a, --b) {// reverse dst
211  dst[len] = *a;// use end of string as temp
212  *a = *b;
213  *b = dst[len];
214  }
215  dst[len] = '\0';// explicitly terminate end of string
216  return dst;
217 }// util::strcpy(char*, int, int)
218 
219 /// @brief Appends a copy of the character string pointed to by @c src to
220 /// the end of the character string pointed to by @c dst on the device.
221 /// @param dst pointer to the null-terminated byte string to append to.
222 /// @param src pointer to the null-terminated byte string to copy from.
223 /// @return pointer to the character array being appended to.
224 /// @note Emulates the behaviour of std::strcat, except this version also runs on the GPU.
225 __hostdev__ inline char* strcat(char *dst, const char *src)
226 {
227  NANOVDB_ASSERT(dst != nullptr && src != nullptr);
228  char *p = dst;
229  while (*p != '\0') ++p;// advance till end of dst
230  strcpy(p, src);// append src
231  return dst;
232 }// util::strcat(char*, const char*)
233 
234 /// @brief concatenates a number after a string using a specific base
235 /// @param dst null terminated destination string
236 /// @param num signed number to be concatenated after @c dst
237 /// @param bas base used when converting @c num to a string
238 /// @return destination string @c dst
239 __hostdev__ inline char* strcat(char* dst, int num, int bas = 10)
240 {
241  NANOVDB_ASSERT(dst != nullptr);
242  char *p = dst;
243  while (*p != '\0') ++p;
244  strcpy(p, num, bas);
245  return dst;
246 }// util::strcat(char*, int, int)
247 
248 /// @brief Compares two null-terminated byte strings lexicographically.
249 /// @param lhs pointer to the null-terminated byte strings to compare
250 /// @param rhs pointer to the null-terminated byte strings to compare
251 /// @return Negative value if @c lhs appears before @c rhs in lexicographical order.
252 /// Zero if @c lhs and @c rhs compare equal. Positive value if @c lhs appears
253 /// after @c rhs in lexicographical order.
254 /// @note Emulates the behaviour of std::strcmp, except this version also runs on the GPU.
255 __hostdev__ inline int strcmp(const char *lhs, const char *rhs)
256 {
257  while(*lhs != '\0' && (*lhs == *rhs)){
258  lhs++;
259  rhs++;
260  }
261  return *(const unsigned char*)lhs - *(const unsigned char*)rhs;// zero if lhs == rhs
262 }// util::strcmp(const char*, const char*)
263 
264 /// @brief Test if two null-terminated byte strings are the same
265 /// @param lhs pointer to the null-terminated byte strings to compare
266 /// @param rhs pointer to the null-terminated byte strings to compare
267 /// @return true if the two c-strings are identical
268 __hostdev__ inline bool streq(const char *lhs, const char *rhs)
269 {
270  return strcmp(lhs, rhs) == 0;
271 }// util::streq
272 
273 namespace impl {// =======================================================
274 // Base-case implementation of Variadic Template function impl::sprint
275 __hostdev__ inline char* sprint(char *dst){return dst;}
276 // Variadic Template function impl::sprint
277 template <typename T, typename... Types>
278 __hostdev__ inline char* sprint(char *dst, T var1, Types... var2)
279 {
280  return impl::sprint(strcat(dst, var1), var2...);
281 }
282 }// namespace impl =========================================================
283 
284 /// @brief prints a variable number of string and/or numbers to a destination string
285 template <typename T, typename... Types>
286 __hostdev__ inline char* sprint(char *dst, T var1, Types... var2)
287 {
288  return impl::sprint(strcpy(dst, var1), var2...);
289 }// util::sprint
290 
291 // --------------------------> memzero <------------------------------------
292 
293 /// @brief Zero initialization of memory
294 /// @param dst pointer to destination
295 /// @param byteCount number of bytes to be initialized to zero
296 /// @return destination pointer @c dst
297 __hostdev__ inline static void* memzero(void *dst, size_t byteCount)
298 {
299  NANOVDB_ASSERT(dst);
300  const size_t wordCount = byteCount >> 3;
301  if (wordCount << 3 == byteCount) {
302  for (auto *d = (uint64_t*)dst, *e = d + wordCount; d != e; ++d) *d = 0ULL;
303  } else {
304  for (auto *d = (char*)dst, *e = d + byteCount; d != e; ++d) *d = '\0';
305  }
306  return dst;
307 }// util::memzero
308 
309 // --------------------------> util::is_same <------------------------------------
310 
311 /// @brief C++11 implementation of std::is_same
312 /// @note When more than two arguments are provided value = T0==T1 || T0==T2 || ...
313 template<typename T0, typename T1, typename ...T>
314 struct is_same
315 {
316  static constexpr bool value = is_same<T0, T1>::value || is_same<T0, T...>::value;
317 };
318 
319 template<typename T0, typename T1>
320 struct is_same<T0, T1> {static constexpr bool value = false;};
321 
322 template<typename T>
323 struct is_same<T, T> {static constexpr bool value = true;};
324 
325 template<typename T0, typename T1, typename ...T>
326 static constexpr bool is_same_v = is_same<T0, T1, T...>::value;
327 
328 // --------------------------> util::is_floating_point <------------------------------------
329 
330 /// @brief C++11 implementation of std::is_floating_point
331 template<typename T>
332 struct is_floating_point {static constexpr bool value = is_same<T, float, double>::value;};
333 
334 template<typename T>
336 
337 // --------------------------> util::enable_if <------------------------------------
338 
339 /// @brief C++11 implementation of std::enable_if
340 template <bool, typename T = void>
341 struct enable_if {};
342 
343 template <typename T>
344 struct enable_if<true, T> {using type = T;};
345 
346 template<bool Test, typename T = void>
348 
349 // --------------------------> util::disable_if <------------------------------------
350 
351 template<bool, typename T = void>
352 struct disable_if {using type = T;};
353 
354 template<typename T>
355 struct disable_if<true, T> {};
356 
357 template<bool Test, typename T = void>
359 
360 // --------------------------> util::is_const <------------------------------------
361 
362 template<typename T>
363 struct is_const {static constexpr bool value = false;};
364 
365 template<typename T>
366 struct is_const<const T> {static constexpr bool value = true;};
367 
368 template<typename T>
369 static constexpr bool is_const_v = is_const<T>::value;
370 
371 // --------------------------> util::is_pointer <------------------------------------
372 
373 /// @brief Trait used to identify template parameter that are pointers
374 /// @tparam T Template parameter to be tested
375 template<class T>
376 struct is_pointer {static constexpr bool value = false;};
377 
378 /// @brief Template specialization of pointers
379 /// @tparam T Template parameter to be tested
380 /// @note T can be both a non-const and const type
381 template<class T>
382 struct is_pointer<T*> {static constexpr bool value = true;};
383 
384 template<typename T>
385 static constexpr bool is_pointer_v = is_pointer<T>::value;
386 
387 // --------------------------> util::conditional <------------------------------------
388 
389 /// @brief C++11 implementation of std::conditional
390 template<bool, class TrueT, class FalseT>
391 struct conditional { using type = TrueT; };
392 
393 /// @brief Template specialization of conditional
394 /// @tparam FalseT Type used when boolean is false
395 /// @tparam TrueT Type used when boolean is true
396 template<class TrueT, class FalseT>
397 struct conditional<false, TrueT, FalseT> { using type = FalseT; };
398 
399 template<bool Test, class TrueT, class FalseT>
401 
402 // --------------------------> util::remove_const <------------------------------------
403 
404 /// @brief Trait use to const from type. Default implementation is just a pass-through
405 /// @tparam T Type
406 /// @details remove_pointer<float>::type = float
407 template<typename T>
408 struct remove_const {using type = T;};
409 
410 /// @brief Template specialization of trait class use to remove const qualifier type from a type
411 /// @tparam T Type of the const type
412 /// @details remove_pointer<const float>::type = float
413 template<typename T>
414 struct remove_const<const T> {using type = T;};
415 
416 template<typename T>
418 
419 // --------------------------> util::remove_reference <------------------------------------
420 
421 /// @brief Trait use to remove reference, i.e. "&", qualifier from a type. Default implementation is just a pass-through
422 /// @tparam T Type
423 /// @details remove_pointer<float>::type = float
424 template <typename T>
425 struct remove_reference {using type = T;};
426 
427 /// @brief Template specialization of trait class use to remove reference, i.e. "&", qualifier from a type
428 /// @tparam T Type of the reference
429 /// @details remove_pointer<float&>::type = float
430 template <typename T>
431 struct remove_reference<T&> {using type = T;};
432 
433 template <typename T>
435 
436 // --------------------------> util::remove_pointer <------------------------------------
437 
438 /// @brief Trait use to remove pointer, i.e. "*", qualifier from a type. Default implementation is just a pass-through
439 /// @tparam T Type
440 /// @details remove_pointer<float>::type = float
441 template <typename T>
442 struct remove_pointer {using type = T;};
443 
444 /// @brief Template specialization of trait class use to to remove pointer, i.e. "*", qualifier from a type
445 /// @tparam T Type of the pointer
446 /// @details remove_pointer<float*>::type = float
447 template <typename T>
448 struct remove_pointer<T*> {using type = T;};
449 
450 template <typename T>
452 
453 // --------------------------> util::match_const <------------------------------------
454 
455 /// @brief Trait used to transfer the const-ness of a reference type to another type
456 /// @tparam T Type whose const-ness needs to match the reference type
457 /// @tparam ReferenceT Reference type that is not const
458 /// @details match_const<const int, float>::type = int
459 /// match_const<int, float>::type = int
460 template<typename T, typename ReferenceT>
461 struct match_const {using type = typename remove_const<T>::type;};
462 
463 /// @brief Template specialization used to transfer the const-ness of a reference type to another type
464 /// @tparam T Type that will adopt the const-ness of the reference type
465 /// @tparam ReferenceT Reference type that is const
466 /// @details match_const<const int, const float>::type = const int
467 /// match_const<int, const float>::type = const int
468 template<typename T, typename ReferenceT>
469 struct match_const<T, const ReferenceT> {using type = const typename remove_const<T>::type;};
470 
471 template<typename T, typename ReferenceT>
473 
474 // --------------------------> util::is_specialization <------------------------------------
475 
476 /// @brief Metafunction used to determine if the first template
477 /// parameter is a specialization of the class template
478 /// given in the second template parameter.
479 ///
480 /// @details is_specialization<Vec3<float>, Vec3>::value == true;
481 /// is_specialization<Vec3f, Vec3>::value == true;
482 /// is_specialization<std::vector<float>, std::vector>::value == true;
483 template<typename AnyType, template<typename...> class TemplateType>
484 struct is_specialization {static const bool value = false;};
485 
486 template<typename... Args, template<typename...> class TemplateType>
487 struct is_specialization<TemplateType<Args...>, TemplateType>
488 {
489  static const bool value = true;
490 };// util::is_specialization
491 
492 // --------------------------> util::PtrDiff <------------------------------------
493 
494 /// @brief Compute the distance, in bytes, between two pointers, dist = p - q
495 /// @param p fist pointer, assumed to NOT be NULL
496 /// @param q second pointer, assumed to NOT be NULL
497 /// @return signed distance between pointer, p - q, addresses in units of bytes
498 __hostdev__ inline static int64_t PtrDiff(const void* p, const void* q)
499 {
500  NANOVDB_ASSERT(p && q);
501  return reinterpret_cast<const char*>(p) - reinterpret_cast<const char*>(q);
502 }// util::PtrDiff
503 
504 // --------------------------> util::PtrAdd <------------------------------------
505 
506 /// @brief Adds a byte offset to a non-const pointer to produce another non-const pointer
507 /// @tparam DstT Type of the return pointer (defaults to void)
508 /// @param p non-const input pointer, assumed to NOT be NULL
509 /// @param offset signed byte offset
510 /// @return a non-const pointer defined as the offset of an input pointer
511 template<typename DstT = void>
512 __hostdev__ inline static DstT* PtrAdd(void* p, int64_t offset)
513 {
514  NANOVDB_ASSERT(p);
515  return reinterpret_cast<DstT*>(reinterpret_cast<char*>(p) + offset);
516 }// util::PtrAdd
517 
518 /// @brief Adds a byte offset to a const pointer to produce another const pointer
519 /// @tparam DstT Type of the return pointer (defaults to void)
520 /// @param p const input pointer, assumed to NOT be NULL
521 /// @param offset signed byte offset
522 /// @return a const pointer defined as the offset of a const input pointer
523 template<typename DstT = void>
524 __hostdev__ inline static const DstT* PtrAdd(const void* p, int64_t offset)
525 {
526  NANOVDB_ASSERT(p);
527  return reinterpret_cast<const DstT*>(reinterpret_cast<const char*>(p) + offset);
528 }// util::PtrAdd
529 
530 // -------------------> findLowestOn <----------------------------
531 
532 /// @brief Returns the index of the lowest, i.e. least significant, on bit in the specified 32 bit word
533 ///
534 /// @warning Assumes that at least one bit is set in the word, i.e. @a v != uint32_t(0)!
536 __hostdev__ inline uint32_t findLowestOn(uint32_t v)
537 {
538  NANOVDB_ASSERT(v);
539 #if (defined(__CUDA_ARCH__) || defined(__HIP__)) && defined(NANOVDB_USE_INTRINSICS)
540  return __ffs(v) - 1; // one based indexing
541 #elif defined(_MSC_VER) && defined(NANOVDB_USE_INTRINSICS)
542  unsigned long index;
543  _BitScanForward(&index, v);
544  return static_cast<uint32_t>(index);
545 #elif (defined(__GNUC__) || defined(__clang__)) && defined(NANOVDB_USE_INTRINSICS)
546  return static_cast<uint32_t>(__builtin_ctzl(v));
547 #else
548  //NANO_WARNING("Using software implementation for findLowestOn(uint32_t v)")
549  static const unsigned char DeBruijn[32] = {
550  0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9};
551 // disable unary minus on unsigned warning
552 #if defined(_MSC_VER) && !defined(__NVCC__)
553 #pragma warning(push)
554 #pragma warning(disable : 4146)
555 #endif
556  return DeBruijn[uint32_t((v & -v) * 0x077CB531U) >> 27];
557 #if defined(_MSC_VER) && !defined(__NVCC__)
558 #pragma warning(pop)
559 #endif
560 
561 #endif
562 }// util::findLowestOn(uint32_t)
563 
564 /// @brief Returns the index of the lowest, i.e. least significant, on bit in the specified 64 bit word
565 ///
566 /// @warning Assumes that at least one bit is set in the word, i.e. @a v != uint32_t(0)!
568 __hostdev__ inline uint32_t findLowestOn(uint64_t v)
569 {
570  NANOVDB_ASSERT(v);
571 #if (defined(__CUDA_ARCH__) || defined(__HIP__)) && defined(NANOVDB_USE_INTRINSICS)
572  return __ffsll(static_cast<unsigned long long int>(v)) - 1; // one based indexing
573 #elif defined(_MSC_VER) && defined(NANOVDB_USE_INTRINSICS)
574  unsigned long index;
575  _BitScanForward64(&index, v);
576  return static_cast<uint32_t>(index);
577 #elif (defined(__GNUC__) || defined(__clang__)) && defined(NANOVDB_USE_INTRINSICS)
578  return static_cast<uint32_t>(__builtin_ctzll(v));
579 #else
580  //NANO_WARNING("Using software implementation for util::findLowestOn(uint64_t)")
581  static const unsigned char DeBruijn[64] = {
582  0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28,
583  62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11,
584  63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10,
585  51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12,
586  };
587 // disable unary minus on unsigned warning
588 #if defined(_MSC_VER) && !defined(__NVCC__)
589 #pragma warning(push)
590 #pragma warning(disable : 4146)
591 #endif
592  return DeBruijn[uint64_t((v & -v) * UINT64_C(0x022FDD63CC95386D)) >> 58];
593 #if defined(_MSC_VER) && !defined(__NVCC__)
594 #pragma warning(pop)
595 #endif
596 
597 #endif
598 }// util::findLowestOn(uint64_t)
599 
600 // -------------------> findHighestOn <----------------------------
601 
602 /// @brief Returns the index of the highest, i.e. most significant, on bit in the specified 32 bit word
603 ///
604 /// @warning Assumes that at least one bit is set in the word, i.e. @a v != uint32_t(0)!
606 __hostdev__ inline uint32_t findHighestOn(uint32_t v)
607 {
608  NANOVDB_ASSERT(v);
609 #if (defined(__CUDA_ARCH__) || defined(__HIP__)) && defined(NANOVDB_USE_INTRINSICS)
610  return sizeof(uint32_t) * 8 - 1 - __clz(v); // Return the number of consecutive high-order zero bits in a 32-bit integer.
611 #elif defined(_MSC_VER) && defined(NANOVDB_USE_INTRINSICS)
612  unsigned long index;
613  _BitScanReverse(&index, v);
614  return static_cast<uint32_t>(index);
615 #elif (defined(__GNUC__) || defined(__clang__)) && defined(NANOVDB_USE_INTRINSICS)
616  return sizeof(unsigned long) * 8 - 1 - __builtin_clzl(v);
617 #else
618  //NANO_WARNING("Using software implementation for util::findHighestOn(uint32_t)")
619  static const unsigned char DeBruijn[32] = {
620  0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
621  8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31};
622  v |= v >> 1; // first round down to one less than a power of 2
623  v |= v >> 2;
624  v |= v >> 4;
625  v |= v >> 8;
626  v |= v >> 16;
627  return DeBruijn[uint32_t(v * 0x07C4ACDDU) >> 27];
628 #endif
629 }// util::findHighestOn
630 
631 /// @brief Returns the index of the highest, i.e. most significant, on bit in the specified 64 bit word
632 ///
633 /// @warning Assumes that at least one bit is set in the word, i.e. @a v != uint32_t(0)!
635 __hostdev__ inline uint32_t findHighestOn(uint64_t v)
636 {
637  NANOVDB_ASSERT(v);
638 #if (defined(__CUDA_ARCH__) || defined(__HIP__)) && defined(NANOVDB_USE_INTRINSICS)
639  return sizeof(unsigned long) * 8 - 1 - __clzll(static_cast<unsigned long long int>(v));
640 #elif defined(_MSC_VER) && defined(NANOVDB_USE_INTRINSICS)
641  unsigned long index;
642  _BitScanReverse64(&index, v);
643  return static_cast<uint32_t>(index);
644 #elif (defined(__GNUC__) || defined(__clang__)) && defined(NANOVDB_USE_INTRINSICS)
645  return sizeof(unsigned long) * 8 - 1 - __builtin_clzll(v);
646 #else
647  const uint32_t* p = reinterpret_cast<const uint32_t*>(&v);
648  return p[1] ? 32u + findHighestOn(p[1]) : findHighestOn(p[0]);
649 #endif
650 }// util::findHighestOn
651 
652 // ----------------------------> util::countOn <--------------------------------------
653 
654 /// @return Number of bits that are on in the specified 64-bit word
656 __hostdev__ inline uint32_t countOn(uint64_t v)
657 {
658 #if (defined(__CUDA_ARCH__) || defined(__HIP__)) && defined(NANOVDB_USE_INTRINSICS)
659  //#warning Using popcll for util::countOn
660  return __popcll(v);
661 // __popcnt64 intrinsic support was added in VS 2019 16.8
662 #elif defined(_MSC_VER) && defined(_M_X64) && (_MSC_VER >= 1928) && defined(NANOVDB_USE_INTRINSICS)
663  //#warning Using popcnt64 for util::countOn
664  return uint32_t(__popcnt64(v));
665 #elif (defined(__GNUC__) || defined(__clang__)) && defined(NANOVDB_USE_INTRINSICS)
666  //#warning Using builtin_popcountll for util::countOn
667  return __builtin_popcountll(v);
668 #else // use software implementation
669  //NANO_WARNING("Using software implementation for util::countOn")
670  v = v - ((v >> 1) & uint64_t(0x5555555555555555));
671  v = (v & uint64_t(0x3333333333333333)) + ((v >> 2) & uint64_t(0x3333333333333333));
672  return (((v + (v >> 4)) & uint64_t(0xF0F0F0F0F0F0F0F)) * uint64_t(0x101010101010101)) >> 56;
673 #endif
674 }// util::countOn(uint64_t)
675 
676 }// namespace util ==================================================================
677 
678 [[deprecated("Use nanovdb::util::findLowestOn instead")]]
679 __hostdev__ inline uint32_t FindLowestOn(uint32_t v){return util::findLowestOn(v);}
680 [[deprecated("Use nanovdb::util::findLowestOn instead")]]
681 __hostdev__ inline uint32_t FindLowestOn(uint64_t v){return util::findLowestOn(v);}
682 [[deprecated("Use nanovdb::util::findHighestOn instead")]]
683 __hostdev__ inline uint32_t FindHighestOn(uint32_t v){return util::findHighestOn(v);}
684 [[deprecated("Use nanovdb::util::findHighestOn instead")]]
685 __hostdev__ inline uint32_t FindHighestOn(uint64_t v){return util::findHighestOn(v);}
686 [[deprecated("Use nanovdb::util::countOn instead")]]
687 __hostdev__ inline uint32_t CountOn(uint64_t v){return util::countOn(v);}
688 
689 } // namespace nanovdb ===================================================================
690 
691 #endif // end of NANOVDB_UTIL_UTIL_H_HAS_BEEN_INCLUDED
typename enable_if< Test, T >::type enable_if_t
Definition: Util.h:347
Definition: Util.h:352
C++11 implementation of std::enable_if.
Definition: Util.h:341
Trait used to identify template parameter that are pointers.
Definition: Util.h:376
static constexpr bool is_floating_point_v
Definition: Util.h:335
T type
Definition: Util.h:352
Definition: Util.h:363
static int64_t PtrDiff(const void *p, const void *q)
Compute the distance, in bytes, between two pointers, dist = p - q.
Definition: Util.h:498
Trait use to const from type. Default implementation is just a pass-through.
Definition: Util.h:408
char * strcpy(char *dst, const char *src)
Copy characters from src to dst.
Definition: Util.h:166
Trait use to remove reference, i.e. "&", qualifier from a type. Default implementation is just a pass...
Definition: Util.h:425
char * strncpy(char *dst, const char *src, size_t max)
Copies the first num characters of src to dst. If the end of the source C string (which is signaled b...
Definition: Util.h:185
uint32_t FindLowestOn(uint32_t v)
Definition: Util.h:679
char * strcat(char *dst, const char *src)
Appends a copy of the character string pointed to by src to the end of the character string pointed t...
Definition: Util.h:225
#define __hostdev__
Definition: Util.h:73
char * sprint(char *dst)
Definition: Util.h:275
typename disable_if< Test, T >::type disable_if_t
Definition: Util.h:358
Metafunction used to determine if the first template parameter is a specialization of the class templ...
Definition: Util.h:484
Definition: GridHandle.h:27
typename conditional< Test, TrueT, FalseT >::type conditional_t
Definition: Util.h:400
C++11 implementation of std::conditional.
Definition: Util.h:391
size_t strlen(const char *str)
length of a c-sting, excluding &#39;\0&#39;.
Definition: Util.h:153
T type
Definition: Util.h:425
typename remove_const< T >::type remove_const_t
Definition: Util.h:417
uint32_t countOn(uint64_t v)
Definition: Util.h:656
T && declval() noexcept
Minimal implementation of std::declval, which converts any type T to.
int strcmp(const char *lhs, const char *rhs)
Compares two null-terminated byte strings lexicographically.
Definition: Util.h:255
uint32_t CountOn(uint64_t v)
Definition: Util.h:687
Trait use to remove pointer, i.e. "*", qualifier from a type. Default implementation is just a pass-t...
Definition: Util.h:442
uint32_t FindHighestOn(uint32_t v)
Definition: Util.h:683
bool empty(const char *str)
tests if a c-string str is empty, that is its first value is &#39;\0&#39;
Definition: Util.h:144
#define NANOVDB_HOSTDEV_DISABLE_WARNING
Definition: Util.h:94
uint32_t findLowestOn(uint32_t v)
Returns the index of the lowest, i.e. least significant, on bit in the specified 32 bit word...
Definition: Util.h:536
bool streq(const char *lhs, const char *rhs)
Test if two null-terminated byte strings are the same.
Definition: Util.h:268
T type
Definition: Util.h:442
static constexpr bool is_const_v
Definition: Util.h:369
#define NANOVDB_ASSERT(x)
Definition: Util.h:50
C++11 implementation of std::is_floating_point.
Definition: Util.h:332
typename remove_const< T >::type remove_reference_t
Definition: Util.h:434
static void * memzero(void *dst, size_t byteCount)
Zero initialization of memory.
Definition: Util.h:297
static DstT * PtrAdd(void *p, int64_t offset)
Adds a byte offset to a non-const pointer to produce another non-const pointer.
Definition: Util.h:512
typename match_const< T, ReferenceT >::type match_const_t
Definition: Util.h:472
static constexpr bool is_pointer_v
Definition: Util.h:385
typename remove_pointer< T >::type remove_pointer_t
Definition: Util.h:451
C++11 implementation of std::is_same.
Definition: Util.h:314
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:110
T type
Definition: Util.h:408
T type
Definition: Util.h:344
Trait used to transfer the const-ness of a reference type to another type.
Definition: Util.h:461
uint32_t findHighestOn(uint32_t v)
Returns the index of the highest, i.e. most significant, on bit in the specified 32 bit word...
Definition: Util.h:606
T type
Definition: Util.h:448
TrueT type
Definition: Util.h:391
static constexpr bool is_same_v
Definition: Util.h:326
typename remove_const< T >::type type
Definition: Util.h:461
const typename remove_const< T >::type type
Definition: Util.h:469