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