Hash.h#
Fully qualified name: carb/Hash.h
File members: carb/Hash.h
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: LicenseRef-NvidiaProprietary
//
// NVIDIA CORPORATION, its affiliates and licensors retain all intellectual
// property and proprietary rights in and to this material, related
// documentation and any modifications thereto. Any use, reproduction,
// disclosure or distribution of this material and related documentation
// without an express license agreement from NVIDIA CORPORATION or
// its affiliates is strictly prohibited.
#pragma once
#include "Warning.h"
#include <cstddef>
#include <cstdint>
// The string hash macro is guaranteed to evaluate at compile time. MSVC raises a warning for this, which we disable.
#if defined(__CUDACC__) || defined(DOXYGEN_BUILD)
# define CARB_HASH_STRING(str) ::carb::detail::hash_constant<uint64_t, carb::fnv1aHash(str)>::value
# define CARB_HASH_STRING_LOWER(str) ::carb::detail::hash_constant<uint64_t, carb::fnv1aHashLower(str)>::value
#else
# define CARB_HASH_STRING(str) \
CARB_IGNOREWARNING_MSC_WITH_PUSH(4307) /* 'operator': integral constant overflow */ \
::carb::detail::hash_constant<uint64_t, carb::fnv1aHash(str)>::value CARB_IGNOREWARNING_MSC_POP
# define CARB_HASH_STRING_LOWER(str) \
CARB_IGNOREWARNING_MSC_WITH_PUSH(4307) /* 'operator': integral constant overflow */ \
::carb::detail::hash_constant<uint64_t, carb::fnv1aHashLower(str)>::value CARB_IGNOREWARNING_MSC_POP
#endif
#define CARB_HASH_TYPE(T) CARB_HASH_STRING(CARB_STRINGIFY(T))
namespace carb::detail
{
// simple type to avoid including type_traits just for integral_constant
template <typename T, T val>
struct hash_constant
{
static constexpr T value = val;
using value_type = T;
using type = hash_constant;
constexpr operator value_type() const noexcept
{
return value;
}
[[nodiscard]] constexpr value_type operator()() const noexcept
{
return value;
}
};
// clang-format off
#define C(a) (unsigned char)(0x##a)
constexpr unsigned char lowerTable[256] = {
C(00), C(01), C(02), C(03), C(04), C(05), C(06), C(07), C(08), C(09), C(0A), C(0B), C(0C), C(0D), C(0E), C(0F),
C(10), C(11), C(12), C(13), C(14), C(15), C(16), C(17), C(18), C(19), C(1A), C(1B), C(1C), C(1D), C(1E), C(1F),
C(20), C(21), C(22), C(23), C(24), C(25), C(26), C(27), C(28), C(29), C(2A), C(2B), C(2C), C(2D), C(2E), C(2F),
C(30), C(31), C(32), C(33), C(34), C(35), C(36), C(37), C(38), C(39), C(3A), C(3B), C(3C), C(3D), C(3E), C(3F),
C(40),
// [0x41, 0x5A] -> [0x61, 0x7A]
C(61), C(62), C(63), C(64), C(65), C(66), C(67), C(68), C(69), C(6A), C(6B), C(6C), C(6D), C(6E), C(6F),
C(70), C(71), C(72), C(73), C(74), C(75), C(76), C(77), C(78), C(79), C(7A),
C(5B), C(5C), C(5D), C(5E), C(5F),
C(60), C(61), C(62), C(63), C(64), C(65), C(66), C(67), C(68), C(69), C(6A), C(6B), C(6C), C(6D), C(6E), C(6F),
C(70), C(71), C(72), C(73), C(74), C(75), C(76), C(77), C(78), C(79), C(7A), C(7B), C(7C), C(7D), C(7E), C(7F),
C(80), C(81), C(82), C(83), C(84), C(85), C(86), C(87), C(88), C(89), C(8A), C(8B), C(8C), C(8D), C(8E), C(8F),
C(90), C(91), C(92), C(93), C(94), C(95), C(96), C(97), C(98), C(99), C(9A), C(9B), C(9C), C(9D), C(9E), C(9F),
C(A0), C(A1), C(A2), C(A3), C(A4), C(A5), C(A6), C(A7), C(A8), C(A9), C(AA), C(AB), C(AC), C(AD), C(AE), C(AF),
C(B0), C(B1), C(B2), C(B3), C(B4), C(B5), C(B6), C(B7), C(B8), C(B9), C(BA), C(BB), C(BC), C(BD), C(BE), C(BF),
C(C0), C(C1), C(C2), C(C3), C(C4), C(C5), C(C6), C(C7), C(C8), C(C9), C(CA), C(CB), C(CC), C(CD), C(CE), C(CF),
C(D0), C(D1), C(D2), C(D3), C(D4), C(D5), C(D6), C(D7), C(D8), C(D9), C(DA), C(DB), C(DC), C(DD), C(DE), C(DF),
C(E0), C(E1), C(E2), C(E3), C(E4), C(E5), C(E6), C(E7), C(E8), C(E9), C(EA), C(EB), C(EC), C(ED), C(EE), C(EF),
C(F0), C(F1), C(F2), C(F3), C(F4), C(F5), C(F6), C(F7), C(F8), C(F9), C(FA), C(FB), C(FC), C(FD), C(FE), C(FF),
};
constexpr unsigned char upperTable[256] = {
C(00), C(01), C(02), C(03), C(04), C(05), C(06), C(07), C(08), C(09), C(0A), C(0B), C(0C), C(0D), C(0E), C(0F),
C(10), C(11), C(12), C(13), C(14), C(15), C(16), C(17), C(18), C(19), C(1A), C(1B), C(1C), C(1D), C(1E), C(1F),
C(20), C(21), C(22), C(23), C(24), C(25), C(26), C(27), C(28), C(29), C(2A), C(2B), C(2C), C(2D), C(2E), C(2F),
C(30), C(31), C(32), C(33), C(34), C(35), C(36), C(37), C(38), C(39), C(3A), C(3B), C(3C), C(3D), C(3E), C(3F),
C(40), C(41), C(42), C(43), C(44), C(45), C(46), C(47), C(48), C(49), C(4A), C(4B), C(4C), C(4D), C(4E), C(4F),
C(50), C(51), C(52), C(53), C(54), C(55), C(56), C(57), C(58), C(59), C(5A), C(5B), C(5C), C(5D), C(5E), C(5F),
C(60),
// [0x61, 0x7A] -> [0x41, 0x5A]
C(41), C(42), C(43), C(44), C(45), C(46), C(47), C(48), C(49), C(4A), C(4B), C(4C), C(4D), C(4E), C(4F),
C(50), C(51), C(52), C(53), C(54), C(55), C(56), C(57), C(58), C(59), C(5A),
C(7B), C(7C), C(7D), C(7E), C(7F),
C(80), C(81), C(82), C(83), C(84), C(85), C(86), C(87), C(88), C(89), C(8A), C(8B), C(8C), C(8D), C(8E), C(8F),
C(90), C(91), C(92), C(93), C(94), C(95), C(96), C(97), C(98), C(99), C(9A), C(9B), C(9C), C(9D), C(9E), C(9F),
C(A0), C(A1), C(A2), C(A3), C(A4), C(A5), C(A6), C(A7), C(A8), C(A9), C(AA), C(AB), C(AC), C(AD), C(AE), C(AF),
C(B0), C(B1), C(B2), C(B3), C(B4), C(B5), C(B6), C(B7), C(B8), C(B9), C(BA), C(BB), C(BC), C(BD), C(BE), C(BF),
C(C0), C(C1), C(C2), C(C3), C(C4), C(C5), C(C6), C(C7), C(C8), C(C9), C(CA), C(CB), C(CC), C(CD), C(CE), C(CF),
C(D0), C(D1), C(D2), C(D3), C(D4), C(D5), C(D6), C(D7), C(D8), C(D9), C(DA), C(DB), C(DC), C(DD), C(DE), C(DF),
C(E0), C(E1), C(E2), C(E3), C(E4), C(E5), C(E6), C(E7), C(E8), C(E9), C(EA), C(EB), C(EC), C(ED), C(EE), C(EF),
C(F0), C(F1), C(F2), C(F3), C(F4), C(F5), C(F6), C(F7), C(F8), C(F9), C(FA), C(FB), C(FC), C(FD), C(FE), C(FF),
};
#undef C
// clang-format on
} // namespace carb::detail
namespace carb
{
constexpr unsigned char tolower(unsigned char c)
{
return detail::lowerTable[c];
};
constexpr unsigned char toupper(unsigned char c)
{
return detail::upperTable[c];
}
constexpr uint64_t kFnvBasis = 14695981039346656037ull;
constexpr uint64_t kFnvPrime = 1099511628211ull;
constexpr uint64_t fnv1aHash(const char* str, const std::size_t n, uint64_t hash = kFnvBasis)
{
for (size_t i = 0; i != n; ++i)
hash = (hash ^ static_cast<unsigned char>(str[i])) * kFnvPrime;
return hash;
}
constexpr uint64_t fnv1aHashLower(const char* str, const std::size_t n, uint64_t hash = kFnvBasis)
{
for (size_t i = 0; i != n; ++i)
hash = (hash ^ tolower(static_cast<unsigned char>(str[i]))) * kFnvPrime;
return hash;
}
constexpr uint64_t fnv1aHashUpper(const char* str, const std::size_t n, uint64_t hash = kFnvBasis)
{
for (size_t i = 0; i != n; ++i)
hash = (hash ^ toupper(static_cast<unsigned char>(str[i]))) * kFnvPrime;
return hash;
}
template <std::size_t N>
constexpr uint64_t fnv1aHash(const char (&array)[N])
{
return fnv1aHash(&array[0], N - 1);
}
template <std::size_t N>
constexpr uint64_t fnv1aHashLower(const char (&array)[N])
{
return fnv1aHashLower(&array[0], N - 1);
}
template <std::size_t N>
constexpr uint64_t fnv1aHashUpper(const char (&array)[N])
{
return fnv1aHashUpper(&array[0], N - 1);
}
constexpr uint64_t hashString(const char* str, uint64_t hash = kFnvBasis)
{
while (*str != '\0')
hash = (hash ^ static_cast<unsigned char>(*(str++))) * kFnvPrime;
return hash;
}
constexpr uint64_t hashLowercaseString(const char* str, uint64_t hash = kFnvBasis)
{
while (*str != '\0')
hash = (hash ^ carb::tolower(static_cast<unsigned char>(*(str++)))) * kFnvPrime;
return hash;
}
constexpr uint64_t hashUppercaseString(const char* str, uint64_t hash = kFnvBasis)
{
while (*str != '\0')
hash = (hash ^ toupper(static_cast<unsigned char>(*(str++)))) * kFnvPrime;
return hash;
}
template <class T>
uint64_t hashBuffer(const T* buffer, const size_t length, uint64_t hash = kFnvBasis);
template <class T>
uint64_t hashLowercaseBuffer(const T* buffer, const size_t length, uint64_t hash = kFnvBasis);
template <class T>
uint64_t hashUppercaseBuffer(const T* buffer, const size_t length, uint64_t hash = kFnvBasis);
#ifndef DOXYGEN_BUILD
template <>
constexpr uint64_t hashBuffer<unsigned char>(const unsigned char* buffer, const size_t length, uint64_t hash)
{
for (size_t i = 0; i != length; ++i)
hash = (hash ^ buffer[i]) * kFnvPrime;
return hash;
}
template <class T>
uint64_t hashBuffer(const T* buffer, const size_t length, uint64_t hash)
{
return hashBuffer(reinterpret_cast<const unsigned char*>(buffer), length, hash);
}
template <>
constexpr uint64_t hashLowercaseBuffer<unsigned char>(const unsigned char* buffer, const size_t length, uint64_t hash)
{
for (size_t i = 0; i != length; ++i)
hash = (hash ^ tolower(buffer[i])) * kFnvPrime;
return hash;
}
template <class T>
uint64_t hashLowercaseBuffer(const T* buffer, const size_t length, uint64_t hash)
{
return hashLowercaseBuffer(reinterpret_cast<const unsigned char*>(buffer), length, hash);
}
template <>
constexpr uint64_t hashUppercaseBuffer<unsigned char>(const unsigned char* buffer, const size_t length, uint64_t hash)
{
for (size_t i = 0; i != length; ++i)
hash = (hash ^ toupper(buffer[i])) * kFnvPrime;
return hash;
}
template <class T>
uint64_t hashUppercaseBuffer(const T* buffer, const size_t length, uint64_t hash)
{
return hashUppercaseBuffer(reinterpret_cast<const unsigned char*>(buffer), length, hash);
}
#endif
constexpr uint64_t hashCombine(uint64_t hash1, uint64_t hash2) noexcept
{
constexpr uint64_t kConstant{ 14313749767032793493ull };
constexpr int kRotate = 47;
hash2 *= kConstant;
hash2 ^= (hash2 >> kRotate);
hash2 *= kConstant;
hash1 ^= hash2;
hash1 *= kConstant;
// Add an arbitrary value to prevent 0 hashing to 0
hash1 += 0x42524143; // CARB
return hash1;
}
} // namespace carb