Coverage Report

Created: 2025-06-13 06:26

/src/boost/boost/container_hash/hash.hpp
Line
Count
Source (jump to first uncovered line)
1
// Copyright 2005-2014 Daniel James.
2
// Copyright 2021, 2022, 2025 Peter Dimov.
3
// Distributed under the Boost Software License, Version 1.0.
4
// https://www.boost.org/LICENSE_1_0.txt
5
6
// Based on Peter Dimov's proposal
7
// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf
8
// issue 6.18.
9
10
#ifndef BOOST_FUNCTIONAL_HASH_HASH_HPP
11
#define BOOST_FUNCTIONAL_HASH_HASH_HPP
12
13
#include <boost/container_hash/hash_fwd.hpp>
14
#include <boost/container_hash/hash_is_avalanching.hpp>
15
#include <boost/container_hash/is_range.hpp>
16
#include <boost/container_hash/is_contiguous_range.hpp>
17
#include <boost/container_hash/is_unordered_range.hpp>
18
#include <boost/container_hash/is_described_class.hpp>
19
#include <boost/container_hash/detail/hash_integral.hpp>
20
#include <boost/container_hash/detail/hash_tuple_like.hpp>
21
#include <boost/container_hash/detail/hash_mix.hpp>
22
#include <boost/container_hash/detail/hash_range.hpp>
23
#include <boost/describe/bases.hpp>
24
#include <boost/describe/members.hpp>
25
#include <type_traits>
26
#include <cstdint>
27
28
#if defined(BOOST_DESCRIBE_CXX14)
29
# include <boost/mp11/algorithm.hpp>
30
#endif
31
32
#include <string>
33
#include <iterator>
34
#include <complex>
35
#include <utility>
36
#include <limits>
37
#include <climits>
38
#include <cstring>
39
40
#if !defined(BOOST_NO_CXX11_SMART_PTR)
41
# include <memory>
42
#endif
43
44
#if !defined(BOOST_NO_CXX11_HDR_TYPEINDEX)
45
#include <typeindex>
46
#endif
47
48
#if !defined(BOOST_NO_CXX11_HDR_SYSTEM_ERROR)
49
#include <system_error>
50
#endif
51
52
#if !defined(BOOST_NO_CXX17_HDR_OPTIONAL)
53
#include <optional>
54
#endif
55
56
#if !defined(BOOST_NO_CXX17_HDR_VARIANT)
57
#include <variant>
58
#endif
59
60
#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
61
# include <string_view>
62
#endif
63
64
namespace boost
65
{
66
67
    //
68
    // boost::hash_value
69
    //
70
71
    // integral types
72
    //   in detail/hash_integral.hpp
73
74
    // enumeration types
75
76
    template <typename T>
77
    typename std::enable_if<std::is_enum<T>::value, std::size_t>::type
78
        hash_value( T v )
79
0
    {
80
        // This should in principle return the equivalent of
81
        //
82
        // boost::hash_value( to_underlying(v) );
83
        //
84
        // However, the C++03 implementation of underlying_type,
85
        //
86
        // conditional<is_signed<T>, make_signed<T>, make_unsigned<T>>::type::type
87
        //
88
        // generates a legitimate -Wconversion warning in is_signed,
89
        // because -1 is not a valid enum value when all the enumerators
90
        // are nonnegative.
91
        //
92
        // So the legacy implementation will have to do for now.
93
94
0
        return static_cast<std::size_t>( v );
95
0
    }
96
97
    // floating point types
98
99
    namespace hash_detail
100
    {
101
        template<class T,
102
            std::size_t Bits = sizeof(T) * CHAR_BIT,
103
            int Digits = std::numeric_limits<T>::digits>
104
        struct hash_float_impl;
105
106
        // float
107
        template<class T, int Digits> struct hash_float_impl<T, 32, Digits>
108
        {
109
            static std::size_t fn( T v )
110
            {
111
                std::uint32_t w;
112
                std::memcpy( &w, &v, sizeof( v ) );
113
114
                return w;
115
            }
116
        };
117
118
        // double
119
        template<class T, int Digits> struct hash_float_impl<T, 64, Digits>
120
        {
121
            static std::size_t fn( T v )
122
0
            {
123
0
                std::uint64_t w;
124
0
                std::memcpy( &w, &v, sizeof( v ) );
125
126
0
                return hash_value( w );
127
0
            }
128
        };
129
130
        // 80 bit long double in 12 bytes
131
        template<class T> struct hash_float_impl<T, 96, 64>
132
        {
133
            static std::size_t fn( T v )
134
            {
135
                std::uint64_t w[ 2 ] = {};
136
                std::memcpy( &w, &v, 80 / CHAR_BIT );
137
138
                std::size_t seed = 0;
139
140
                seed = hash_value( w[0] ) + hash_detail::hash_mix( seed );
141
                seed = hash_value( w[1] ) + hash_detail::hash_mix( seed );
142
143
                return seed;
144
            }
145
        };
146
147
        // 80 bit long double in 16 bytes
148
        template<class T> struct hash_float_impl<T, 128, 64>
149
        {
150
            static std::size_t fn( T v )
151
            {
152
                std::uint64_t w[ 2 ] = {};
153
                std::memcpy( &w, &v, 80 / CHAR_BIT );
154
155
                std::size_t seed = 0;
156
157
                seed = hash_value( w[0] ) + hash_detail::hash_mix( seed );
158
                seed = hash_value( w[1] ) + hash_detail::hash_mix( seed );
159
160
                return seed;
161
            }
162
        };
163
164
        // 128 bit long double
165
        template<class T, int Digits> struct hash_float_impl<T, 128, Digits>
166
        {
167
            static std::size_t fn( T v )
168
            {
169
                std::uint64_t w[ 2 ];
170
                std::memcpy( &w, &v, sizeof( v ) );
171
172
                std::size_t seed = 0;
173
174
#if defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__
175
176
                seed = hash_value( w[1] ) + hash_detail::hash_mix( seed );
177
                seed = hash_value( w[0] ) + hash_detail::hash_mix( seed );
178
179
#else
180
181
                seed = hash_value( w[0] ) + hash_detail::hash_mix( seed );
182
                seed = hash_value( w[1] ) + hash_detail::hash_mix( seed );
183
184
#endif
185
                return seed;
186
            }
187
        };
188
189
    } // namespace hash_detail
190
191
    template <typename T>
192
    typename std::enable_if<std::is_floating_point<T>::value, std::size_t>::type
193
        hash_value( T v )
194
0
    {
195
0
        return boost::hash_detail::hash_float_impl<T>::fn( v + 0 );
196
0
    }
197
198
    // pointer types
199
200
    // `x + (x >> 3)` adjustment by Alberto Barbati and Dave Harris.
201
    template <class T> std::size_t hash_value( T* const& v )
202
0
    {
203
0
        std::uintptr_t x = reinterpret_cast<std::uintptr_t>( v );
204
0
        return boost::hash_value( x + (x >> 3) );
205
0
    }
Unexecuted instantiation: unsigned long boost::hash_value<void>(void* const&)
Unexecuted instantiation: unsigned long boost::hash_value<std::__1::error_category const>(std::__1::error_category const* const&)
206
207
    // array types
208
209
    template<class T, std::size_t N>
210
    inline std::size_t hash_value( T const (&x)[ N ] )
211
    {
212
        return boost::hash_range( x, x + N );
213
    }
214
215
    template<class T, std::size_t N>
216
    inline std::size_t hash_value( T (&x)[ N ] )
217
    {
218
        return boost::hash_range( x, x + N );
219
    }
220
221
    // complex
222
223
    template <class T>
224
    std::size_t hash_value( std::complex<T> const& v )
225
    {
226
        std::size_t re = boost::hash<T>()( v.real() );
227
        std::size_t im = boost::hash<T>()( v.imag() );
228
229
        return re + hash_detail::hash_mix( im );
230
    }
231
232
    // pair
233
234
    template <class A, class B>
235
    std::size_t hash_value( std::pair<A, B> const& v )
236
    {
237
        std::size_t seed = 0;
238
239
        boost::hash_combine( seed, v.first );
240
        boost::hash_combine( seed, v.second );
241
242
        return seed;
243
    }
244
245
    // ranges (list, set, deque...)
246
247
    template <typename T>
248
    typename std::enable_if<container_hash::is_range<T>::value && !container_hash::is_contiguous_range<T>::value && !container_hash::is_unordered_range<T>::value, std::size_t>::type
249
        hash_value( T const& v )
250
    {
251
        return boost::hash_range( v.begin(), v.end() );
252
    }
253
254
    // contiguous ranges (string, vector, array)
255
256
    template <typename T>
257
    typename std::enable_if<container_hash::is_contiguous_range<T>::value, std::size_t>::type
258
        hash_value( T const& v )
259
0
    {
260
0
        return boost::hash_range( v.data(), v.data() + v.size() );
261
0
    }
Unexecuted instantiation: _ZN5boost10hash_valueINS_4json5arrayEEENSt3__19enable_ifIXsr14container_hash19is_contiguous_rangeIT_EE5valueEmE4typeERKS5_
Unexecuted instantiation: _ZN5boost10hash_valueINS_4core17basic_string_viewIcEEEENSt3__19enable_ifIXsr14container_hash19is_contiguous_rangeIT_EE5valueEmE4typeERKS6_
Unexecuted instantiation: _ZN5boost10hash_valueINS_4json6stringEEENSt3__19enable_ifIXsr14container_hash19is_contiguous_rangeIT_EE5valueEmE4typeERKS5_
262
263
    // unordered ranges (unordered_set, unordered_map)
264
265
    template <typename T>
266
    typename std::enable_if<container_hash::is_unordered_range<T>::value, std::size_t>::type
267
        hash_value( T const& v )
268
0
    {
269
0
        return boost::hash_unordered_range( v.begin(), v.end() );
270
0
    }
271
272
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && ( \
273
    ( defined(_MSVC_STL_VERSION) && _MSVC_STL_VERSION < 142 ) || \
274
    ( !defined(_MSVC_STL_VERSION) && defined(_CPPLIB_VER) && _CPPLIB_VER >= 520 ) )
275
276
    // resolve ambiguity with unconstrained stdext::hash_value in <xhash> :-/
277
278
    template<template<class...> class L, class... T>
279
    typename std::enable_if<container_hash::is_range<L<T...>>::value && !container_hash::is_contiguous_range<L<T...>>::value && !container_hash::is_unordered_range<L<T...>>::value, std::size_t>::type
280
        hash_value( L<T...> const& v )
281
    {
282
        return boost::hash_range( v.begin(), v.end() );
283
    }
284
285
    // contiguous ranges (string, vector, array)
286
287
    template<template<class...> class L, class... T>
288
    typename std::enable_if<container_hash::is_contiguous_range<L<T...>>::value, std::size_t>::type
289
        hash_value( L<T...> const& v )
290
    {
291
        return boost::hash_range( v.data(), v.data() + v.size() );
292
    }
293
294
    template<template<class, std::size_t> class L, class T, std::size_t N>
295
    typename std::enable_if<container_hash::is_contiguous_range<L<T, N>>::value, std::size_t>::type
296
        hash_value( L<T, N> const& v )
297
    {
298
        return boost::hash_range( v.data(), v.data() + v.size() );
299
    }
300
301
    // unordered ranges (unordered_set, unordered_map)
302
303
    template<template<class...> class L, class... T>
304
    typename std::enable_if<container_hash::is_unordered_range<L<T...>>::value, std::size_t>::type
305
        hash_value( L<T...> const& v )
306
    {
307
        return boost::hash_unordered_range( v.begin(), v.end() );
308
    }
309
310
#endif
311
312
    // described classes
313
314
#if defined(BOOST_DESCRIBE_CXX14)
315
316
#if defined(_MSC_VER) && _MSC_VER == 1900
317
# pragma warning(push)
318
# pragma warning(disable: 4100) // unreferenced formal parameter
319
#endif
320
321
    template <typename T>
322
    typename std::enable_if<container_hash::is_described_class<T>::value, std::size_t>::type
323
        hash_value( T const& v )
324
    {
325
        static_assert( !std::is_union<T>::value, "described unions are not supported" );
326
327
        std::size_t r = 0;
328
329
        using Bd = describe::describe_bases<T, describe::mod_any_access>;
330
331
        mp11::mp_for_each<Bd>([&](auto D){
332
333
            using B = typename decltype(D)::type;
334
            boost::hash_combine( r, (B const&)v );
335
336
        });
337
338
        using Md = describe::describe_members<T, describe::mod_any_access>;
339
340
        mp11::mp_for_each<Md>([&](auto D){
341
342
            boost::hash_combine( r, v.*D.pointer );
343
344
        });
345
346
        return r;
347
    }
348
349
#if defined(_MSC_VER) && _MSC_VER == 1900
350
# pragma warning(pop)
351
#endif
352
353
#endif
354
355
    // std::unique_ptr, std::shared_ptr
356
357
#if !defined(BOOST_NO_CXX11_SMART_PTR)
358
359
    template <typename T>
360
    std::size_t hash_value( std::shared_ptr<T> const& x )
361
    {
362
        return boost::hash_value( x.get() );
363
    }
364
365
    template <typename T, typename Deleter>
366
    std::size_t hash_value( std::unique_ptr<T, Deleter> const& x )
367
    {
368
        return boost::hash_value( x.get() );
369
    }
370
371
#endif
372
373
    // std::type_index
374
375
#if !defined(BOOST_NO_CXX11_HDR_TYPEINDEX)
376
377
    inline std::size_t hash_value( std::type_index const& v )
378
0
    {
379
0
        return v.hash_code();
380
0
    }
381
382
#endif
383
384
    // std::error_code, std::error_condition
385
386
#if !defined(BOOST_NO_CXX11_HDR_SYSTEM_ERROR)
387
388
    inline std::size_t hash_value( std::error_code const& v )
389
0
    {
390
0
        std::size_t seed = 0;
391
0
392
0
        boost::hash_combine( seed, v.value() );
393
0
        boost::hash_combine( seed, &v.category() );
394
0
395
0
        return seed;
396
0
    }
397
398
    inline std::size_t hash_value( std::error_condition const& v )
399
0
    {
400
0
        std::size_t seed = 0;
401
0
402
0
        boost::hash_combine( seed, v.value() );
403
0
        boost::hash_combine( seed, &v.category() );
404
0
405
0
        return seed;
406
0
    }
407
408
#endif
409
410
    // std::nullptr_t
411
412
#if !defined(BOOST_NO_CXX11_NULLPTR)
413
414
    template <typename T>
415
    typename std::enable_if<std::is_same<T, std::nullptr_t>::value, std::size_t>::type
416
        hash_value( T const& /*v*/ )
417
0
    {
418
0
        return boost::hash_value( static_cast<void*>( nullptr ) );
419
0
    }
420
421
#endif
422
423
    // std::optional
424
425
#if !defined(BOOST_NO_CXX17_HDR_OPTIONAL)
426
427
    template <typename T>
428
    std::size_t hash_value( std::optional<T> const& v )
429
    {
430
        if( !v )
431
        {
432
            // Arbitrary value for empty optional.
433
            return 0x12345678;
434
        }
435
        else
436
        {
437
            return boost::hash<T>()(*v);
438
        }
439
    }
440
441
#endif
442
443
    // std::variant
444
445
#if !defined(BOOST_NO_CXX17_HDR_VARIANT)
446
447
    inline std::size_t hash_value( std::monostate )
448
0
    {
449
0
        return 0x87654321;
450
0
    }
451
452
    template <typename... Types>
453
    std::size_t hash_value( std::variant<Types...> const& v )
454
    {
455
        std::size_t seed = 0;
456
457
        hash_combine( seed, v.index() );
458
        std::visit( [&seed](auto&& x) { hash_combine(seed, x); }, v );
459
460
        return seed;
461
    }
462
463
#endif
464
465
    //
466
    // boost::hash_combine
467
    //
468
469
    template <class T>
470
    inline void hash_combine( std::size_t& seed, T const& v )
471
0
    {
472
0
        seed = boost::hash_detail::hash_mix( seed + 0x9e3779b9 + boost::hash<T>()( v ) );
473
0
    }
Unexecuted instantiation: void boost::hash_combine<boost::json::value>(unsigned long&, boost::json::value const&)
Unexecuted instantiation: void boost::hash_combine<boost::json::key_value_pair>(unsigned long&, boost::json::key_value_pair const&)
Unexecuted instantiation: void boost::hash_combine<boost::core::basic_string_view<char> >(unsigned long&, boost::core::basic_string_view<char> const&)
Unexecuted instantiation: void boost::hash_combine<boost::json::kind>(unsigned long&, boost::json::kind const&)
Unexecuted instantiation: void boost::hash_combine<boost::json::string>(unsigned long&, boost::json::string const&)
Unexecuted instantiation: void boost::hash_combine<boost::json::array>(unsigned long&, boost::json::array const&)
Unexecuted instantiation: void boost::hash_combine<boost::json::object>(unsigned long&, boost::json::object const&)
Unexecuted instantiation: void boost::hash_combine<bool>(unsigned long&, bool const&)
Unexecuted instantiation: void boost::hash_combine<long>(unsigned long&, long const&)
Unexecuted instantiation: void boost::hash_combine<unsigned long>(unsigned long&, unsigned long const&)
Unexecuted instantiation: void boost::hash_combine<double>(unsigned long&, double const&)
Unexecuted instantiation: void boost::hash_combine<decltype(nullptr)>(unsigned long&, decltype(nullptr) const&)
Unexecuted instantiation: void boost::hash_combine<int>(unsigned long&, int const&)
Unexecuted instantiation: void boost::hash_combine<std::__1::error_category const*>(unsigned long&, std::__1::error_category const* const&)
474
475
    //
476
    // boost::hash_range
477
    //
478
479
    template <class It>
480
    inline void hash_range( std::size_t& seed, It first, It last )
481
0
    {
482
0
        seed = hash_detail::hash_range( seed, first, last );
483
0
    }
Unexecuted instantiation: void boost::hash_range<boost::json::value const*>(unsigned long&, boost::json::value const*, boost::json::value const*)
Unexecuted instantiation: void boost::hash_range<char const*>(unsigned long&, char const*, char const*)
484
485
    template <class It>
486
    inline std::size_t hash_range( It first, It last )
487
0
    {
488
0
        std::size_t seed = 0;
489
490
0
        hash_range( seed, first, last );
491
492
0
        return seed;
493
0
    }
Unexecuted instantiation: unsigned long boost::hash_range<boost::json::value const*>(boost::json::value const*, boost::json::value const*)
Unexecuted instantiation: unsigned long boost::hash_range<char const*>(char const*, char const*)
494
495
    //
496
    // boost::hash_unordered_range
497
    //
498
499
    template <class It>
500
    inline void hash_unordered_range( std::size_t& seed, It first, It last )
501
0
    {
502
0
        std::size_t r = 0;
503
0
        std::size_t const s2( seed );
504
505
0
        for( ; first != last; ++first )
506
0
        {
507
0
            std::size_t s3( s2 );
508
509
0
            hash_combine<typename std::iterator_traits<It>::value_type>( s3, *first );
510
511
0
            r += s3;
512
0
        }
513
514
0
        seed += r;
515
0
    }
516
517
    template <class It>
518
    inline std::size_t hash_unordered_range( It first, It last )
519
0
    {
520
0
        std::size_t seed = 0;
521
522
0
        hash_unordered_range( seed, first, last );
523
524
0
        return seed;
525
0
    }
526
527
    //
528
    // boost::hash
529
    //
530
531
    template <class T> struct hash
532
    {
533
        typedef T argument_type;
534
        typedef std::size_t result_type;
535
536
        std::size_t operator()( T const& val ) const
537
0
        {
538
0
            return hash_value( val );
539
0
        }
Unexecuted instantiation: boost::hash<boost::json::array>::operator()(boost::json::array const&) const
Unexecuted instantiation: boost::hash<boost::json::object>::operator()(boost::json::object const&) const
Unexecuted instantiation: boost::hash<boost::json::key_value_pair>::operator()(boost::json::key_value_pair const&) const
Unexecuted instantiation: boost::hash<boost::core::basic_string_view<char> >::operator()(boost::core::basic_string_view<char> const&) const
Unexecuted instantiation: boost::hash<boost::json::string>::operator()(boost::json::string const&) const
Unexecuted instantiation: boost::hash<boost::json::kind>::operator()(boost::json::kind const&) const
Unexecuted instantiation: boost::hash<bool>::operator()(bool const&) const
Unexecuted instantiation: boost::hash<long>::operator()(long const&) const
Unexecuted instantiation: boost::hash<unsigned long>::operator()(unsigned long const&) const
Unexecuted instantiation: boost::hash<double>::operator()(double const&) const
Unexecuted instantiation: boost::hash<decltype(nullptr)>::operator()(decltype(nullptr) const&) const
Unexecuted instantiation: boost::hash<boost::json::value>::operator()(boost::json::value const&) const
Unexecuted instantiation: boost::hash<int>::operator()(int const&) const
Unexecuted instantiation: boost::hash<std::__1::error_category const*>::operator()(std::__1::error_category const* const&) const
540
    };
541
542
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && ( \
543
    ( defined(_MSVC_STL_VERSION) && _MSVC_STL_VERSION < 142 ) || \
544
    ( !defined(_MSVC_STL_VERSION) && defined(_CPPLIB_VER) && _CPPLIB_VER >= 520 ) )
545
546
    // Dinkumware has stdext::hash_value for basic_string in <xhash> :-/
547
548
    template<class E, class T, class A> struct hash< std::basic_string<E, T, A> >
549
    {
550
        typedef std::basic_string<E, T, A> argument_type;
551
        typedef std::size_t result_type;
552
553
        std::size_t operator()( std::basic_string<E, T, A> const& val ) const
554
        {
555
            return boost::hash_value( val );
556
        }
557
    };
558
559
#endif
560
561
    // hash_is_avalanching
562
563
    template<class Ch> struct hash_is_avalanching< boost::hash< std::basic_string<Ch> > >: std::is_integral<Ch> {};
564
565
#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
566
567
    template<class Ch> struct hash_is_avalanching< boost::hash< std::basic_string_view<Ch> > >: std::is_integral<Ch> {};
568
569
#endif
570
571
} // namespace boost
572
573
#endif // #ifndef BOOST_FUNCTIONAL_HASH_HASH_HPP