Coverage Report

Created: 2026-08-13 07:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ninja/src/third_party/emhash/hash_table8.hpp
Line
Count
Source
1
// version 1.7.4
2
// https://github.com/ktprime/emhash/blob/master/hash_table8.hpp
3
//
4
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
5
// SPDX-License-Identifier: MIT
6
// Copyright (c) 2021-2026 Huang Yuanbing & bailuzhou AT 163.com
7
//
8
// Permission is hereby granted, free of charge, to any person obtaining a copy
9
// of this software and associated documentation files (the "Software"), to deal
10
// in the Software without restriction, including without limitation the rights
11
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
// copies of the Software, and to permit persons to whom the Software is
13
// furnished to do so, subject to the following conditions:
14
//
15
// The above copyright notice and this permission notice shall be included in all
16
// copies or substantial portions of the Software.
17
//
18
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
// SOFTWARE
25
26
/// @file hash_table8.hpp
27
/// @brief Split-index + dense-pairs open addressing hash map (emhash8)
28
/// @version 1.7.4
29
/// @copyright Copyright (c) 2021-2026 Huang Yuanbing
30
31
#pragma once
32
33
#include <cstring>
34
#include <string>
35
#include <cstdlib>
36
#include <type_traits>
37
#include <cassert>
38
#include <utility>
39
#include <cstdint>
40
#include <functional>
41
#include <iterator>
42
#include <algorithm>
43
#include <memory>
44
45
#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__)
46
#include <xmmintrin.h>
47
#elif _WIN32 && defined(_M_ARM64)
48
#include <intrin.h>
49
#endif
50
51
#undef  EMH_NEW
52
#undef  EMH_EMPTY
53
#undef  EMH_EQHASH
54
55
// likely/unlikely
56
#if defined(__GNUC__) && (__GNUC__ >= 3) && (__GNUC_MINOR__ >= 1) || defined(__clang__)
57
1.05M
    #define EMH_LIKELY(condition)   __builtin_expect(!!(condition), 1)
58
204k
    #define EMH_UNLIKELY(condition) __builtin_expect(!!(condition), 0)
59
#elif defined(_MSC_VER) && (_MSC_VER >= 1920)
60
    #define EMH_LIKELY(condition)   ((condition) ? ((void)__assume(condition), 1) : 0)
61
    #define EMH_UNLIKELY(condition) ((condition) ? 1 : ((void)__assume(!(condition)), 0))
62
#else
63
    #define EMH_LIKELY(condition)   (condition)
64
    #define EMH_UNLIKELY(condition) (condition)
65
#endif
66
67
1.81M
#define EMH_EMPTY(n) (0 > (int)(_index[n].next))
68
1.41M
#define EMH_EQHASH(n, key_hash) (((size_type)(key_hash) & ~_mask) == (_index[n].slot & ~_mask))
69
//#define EMH_EQHASH(n, key_hash) ((size_type)(key_hash - _index[n].slot) & ~_mask) == 0
70
#define EMH_NEW(key, val, bucket, key_hash) \
71
347k
    new(_pairs + _num_filled) value_type(key, val); \
72
347k
    _etail = bucket; \
73
347k
    _index[bucket] = {bucket, _num_filled++ | ((size_type)(key_hash) & ~_mask)}
74
75
namespace emhash8 {
76
77
struct DefaultPolicy {
78
    static constexpr float load_factor = 0.80f;
79
    static constexpr float min_load_factor = 0.20f;
80
    static constexpr size_t cacheline_size = 64U;
81
};
82
83
/// @brief High-performance hash map with split index + dense pairs layout.
84
///
85
/// emhash8 uses a two-array design:
86
/// - `_index[]` maps buckets to slots via linked-bucket chains
87
/// - `_pairs[]` stores key-value pairs in a dense, packed array
88
///
89
/// This layout provides extremely fast iteration (sequential scan of `_pairs`)
90
/// and is ideal for complex/large key or value types.
91
///
92
/// @tparam KeyT    Key type
93
/// @tparam ValueT  Mapped value type
94
/// @tparam HashT   Hash functor (default: std::hash<KeyT>)
95
/// @tparam EqT     Key equality functor (default: std::equal_to<KeyT>)
96
/// @tparam AllocT  Allocator type (default: std::allocator<std::pair<KeyT, ValueT>>)
97
/// @tparam Policy  Configuration policy (default: DefaultPolicy)
98
///
99
/// @note Header-only: just `#include "emhash/hash_table8.hpp"` and use `emhash8::HashMap`.
100
/// @note Not thread-safe. Concurrent read-only access is safe.
101
template<typename KeyT, typename ValueT,
102
        typename HashT = std::hash<KeyT>,
103
        typename EqT = std::equal_to<KeyT>,
104
        typename AllocT = std::allocator<std::pair<KeyT, ValueT>>,
105
        typename Policy = DefaultPolicy>
106
class HashMap
107
{
108
    static_assert(std::is_copy_constructible<KeyT>::value || std::is_move_constructible<KeyT>::value,
109
                  "KeyT must be copy-constructible or move-constructible");
110
    static_assert(std::is_copy_constructible<ValueT>::value || std::is_move_constructible<ValueT>::value,
111
                  "ValueT must be copy-constructible or move-constructible");
112
113
#ifndef EMH_DEFAULT_LOAD_FACTOR
114
    constexpr static float EMH_DEFAULT_LOAD_FACTOR = 0.80f;
115
#endif
116
    constexpr static float EMH_MIN_LOAD_FACTOR     = 0.25f; //< 0.5
117
#ifndef EMH_CACHE_LINE_SIZE
118
    constexpr static uint32_t EMH_CACHE_LINE_SIZE  = 64;
119
#endif
120
121
public:
122
    using htype = HashMap<KeyT, ValueT, HashT, EqT, AllocT, Policy>;
123
    using value_type = std::pair<KeyT, ValueT>; //TODO set to const KeyT
124
//    using value_type = std::pair<const KeyT, ValueT>; //TODO set to const KeyT
125
    using key_type = const KeyT;
126
    using mapped_type = ValueT;
127
    //using dPolicy = Policy;
128
129
#ifdef EMH_SMALL_TYPE
130
    using size_type = uint16_t;
131
#elif EMH_SIZE_TYPE == 0
132
    using size_type = uint32_t;
133
#else
134
    using size_type = uint64_t;
135
#endif
136
137
    using hasher = HashT;
138
    using key_equal = EqT;
139
    using allocator_type = AllocT;
140
141
    constexpr static size_type INACTIVE = size_type(-1);
142
    constexpr static size_type EAD      = 2;
143
144
    struct Index
145
    {
146
        size_type next;
147
        size_type slot;
148
    };
149
150
    template <bool IsConst, typename HashMapType>
151
    class hashmap_iterator
152
    {
153
    public:
154
        using iterator_category = std::bidirectional_iterator_tag;
155
        using difference_type = std::ptrdiff_t;
156
        using value_type = typename HashMapType::value_type;
157
        using reference = std::conditional_t<IsConst, const value_type&, value_type&>;
158
        using pointer = std::conditional_t<IsConst, const value_type*, value_type*>;
159
        using hash_map_type = std::conditional_t<IsConst, const HashMapType, HashMapType>;
160
161
        constexpr hashmap_iterator() noexcept : kv_(nullptr) {}
162
        constexpr hashmap_iterator(pointer kv) noexcept : kv_(kv) {}
163
        constexpr hashmap_iterator(hash_map_type* hash_map, size_type bucket) noexcept
164
2.11M
            : kv_(hash_map->_pairs + bucket) {}
emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::hashmap_iterator<true, emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy> >::hashmap_iterator(emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy> const*, unsigned int)
Line
Count
Source
164
2.11M
            : kv_(hash_map->_pairs + bucket) {}
Unexecuted instantiation: emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::hashmap_iterator<false, emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy> >::hashmap_iterator(emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>*, unsigned int)
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::hashmap_iterator<false, emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy> >::hashmap_iterator(emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>*, unsigned int)
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::hashmap_iterator<true, emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy> >::hashmap_iterator(emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy> const*, unsigned int)
165
166
        // Non-const to const iterator conversion (not needed when already const)
167
#if defined(__clang__)
168
#pragma clang diagnostic push
169
#pragma clang diagnostic ignored "-Wclass-conversion"
170
#endif
171
        template <bool OtherIsConst = IsConst, std::enable_if_t<!OtherIsConst, int> = 0>
172
        constexpr operator hashmap_iterator<true, HashMapType>() const noexcept {
173
            return hashmap_iterator<true, HashMapType>(kv_);
174
        }
175
#if defined(__clang__)
176
#pragma clang diagnostic pop
177
#endif
178
179
        constexpr hashmap_iterator& operator++() noexcept
180
0
        {
181
0
            ++kv_;
182
0
            return *this;
183
0
        }
Unexecuted instantiation: emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::hashmap_iterator<false, emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy> >::operator++()
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::hashmap_iterator<false, emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy> >::operator++()
184
185
        constexpr hashmap_iterator operator++(int) noexcept
186
        {
187
            auto copy = *this;
188
            ++(*this);
189
            return copy;
190
        }
191
192
        constexpr hashmap_iterator& operator--() noexcept
193
        {
194
            --kv_;
195
            return *this;
196
        }
197
198
        constexpr hashmap_iterator operator--(int) noexcept
199
        {
200
            auto copy = *this;
201
            --(*this);
202
            return copy;
203
        }
204
205
        constexpr hashmap_iterator operator+(difference_type diff) const noexcept
206
        {
207
            auto copy = *this;
208
            copy.kv_ += diff;
209
            return copy;
210
        }
211
212
0
        constexpr reference operator*() const noexcept { return *kv_; }
213
708k
        constexpr pointer operator->() const noexcept { return kv_; }
emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::hashmap_iterator<true, emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy> >::operator->() const
Line
Count
Source
213
708k
        constexpr pointer operator->() const noexcept { return kv_; }
Unexecuted instantiation: emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::hashmap_iterator<false, emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy> >::operator->() const
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::hashmap_iterator<false, emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy> >::operator->() const
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::hashmap_iterator<true, emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy> >::operator->() const
214
215
        template <bool OtherIsConst>
216
        constexpr bool operator==(const hashmap_iterator<OtherIsConst, HashMapType>& rhs) const noexcept
217
1.05M
        {
218
1.05M
            return kv_ == rhs.kv_;
219
1.05M
        }
bool emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::hashmap_iterator<true, emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy> >::operator==<true>(emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::hashmap_iterator<true, emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy> > const&) const
Line
Count
Source
217
1.05M
        {
218
1.05M
            return kv_ == rhs.kv_;
219
1.05M
        }
Unexecuted instantiation: bool emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::hashmap_iterator<false, emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy> >::operator==<false>(emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::hashmap_iterator<false, emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy> > const&) const
Unexecuted instantiation: bool emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::hashmap_iterator<false, emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy> >::operator==<false>(emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::hashmap_iterator<false, emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy> > const&) const
Unexecuted instantiation: bool emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::hashmap_iterator<true, emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy> >::operator==<true>(emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::hashmap_iterator<true, emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy> > const&) const
220
221
        template <bool OtherIsConst>
222
        constexpr bool operator!=(const hashmap_iterator<OtherIsConst, HashMapType>& rhs) const noexcept
223
1.05M
        {
224
1.05M
            return !(*this == rhs);
225
1.05M
        }
bool emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::hashmap_iterator<true, emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy> >::operator!=<true>(emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::hashmap_iterator<true, emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy> > const&) const
Line
Count
Source
223
1.05M
        {
224
1.05M
            return !(*this == rhs);
225
1.05M
        }
Unexecuted instantiation: bool emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::hashmap_iterator<false, emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy> >::operator!=<false>(emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::hashmap_iterator<false, emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy> > const&) const
Unexecuted instantiation: bool emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::hashmap_iterator<false, emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy> >::operator!=<false>(emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::hashmap_iterator<false, emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy> > const&) const
Unexecuted instantiation: bool emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::hashmap_iterator<true, emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy> >::operator!=<true>(emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::hashmap_iterator<true, emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy> > const&) const
226
227
    private:
228
        pointer kv_;
229
        template <bool, typename> friend class hashmap_iterator;
230
        friend HashMapType;
231
    };
232
233
    using iterator = hashmap_iterator<false, htype>;
234
    using const_iterator = hashmap_iterator<true, htype>;
235
236
    void init(size_type bucket, float mlf = EMH_DEFAULT_LOAD_FACTOR)
237
617
    {
238
617
        _pairs = nullptr;
239
617
        _index = nullptr;
240
617
        _mask  = _num_buckets = 0;
241
617
        _num_filled = 0;
242
617
        _pairs_capacity = 0;
243
617
        _mlf = (uint32_t)((1 << 28) / EMH_DEFAULT_LOAD_FACTOR);
244
617
        max_load_factor(mlf);
245
617
        rehash(bucket);
246
617
    }
emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::init(unsigned int, float)
Line
Count
Source
237
617
    {
238
617
        _pairs = nullptr;
239
617
        _index = nullptr;
240
617
        _mask  = _num_buckets = 0;
241
617
        _num_filled = 0;
242
617
        _pairs_capacity = 0;
243
617
        _mlf = (uint32_t)((1 << 28) / EMH_DEFAULT_LOAD_FACTOR);
244
617
        max_load_factor(mlf);
245
617
        rehash(bucket);
246
617
    }
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::init(unsigned int, float)
247
248
    HashMap(size_type bucket = 2, float mlf = EMH_DEFAULT_LOAD_FACTOR)
249
617
    {
250
617
        init(bucket, mlf);
251
617
    }
emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::HashMap(unsigned int, float)
Line
Count
Source
249
617
    {
250
617
        init(bucket, mlf);
251
617
    }
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::HashMap(unsigned int, float)
252
253
    HashMap(const HashMap& rhs)
254
        : _pair_allocator(PairAllocTraits::select_on_container_copy_construction(rhs._pair_allocator))
255
        , _index_allocator(IndexAllocTraits::select_on_container_copy_construction(rhs._index_allocator))
256
    {
257
        if (rhs.load_factor() > EMH_MIN_LOAD_FACTOR) {
258
            _pairs_capacity = (size_type)((float)rhs._num_buckets * rhs.max_load_factor()) + 4;
259
            _pairs = alloc_bucket(_pairs_capacity);
260
            _index = alloc_index(rhs._num_buckets);
261
            clone(rhs);
262
        } else {
263
            init(rhs._num_filled + 2, rhs.max_load_factor());
264
            for (auto it = rhs.begin(); it != rhs.end(); ++it)
265
                insert_unique(it->first, it->second);
266
        }
267
    }
268
269
    HashMap(HashMap&& rhs) noexcept
270
        : _pair_allocator(std::move(rhs._pair_allocator))
271
        , _index_allocator(std::move(rhs._index_allocator))
272
    {
273
        init(0);
274
        *this = std::move(rhs);
275
    }
276
277
    HashMap(std::initializer_list<value_type> ilist)
278
    {
279
        init((size_type)ilist.size());
280
        for (auto it = ilist.begin(); it != ilist.end(); ++it)
281
            do_insert(*it);
282
    }
283
284
    template<class InputIt>
285
    HashMap(InputIt first, InputIt last, size_type bucket_count=4)
286
    {
287
        init((size_type)std::distance(first, last) + bucket_count);
288
        for (; first != last; ++first)
289
            emplace(*first);
290
    }
291
292
    explicit HashMap(const allocator_type& alloc)
293
        : _pair_allocator(alloc)
294
        , _index_allocator(alloc)
295
    {
296
        init(2);
297
    }
298
299
    HashMap(size_type bucket, float mlf, const allocator_type& alloc)
300
        : _pair_allocator(alloc)
301
        , _index_allocator(alloc)
302
    {
303
        init(bucket, mlf);
304
    }
305
306
    HashMap(const HashMap& rhs, const allocator_type& alloc)
307
        : _pair_allocator(alloc)
308
        , _index_allocator(alloc)
309
    {
310
        if (rhs.load_factor() > EMH_MIN_LOAD_FACTOR) {
311
            _pairs_capacity = (size_type)((float)rhs._num_buckets * rhs.max_load_factor()) + 4;
312
            _pairs = alloc_bucket(_pairs_capacity);
313
            _index = alloc_index(rhs._num_buckets);
314
            clone(rhs);
315
        } else {
316
            init(rhs._num_filled + 2, rhs.max_load_factor());
317
            for (auto it = rhs.begin(); it != rhs.end(); ++it)
318
                insert_unique(it->first, it->second);
319
        }
320
    }
321
322
    HashMap(HashMap&& rhs, const allocator_type& alloc) noexcept
323
        : _pair_allocator(alloc)
324
        , _index_allocator(alloc)
325
    {
326
        init(0);
327
        *this = std::move(rhs);
328
    }
329
330
    HashMap& operator=(const HashMap& rhs)
331
    {
332
        if (this == &rhs)
333
            return *this;
334
335
        if constexpr (PairAllocTraits::propagate_on_container_copy_assignment::value) {
336
            _pair_allocator = rhs._pair_allocator;
337
            _index_allocator = rhs._index_allocator;
338
        }
339
340
        if (rhs.load_factor() < EMH_MIN_LOAD_FACTOR) {
341
            clear(); dealloc_bucket(_pairs, _pairs_capacity); _pairs = nullptr; _pairs_capacity = 0;
342
            rehash(rhs._num_filled + 2);
343
            for (auto it = rhs.begin(); it != rhs.end(); ++it)
344
                insert_unique(it->first, it->second);
345
            return *this;
346
        }
347
348
        clearkv();
349
350
        if (_num_buckets != rhs._num_buckets) {
351
            dealloc_bucket(_pairs, _pairs_capacity); dealloc_index(_index, _num_buckets);
352
            _index = alloc_index(rhs._num_buckets);
353
            _pairs_capacity = (size_type)((float)rhs._num_buckets * rhs.max_load_factor()) + 4;
354
            _pairs = alloc_bucket(_pairs_capacity);
355
        }
356
357
        clone(rhs);
358
        return *this;
359
    }
360
361
    HashMap& operator=(HashMap&& rhs) noexcept
362
    {
363
        if (this != &rhs) {
364
            swap(rhs);
365
            rhs.clear();
366
        }
367
        return *this;
368
    }
369
370
    template<typename Con>
371
    bool operator == (const Con& rhs) const
372
    {
373
        if (size() != rhs.size())
374
            return false;
375
376
        for (auto it = begin(), last = end(); it != last; ++it) {
377
            auto oi = rhs.find(it->first);
378
            if (oi == rhs.end() || it->second != oi->second)
379
                return false;
380
        }
381
        return true;
382
    }
383
384
    template<typename Con>
385
    bool operator != (const Con& rhs) const { return !(*this == rhs); }
386
387
    ~HashMap() noexcept
388
617
    {
389
617
        clearkv();
390
617
        dealloc_bucket(_pairs, _pairs_capacity);
391
617
        dealloc_index(_index, _num_buckets);
392
617
        _num_filled = 0;
393
617
        _index = nullptr;
394
617
        _pairs = nullptr;
395
617
    }
emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::~HashMap()
Line
Count
Source
388
617
    {
389
617
        clearkv();
390
617
        dealloc_bucket(_pairs, _pairs_capacity);
391
617
        dealloc_index(_index, _num_buckets);
392
617
        _num_filled = 0;
393
617
        _index = nullptr;
394
617
        _pairs = nullptr;
395
617
    }
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::~HashMap()
396
397
    void clone(const HashMap& rhs)
398
    {
399
        _hasher      = rhs._hasher;
400
//        _eq          = rhs._eq;
401
        _num_buckets = rhs._num_buckets;
402
        _num_filled  = rhs._num_filled;
403
        _pairs_capacity = rhs._pairs_capacity;
404
        _mlf         = rhs._mlf;
405
        _last        = rhs._last;
406
        _mask        = rhs._mask;
407
#if EMH_HIGH_LOAD
408
        _ehead       = rhs._ehead;
409
#endif
410
        _etail       = rhs._etail;
411
412
        auto opairs  = rhs._pairs;
413
        memcpy((char*)_index, (char*)rhs._index, (_num_buckets + EAD) * sizeof(Index));
414
415
        if (is_trivially_copyable()) {
416
            memcpy((char*)_pairs, (char*)opairs, _num_filled * sizeof(value_type));
417
        } else {
418
            for (size_type slot = 0; slot < _num_filled; slot++)
419
                new(_pairs + slot) value_type(opairs[slot]);
420
        }
421
    }
422
423
    void swap(HashMap& rhs)
424
    {
425
        //      std::swap(_eq, rhs._eq);
426
        std::swap(_hasher, rhs._hasher);
427
        std::swap(_pairs, rhs._pairs);
428
        std::swap(_index, rhs._index);
429
        std::swap(_num_buckets, rhs._num_buckets);
430
        std::swap(_num_filled, rhs._num_filled);
431
        std::swap(_pairs_capacity, rhs._pairs_capacity);
432
        std::swap(_mask, rhs._mask);
433
        std::swap(_mlf, rhs._mlf);
434
        std::swap(_last, rhs._last);
435
#if EMH_HIGH_LOAD
436
        std::swap(_ehead, rhs._ehead);
437
#endif
438
        std::swap(_etail, rhs._etail);
439
        std::swap(_pair_allocator, rhs._pair_allocator);
440
        std::swap(_index_allocator, rhs._index_allocator);
441
    }
442
443
    // -------------------------------------------------------------
444
0
    iterator first() { return iterator{this, 0}; }
Unexecuted instantiation: emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::first()
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::first()
445
    iterator last()  { return iterator{this, _num_filled - 1}; }
446
    const_iterator first() const { return const_iterator{ this, 0 }; }
447
    const_iterator last() const { return const_iterator{ this, _num_filled - 1 }; }
448
449
    //no exception if empty
450
    value_type& front() { return _pairs[0]; }
451
    const value_type& front() const { return _pairs[0]; }
452
    value_type& back() { return _pairs[_num_filled - 1]; }
453
    const value_type& back() const { return _pairs[_num_filled - 1]; }
454
455
    void pop_front() { erase(begin()); } //TODO. only erase first without move last
456
    void pop_back() { erase(last()); }
457
458
0
    constexpr iterator begin() { return first(); }
Unexecuted instantiation: emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::begin()
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::begin()
459
    constexpr const_iterator cbegin() const { return first(); }
460
    constexpr const_iterator begin() const { return first(); }
461
462
0
    constexpr iterator end() { return { this, _num_filled }; }
Unexecuted instantiation: emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::end()
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::end()
463
1.05M
    constexpr const_iterator cend() const { return { this, _num_filled }; }
emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::cend() const
Line
Count
Source
463
1.05M
    constexpr const_iterator cend() const { return { this, _num_filled }; }
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::cend() const
464
1.05M
    constexpr const_iterator end() const { return cend(); }
emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::end() const
Line
Count
Source
464
1.05M
    constexpr const_iterator end() const { return cend(); }
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::end() const
465
466
    const value_type* values() const { return _pairs; }
467
    const Index* index() const { return _index; }
468
469
    size_type size() const { return _num_filled; }
470
    bool empty() const { return _num_filled == 0; }
471
    size_type bucket_count() const { return _num_buckets; }
472
    float load_factor() const { return static_cast<float>(_num_filled) / ((float)_mask + 1.0f); }
473
474
    const HashT& hash_function() const { return _hasher; }
475
    const EqT& key_eq() const { return _eq; }
476
    allocator_type get_allocator() const { return allocator_type(_pair_allocator); }
477
478
    void max_load_factor(float mlf)
479
617
    {
480
617
        if (mlf <= 0.999 && mlf > EMH_MIN_LOAD_FACTOR) {
481
617
            _mlf = (uint32_t)((1 << 28) / mlf);
482
            //if (_num_buckets > 0) rehash(_num_buckets);
483
617
        }
484
617
    }
emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::max_load_factor(float)
Line
Count
Source
479
617
    {
480
617
        if (mlf <= 0.999 && mlf > EMH_MIN_LOAD_FACTOR) {
481
617
            _mlf = (uint32_t)((1 << 28) / mlf);
482
            //if (_num_buckets > 0) rehash(_num_buckets);
483
617
        }
484
617
    }
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::max_load_factor(float)
485
486
2.73k
    constexpr float max_load_factor() const { return (1 << 28) / (float)_mlf; }
emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::max_load_factor() const
Line
Count
Source
486
2.73k
    constexpr float max_load_factor() const { return (1 << 28) / (float)_mlf; }
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::max_load_factor() const
487
2.73k
    constexpr uint64_t max_size() const { return 1ull << (sizeof(_num_buckets) * 8 - 1); }
emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::max_size() const
Line
Count
Source
487
2.73k
    constexpr uint64_t max_size() const { return 1ull << (sizeof(_num_buckets) * 8 - 1); }
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::max_size() const
488
    constexpr uint64_t max_bucket_count() const { return max_size(); }
489
490
#if EMH_STATIS
491
    //Returns the bucket number where the element with key k is located.
492
    size_type bucket(const KeyT& key) const
493
    {
494
        const auto bucket = hash_bucket(key);
495
        const auto next_bucket = _index[bucket].next;
496
        if ((int)next_bucket < 0)
497
            return 0;
498
        else if (bucket == next_bucket)
499
            return bucket + 1;
500
501
        return hash_main(bucket) + 1;
502
    }
503
504
    //Returns the number of collision elements in pos bucket.
505
    size_type bucket_size(const size_type bucket) const
506
    {
507
        auto next_bucket = _index[bucket].next;
508
        if ((int)next_bucket < 0)
509
            return 0;
510
511
        next_bucket = hash_main(bucket);
512
        size_type ibucket_size = 1;
513
514
        while (true) {
515
            const auto nbucket = _index[next_bucket].next;
516
            if (nbucket == next_bucket) {
517
                break;
518
            }
519
            ibucket_size ++;
520
            next_bucket = nbucket;
521
        }
522
        return ibucket_size;
523
    }
524
525
    size_type get_main_bucket(const size_type bucket) const
526
    {
527
        auto next_bucket = _index[bucket].next;
528
        if ((int)next_bucket < 0)
529
            return INACTIVE;
530
531
        return hash_main(bucket);
532
    }
533
534
    size_type get_diss(size_type bucket, size_type next_bucket, const size_type slots) const
535
    {
536
        auto pbucket = reinterpret_cast<uint64_t>(&_pairs[bucket]);
537
        auto pnext   = reinterpret_cast<uint64_t>(&_pairs[next_bucket]);
538
        if (pbucket / EMH_CACHE_LINE_SIZE == pnext / EMH_CACHE_LINE_SIZE)
539
            return 0;
540
        size_type diff = pbucket > pnext ? (pbucket - pnext) : (pnext - pbucket);
541
        if (diff / EMH_CACHE_LINE_SIZE < slots - 1)
542
            return diff / EMH_CACHE_LINE_SIZE + 1;
543
        return slots - 1;
544
    }
545
546
    int get_bucket_info(const size_type bucket, size_type steps[], const size_type slots) const
547
    {
548
        auto next_bucket = _index[bucket].next;
549
        if ((int)next_bucket < 0)
550
            return -1;
551
552
        const auto main_bucket = hash_main(bucket);
553
        if (next_bucket == main_bucket)
554
            return 1;
555
        else if (main_bucket != bucket)
556
            return 0;
557
558
        steps[get_diss(bucket, next_bucket, slots)] ++;
559
        size_type ibucket_size = 2;
560
        //find a empty and linked it to tail
561
        while (true) {
562
            const auto nbucket = _index[next_bucket].next;
563
            if (nbucket == next_bucket)
564
                break;
565
566
            steps[get_diss(nbucket, next_bucket, slots)] ++;
567
            ibucket_size ++;
568
            next_bucket = nbucket;
569
        }
570
        return (int)ibucket_size;
571
    }
572
573
    void dump_statics() const
574
    {
575
        const size_type slots = 128;
576
        size_type buckets[slots + 1] = {0};
577
        size_type steps[slots + 1]   = {0};
578
        for (size_type bucket = 0; bucket < _num_buckets; ++bucket) {
579
            auto bsize = get_bucket_info(bucket, steps, slots);
580
            if (bsize > 0)
581
                buckets[bsize] ++;
582
        }
583
584
        size_type sumb = 0, collision = 0, sumc = 0, finds = 0, sumn = 0;
585
        puts("============== buckets size ration =========");
586
        for (size_type i = 0; i < sizeof(buckets) / sizeof(buckets[0]); i++) {
587
            const auto bucketsi = buckets[i];
588
            if (bucketsi == 0)
589
                continue;
590
            sumb += bucketsi;
591
            sumn += bucketsi * i;
592
            collision += bucketsi * (i - 1);
593
            finds += bucketsi * i * (i + 1) / 2;
594
            printf("  %2u  %8u  %2.2lf|  %.2lf\n", i, bucketsi, bucketsi * 100.0 * i / _num_filled, sumn * 100.0 / _num_filled);
595
        }
596
597
        puts("========== collision miss ration ===========");
598
        for (size_type i = 0; i < sizeof(steps) / sizeof(steps[0]); i++) {
599
            sumc += steps[i];
600
            if (steps[i] <= 2)
601
                continue;
602
            printf("  %2u  %8u  %.2lf  %.2lf\n", i, steps[i], steps[i] * 100.0 / collision, sumc * 100.0 / collision);
603
        }
604
605
        if (sumb == 0)  return;
606
        printf("    _num_filled/bucket_size/packed collision/cache_miss/hit_find = %u/%.2lf/%zd/ %.2lf%%/%.2lf%%/%.2lf\n",
607
                _num_filled, _num_filled * 1.0 / sumb, sizeof(value_type), (collision * 100.0 / _num_filled), (collision - steps[0]) * 100.0 / _num_filled, finds * 1.0 / _num_filled);
608
        assert(sumn == _num_filled);
609
        assert(sumc == collision);
610
        puts("============== buckets size end =============");
611
    }
612
#endif
613
614
    //only useful for at function if not find key then return zero
615
    void pack_zero(ValueT zero)
616
    {
617
        _pairs[_num_filled] = { KeyT(), zero };
618
    }
619
620
    // ------------------------------------------------------------
621
    template<typename K=KeyT>
622
    iterator find(const K& key) noexcept
623
0
    {
624
0
        return {this, find_filled_slot(key)};
625
0
    }
626
627
    template<typename K=KeyT>
628
    const_iterator find(const K& key) const noexcept
629
1.05M
    {
630
1.05M
        return {this, find_filled_slot(key)};
631
1.05M
    }
emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::hashmap_iterator<true, emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy> > emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::find<StringPiece>(StringPiece const&) const
Line
Count
Source
629
1.05M
    {
630
1.05M
        return {this, find_filled_slot(key)};
631
1.05M
    }
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::hashmap_iterator<true, emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy> > emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::find<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) const
632
633
    //it key is not found, it will return value at end()
634
    template<typename K=KeyT>
635
    ValueT& at(const K& key) noexcept
636
    {
637
        const auto slot = find_filled_slot(key);
638
        return _pairs[slot].second;
639
    }
640
641
    template<typename K=KeyT>
642
    const ValueT& at(const K& key) const noexcept
643
    {
644
        const auto slot = find_filled_slot(key);
645
        return _pairs[slot].second;
646
    }
647
648
    const ValueT& index(const uint32_t index) const noexcept
649
    {
650
        return _pairs[index].second;
651
    }
652
653
    ValueT& index(const uint32_t index) noexcept
654
    {
655
        return _pairs[index].second;
656
    }
657
658
    /// @brief Check if a key exists in the map.
659
    /// @param key The key to search for.
660
    /// @return true if the key exists, false otherwise.
661
    /// @note Faster than count() > 0 for existence checks.
662
    template<typename K=KeyT>
663
    bool contains(const K& key) const noexcept
664
    {
665
        return find_filled_slot(key) != _num_filled;
666
    }
667
668
    template<typename K=KeyT>
669
    size_type count(const K& key) const noexcept
670
    {
671
        return find_filled_slot(key) == _num_filled ? 0 : 1;
672
        //return find_sorted_bucket(key) == END ? 0 : 1;
673
        //return find_hash_bucket(key) == END ? 0 : 1;
674
    }
675
676
    template<typename K=KeyT>
677
    std::pair<iterator, iterator> equal_range(const K& key)
678
    {
679
        const auto found = find(key);
680
        if (found.second == _num_filled)
681
            return { found, found };
682
        else
683
            return { found, std::next(found) };
684
    }
685
686
    void merge(HashMap& rhs)
687
    {
688
        if (empty()) {
689
            *this = std::move(rhs);
690
            return;
691
        }
692
693
        for (auto rit = rhs.begin(); rit != rhs.end(); ) {
694
            auto fit = find(rit->first);
695
            if (fit == end()) {
696
                insert_unique(rit->first, std::move(rit->second));
697
                rit = rhs.erase(rit);
698
            } else {
699
                ++rit;
700
            }
701
        }
702
    }
703
704
    /// Returns the matching ValueT or nullptr if k isn't found.
705
    bool try_get(const KeyT& key, ValueT& val) const noexcept
706
    {
707
        const auto slot = find_filled_slot(key);
708
        const auto found = slot != _num_filled;
709
        if (found) {
710
            val = _pairs[slot].second;
711
        }
712
        return found;
713
    }
714
715
    /// @brief Get a pointer to the value for a key, or nullptr if not found.
716
    /// @param key The key to look up.
717
    /// @return Pointer to the value if found, nullptr otherwise.
718
    /// @note More efficient than find() + iterator dereference.
719
    /// @code
720
    ///   if (auto* pval = map.try_get(key)) { use(*pval); }
721
    /// @endcode
722
    ValueT* try_get(const KeyT& key) noexcept
723
    {
724
        const auto slot = find_filled_slot(key);
725
        return slot != _num_filled ? &_pairs[slot].second : nullptr;
726
    }
727
728
    /// @brief Const version of try_get().
729
    ValueT* try_get(const KeyT& key) const noexcept
730
    {
731
        const auto slot = find_filled_slot(key);
732
        return slot != _num_filled ? &_pairs[slot].second : nullptr;
733
    }
734
735
    /// @brief Set value if key exists, do nothing if it doesn't.
736
    /// @param key The key to look up.
737
    /// @param val The new value to set.
738
    /// @return true if the key existed and value was updated, false if key not found.
739
    /// @note Only available in emhash5/8.
740
    bool try_set(const KeyT& key, const ValueT& val) noexcept
741
    {
742
        const auto slot = find_filled_slot(key);
743
        if (slot == _num_filled)
744
            return false;
745
746
        _pairs[slot].second = val;
747
        return true;
748
    }
749
750
    /// set value if key exist
751
    bool try_set(const KeyT& key, ValueT&& val) noexcept
752
    {
753
        const auto slot = find_filled_slot(key);
754
        if (slot == _num_filled)
755
            return false;
756
757
        _pairs[slot].second = std::move(val);
758
        return true;
759
    }
760
761
    /// Convenience function.
762
    ValueT get_or_return_default(const KeyT& key) const noexcept
763
    {
764
        const auto slot = find_filled_slot(key);
765
        return slot == _num_filled ? ValueT() : _pairs[slot].second;
766
    }
767
768
    // -----------------------------------------------------
769
    std::pair<iterator, bool> do_insert(const value_type& value) noexcept
770
    {
771
        const auto key_hash = hash_key(value.first);
772
        const auto bucket = find_or_allocate(value.first, key_hash);
773
        const auto bempty = EMH_EMPTY(bucket);
774
        if (bempty) {
775
            EMH_NEW(value.first, value.second, bucket, key_hash);
776
        }
777
778
        const auto slot = _index[bucket].slot & _mask;
779
        return { {this, slot}, bempty };
780
    }
781
782
    std::pair<iterator, bool> do_insert(value_type&& value) noexcept
783
    {
784
        const auto key_hash = hash_key(value.first);
785
        const auto bucket = find_or_allocate(value.first, key_hash);
786
        const auto bempty = EMH_EMPTY(bucket);
787
        if (bempty) {
788
            EMH_NEW(std::move(value.first), std::move(value.second), bucket, key_hash);
789
        }
790
791
        const auto slot = _index[bucket].slot & _mask;
792
        return { {this, slot}, bempty };
793
    }
794
795
    template<typename K, typename V>
796
    std::pair<iterator, bool> do_insert(K&& key, V&& val) noexcept
797
0
    {
798
0
        const auto key_hash = hash_key(key);
799
0
        const auto bucket = find_or_allocate(key, key_hash);
800
0
        const auto bempty = EMH_EMPTY(bucket);
801
0
        if (bempty) {
802
0
            EMH_NEW(std::forward<K>(key), std::forward<V>(val), bucket, key_hash);
803
0
        }
804
805
0
        const auto slot = _index[bucket].slot & _mask;
806
0
        return { {this, slot}, bempty };
807
0
    }
808
809
    template<typename K, typename V>
810
    std::pair<iterator, bool> do_assign(K&& key, V&& val) noexcept
811
    {
812
        check_expand_need();
813
        const auto key_hash = hash_key(key);
814
        const auto bucket = find_or_allocate(key, key_hash);
815
        const auto bempty = EMH_EMPTY(bucket);
816
        if (bempty) {
817
            EMH_NEW(std::forward<K>(key), std::forward<V>(val), bucket, key_hash);
818
        } else {
819
            _pairs[_index[bucket].slot & _mask].second = std::move(val);
820
        }
821
822
        const auto slot = _index[bucket].slot & _mask;
823
        return { {this, slot}, bempty };
824
    }
825
826
    std::pair<iterator, bool> insert(const value_type& p)
827
    {
828
        check_expand_need();
829
        return do_insert(p);
830
    }
831
832
    std::pair<iterator, bool> insert(value_type && p)
833
    {
834
        check_expand_need();
835
        return do_insert(std::move(p));
836
    }
837
838
    template <typename Iter>
839
    void insert(Iter first, Iter last)
840
    {
841
        reserve(std::distance(first, last) + _num_filled, false);
842
        for (; first != last; ++first)
843
            do_insert(first->first, first->second);
844
    }
845
846
    void insert(std::initializer_list<value_type> ilist)
847
    {
848
        reserve(ilist.size() + _num_filled, false);
849
        for (auto it = ilist.begin(); it != ilist.end(); ++it)
850
            do_insert(*it);
851
    }
852
853
#if 0
854
    template <typename Iter>
855
    void insert_unique(Iter begin, Iter end)
856
    {
857
        reserve(std::distance(begin, end) + _num_filled, false);
858
        for (; begin != end; ++begin) {
859
            insert_unique(*begin);
860
        }
861
    }
862
#endif
863
864
    /// @brief Insert a key-value pair without checking for duplicates.
865
    /// @param key The key to insert.
866
    /// @param val The value to insert.
867
    /// @return The bucket index where the element was inserted.
868
    /// @pre The key must NOT already exist in the map.
869
    /// @note 20-40% faster than insert() when uniqueness is guaranteed.
870
    /// @warning Inserting a duplicate key causes undefined behavior.
871
    template<typename K, typename V>
872
    size_type insert_unique(K&& key, V&& val)
873
    {
874
        check_expand_need();
875
        const auto key_hash = hash_key(key);
876
        auto bucket = find_unique_bucket(key_hash);
877
        EMH_NEW(std::forward<K>(key), std::forward<V>(val), bucket, key_hash);
878
        return bucket;
879
    }
880
881
    size_type insert_unique(value_type&& value)
882
    {
883
        return insert_unique(std::move(value.first), std::move(value.second));
884
    }
885
886
    size_type insert_unique(const value_type& value)
887
    {
888
        return insert_unique(value.first, value.second);
889
    }
890
891
    template <class... Args>
892
    std::pair<iterator, bool> emplace(Args&&... args) noexcept
893
0
    {
894
0
        check_expand_need();
895
0
        return do_insert(std::forward<Args>(args)...);
896
0
    }
897
898
    //no any optimize for position
899
    template <class... Args>
900
    iterator emplace_hint(const_iterator hint, Args&&... args)
901
    {
902
        (void)hint;
903
        check_expand_need();
904
        return do_insert(std::forward<Args>(args)...).first;
905
    }
906
907
    template<class... Args>
908
    std::pair<iterator, bool> try_emplace(const KeyT& k, Args&&... args)
909
    {
910
        check_expand_need();
911
        return do_insert(k, std::forward<Args>(args)...);
912
    }
913
914
    template<class... Args>
915
    std::pair<iterator, bool> try_emplace(KeyT&& k, Args&&... args)
916
    {
917
        check_expand_need();
918
        return do_insert(std::move(k), std::forward<Args>(args)...);
919
    }
920
921
    template <class... Args>
922
    size_type emplace_unique(Args&&... args)
923
    {
924
        return insert_unique(std::forward<Args>(args)...);
925
    }
926
927
    std::pair<iterator, bool> insert_or_assign(const KeyT& key, ValueT&& val)
928
    {
929
        return do_assign(key, std::forward<ValueT>(val));
930
    }
931
932
    std::pair<iterator, bool> insert_or_assign(KeyT&& key, ValueT&& val)
933
    {
934
        return do_assign(std::move(key), std::forward<ValueT>(val));
935
    }
936
937
    /// Return the old value or ValueT() if it didn't exist.
938
    ValueT set_get(const KeyT& key, const ValueT& val)
939
    {
940
        check_expand_need();
941
        const auto key_hash = hash_key(key);
942
        const auto bucket = find_or_allocate(key, key_hash);
943
        if (EMH_EMPTY(bucket)) {
944
            EMH_NEW(key, val, bucket, key_hash);
945
            return ValueT();
946
        } else {
947
            const auto slot = _index[bucket].slot & _mask;
948
            ValueT old_value(val);
949
            std::swap(_pairs[slot].second, old_value);
950
            return old_value;
951
        }
952
    }
953
954
    /// Like std::map<KeyT, ValueT>::operator[].
955
    ValueT& operator[](const KeyT& key) noexcept
956
    {
957
        check_expand_need();
958
        const auto key_hash = hash_key(key);
959
        const auto bucket = find_or_allocate(key, key_hash);
960
        if (EMH_EMPTY(bucket)) {
961
            /* Check if inserting a value rather than overwriting an old entry */
962
            EMH_NEW(key, std::move(ValueT()), bucket, key_hash);
963
        }
964
965
        const auto slot = _index[bucket].slot & _mask;
966
        return _pairs[slot].second;
967
    }
968
969
    ValueT& operator[](KeyT&& key) noexcept
970
347k
    {
971
347k
        check_expand_need();
972
347k
        const auto key_hash = hash_key(key);
973
347k
        const auto bucket = find_or_allocate(key, key_hash);
974
347k
        if (EMH_EMPTY(bucket)) {
975
347k
            EMH_NEW(std::move(key), std::move(ValueT()), bucket, key_hash);
976
347k
        }
977
978
347k
        const auto slot = _index[bucket].slot & _mask;
979
347k
        return _pairs[slot].second;
980
347k
    }
981
982
    /// @brief Erase an element by key.
983
    /// @param key The key of the element to erase.
984
    /// @return 1 if the element was erased, 0 if the key was not found.
985
    /// Erase an element from the hash table.
986
    /// return 0 if element was not found
987
    size_type erase(const KeyT& key) noexcept
988
0
    {
989
0
        const auto key_hash = hash_key(key);
990
0
        const auto sbucket = find_filled_bucket(key, key_hash);
991
0
        if (sbucket == INACTIVE)
992
0
            return 0;
993
994
0
        const auto main_bucket = key_hash & _mask;
995
0
        erase_slot(sbucket, (size_type)main_bucket);
996
0
        return 1;
997
0
    }
998
999
    //iterator erase(const_iterator begin_it, const_iterator end_it)
1000
    iterator erase(const const_iterator& cit) noexcept
1001
    {
1002
        const auto slot = (size_type)(cit.kv_ - _pairs);
1003
        size_type main_bucket;
1004
        const auto sbucket = find_slot_bucket(slot, main_bucket); //TODO
1005
        erase_slot(sbucket, main_bucket);
1006
        return {this, slot};
1007
    }
1008
1009
    //only last >= first
1010
    iterator erase(const_iterator first, const_iterator last) noexcept
1011
    {
1012
        auto esize = long(last.kv_ - first.kv_);
1013
        auto tsize = long((_pairs + _num_filled) - last.kv_); //last to tail size
1014
        auto next = first;
1015
        while (tsize -- > 0) {
1016
            if (esize-- <= 0)
1017
                break;
1018
            next = ++erase(next);
1019
        }
1020
1021
        //fast erase from last
1022
        next = this->last();
1023
        while (esize -- > 0)
1024
            next = --erase(next);
1025
1026
        return {this, size_type(next.kv_ - _pairs)};
1027
    }
1028
1029
    template<typename Pred>
1030
    size_type erase_if(Pred pred)
1031
    {
1032
        auto old_size = size();
1033
        for (auto it = begin(); it != end();) {
1034
            if (pred(*it))
1035
                it = erase(it);
1036
            else
1037
                ++it;
1038
        }
1039
        return old_size - size();
1040
    }
1041
1042
    static constexpr bool is_trivially_destructible()
1043
0
    {
1044
0
#if __cplusplus >= 201402L || _MSC_VER > 1600
1045
0
        return (std::is_trivially_destructible<KeyT>::value && std::is_trivially_destructible<ValueT>::value);
1046
0
#else
1047
0
        return (std::is_pod<KeyT>::value && std::is_pod<ValueT>::value);
1048
0
#endif
1049
0
    }
Unexecuted instantiation: emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::is_trivially_destructible()
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::is_trivially_destructible()
1050
1051
    static constexpr bool is_trivially_copyable()
1052
0
    {
1053
0
#if __cplusplus >= 201103L || _MSC_VER > 1600
1054
0
        return (std::is_trivially_copyable<KeyT>::value && std::is_trivially_copyable<ValueT>::value);
1055
0
#else
1056
0
        return (std::is_pod<KeyT>::value && std::is_pod<ValueT>::value);
1057
0
#endif
1058
0
    }
Unexecuted instantiation: emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::is_trivially_copyable()
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::is_trivially_copyable()
1059
1060
    void clearkv()
1061
617
    {
1062
617
        if (!is_trivially_destructible()) {
1063
0
            while (_num_filled --)
1064
0
                _pairs[_num_filled].~value_type();
1065
0
        }
1066
617
    }
emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::clearkv()
Line
Count
Source
1061
617
    {
1062
617
        if (!is_trivially_destructible()) {
1063
0
            while (_num_filled --)
1064
0
                _pairs[_num_filled].~value_type();
1065
0
        }
1066
617
    }
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::clearkv()
1067
1068
    /// Remove all elements, keeping full capacity.
1069
    void clear() noexcept
1070
    {
1071
        clearkv();
1072
1073
        if (_num_filled > 0)
1074
            memset((char*)_index, (int)INACTIVE, sizeof(_index[0]) * _num_buckets);
1075
1076
        _last = _num_filled = 0;
1077
        _etail = INACTIVE;
1078
1079
#if EMH_HIGH_LOAD
1080
        _ehead = 0;
1081
#endif
1082
    }
1083
1084
    void shrink_to_fit(const float min_factor = EMH_DEFAULT_LOAD_FACTOR / 4)
1085
    {
1086
        if (load_factor() < min_factor && bucket_count() > 10) //safe guard
1087
            rehash(_num_filled + 1);
1088
    }
1089
1090
#if EMH_HIGH_LOAD
1091
    #ifdef EMH_PREVET
1092
    #undef EMH_PREVET
1093
    #endif
1094
    #define EMH_PREVET(i, n) i[n].slot
1095
    void set_empty()
1096
    {
1097
        auto prev = 0;
1098
        for (int32_t bucket = 1; bucket < _num_buckets; ++bucket) {
1099
            if (EMH_EMPTY(bucket)) {
1100
                if (prev != 0) {
1101
                    EMH_PREVET(_index, bucket) = prev;
1102
                    _index[prev].next = -bucket;
1103
                }
1104
                else
1105
                    _ehead = bucket;
1106
                prev = bucket;
1107
            }
1108
        }
1109
1110
        if (prev == 0) { _ehead = 0; return; } //no empty bucket
1111
        EMH_PREVET(_index, _ehead) = prev;
1112
        _index[prev].next = 0-_ehead;
1113
        _ehead = 0-_index[_ehead].next;
1114
    }
1115
1116
    void clear_empty()
1117
    {
1118
        auto prev = EMH_PREVET(_index, _ehead);
1119
        while (prev != _ehead) {
1120
            _index[prev].next = INACTIVE;
1121
            prev = EMH_PREVET(_index, prev);
1122
        }
1123
        _index[_ehead].next = INACTIVE;
1124
        _ehead = 0;
1125
    }
1126
1127
    //prev-ehead->next
1128
    size_type pop_empty(const size_type bucket)
1129
    {
1130
        const auto prev_bucket = EMH_PREVET(_index, bucket);
1131
        const int next_bucket = 0-_index[bucket].next;
1132
1133
        EMH_PREVET(_index, next_bucket) = prev_bucket;
1134
        _index[prev_bucket].next = -next_bucket;
1135
1136
        _ehead = next_bucket;
1137
        return bucket;
1138
    }
1139
1140
    //ehead->bucket->next
1141
    void push_empty(const int32_t bucket)
1142
    {
1143
        const int next_bucket = 0-_index[_ehead].next;
1144
        assert(next_bucket > 0);
1145
1146
        EMH_PREVET(_index, bucket) = _ehead;
1147
        _index[bucket].next = -next_bucket;
1148
1149
        EMH_PREVET(_index, next_bucket) = bucket;
1150
        _index[_ehead].next = -bucket;
1151
        //        _ehead = bucket;
1152
    }
1153
#endif
1154
1155
    /// Make room for this many elements
1156
    bool reserve(uint64_t num_elems, bool force)
1157
347k
    {
1158
347k
        (void)force;
1159
347k
#if EMH_HIGH_LOAD == 0
1160
347k
        const auto required_buckets = num_elems * _mlf >> 28;
1161
347k
        if (EMH_LIKELY(required_buckets < _num_buckets)) // && !force
1162
345k
            return false;
1163
#else
1164
        const auto required_buckets = num_elems + num_elems * 1 / 9;
1165
        if (EMH_LIKELY(required_buckets < _mask))
1166
            return false;
1167
1168
        else if (_num_buckets < 16 && _num_filled < _num_buckets)
1169
            return false;
1170
1171
        else if (_num_buckets > EMH_HIGH_LOAD) {
1172
            if (_ehead == 0) {
1173
                set_empty();
1174
                return false;
1175
            } else if (/*_num_filled + 100 < _num_buckets && */_index[_ehead].next != 0-_ehead) {
1176
                return false;
1177
            }
1178
        }
1179
#endif
1180
#if EMH_STATIS
1181
        if (_num_filled > EMH_STATIS) dump_statics();
1182
#endif
1183
1184
        //assert(required_buckets < max_size());
1185
2.12k
        rehash(required_buckets + 2);
1186
2.12k
        return true;
1187
347k
    }
emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::reserve(unsigned long, bool)
Line
Count
Source
1157
347k
    {
1158
347k
        (void)force;
1159
347k
#if EMH_HIGH_LOAD == 0
1160
347k
        const auto required_buckets = num_elems * _mlf >> 28;
1161
347k
        if (EMH_LIKELY(required_buckets < _num_buckets)) // && !force
1162
345k
            return false;
1163
#else
1164
        const auto required_buckets = num_elems + num_elems * 1 / 9;
1165
        if (EMH_LIKELY(required_buckets < _mask))
1166
            return false;
1167
1168
        else if (_num_buckets < 16 && _num_filled < _num_buckets)
1169
            return false;
1170
1171
        else if (_num_buckets > EMH_HIGH_LOAD) {
1172
            if (_ehead == 0) {
1173
                set_empty();
1174
                return false;
1175
            } else if (/*_num_filled + 100 < _num_buckets && */_index[_ehead].next != 0-_ehead) {
1176
                return false;
1177
            }
1178
        }
1179
#endif
1180
#if EMH_STATIS
1181
        if (_num_filled > EMH_STATIS) dump_statics();
1182
#endif
1183
1184
        //assert(required_buckets < max_size());
1185
2.12k
        rehash(required_buckets + 2);
1186
2.12k
        return true;
1187
347k
    }
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::reserve(unsigned long, bool)
1188
1189
    value_type* alloc_bucket(size_type num_buckets)
1190
2.73k
    {
1191
2.73k
        return PairAllocTraits::allocate(_pair_allocator, num_buckets);
1192
2.73k
    }
emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::alloc_bucket(unsigned int)
Line
Count
Source
1190
2.73k
    {
1191
2.73k
        return PairAllocTraits::allocate(_pair_allocator, num_buckets);
1192
2.73k
    }
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::alloc_bucket(unsigned int)
1193
1194
    void dealloc_bucket(value_type* ptr, size_type num_buckets)
1195
3.35k
    {
1196
3.35k
        if (ptr)
1197
2.73k
            PairAllocTraits::deallocate(_pair_allocator, ptr, num_buckets);
1198
3.35k
    }
emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::dealloc_bucket(std::__1::pair<StringPiece, Node*>*, unsigned int)
Line
Count
Source
1195
3.35k
    {
1196
3.35k
        if (ptr)
1197
2.73k
            PairAllocTraits::deallocate(_pair_allocator, ptr, num_buckets);
1198
3.35k
    }
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::dealloc_bucket(std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > >*, unsigned int)
1199
1200
    Index* alloc_index(size_type num_buckets)
1201
2.73k
    {
1202
2.73k
        return IndexAllocTraits::allocate(_index_allocator, num_buckets + EAD);
1203
2.73k
    }
emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::alloc_index(unsigned int)
Line
Count
Source
1201
2.73k
    {
1202
2.73k
        return IndexAllocTraits::allocate(_index_allocator, num_buckets + EAD);
1203
2.73k
    }
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::alloc_index(unsigned int)
1204
1205
    void dealloc_index(Index* ptr, size_type num_buckets)
1206
3.35k
    {
1207
3.35k
        if (ptr)
1208
2.73k
            IndexAllocTraits::deallocate(_index_allocator, ptr, num_buckets + EAD);
1209
3.35k
    }
emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::dealloc_index(emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::Index*, unsigned int)
Line
Count
Source
1206
3.35k
    {
1207
3.35k
        if (ptr)
1208
2.73k
            IndexAllocTraits::deallocate(_index_allocator, ptr, num_buckets + EAD);
1209
3.35k
    }
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::dealloc_index(emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::Index*, unsigned int)
1210
1211
    bool reserve(size_type required_buckets) noexcept
1212
    {
1213
        if (_num_filled != required_buckets)
1214
            return reserve(required_buckets, true);
1215
1216
        _last = 0;
1217
#if EMH_HIGH_LOAD
1218
        _ehead = 0;
1219
#endif
1220
1221
        memset((char*)_index, (int)INACTIVE, sizeof(_index[0]) * _num_buckets);
1222
        for (size_type slot = 0; slot < _num_filled; ++slot) {
1223
            const auto& key = _pairs[slot].first;
1224
            const auto key_hash = hash_key(key);
1225
            const auto bucket = find_unique_bucket(key_hash);
1226
            _index[bucket] = { bucket, slot | ((size_type)(key_hash) & ~_mask) };
1227
        }
1228
        return true;
1229
    }
1230
1231
    void rebuild(size_type num_buckets, size_type required_buckets, size_type old_num_buckets) noexcept
1232
2.73k
    {
1233
2.73k
        dealloc_index(_index, old_num_buckets);
1234
2.73k
        const auto need_size = std::max((size_type)((double)num_buckets * max_load_factor()) + 4, required_buckets + 2);
1235
2.73k
        auto new_pairs = alloc_bucket(need_size);
1236
2.73k
        if (is_trivially_copyable()) {
1237
2.73k
            if (_pairs)
1238
2.12k
            memcpy((char*)new_pairs, (char*)_pairs, _num_filled * sizeof(value_type));
1239
2.73k
        } else {
1240
0
            for (size_type slot = 0; slot < _num_filled; slot++) {
1241
0
                new(new_pairs + slot) value_type(std::move(_pairs[slot]));
1242
0
                if (!is_trivially_destructible())
1243
0
                    _pairs[slot].~value_type();
1244
0
            }
1245
0
        }
1246
2.73k
        dealloc_bucket(_pairs, _pairs_capacity);
1247
2.73k
        _pairs = new_pairs;
1248
2.73k
        _pairs_capacity = need_size;
1249
2.73k
        _index = alloc_index(num_buckets);
1250
1251
2.73k
        memset((char*)_index, (int)INACTIVE, sizeof(_index[0]) * num_buckets);
1252
2.73k
        memset((char*)(_index + num_buckets), 0, sizeof(_index[0]) * EAD);
1253
2.73k
    }
emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::rebuild(unsigned int, unsigned int, unsigned int)
Line
Count
Source
1232
2.73k
    {
1233
2.73k
        dealloc_index(_index, old_num_buckets);
1234
2.73k
        const auto need_size = std::max((size_type)((double)num_buckets * max_load_factor()) + 4, required_buckets + 2);
1235
2.73k
        auto new_pairs = alloc_bucket(need_size);
1236
2.73k
        if (is_trivially_copyable()) {
1237
2.73k
            if (_pairs)
1238
2.12k
            memcpy((char*)new_pairs, (char*)_pairs, _num_filled * sizeof(value_type));
1239
2.73k
        } else {
1240
0
            for (size_type slot = 0; slot < _num_filled; slot++) {
1241
0
                new(new_pairs + slot) value_type(std::move(_pairs[slot]));
1242
0
                if (!is_trivially_destructible())
1243
0
                    _pairs[slot].~value_type();
1244
0
            }
1245
0
        }
1246
2.73k
        dealloc_bucket(_pairs, _pairs_capacity);
1247
2.73k
        _pairs = new_pairs;
1248
2.73k
        _pairs_capacity = need_size;
1249
2.73k
        _index = alloc_index(num_buckets);
1250
1251
2.73k
        memset((char*)_index, (int)INACTIVE, sizeof(_index[0]) * num_buckets);
1252
2.73k
        memset((char*)(_index + num_buckets), 0, sizeof(_index[0]) * EAD);
1253
2.73k
    }
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::rebuild(unsigned int, unsigned int, unsigned int)
1254
1255
    void rehash(uint64_t required_buckets)
1256
2.73k
    {
1257
2.73k
        if (required_buckets < _num_filled)
1258
0
            return;
1259
1260
2.73k
        uint64_t buckets = _num_filled > (1u << 16) ? (1u << 16) : 4u;
1261
12.2k
        while (buckets < required_buckets) { buckets *= 2; }
1262
2.73k
        if (buckets > (uint64_t)max_size() || buckets < _num_filled)
1263
0
            std::abort(); //throw std::length_error("too large size");
1264
1265
#if EMH_SAVE_MEM
1266
        if (sizeof(KeyT) < sizeof(size_type) && buckets >= (1ul << (2 * 8)))
1267
            buckets = 2ul << (sizeof(KeyT) * 8);
1268
#endif
1269
1270
2.73k
        auto num_buckets = (size_type)buckets;
1271
1272
#if EMH_REHASH_LOG
1273
        auto last = _last;
1274
        size_type collision = 0;
1275
#endif
1276
1277
#if EMH_HIGH_LOAD
1278
        _ehead = 0;
1279
#endif
1280
2.73k
        _last = 0;
1281
1282
2.73k
        _mask        = num_buckets - 1;
1283
#if EMH_PACK_TAIL > 1
1284
        _last = _mask;
1285
        num_buckets += num_buckets * EMH_PACK_TAIL / 100; //add more 5-10%
1286
#endif
1287
2.73k
        auto old_num_buckets = _num_buckets;
1288
2.73k
        _num_buckets = num_buckets;
1289
1290
2.73k
        rebuild(num_buckets, (size_type)required_buckets, old_num_buckets);
1291
1292
#ifdef EMH_SORT
1293
        std::sort(_pairs, _pairs + _num_filled, [this](const value_type & l, const value_type & r) {
1294
            const auto hashl = hash_key(l.first), hashr = hash_key(r.first);
1295
            auto diff = int64_t((hashl & _mask) - (hashr & _mask));
1296
            if (diff != 0)
1297
                return diff < 0;
1298
            return hashl < hashr;
1299
        });
1300
#endif
1301
1302
2.73k
        _etail = INACTIVE;
1303
526k
        for (size_type slot = 0; slot < _num_filled; ++slot) {
1304
523k
            const auto& key = _pairs[slot].first;
1305
523k
            const auto key_hash = hash_key(key);
1306
523k
            const auto bucket = find_unique_bucket(key_hash);
1307
523k
            _index[bucket] = { bucket, slot | ((size_type)(key_hash) & ~_mask) };
1308
1309
#if EMH_REHASH_LOG
1310
            if (bucket != hash_main(bucket))
1311
                collision ++;
1312
#endif
1313
523k
        }
1314
1315
#if EMH_REHASH_LOG
1316
        if (_num_filled > EMH_REHASH_LOG) {
1317
            auto mbucket = _num_filled - collision;
1318
            char buff[255] = {0};
1319
            sprintf(buff, "    _num_filled/aver_size/K.V/pack/collision|last = %u/%.2lf/%s.%s/%zd|%.2lf%%,%.2lf%%",
1320
                    _num_filled, double (_num_filled) / mbucket, typeid(KeyT).name(), typeid(ValueT).name(), sizeof(_pairs[0]), collision * 100.0 / _num_filled, last * 100.0 / _num_buckets);
1321
#ifdef EMH_LOG
1322
            static uint32_t ihashs = 0; EMH_LOG() << "hash_nums = " << ihashs ++ << "|" <<__FUNCTION__ << "|" << buff << endl;
1323
#else
1324
            puts(buff);
1325
#endif
1326
        }
1327
#endif
1328
2.73k
    }
emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::rehash(unsigned long)
Line
Count
Source
1256
2.73k
    {
1257
2.73k
        if (required_buckets < _num_filled)
1258
0
            return;
1259
1260
2.73k
        uint64_t buckets = _num_filled > (1u << 16) ? (1u << 16) : 4u;
1261
12.2k
        while (buckets < required_buckets) { buckets *= 2; }
1262
2.73k
        if (buckets > (uint64_t)max_size() || buckets < _num_filled)
1263
0
            std::abort(); //throw std::length_error("too large size");
1264
1265
#if EMH_SAVE_MEM
1266
        if (sizeof(KeyT) < sizeof(size_type) && buckets >= (1ul << (2 * 8)))
1267
            buckets = 2ul << (sizeof(KeyT) * 8);
1268
#endif
1269
1270
2.73k
        auto num_buckets = (size_type)buckets;
1271
1272
#if EMH_REHASH_LOG
1273
        auto last = _last;
1274
        size_type collision = 0;
1275
#endif
1276
1277
#if EMH_HIGH_LOAD
1278
        _ehead = 0;
1279
#endif
1280
2.73k
        _last = 0;
1281
1282
2.73k
        _mask        = num_buckets - 1;
1283
#if EMH_PACK_TAIL > 1
1284
        _last = _mask;
1285
        num_buckets += num_buckets * EMH_PACK_TAIL / 100; //add more 5-10%
1286
#endif
1287
2.73k
        auto old_num_buckets = _num_buckets;
1288
2.73k
        _num_buckets = num_buckets;
1289
1290
2.73k
        rebuild(num_buckets, (size_type)required_buckets, old_num_buckets);
1291
1292
#ifdef EMH_SORT
1293
        std::sort(_pairs, _pairs + _num_filled, [this](const value_type & l, const value_type & r) {
1294
            const auto hashl = hash_key(l.first), hashr = hash_key(r.first);
1295
            auto diff = int64_t((hashl & _mask) - (hashr & _mask));
1296
            if (diff != 0)
1297
                return diff < 0;
1298
            return hashl < hashr;
1299
        });
1300
#endif
1301
1302
2.73k
        _etail = INACTIVE;
1303
526k
        for (size_type slot = 0; slot < _num_filled; ++slot) {
1304
523k
            const auto& key = _pairs[slot].first;
1305
523k
            const auto key_hash = hash_key(key);
1306
523k
            const auto bucket = find_unique_bucket(key_hash);
1307
523k
            _index[bucket] = { bucket, slot | ((size_type)(key_hash) & ~_mask) };
1308
1309
#if EMH_REHASH_LOG
1310
            if (bucket != hash_main(bucket))
1311
                collision ++;
1312
#endif
1313
523k
        }
1314
1315
#if EMH_REHASH_LOG
1316
        if (_num_filled > EMH_REHASH_LOG) {
1317
            auto mbucket = _num_filled - collision;
1318
            char buff[255] = {0};
1319
            sprintf(buff, "    _num_filled/aver_size/K.V/pack/collision|last = %u/%.2lf/%s.%s/%zd|%.2lf%%,%.2lf%%",
1320
                    _num_filled, double (_num_filled) / mbucket, typeid(KeyT).name(), typeid(ValueT).name(), sizeof(_pairs[0]), collision * 100.0 / _num_filled, last * 100.0 / _num_buckets);
1321
#ifdef EMH_LOG
1322
            static uint32_t ihashs = 0; EMH_LOG() << "hash_nums = " << ihashs ++ << "|" <<__FUNCTION__ << "|" << buff << endl;
1323
#else
1324
            puts(buff);
1325
#endif
1326
        }
1327
#endif
1328
2.73k
    }
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::rehash(unsigned long)
1329
1330
private:
1331
    // Can we fit another element?
1332
    bool check_expand_need()
1333
347k
    {
1334
347k
        return reserve(_num_filled, false);
1335
347k
    }
emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::check_expand_need()
Line
Count
Source
1333
347k
    {
1334
347k
        return reserve(_num_filled, false);
1335
347k
    }
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::check_expand_need()
1336
1337
    static void prefetch_heap_block(char* ctrl)
1338
1.32M
    {
1339
        // Prefetch the heap-allocated memory region to resolve potential TLB
1340
        // misses.  This is intended to overlap with execution of calculating the hash for a key.
1341
1.32M
#if defined(__GNUC__) || defined(__clang__)
1342
1.32M
        __builtin_prefetch(static_cast<const void*>(ctrl), 0, 1);
1343
#elif _WIN32 && defined(_M_ARM64)
1344
        __prefetch((const char*)ctrl);
1345
#elif _WIN32
1346
        _mm_prefetch((const char*)ctrl, _MM_HINT_T0);
1347
#endif
1348
1.32M
    }
emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::prefetch_heap_block(char*)
Line
Count
Source
1338
1.32M
    {
1339
        // Prefetch the heap-allocated memory region to resolve potential TLB
1340
        // misses.  This is intended to overlap with execution of calculating the hash for a key.
1341
1.32M
#if defined(__GNUC__) || defined(__clang__)
1342
1.32M
        __builtin_prefetch(static_cast<const void*>(ctrl), 0, 1);
1343
#elif _WIN32 && defined(_M_ARM64)
1344
        __prefetch((const char*)ctrl);
1345
#elif _WIN32
1346
        _mm_prefetch((const char*)ctrl, _MM_HINT_T0);
1347
#endif
1348
1.32M
    }
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::prefetch_heap_block(char*)
1349
1350
    size_type slot_to_bucket(const size_type slot) const noexcept
1351
0
    {
1352
0
        size_type main_bucket;
1353
0
        return find_slot_bucket(slot, main_bucket); //TODO
1354
0
    }
1355
1356
    //very slow
1357
    void erase_slot(const size_type sbucket, const size_type main_bucket) noexcept
1358
0
    {
1359
0
        const auto slot = _index[sbucket].slot & _mask;
1360
0
        const auto last_slot = _num_filled - 1;
1361
        // Find last_slot's bucket BEFORE erase_bucket modifies the chain
1362
0
        const auto last_bucket = (slot == last_slot) ? sbucket : slot_to_bucket(last_slot);
1363
1364
0
        const auto ebucket = erase_bucket(sbucket, main_bucket);
1365
0
        --_num_filled;
1366
0
        if (EMH_LIKELY(slot != last_slot)) {
1367
            // When sbucket == main_bucket, erase_bucket promotes next_bucket to
1368
            // main_bucket. If last_bucket was next_bucket (== ebucket), the data
1369
            // is now at main_bucket, so update main_bucket instead.
1370
0
            const auto update_bucket = (last_bucket == ebucket && sbucket == main_bucket)
1371
0
                ? main_bucket : last_bucket;
1372
1373
0
            _pairs[slot] = std::move(_pairs[last_slot]);
1374
0
            _index[update_bucket].slot = slot | (_index[update_bucket].slot & ~_mask);
1375
0
        }
1376
1377
0
        if (!is_trivially_destructible())
1378
0
            _pairs[last_slot].~value_type();
1379
1380
0
        _etail = INACTIVE;
1381
0
        _index[ebucket] = {INACTIVE, 0};
1382
#if EMH_HIGH_LOAD
1383
        if (_ehead) {
1384
            if (10 * _num_filled < 8 * _num_buckets)
1385
                clear_empty();
1386
            else if (ebucket)
1387
                push_empty(ebucket);
1388
        }
1389
#endif
1390
0
    }
1391
1392
    size_type erase_bucket(const size_type bucket, const size_type main_bucket) noexcept
1393
0
    {
1394
0
        const auto next_bucket = _index[bucket].next;
1395
0
        if (bucket == main_bucket) {
1396
0
            if (main_bucket != next_bucket) {
1397
0
                const auto nbucket = _index[next_bucket].next;
1398
0
                _index[main_bucket] = {
1399
0
                    (nbucket == next_bucket) ? main_bucket : nbucket,
1400
0
                    _index[next_bucket].slot
1401
0
                };
1402
0
            }
1403
0
            return next_bucket;
1404
0
        }
1405
1406
0
        const auto prev_bucket = find_prev_bucket(main_bucket, bucket);
1407
0
        _index[prev_bucket].next = (bucket == next_bucket) ? prev_bucket : next_bucket;
1408
0
        return bucket;
1409
0
    }
1410
1411
    // Find the slot with this key, or return bucket size
1412
    size_type find_slot_bucket(const size_type slot, size_type& main_bucket) const
1413
0
    {
1414
0
        const auto key_hash = hash_key(_pairs[slot].first);
1415
0
        const auto bucket = main_bucket = size_type(key_hash & _mask);
1416
0
        if (slot == (_index[bucket].slot & _mask))
1417
0
            return bucket;
1418
1419
0
        auto next_bucket = _index[bucket].next;
1420
0
        while (true) {
1421
0
            if (EMH_LIKELY(slot == (_index[next_bucket].slot & _mask)))
1422
0
                return next_bucket;
1423
0
            next_bucket = _index[next_bucket].next;
1424
0
        }
1425
1426
0
        return INACTIVE;
1427
0
    }
1428
1429
    // Find the slot with this key, or return bucket size
1430
    size_type find_filled_bucket(const KeyT& key, uint64_t key_hash) const noexcept
1431
0
    {
1432
0
        const auto bucket = size_type(key_hash & _mask);
1433
0
        const auto& idx = _index[bucket];
1434
0
        auto next_bucket  = idx.next;
1435
0
        if (EMH_UNLIKELY((int)next_bucket < 0))
1436
0
            return INACTIVE;
1437
1438
0
        const auto slot = idx.slot & _mask;
1439
0
        prefetch_heap_block((char*)&_pairs[slot]);
1440
0
        if (EMH_EQHASH(bucket, key_hash)) {
1441
0
            if (EMH_LIKELY(_eq(key, _pairs[slot].first)))
1442
0
                return bucket;
1443
0
        }
1444
0
        if (next_bucket == bucket)
1445
0
            return INACTIVE;
1446
1447
0
        while (true) {
1448
0
            if (EMH_EQHASH(next_bucket, key_hash)) {
1449
0
                const auto eslot = _index[next_bucket].slot & _mask;
1450
0
                if (EMH_LIKELY(_eq(key, _pairs[eslot].first)))
1451
0
                    return next_bucket;
1452
0
            }
1453
1454
0
            const auto nbucket = _index[next_bucket].next;
1455
0
            if (nbucket == next_bucket)
1456
0
                return INACTIVE;
1457
0
            next_bucket = nbucket;
1458
0
        }
1459
1460
0
        return INACTIVE;
1461
0
    }
1462
1463
    // Find the slot with this key, or return bucket size
1464
    template<typename K=KeyT>
1465
    size_type find_filled_slot(const K& key) const noexcept
1466
1.05M
    {
1467
1.05M
        const auto key_hash = hash_key(key);
1468
1.05M
        const auto bucket = size_type(key_hash & _mask);
1469
1.05M
        const auto& idx = _index[bucket];
1470
1.05M
        auto next_bucket = idx.next;
1471
1.05M
        if ((int)next_bucket < 0)
1472
142k
            return _num_filled;
1473
1474
913k
        const auto slot = idx.slot & _mask;
1475
913k
        prefetch_heap_block((char*)&_pairs[slot]);
1476
913k
        if (EMH_EQHASH(bucket, key_hash)) {
1477
573k
            if (EMH_LIKELY(_eq(key, _pairs[slot].first)))
1478
573k
                return slot;
1479
573k
        }
1480
340k
        if (next_bucket == bucket)
1481
151k
            return _num_filled;
1482
1483
242k
        while (true) {
1484
242k
            if (EMH_EQHASH(next_bucket, key_hash)) {
1485
136k
                const auto eslot = _index[next_bucket].slot & _mask;
1486
136k
                if (EMH_LIKELY(_eq(key, _pairs[eslot].first)))
1487
135k
                    return eslot;
1488
136k
            }
1489
1490
106k
            const auto nbucket = _index[next_bucket].next;
1491
106k
            if (nbucket == next_bucket)
1492
52.8k
                return _num_filled;
1493
53.8k
            next_bucket = nbucket;
1494
53.8k
        }
1495
1496
0
        return _num_filled;
1497
188k
    }
unsigned int emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::find_filled_slot<StringPiece>(StringPiece const&) const
Line
Count
Source
1466
1.05M
    {
1467
1.05M
        const auto key_hash = hash_key(key);
1468
1.05M
        const auto bucket = size_type(key_hash & _mask);
1469
1.05M
        const auto& idx = _index[bucket];
1470
1.05M
        auto next_bucket = idx.next;
1471
1.05M
        if ((int)next_bucket < 0)
1472
142k
            return _num_filled;
1473
1474
913k
        const auto slot = idx.slot & _mask;
1475
913k
        prefetch_heap_block((char*)&_pairs[slot]);
1476
913k
        if (EMH_EQHASH(bucket, key_hash)) {
1477
573k
            if (EMH_LIKELY(_eq(key, _pairs[slot].first)))
1478
573k
                return slot;
1479
573k
        }
1480
340k
        if (next_bucket == bucket)
1481
151k
            return _num_filled;
1482
1483
242k
        while (true) {
1484
242k
            if (EMH_EQHASH(next_bucket, key_hash)) {
1485
136k
                const auto eslot = _index[next_bucket].slot & _mask;
1486
136k
                if (EMH_LIKELY(_eq(key, _pairs[eslot].first)))
1487
135k
                    return eslot;
1488
136k
            }
1489
1490
106k
            const auto nbucket = _index[next_bucket].next;
1491
106k
            if (nbucket == next_bucket)
1492
52.8k
                return _num_filled;
1493
53.8k
            next_bucket = nbucket;
1494
53.8k
        }
1495
1496
0
        return _num_filled;
1497
188k
    }
Unexecuted instantiation: unsigned int emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::find_filled_slot<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) const
1498
1499
#if EMH_SORT
1500
    size_type find_hash_bucket(const KeyT& key) const noexcept
1501
    {
1502
        const auto key_hash = hash_key(key);
1503
        const auto bucket = size_type(key_hash & _mask);
1504
        const auto next_bucket = _index[bucket].next;
1505
        if ((int)next_bucket < 0)
1506
            return END;
1507
1508
        auto slot = _index[bucket].slot & _mask;
1509
        if (_eq(key, _pairs[slot++].first))
1510
            return slot;
1511
        else if (next_bucket == bucket)
1512
            return END;
1513
1514
        while (true) {
1515
            const auto& okey = _pairs[slot++].first;
1516
            if (_eq(key, okey))
1517
                return slot;
1518
1519
            const auto hasho = hash_key(okey);
1520
            if ((hasho & _mask) != bucket)
1521
                break;
1522
            else if (hasho > key_hash)
1523
                break;
1524
            else if (EMH_UNLIKELY(slot >= _num_filled))
1525
                break;
1526
        }
1527
1528
        return END;
1529
    }
1530
1531
    //only for find/can not insert
1532
    size_type find_sorted_bucket(const KeyT& key) const noexcept
1533
    {
1534
        const auto key_hash = hash_key(key);
1535
        const auto bucket = size_type(key_hash & _mask);
1536
        const auto slots = (int)(_index[bucket].next); //TODO
1537
        if (slots < 0 /**|| key < _pairs[slot].first*/)
1538
            return END;
1539
1540
        const auto slot = _index[bucket].slot & _mask;
1541
        auto ormask = _index[bucket].slot & ~_mask;
1542
        auto hmask  = (size_type)(key_hash) & ~_mask;
1543
        if ((hmask | ormask) != ormask)
1544
            return END;
1545
1546
        if (_eq(key, _pairs[slot].first))
1547
            return slot;
1548
        else if (slots == 1 || key < _pairs[slot].first)
1549
            return END;
1550
1551
#if EMH_SORT
1552
        if (key < _pairs[slot].first || key > _pairs[slots + slot - 1].first)
1553
            return END;
1554
#endif
1555
1556
        for (size_type i = 1; i < slots; ++i) {
1557
            const auto& okey = _pairs[slot + i].first;
1558
            if (_eq(key, okey))
1559
                return slot + i;
1560
            //            else if (okey > key)
1561
            //                return END;
1562
        }
1563
1564
        return END;
1565
    }
1566
#endif
1567
1568
    //kick out bucket and find empty to occupy
1569
    //it will break the original link and relink again.
1570
    //before: main_bucket --> prev_bucket --> bucket --> next_bucket(maybe none exist)
1571
    //after : main_bucket --> prev_bucket   (kickout)    next_bucket <-- new_bucket(bucket)
1572
    //                          \|/                                         ^
1573
    //                          -|------------------------------------------|
1574
    size_type kickout_bucket(const size_type kmain, const size_type bucket) noexcept
1575
65.8k
    {
1576
65.8k
        const auto next_bucket = _index[bucket].next;
1577
65.8k
        const auto new_bucket  = find_empty_bucket(next_bucket, 2);
1578
65.8k
        const auto prev_bucket = find_prev_bucket(kmain, bucket);
1579
1580
65.8k
        const auto last = next_bucket == bucket ? new_bucket : next_bucket;
1581
65.8k
        _index[new_bucket] = {last, _index[bucket].slot};
1582
1583
65.8k
        _index[prev_bucket].next = new_bucket;
1584
65.8k
        _index[bucket].next = INACTIVE;
1585
1586
65.8k
        return bucket;
1587
65.8k
    }
emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::kickout_bucket(unsigned int, unsigned int)
Line
Count
Source
1575
65.8k
    {
1576
65.8k
        const auto next_bucket = _index[bucket].next;
1577
65.8k
        const auto new_bucket  = find_empty_bucket(next_bucket, 2);
1578
65.8k
        const auto prev_bucket = find_prev_bucket(kmain, bucket);
1579
1580
65.8k
        const auto last = next_bucket == bucket ? new_bucket : next_bucket;
1581
65.8k
        _index[new_bucket] = {last, _index[bucket].slot};
1582
1583
65.8k
        _index[prev_bucket].next = new_bucket;
1584
65.8k
        _index[bucket].next = INACTIVE;
1585
1586
65.8k
        return bucket;
1587
65.8k
    }
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::kickout_bucket(unsigned int, unsigned int)
1588
1589
    /*
1590
     ** inserts a new key into a hash table; first, check whether key's main
1591
     ** bucket/position is free. If not, check whether colliding node/bucket is in its main
1592
     ** position or not: if it is not, move colliding bucket to an empty place and
1593
     ** put new key in its main position; otherwise (colliding bucket is in its main
1594
     ** position), new key goes to an empty position.
1595
     */
1596
    template<typename K=KeyT>
1597
    size_type find_or_allocate(const K& key, uint64_t key_hash) noexcept
1598
347k
    {
1599
347k
        const auto bucket = size_type(key_hash & _mask);
1600
347k
        const auto& idx = _index[bucket];
1601
347k
        auto next_bucket = idx.next;
1602
347k
        prefetch_heap_block((char*)&_pairs[bucket]);
1603
347k
        if ((int)next_bucket < 0) {
1604
#if EMH_HIGH_LOAD
1605
            if (next_bucket != INACTIVE)
1606
                pop_empty(bucket);
1607
#endif
1608
143k
            return bucket;
1609
143k
        }
1610
1611
203k
        const auto slot = idx.slot & _mask;
1612
203k
        if (EMH_EQHASH(bucket, key_hash))
1613
12
            if (EMH_LIKELY(_eq(key, _pairs[slot].first)))
1614
0
                return bucket;
1615
1616
        //check current bucket_key is in main bucket or not
1617
203k
        const auto kmain = hash_bucket(_pairs[slot].first);
1618
203k
        if (kmain != bucket)
1619
51.2k
            return kickout_bucket(kmain, bucket);
1620
152k
        else if (next_bucket == bucket)
1621
110k
            return _index[next_bucket].next = find_empty_bucket(next_bucket, 1);
1622
1623
42.1k
        uint32_t csize = 1;
1624
        //find next linked bucket and check key
1625
53.3k
        while (true) {
1626
53.3k
            const auto eslot = _index[next_bucket].slot & _mask;
1627
53.3k
            if (EMH_EQHASH(next_bucket, key_hash)) {
1628
12
                if (EMH_LIKELY(_eq(key, _pairs[eslot].first)))
1629
0
                    return next_bucket;
1630
12
            }
1631
1632
53.3k
            csize += 1;
1633
53.3k
            const auto nbucket = _index[next_bucket].next;
1634
53.3k
            if (nbucket == next_bucket)
1635
42.1k
                break;
1636
11.2k
            next_bucket = nbucket;
1637
11.2k
        }
1638
1639
        //find a empty and link it to tail
1640
42.1k
        const auto new_bucket = find_empty_bucket(next_bucket, csize);
1641
42.1k
        prefetch_heap_block((char*)&_pairs[new_bucket]);
1642
42.1k
        return _index[next_bucket].next = new_bucket;
1643
42.1k
    }
unsigned int emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::find_or_allocate<StringPiece>(StringPiece const&, unsigned long)
Line
Count
Source
1598
347k
    {
1599
347k
        const auto bucket = size_type(key_hash & _mask);
1600
347k
        const auto& idx = _index[bucket];
1601
347k
        auto next_bucket = idx.next;
1602
347k
        prefetch_heap_block((char*)&_pairs[bucket]);
1603
347k
        if ((int)next_bucket < 0) {
1604
#if EMH_HIGH_LOAD
1605
            if (next_bucket != INACTIVE)
1606
                pop_empty(bucket);
1607
#endif
1608
143k
            return bucket;
1609
143k
        }
1610
1611
203k
        const auto slot = idx.slot & _mask;
1612
203k
        if (EMH_EQHASH(bucket, key_hash))
1613
12
            if (EMH_LIKELY(_eq(key, _pairs[slot].first)))
1614
0
                return bucket;
1615
1616
        //check current bucket_key is in main bucket or not
1617
203k
        const auto kmain = hash_bucket(_pairs[slot].first);
1618
203k
        if (kmain != bucket)
1619
51.2k
            return kickout_bucket(kmain, bucket);
1620
152k
        else if (next_bucket == bucket)
1621
110k
            return _index[next_bucket].next = find_empty_bucket(next_bucket, 1);
1622
1623
42.1k
        uint32_t csize = 1;
1624
        //find next linked bucket and check key
1625
53.3k
        while (true) {
1626
53.3k
            const auto eslot = _index[next_bucket].slot & _mask;
1627
53.3k
            if (EMH_EQHASH(next_bucket, key_hash)) {
1628
12
                if (EMH_LIKELY(_eq(key, _pairs[eslot].first)))
1629
0
                    return next_bucket;
1630
12
            }
1631
1632
53.3k
            csize += 1;
1633
53.3k
            const auto nbucket = _index[next_bucket].next;
1634
53.3k
            if (nbucket == next_bucket)
1635
42.1k
                break;
1636
11.2k
            next_bucket = nbucket;
1637
11.2k
        }
1638
1639
        //find a empty and link it to tail
1640
42.1k
        const auto new_bucket = find_empty_bucket(next_bucket, csize);
1641
42.1k
        prefetch_heap_block((char*)&_pairs[new_bucket]);
1642
42.1k
        return _index[next_bucket].next = new_bucket;
1643
42.1k
    }
Unexecuted instantiation: unsigned int emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::find_or_allocate<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, unsigned long)
1644
1645
    size_type find_unique_bucket(uint64_t key_hash) noexcept
1646
523k
    {
1647
523k
        const auto bucket = size_type(key_hash & _mask);
1648
523k
        auto next_bucket = _index[bucket].next;
1649
523k
        if ((int)next_bucket < 0) {
1650
#if EMH_HIGH_LOAD
1651
            if (next_bucket != INACTIVE)
1652
                pop_empty(bucket);
1653
#endif
1654
414k
            return bucket;
1655
414k
        }
1656
1657
        //check current bucket_key is in main bucket or not
1658
109k
        const auto kmain = hash_main(bucket);
1659
109k
        if (EMH_UNLIKELY(kmain != bucket))
1660
14.6k
            return kickout_bucket(kmain, bucket);
1661
95.1k
        else if (EMH_UNLIKELY(next_bucket != bucket))
1662
13.0k
            next_bucket = find_last_bucket(next_bucket);
1663
1664
95.1k
        return _index[next_bucket].next = find_empty_bucket(next_bucket, 2);
1665
109k
    }
emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::find_unique_bucket(unsigned long)
Line
Count
Source
1646
523k
    {
1647
523k
        const auto bucket = size_type(key_hash & _mask);
1648
523k
        auto next_bucket = _index[bucket].next;
1649
523k
        if ((int)next_bucket < 0) {
1650
#if EMH_HIGH_LOAD
1651
            if (next_bucket != INACTIVE)
1652
                pop_empty(bucket);
1653
#endif
1654
414k
            return bucket;
1655
414k
        }
1656
1657
        //check current bucket_key is in main bucket or not
1658
109k
        const auto kmain = hash_main(bucket);
1659
109k
        if (EMH_UNLIKELY(kmain != bucket))
1660
14.6k
            return kickout_bucket(kmain, bucket);
1661
95.1k
        else if (EMH_UNLIKELY(next_bucket != bucket))
1662
13.0k
            next_bucket = find_last_bucket(next_bucket);
1663
1664
95.1k
        return _index[next_bucket].next = find_empty_bucket(next_bucket, 2);
1665
109k
    }
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::find_unique_bucket(unsigned long)
1666
1667
/***
1668
    Different probing techniques usually provide a trade-off between memory locality and avoidance of clustering.
1669
    Since Robin Hood hashing is relatively resilient to clustering (both primary and secondary), linear probing is the most cache friendly alternativeis typically used.
1670
1671
    It's the core algorithm of this hash map with highly optimization/benchmark.
1672
    normally linear probing is inefficient with high load factor, it use a new 3-way linear
1673
    probing strategy to search empty slot. from benchmark even the load factor > 0.9, it's more 2-3 timer fast than
1674
    one-way search strategy.
1675
1676
    1. linear or quadratic probing a few cache line for less cache miss from input slot "bucket_from".
1677
    2. the first  search slot from member variant "_last", init with 0 with linear probe
1678
    3. the second search slot from calculated pos "(_num_filled + _last) & _mask", it's like a rand value
1679
****/
1680
    // key is not in this slot. Find a place to put it.
1681
    size_type find_empty_bucket(const size_type bucket_from, uint32_t csize) noexcept
1682
313k
    {
1683
#if EMH_HIGH_LOAD
1684
        if (_ehead)
1685
            return pop_empty(_ehead);
1686
#endif
1687
1688
313k
        auto bucket = bucket_from;
1689
313k
        if (EMH_EMPTY(++bucket & _mask) || EMH_EMPTY(++bucket & _mask))
1690
211k
            return bucket & _mask;
1691
1692
#ifdef EMH_QUADRATIC
1693
        constexpr size_type linear_probe_length = 2 + 2 * EMH_CACHE_LINE_SIZE / sizeof(Index);
1694
        for (size_type offset = csize + 2, step = 4; offset <= linear_probe_length; ) {
1695
            bucket = (bucket_from + offset) & _mask;
1696
            if (EMH_EMPTY(bucket) || EMH_EMPTY(++bucket))
1697
                return bucket;
1698
            offset += step; //7/8. 12. 16
1699
        }
1700
#else
1701
101k
        constexpr size_type quadratic_probe_length = 6u;
1702
235k
        for (size_type offset = 1 + csize, step = 3u; step < quadratic_probe_length; ) {
1703
208k
            bucket = (bucket_from + offset) & _mask;
1704
208k
            if (EMH_EMPTY(bucket) || EMH_EMPTY(++bucket))
1705
75.3k
                return bucket;
1706
133k
            offset += step++;
1707
133k
        }
1708
26.6k
#endif
1709
1710
26.6k
        prefetch_heap_block((char*)&_index[_last]);
1711
1712
58.2k
        for (;;) {
1713
#if EMH_PACK_TAIL
1714
            //find empty bucket and skip next
1715
            if (EMH_EMPTY(_last++))// || EMH_EMPTY(_last++))
1716
                return _last++ - 1;
1717
1718
            if (EMH_UNLIKELY(_last >= _num_buckets))
1719
                _last = 0;
1720
1721
            auto medium = (_mask / 4 + _last++) & _mask;
1722
            if (EMH_EMPTY(medium))
1723
                return medium;
1724
#else
1725
58.2k
            _last &= _mask;
1726
58.2k
            if (EMH_EMPTY(++_last))// || EMH_EMPTY(++_last))
1727
14.0k
                return _last;
1728
1729
44.1k
            auto medium = (_num_buckets / 2 + _last) & _mask;
1730
44.1k
            if (EMH_EMPTY(medium))// || EMH_EMPTY(++medium))
1731
12.6k
                return medium;
1732
44.1k
#endif
1733
44.1k
        }
1734
1735
26.6k
    }
emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::find_empty_bucket(unsigned int, unsigned int)
Line
Count
Source
1682
313k
    {
1683
#if EMH_HIGH_LOAD
1684
        if (_ehead)
1685
            return pop_empty(_ehead);
1686
#endif
1687
1688
313k
        auto bucket = bucket_from;
1689
313k
        if (EMH_EMPTY(++bucket & _mask) || EMH_EMPTY(++bucket & _mask))
1690
211k
            return bucket & _mask;
1691
1692
#ifdef EMH_QUADRATIC
1693
        constexpr size_type linear_probe_length = 2 + 2 * EMH_CACHE_LINE_SIZE / sizeof(Index);
1694
        for (size_type offset = csize + 2, step = 4; offset <= linear_probe_length; ) {
1695
            bucket = (bucket_from + offset) & _mask;
1696
            if (EMH_EMPTY(bucket) || EMH_EMPTY(++bucket))
1697
                return bucket;
1698
            offset += step; //7/8. 12. 16
1699
        }
1700
#else
1701
101k
        constexpr size_type quadratic_probe_length = 6u;
1702
235k
        for (size_type offset = 1 + csize, step = 3u; step < quadratic_probe_length; ) {
1703
208k
            bucket = (bucket_from + offset) & _mask;
1704
208k
            if (EMH_EMPTY(bucket) || EMH_EMPTY(++bucket))
1705
75.3k
                return bucket;
1706
133k
            offset += step++;
1707
133k
        }
1708
26.6k
#endif
1709
1710
26.6k
        prefetch_heap_block((char*)&_index[_last]);
1711
1712
58.2k
        for (;;) {
1713
#if EMH_PACK_TAIL
1714
            //find empty bucket and skip next
1715
            if (EMH_EMPTY(_last++))// || EMH_EMPTY(_last++))
1716
                return _last++ - 1;
1717
1718
            if (EMH_UNLIKELY(_last >= _num_buckets))
1719
                _last = 0;
1720
1721
            auto medium = (_mask / 4 + _last++) & _mask;
1722
            if (EMH_EMPTY(medium))
1723
                return medium;
1724
#else
1725
58.2k
            _last &= _mask;
1726
58.2k
            if (EMH_EMPTY(++_last))// || EMH_EMPTY(++_last))
1727
14.0k
                return _last;
1728
1729
44.1k
            auto medium = (_num_buckets / 2 + _last) & _mask;
1730
44.1k
            if (EMH_EMPTY(medium))// || EMH_EMPTY(++medium))
1731
12.6k
                return medium;
1732
44.1k
#endif
1733
44.1k
        }
1734
1735
26.6k
    }
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::find_empty_bucket(unsigned int, unsigned int)
1736
1737
    size_type find_last_bucket(size_type main_bucket) const
1738
13.0k
    {
1739
13.0k
        auto next_bucket = _index[main_bucket].next;
1740
13.0k
        if (next_bucket == main_bucket)
1741
11.2k
            return main_bucket;
1742
1743
2.29k
        while (true) {
1744
2.29k
            const auto nbucket = _index[next_bucket].next;
1745
2.29k
            if (nbucket == next_bucket)
1746
1.76k
                return next_bucket;
1747
531
            next_bucket = nbucket;
1748
531
        }
1749
1.76k
    }
emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::find_last_bucket(unsigned int) const
Line
Count
Source
1738
13.0k
    {
1739
13.0k
        auto next_bucket = _index[main_bucket].next;
1740
13.0k
        if (next_bucket == main_bucket)
1741
11.2k
            return main_bucket;
1742
1743
2.29k
        while (true) {
1744
2.29k
            const auto nbucket = _index[next_bucket].next;
1745
2.29k
            if (nbucket == next_bucket)
1746
1.76k
                return next_bucket;
1747
531
            next_bucket = nbucket;
1748
531
        }
1749
1.76k
    }
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::find_last_bucket(unsigned int) const
1750
1751
    size_type find_prev_bucket(const size_type main_bucket, const size_type bucket) const
1752
65.8k
    {
1753
65.8k
        auto next_bucket = _index[main_bucket].next;
1754
65.8k
        if (next_bucket == bucket)
1755
54.1k
            return main_bucket;
1756
1757
14.3k
        while (true) {
1758
14.3k
            const auto nbucket = _index[next_bucket].next;
1759
14.3k
            if (nbucket == bucket)
1760
11.7k
                return next_bucket;
1761
2.62k
            next_bucket = nbucket;
1762
2.62k
        }
1763
11.7k
    }
emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::find_prev_bucket(unsigned int, unsigned int) const
Line
Count
Source
1752
65.8k
    {
1753
65.8k
        auto next_bucket = _index[main_bucket].next;
1754
65.8k
        if (next_bucket == bucket)
1755
54.1k
            return main_bucket;
1756
1757
14.3k
        while (true) {
1758
14.3k
            const auto nbucket = _index[next_bucket].next;
1759
14.3k
            if (nbucket == bucket)
1760
11.7k
                return next_bucket;
1761
2.62k
            next_bucket = nbucket;
1762
2.62k
        }
1763
11.7k
    }
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::find_prev_bucket(unsigned int, unsigned int) const
1764
1765
    size_type hash_bucket(const KeyT& key) const noexcept
1766
203k
    {
1767
203k
        return (size_type)hash_key(key) & _mask;
1768
203k
    }
emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::hash_bucket(StringPiece const&) const
Line
Count
Source
1766
203k
    {
1767
203k
        return (size_type)hash_key(key) & _mask;
1768
203k
    }
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::hash_bucket(StringPiece const&) const
1769
1770
    size_type hash_main(const size_type bucket) const noexcept
1771
109k
    {
1772
109k
        const auto slot = _index[bucket].slot & _mask;
1773
109k
        return (size_type)hash_key(_pairs[slot].first) & _mask;
1774
109k
    }
emhash8::HashMap<StringPiece, Node*, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, Node*> >, emhash8::DefaultPolicy>::hash_main(unsigned int) const
Line
Count
Source
1771
109k
    {
1772
109k
        const auto slot = _index[bucket].slot & _mask;
1773
109k
        return (size_type)hash_key(_pairs[slot].first) & _mask;
1774
109k
    }
Unexecuted instantiation: emhash8::HashMap<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> >, std::__1::hash<StringPiece>, std::__1::equal_to<StringPiece>, std::__1::allocator<std::__1::pair<StringPiece, std::__1::unique_ptr<BuildLog::LogEntry, std::__1::default_delete<BuildLog::LogEntry> > > >, emhash8::DefaultPolicy>::hash_main(unsigned int) const
1775
1776
#if EMH_INT_HASH
1777
    static constexpr uint64_t KC = UINT64_C(11400714819323198485);
1778
    static uint64_t hash64(uint64_t key)
1779
    {
1780
#if __SIZEOF_INT128__ && EMH_INT_HASH == 1
1781
        __uint128_t r = key; r *= KC;
1782
        return (uint64_t)(r >> 64) + (uint64_t)r;
1783
#elif EMH_INT_HASH == 2
1784
        //MurmurHash3Mixer
1785
        uint64_t h = key;
1786
        h ^= h >> 33;
1787
        h *= 0xff51afd7ed558ccd;
1788
        h ^= h >> 33;
1789
        h *= 0xc4ceb9fe1a85ec53;
1790
        h ^= h >> 33;
1791
        return h;
1792
#elif _WIN64 && EMH_INT_HASH == 1
1793
        uint64_t high;
1794
        return _umul128(key, KC, &high) + high;
1795
#elif EMH_INT_HASH == 3
1796
        auto ror  = (key >> 32) | (key << 32);
1797
        auto low  = key * 0xA24BAED4963EE407ull;
1798
        auto high = ror * 0x9FB21C651E98DF25ull;
1799
        auto mix  = low + high;
1800
        return mix;
1801
#elif EMH_INT_HASH == 1
1802
        uint64_t r = key * UINT64_C(0xca4bcaa75ec3f625);
1803
        return (r >> 32) + r;
1804
#elif EMH_WYHASH64
1805
        return wyhash64(key, KC);
1806
#else
1807
        uint64_t x = key;
1808
        x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9);
1809
        x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb);
1810
        x = x ^ (x >> 31);
1811
        return x;
1812
#endif
1813
    }
1814
#endif
1815
1816
#if EMH_WYHASH_HASH
1817
    //#define WYHASH_CONDOM 1
1818
    static uint64_t wymix(uint64_t A, uint64_t B)
1819
    {
1820
#if defined(__SIZEOF_INT128__)
1821
        __uint128_t r = A; r *= B;
1822
#if WYHASH_CONDOM2
1823
        A ^= (uint64_t)r; B ^= (uint64_t)(r >> 64);
1824
#else
1825
        A = (uint64_t)r; B = (uint64_t)(r >> 64);
1826
#endif
1827
1828
#elif defined(_MSC_VER) && defined(_M_X64)
1829
#if WYHASH_CONDOM2
1830
        uint64_t a, b;
1831
        a = _umul128(A, B, &b);
1832
        A ^= a; B ^= b;
1833
#else
1834
        A = _umul128(A, B, &B);
1835
#endif
1836
#else
1837
        uint64_t ha = A >> 32, hb = B >> 32, la = (uint32_t)A, lb = (uint32_t)B, hi, lo;
1838
        uint64_t rh = ha * hb, rm0 = ha * lb, rm1 = hb * la, rl = la * lb, t = rl + (rm0 << 32), c = t < rl;
1839
        lo = t + (rm1 << 32); c += lo < t; hi = rh + (rm0 >> 32) + (rm1 >> 32) + c;
1840
#if WYHASH_CONDOM2
1841
        A ^= lo; B ^= hi;
1842
#else
1843
        A = lo; B = hi;
1844
#endif
1845
#endif
1846
        return A ^ B;
1847
    }
1848
1849
    //multiply and xor mix function, aka MUM
1850
    static inline uint64_t wyr8(const uint8_t *p) { uint64_t v; memcpy(&v, p, 8); return v; }
1851
    static inline uint64_t wyr4(const uint8_t *p) { uint32_t v; memcpy(&v, p, 4); return v; }
1852
    static inline uint64_t wyr3(const uint8_t *p, size_t k) {
1853
        return (((uint64_t)p[0]) << 16) | (((uint64_t)p[k >> 1]) << 8) | p[k - 1];
1854
    }
1855
1856
    inline static const uint64_t secret[4] = {
1857
        0x2d358dccaa6c78a5ull, 0x8bb84b93962eacc9ull,
1858
        0x4b33a62ed433d4a3ull, 0x4d5a2da51de1aa47ull};
1859
public:
1860
    //wyhash main function https://github.com/wangyi-fudan/wyhash
1861
    static uint64_t wyhashstr(const char *key, const size_t len)
1862
    {
1863
        uint64_t a = 0, b = 0, seed = secret[0];
1864
        const uint8_t *p = (const uint8_t*)key;
1865
        if (EMH_LIKELY(len <= 16)) {
1866
            if (EMH_LIKELY(len >= 4)) {
1867
                const auto half = (len >> 3) << 2;
1868
                a = (wyr4(p) << 32U) | wyr4(p + half); p += len - 4;
1869
                b = (wyr4(p) << 32U) | wyr4(p - half);
1870
            } else if (len) {
1871
                a = wyr3(p, len);
1872
            }
1873
        } else {
1874
            size_t i = len;
1875
            if (EMH_UNLIKELY(i > 48)) {
1876
                uint64_t see1 = seed, see2 = seed;
1877
                do {
1878
                    seed = wymix(wyr8(p +  0) ^ secret[1], wyr8(p +  8) ^ seed);
1879
                    see1 = wymix(wyr8(p + 16) ^ secret[2], wyr8(p + 24) ^ see1);
1880
                    see2 = wymix(wyr8(p + 32) ^ secret[3], wyr8(p + 40) ^ see2);
1881
                    p += 48; i -= 48;
1882
                } while (EMH_LIKELY(i > 48));
1883
                seed ^= see1 ^ see2;
1884
            }
1885
            while (i > 16) {
1886
                seed = wymix(wyr8(p) ^ secret[1], wyr8(p + 8) ^ seed);
1887
                i -= 16; p += 16;
1888
            }
1889
            a = wyr8(p + i - 16);
1890
            b = wyr8(p + i - 8);
1891
        }
1892
1893
        return wymix(secret[1] ^ len, wymix(a ^ secret[1], b ^ seed));
1894
    }
1895
#endif
1896
1897
private:
1898
    template<typename UType, typename std::enable_if<std::is_integral<UType>::value, uint32_t>::type = 0>
1899
        inline uint64_t hash_key(const UType key) const
1900
        {
1901
#if EMH_INT_HASH
1902
            return hash64(key);
1903
#else
1904
            return _hasher(key);
1905
#endif
1906
        }
1907
1908
    template<typename UType, typename std::enable_if<std::is_same<UType, std::string>::value, uint32_t>::type = 0>
1909
        inline uint64_t hash_key(const UType& key) const
1910
0
        {
1911
#if EMH_WYHASH_HASH
1912
            return wyhashstr(key.data(), key.size());
1913
#else
1914
0
            return _hasher(key);
1915
0
#endif
1916
0
        }
1917
1918
    template<typename UType, typename std::enable_if<!std::is_integral<UType>::value && !std::is_same<UType, std::string>::value, uint32_t>::type = 0>
1919
        inline uint64_t hash_key(const UType& key) const
1920
2.24M
        {
1921
2.24M
            return _hasher(key);
1922
2.24M
        }
_ZNK7emhash87HashMapI11StringPieceP4NodeNSt3__14hashIS1_EENS4_8equal_toIS1_EENS4_9allocatorINS4_4pairIS1_S3_EEEENS_13DefaultPolicyEE8hash_keyIS1_TnNS4_9enable_ifIXaantsr3std11is_integralIT_EE5valuentsr3std7is_sameISH_NS4_12basic_stringIcNS4_11char_traitsIcEENS9_IcEEEEEE5valueEjE4typeELj0EEEmRKSH_
Line
Count
Source
1920
2.24M
        {
1921
2.24M
            return _hasher(key);
1922
2.24M
        }
Unexecuted instantiation: _ZNK7emhash87HashMapI11StringPieceNSt3__110unique_ptrIN8BuildLog8LogEntryENS2_14default_deleteIS5_EEEENS2_4hashIS1_EENS2_8equal_toIS1_EENS2_9allocatorINS2_4pairIS1_S8_EEEENS_13DefaultPolicyEE8hash_keyIS1_TnNS2_9enable_ifIXaantsr3std11is_integralIT_EE5valuentsr3std7is_sameISL_NS2_12basic_stringIcNS2_11char_traitsIcEENSD_IcEEEEEE5valueEjE4typeELj0EEEmRKSL_
1923
1924
private:
1925
    using PairAlloc = typename std::allocator_traits<AllocT>::template rebind_alloc<value_type>;
1926
    using PairAllocTraits = std::allocator_traits<PairAlloc>;
1927
    using IndexAlloc = typename std::allocator_traits<AllocT>::template rebind_alloc<Index>;
1928
    using IndexAllocTraits = std::allocator_traits<IndexAlloc>;
1929
1930
    Index*    _index;
1931
    value_type*_pairs;
1932
1933
    HashT     _hasher;
1934
    EqT       _eq;
1935
    uint32_t  _mlf;
1936
    size_type _mask;
1937
    size_type _num_buckets;
1938
    size_type _num_filled;
1939
    size_type _last;
1940
#if EMH_HIGH_LOAD
1941
    size_type _ehead;
1942
#endif
1943
    size_type _etail;
1944
    size_type _pairs_capacity;
1945
    PairAlloc _pair_allocator;
1946
    IndexAlloc _index_allocator;
1947
};
1948
} // namespace emhash
1949