File indexing completed on 2025-09-17 09:13:47
0001 #ifndef BVH_V2_UTILS_H
0002 #define BVH_V2_UTILS_H
0003
0004 #include "bvh/v2/platform.h"
0005
0006 #include <limits>
0007 #include <climits>
0008 #include <cstdint>
0009 #include <cstring>
0010 #include <cmath>
0011 #include <atomic>
0012
0013 namespace bvh::v2 {
0014
0015
0016 template <size_t Bits>
0017 struct UnsignedInt {};
0018
0019 template <> struct UnsignedInt< 8> { using Type = uint8_t ; };
0020 template <> struct UnsignedInt<16> { using Type = uint16_t; };
0021 template <> struct UnsignedInt<32> { using Type = uint32_t; };
0022 template <> struct UnsignedInt<64> { using Type = uint64_t; };
0023
0024 template <size_t Bits>
0025 using UnsignedIntType = typename UnsignedInt<Bits>::Type;
0026
0027
0028 struct IgnoreArgs {
0029 template <typename... Args>
0030 void operator () (Args&&...) const {}
0031 };
0032
0033
0034 template <typename T, std::enable_if_t<std::is_unsigned_v<T>, bool> = true>
0035 BVH_ALWAYS_INLINE constexpr T make_bitmask(size_t bits) {
0036 return bits >= std::numeric_limits<T>::digits ? static_cast<T>(-1) : (static_cast<T>(1) << bits) - 1;
0037 }
0038
0039
0040 template <typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
0041 BVH_ALWAYS_INLINE T robust_min(T a, T b) { return a < b ? a : b; }
0042 template <typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
0043 BVH_ALWAYS_INLINE T robust_max(T a, T b) { return a > b ? a : b; }
0044
0045
0046 template <typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
0047 BVH_ALWAYS_INLINE T add_ulp_magnitude(T t, unsigned ulp) {
0048 if (!std::isfinite(t))
0049 return t;
0050 UnsignedIntType<sizeof(T) * CHAR_BIT> u;
0051 std::memcpy(&u, &t, sizeof(T));
0052 u += ulp;
0053 std::memcpy(&t, &u, sizeof(T));
0054 return t;
0055 }
0056
0057
0058 template <typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
0059 BVH_ALWAYS_INLINE T safe_inverse(T x) {
0060 return std::fabs(x) <= std::numeric_limits<T>::epsilon()
0061 ? std::copysign(std::numeric_limits<T>::max(), x)
0062 : static_cast<T>(1.) / x;
0063 }
0064
0065
0066
0067
0068 #if defined(_MSC_VER) && !defined(__clang__)
0069 #pragma float_control(push)
0070 #pragma float_control(precise, off)
0071 #pragma fp_contract(on)
0072 #endif
0073 template <typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
0074 BVH_ALWAYS_INLINE T fast_mul_add(T a, T b, T c) {
0075 #ifdef FP_FAST_FMAF
0076 return std::fma(a, b, c);
0077 #elif defined(__clang__)
0078 BVH_CLANG_ENABLE_FP_CONTRACT
0079 #endif
0080 return a * b + c;
0081 }
0082 #if defined(_MSC_VER) && !defined(__clang__)
0083 #pragma float_control(pop)
0084 #endif
0085
0086
0087 template <size_t Begin, size_t End, typename F>
0088 BVH_ALWAYS_INLINE void static_for(F&& f) {
0089 if constexpr (Begin < End) {
0090 f(Begin);
0091 static_for<Begin + 1, End>(std::forward<F>(f));
0092 }
0093 }
0094
0095
0096 template <typename T, std::enable_if_t<std::is_unsigned_v<T>, bool> = true>
0097 inline constexpr T round_up_log2(T i, T p = 0) {
0098 return (static_cast<T>(1) << p) >= i ? p : round_up_log2(i, p + 1);
0099 }
0100
0101
0102
0103 template <typename T, std::enable_if_t<std::is_unsigned_v<T>, bool> = true>
0104 BVH_ALWAYS_INLINE T split_bits(T x) {
0105 constexpr size_t bit_count = sizeof(T) * CHAR_BIT;
0106 constexpr size_t log_bits = round_up_log2(bit_count);
0107 auto mask = static_cast<T>(-1) >> (bit_count / 2);
0108 x &= mask;
0109 for (size_t i = log_bits - 1, n = size_t{1} << i; i > 0; --i, n >>= 1) {
0110 mask = (mask | (mask << n)) & ~(mask << (n / 2));
0111 x = (x | (x << n)) & mask;
0112 }
0113 return x;
0114 }
0115
0116
0117 template <typename T, std::enable_if_t<std::is_unsigned_v<T>, bool> = true>
0118 BVH_ALWAYS_INLINE T morton_encode(T x, T y, T z) {
0119 return split_bits(x) | (split_bits(y) << 1) | (split_bits(z) << 2);
0120 }
0121
0122
0123
0124 template <typename T>
0125 BVH_ALWAYS_INLINE T atomic_max(std::atomic<T>& atomic, const T& value) {
0126 auto prev_value = atomic;
0127 while (prev_value < value && !atomic.compare_exchange_weak(prev_value, value));
0128 return prev_value;
0129 }
0130
0131 }
0132
0133 #endif