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