Coverage Report

Created: 2026-10-17 06:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/glaze/include/glaze/api/hash.hpp
Line
Count
Source
1
// Glaze Library
2
// For the license information refer to glaze.hpp
3
4
#pragma once
5
6
#include <climits>
7
8
#include "glaze/api/xxh64.hpp"
9
#include "glaze/core/meta.hpp"
10
11
// Collision calculations done with the formula: e^((-k * (k - 1)/(2 * N)))
12
// The approximation error tends to zero as N increases, and we are dealing with a large N
13
// https://preshing.com/20110504/hash-collision-probabilities/
14
// With 10,000 registered types the probabilities of a collision are:
15
// 64 bit hash: 2.71027645e-12 === 1 - 1/e^(6249375/2305843009213693952)
16
// 128 bit hash: 1.469221e-31 === 1 - 1/e^(6249375/42535295865117307932921825928971026432)
17
// 256 bit hash: 4.317652e-70 === 1 -
18
// 1/e^(6249375/14474011154664524427946373126085988481658748083205070504932198000989141204992) Probability of winning
19
// the Mega Millions lottery: 1 / 302,575,350 === 3.30496189e-9 Number of times winning to equal a collision chance: 64
20
// bit: 1220 times 128 bit: 2.2494655e22 times (or 22 sextillion times) 256 bit: 7.6545351e60 times From these
21
// calculations it is apparent that a 128 bit hash is more than sufficient
22
23
namespace glz
24
{
25
   template <class T, T Value>
26
   consteval auto make_array()
27
   {
28
      return []<size_t... I>(std::index_sequence<I...>) {
29
         return std::array<char, sizeof(T)>{static_cast<char>(((Value >> (CHAR_BIT * I)) & 0xff))...};
30
      }(std::make_index_sequence<sizeof(T)>{});
31
   }
32
33
   namespace detail
34
   {
35
      // convert an integer to a string_view at compile time
36
37
      constexpr uint64_t num_digits(auto x) noexcept // number of digits needed, including minus sign
38
0
      {
39
0
         return x < 10 ? 1 : 1 + num_digits(x / 10);
40
0
      }
41
42
      template <char... args>
43
      struct metastring
44
      {
45
         const char data[sizeof...(args)] = {args...};
46
      };
47
48
      // recursive number-printing template, general case (for three or more digits)
49
      template <uint64_t size, uint64_t x, char... args>
50
      struct numeric_builder
51
      {
52
         using type = typename numeric_builder<size - 1, x / 10, '0' + x % 10, args...>::type;
53
      };
54
55
      // special case for two digits; minus sign is handled here
56
      template <uint64_t x, char... args>
57
      struct numeric_builder<2, x, args...>
58
      {
59
         using type = metastring<'0' + x / 10, '0' + x % 10, args...>;
60
      };
61
62
      // special case for one digit (positive numbers only)
63
      template <uint64_t x, char... args>
64
      struct numeric_builder<1, x, args...>
65
      {
66
         using type = metastring<'0' + x, args...>;
67
      };
68
69
      // convenience wrapper for numeric_builder
70
      template <uint64_t x>
71
      struct numeric_string
72
      {
73
         // generate a unique string type representing this number
74
         using type = typename numeric_builder<num_digits(x), x, '\0'>::type;
75
76
         // declare a static string of that type (instantiated later at file scope)
77
         static constexpr type value{};
78
         static constexpr const std::string_view get() { return {value.data, num_digits(x)}; }
79
      };
80
   }
81
82
   template <class T, T Value>
83
   struct int_to_sv
84
   {
85
      static constexpr auto arr = make_array<T, Value>();
86
      static consteval std::string_view get() { return {arr.data(), arr.size()}; }
87
   };
88
89
   template <class T, T Value>
90
   inline constexpr std::string_view int_to_sv_v = int_to_sv<T, Value>{}.get();
91
92
   template <uint64_t I>
93
   inline consteval auto to_sv()
94
   {
95
      return detail::numeric_string<I>::get();
96
   }
97
98
   template <size_t I>
99
   struct hash128_i
100
   {
101
      static constexpr sv str = to_sv<I>();
102
      static constexpr sv h0 = int_to_sv_v<uint64_t, xxh64::hash(str.data(), str.size(), 0)>;
103
      static constexpr sv h1 = int_to_sv_v<uint64_t, xxh64::hash(str.data(), str.size(), 1)>;
104
      static constexpr sv value = join_v<h0, h1>;
105
   };
106
107
   template <size_t I>
108
   inline constexpr std::string_view hash128_i_v = hash128_i<I>::value;
109
110
   template <const std::string_view& Str>
111
   struct hash128
112
   {
113
      static constexpr sv h0 = int_to_sv_v<uint64_t, xxh64::hash(Str.data(), Str.size(), 0)>;
114
      static constexpr sv h1 = int_to_sv_v<uint64_t, xxh64::hash(Str.data(), Str.size(), 1)>;
115
      static constexpr sv value = join_v<h0, h1>;
116
   };
117
118
   template <const std::string_view& Str>
119
   constexpr std::string_view hash128_v = hash128<Str>::value;
120
}