Coverage Report

Created: 2025-08-29 06:44

/src/s2geometry/src/s2/util/gtl/hashtable_common.h
Line
Count
Source (jump to first uncovered line)
1
// Copyright 2010 Google Inc. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS-IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
//
15
16
// All rights reserved.
17
//
18
// Redistribution and use in source and binary forms, with or without
19
// modification, are permitted provided that the following conditions are
20
// met:
21
//
22
//     * Redistributions of source code must retain the above copyright
23
// notice, this list of conditions and the following disclaimer.
24
//     * Redistributions in binary form must reproduce the above
25
// copyright notice, this list of conditions and the following disclaimer
26
// in the documentation and/or other materials provided with the
27
// distribution.
28
//     * Neither the name of Google Inc. nor the names of its
29
// contributors may be used to endorse or promote products derived from
30
// this software without specific prior written permission.
31
//
32
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
35
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
36
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
37
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
38
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
39
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
40
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
41
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
42
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43
44
// ---
45
46
#ifndef S2_UTIL_GTL_HASHTABLE_COMMON_H_
47
#define S2_UTIL_GTL_HASHTABLE_COMMON_H_
48
49
#include <cassert>
50
#include <cstddef>
51
52
#include <algorithm>
53
54
#include <stdexcept>                 // For length_error
55
56
// Settings contains parameters for growing and shrinking the table.
57
// It also packages zero-size functor (ie. hasher).  One invariant
58
// enforced in enlarge_size() is that we never allow all slots
59
// occupied.  (This is unlikely to matter to users, because using
60
// a load near 1 is slow and not recommended.  It allows other code
61
// to assume there is at least one empty bucket.)
62
//
63
// It does some munging of the hash value in cases where we think
64
// (fear) the original hash function might not be very good.  In
65
// particular, the default hash of pointers is the identity hash,
66
// so probably all the low bits are 0.  We identify when we think
67
// we're hashing a pointer, and chop off the low bits.  Note this
68
// isn't perfect: even when the key is a pointer, we can't tell
69
// for sure that the hash is the identity hash.  If it's not, this
70
// is needless work (and possibly, though not likely, harmful).
71
72
template <typename Key, typename HashFunc, typename SizeType,
73
          int HT_MIN_BUCKETS>
74
class sh_hashtable_settings : public HashFunc {
75
 public:
76
  typedef Key key_type;
77
  typedef HashFunc hasher;
78
  typedef SizeType size_type;
79
80
 public:
81
  sh_hashtable_settings(const hasher& hf, const float ht_occupancy_flt,
82
                        const float ht_empty_flt)
83
0
      : hasher(hf),
84
0
        enlarge_threshold_(0),
85
0
        shrink_threshold_(0),
86
0
        consider_shrink_(false),
87
0
        use_empty_(false),
88
0
        use_deleted_(false),
89
0
        num_ht_copies_(0) {
90
0
    set_enlarge_factor(ht_occupancy_flt);
91
0
    set_shrink_factor(ht_empty_flt);
92
0
  }
93
94
  template <class K>
95
0
  size_type hash(const K& v) const {
96
    // We munge the hash value when we don't trust hasher::operator().  It is
97
    // very important that we use hash_munger<Key> instead of hash_munger<K>.
98
    // Within a given hashtable, all hash values must be munged in the same way.
99
0
    return hash_munger<Key>::MungedHash(hasher::operator()(v));
100
0
  }
101
102
0
  float enlarge_factor() const { return enlarge_factor_; }
103
0
  void set_enlarge_factor(float f) { enlarge_factor_ = f; }
104
0
  float shrink_factor() const { return shrink_factor_; }
105
0
  void set_shrink_factor(float f) { shrink_factor_ = f; }
106
107
0
  size_type enlarge_threshold() const { return enlarge_threshold_; }
108
0
  void set_enlarge_threshold(size_type t) { enlarge_threshold_ = t; }
109
0
  size_type shrink_threshold() const { return shrink_threshold_; }
110
0
  void set_shrink_threshold(size_type t) { shrink_threshold_ = t; }
111
112
0
  size_type enlarge_size(size_type x) const {
113
0
    return std::min<size_type>(x - 1, x * enlarge_factor_);
114
0
  }
115
0
  size_type shrink_size(size_type x) const {
116
0
    return static_cast<size_type>(x * shrink_factor_);
117
0
  }
118
119
0
  bool consider_shrink() const { return consider_shrink_; }
120
0
  void set_consider_shrink(bool t) { consider_shrink_ = t; }
121
122
0
  bool use_empty() const { return use_empty_; }
123
0
  void set_use_empty(bool t) { use_empty_ = t; }
124
125
0
  bool use_deleted() const { return use_deleted_; }
126
0
  void set_use_deleted(bool t) { use_deleted_ = t; }
127
128
  size_type num_ht_copies() const {
129
    return static_cast<size_type>(num_ht_copies_);
130
  }
131
0
  void inc_num_ht_copies() { ++num_ht_copies_; }
132
133
  // Reset the enlarge and shrink thresholds
134
0
  void reset_thresholds(size_type num_buckets) {
135
0
    set_enlarge_threshold(enlarge_size(num_buckets));
136
0
    set_shrink_threshold(shrink_size(num_buckets));
137
    // whatever caused us to reset already considered
138
0
    set_consider_shrink(false);
139
0
  }
140
141
  // Caller is responsible for calling reset_threshold right after
142
  // set_resizing_parameters.
143
  void set_resizing_parameters(float shrink, float grow) {
144
    assert(shrink >= 0.0);
145
    assert(grow <= 1.0);
146
    if (shrink > grow / 2.0f)
147
      shrink = grow / 2.0f;  // otherwise we thrash hashtable size
148
    set_shrink_factor(shrink);
149
    set_enlarge_factor(grow);
150
  }
151
152
  // This is the smallest size a hashtable can be without being too crowded.
153
  // If you like, you can give a min #buckets as well as a min #elts.
154
  // This is guaranteed to return a power of two.
155
0
  size_type min_buckets(size_type num_elts, size_type min_buckets_wanted) {
156
0
    float enlarge = enlarge_factor();
157
0
    size_type sz = HT_MIN_BUCKETS;  // min buckets allowed
158
0
    while (sz < min_buckets_wanted ||
159
0
           num_elts >= static_cast<size_type>(sz * enlarge)) {
160
      // This just prevents overflowing size_type, since sz can exceed
161
      // max_size() here.
162
0
      if (static_cast<size_type>(sz * 2) < sz) {
163
0
        throw std::length_error("resize overflow");  // protect against overflow
164
0
      }
165
0
      sz *= 2;
166
0
    }
167
0
    return sz;
168
0
  }
169
170
 private:
171
  template <class HashKey>
172
  class hash_munger {
173
   public:
174
0
    static size_t MungedHash(size_t hash) { return hash; }
175
  };
176
  // This matches when the hashtable key is a pointer.
177
  template <class HashKey>
178
  class hash_munger<HashKey*> {
179
   public:
180
    static size_t MungedHash(size_t hash) {
181
      // TODO(user): consider rotating instead:
182
      //    static const int shift = (sizeof(void *) == 4) ? 2 : 3;
183
      //    return (hash << (sizeof(hash) * 8) - shift)) | (hash >> shift);
184
      // This matters if we ever change sparse/dense_hash_* to compare
185
      // hashes before comparing actual values.  It's speedy on x86.
186
      return hash / sizeof(void*);  // get rid of known-0 bits
187
    }
188
  };
189
190
  size_type enlarge_threshold_;  // table.size() * enlarge_factor
191
  size_type shrink_threshold_;   // table.size() * shrink_factor
192
  float enlarge_factor_;         // how full before resize
193
  float shrink_factor_;          // how empty before resize
194
  // consider_shrink=true if we should try to shrink before next insert
195
  bool consider_shrink_;
196
  bool use_empty_;    // used only by densehashtable, not sparsehashtable
197
  bool use_deleted_;  // false until delkey has been set
198
  // num_ht_copies is a counter incremented every Copy/Move
199
  unsigned int num_ht_copies_;
200
};
201
202
// This traits class checks whether T::is_transparent exists and names a type.
203
//
204
//   struct Foo { using is_transparent = void; };
205
//   struct Bar {};
206
//   static_assert(sh_is_transparent<Foo>::value, "Foo is transparent.");
207
//   staitc_assert(!sh_is_transparent<Bar>::value, "Bar is not transparent.");
208
template <class T>
209
struct sh_is_transparent {
210
 private:
211
  struct No {};
212
  struct Yes {
213
    No x[2];
214
  };
215
216
  template <class U>
217
  static Yes Test(typename U::is_transparent*);
218
  template <class U>
219
  static No Test(...);
220
221
 public:
222
  enum { value = sizeof(Test<T>(nullptr)) == sizeof(Yes) };
223
};
224
225
226
#endif  // S2_UTIL_GTL_HASHTABLE_COMMON_H_