cpp

Coverage Report

Created: 2024-03-13 14:13

/home/andy/git/oilshell/oil/mycpp/gc_dict.h
Line
Count
Source (jump to first uncovered line)
1
// Hash table based on CPython's "compact dict":
2
//
3
//   https://mail.python.org/pipermail/python-dev/2012-December/123028.html
4
//   https://code.activestate.com/recipes/578375/
5
//
6
// Main differences:
7
// - It's type-specialized in C++ -- Dict<K, V>.
8
// - It's integrated with our mark and sweep GC, using Slab<int>, Slab<K>, and
9
//   Slab<V>
10
// - We use linear probing, not the pseudo-random number generator
11
12
#ifndef MYCPP_GC_DICT_H
13
#define MYCPP_GC_DICT_H
14
15
#include "mycpp/comparators.h"
16
#include "mycpp/gc_builtins.h"
17
#include "mycpp/gc_list.h"
18
#include "mycpp/hash.h"
19
20
// Non-negative entries in index_ are array indices into keys_ and values_.
21
// There are two special negative entries:
22
23
// index_ value to say this Dict item was deleted (a tombstone).
24
const int kDeletedEntry = -1;
25
26
// index_ value to say this Dict entry is free.
27
const int kEmptyEntry = -2;
28
29
// Return value for find_kv_index(), not stored in index_.
30
const int kNotFound = -3;
31
32
// Return value for hash_and_probe(), not stored in index_.
33
const int kTooSmall = -4;
34
35
// Helper for keys() and values()
36
template <typename T>
37
18
List<T>* ListFromDictSlab(Slab<T>* slab, int n) {
38
18
  List<T>* result = Alloc<List<T>>();
39
18
  result->reserve(n);
40
41
102
  for (int i = 0; i < n; ++i) {
42
84
    result->append(slab->items_[i]);
43
84
  }
44
18
  return result;
45
18
}
_Z16ListFromDictSlabIP6BigStrEP4ListIT_EP4SlabIS3_Ei
Line
Count
Source
37
12
List<T>* ListFromDictSlab(Slab<T>* slab, int n) {
38
12
  List<T>* result = Alloc<List<T>>();
39
12
  result->reserve(n);
40
41
38
  for (int i = 0; i < n; ++i) {
42
26
    result->append(slab->items_[i]);
43
26
  }
44
12
  return result;
45
12
}
_Z16ListFromDictSlabIiEP4ListIT_EP4SlabIS1_Ei
Line
Count
Source
37
6
List<T>* ListFromDictSlab(Slab<T>* slab, int n) {
38
6
  List<T>* result = Alloc<List<T>>();
39
6
  result->reserve(n);
40
41
64
  for (int i = 0; i < n; ++i) {
42
58
    result->append(slab->items_[i]);
43
58
  }
44
6
  return result;
45
6
}
46
47
// GlobalDict is layout-compatible with Dict (unit tests assert this), and it
48
// can be a true C global (incurs zero startup time)
49
50
template <typename K, typename V, int N>
51
class GlobalDict {
52
 public:
53
  int len_;
54
  int capacity_;
55
  int index_len_;
56
  GlobalSlab<int, N>* index_;
57
  GlobalSlab<K, N>* keys_;
58
  GlobalSlab<V, N>* values_;
59
};
60
61
#define GLOBAL_DICT(name, K, V, N, keys, vals)                                 \
62
  GcGlobal<GlobalSlab<K, N>> _keys_##name = {ObjHeader::Global(TypeTag::Slab), \
63
                                             {.items_ = keys}};                \
64
  GcGlobal<GlobalSlab<V, N>> _vals_##name = {ObjHeader::Global(TypeTag::Slab), \
65
                                             {.items_ = vals}};                \
66
  GcGlobal<GlobalDict<K, V, N>> _dict_##name = {                               \
67
      ObjHeader::Global(TypeTag::Dict),                                        \
68
      {.len_ = N,                                                              \
69
       .capacity_ = N,                                                         \
70
       .index_len_ = 0,                                                        \
71
       .index_ = nullptr,                                                      \
72
       .keys_ = &_keys_##name.obj,                                             \
73
       .values_ = &_vals_##name.obj},                                          \
74
  };                                                                           \
75
  Dict<K, V>* name = reinterpret_cast<Dict<K, V>*>(&_dict_##name.obj);
76
77
template <class K, class V>
78
class Dict {
79
 public:
80
  Dict()
81
      : len_(0),
82
        capacity_(0),
83
        index_len_(0),
84
        index_(nullptr),
85
        keys_(nullptr),
86
74
        values_(nullptr) {
87
74
  }
_ZN4DictIP6BigStriEC2Ev
Line
Count
Source
86
19
        values_(nullptr) {
87
19
  }
_ZN4DictIibEC2Ev
Line
Count
Source
86
9
        values_(nullptr) {
87
9
  }
_ZN4DictIiiEC2Ev
Line
Count
Source
86
16
        values_(nullptr) {
87
16
  }
_ZN4DictIP6BigStrS1_EC2Ev
Line
Count
Source
86
9
        values_(nullptr) {
87
9
  }
_ZN4DictIiP6BigStrEC2Ev
Line
Count
Source
86
8
        values_(nullptr) {
87
8
  }
_ZN4DictIP6Tuple2IiiEiEC2Ev
Line
Count
Source
86
2
        values_(nullptr) {
87
2
  }
_ZN4DictIP6Tuple2IP6BigStriEiEC2Ev
Line
Count
Source
86
2
        values_(nullptr) {
87
2
  }
Unexecuted instantiation: _ZN4DictIiP6Tuple2IP4ListIPS1_IPS0_IiiEEEPS_IiiEEEC2Ev
_ZN4DictIP6BigStrPN4args7_ActionEEC2Ev
Line
Count
Source
86
6
        values_(nullptr) {
87
6
  }
_ZN4DictIP6BigStrPN10value_asdl7value_tEEC2Ev
Line
Count
Source
86
3
        values_(nullptr) {
87
3
  }
88
89
  Dict(std::initializer_list<K> keys, std::initializer_list<V> values)
90
      : len_(0),
91
        capacity_(0),
92
        index_len_(0),
93
        index_(nullptr),
94
        keys_(nullptr),
95
5
        values_(nullptr) {
96
5
    DCHECK(keys.size() == values.size());
97
0
    auto v = values.begin();  // This simulates a "zip" loop
98
8
    for (auto key : keys) {
99
      // note: calls reserve(), and may allocate
100
8
      this->set(key, *v);
101
8
      ++v;
102
8
    }
103
5
  }
_ZN4DictIP6BigStriEC2ESt16initializer_listIS1_ES3_IiE
Line
Count
Source
95
3
        values_(nullptr) {
96
3
    DCHECK(keys.size() == values.size());
97
0
    auto v = values.begin();  // This simulates a "zip" loop
98
6
    for (auto key : keys) {
99
      // note: calls reserve(), and may allocate
100
6
      this->set(key, *v);
101
6
      ++v;
102
6
    }
103
3
  }
_ZN4DictIiP6BigStrEC2ESt16initializer_listIiES3_IS1_E
Line
Count
Source
95
2
        values_(nullptr) {
96
2
    DCHECK(keys.size() == values.size());
97
0
    auto v = values.begin();  // This simulates a "zip" loop
98
2
    for (auto key : keys) {
99
      // note: calls reserve(), and may allocate
100
2
      this->set(key, *v);
101
2
      ++v;
102
2
    }
103
2
  }
104
105
  // Reserve enough space for at LEAST this many key-value pairs.
106
  void reserve(int num_desired);
107
108
  // d[key] in Python: raises KeyError if not found
109
  V at(K key) const;
110
111
  // d.get(key) in Python. (Can't use this if V isn't a pointer!)
112
  V get(K key) const;
113
114
  // Get a key, but return a default if not found.
115
  // expr_parse.py uses this with OTHER_BALANCE
116
  V get(K key, V default_val) const;
117
118
  // Implements d[k] = v.  May resize the dictionary.
119
  void set(K key, V val);
120
121
  void update(List<Tuple2<K, V>*>* pairs);
122
  void update(Dict<K, V>* other);
123
124
  List<K>* keys() const;
125
126
  List<V>* values() const;
127
128
  void clear();
129
130
  // Helper used by find_kv_index(), set(), mylib::dict_erase() in
131
  // gc_mylib.h
132
  // Returns either:
133
  // - the slot for an existing key, or an empty slot for a new key
134
  // - kTooSmall if the table is full
135
  int hash_and_probe(K key) const;
136
137
  // Helper used by at(), get(), dict_contains()
138
  // Given a key, returns either:
139
  // - an index into keys_ and values_
140
  // - kNotFound
141
  int find_kv_index(K key) const;
142
143
359
  static constexpr ObjHeader obj_header() {
144
359
    return ObjHeader::ClassFixed(field_mask(), sizeof(Dict));
145
359
  }
_ZN4DictIP6BigStriE10obj_headerEv
Line
Count
Source
143
24
  static constexpr ObjHeader obj_header() {
144
24
    return ObjHeader::ClassFixed(field_mask(), sizeof(Dict));
145
24
  }
_ZN4DictIibE10obj_headerEv
Line
Count
Source
143
9
  static constexpr ObjHeader obj_header() {
144
9
    return ObjHeader::ClassFixed(field_mask(), sizeof(Dict));
145
9
  }
_ZN4DictIiiE10obj_headerEv
Line
Count
Source
143
290
  static constexpr ObjHeader obj_header() {
144
290
    return ObjHeader::ClassFixed(field_mask(), sizeof(Dict));
145
290
  }
_ZN4DictIP6BigStrS1_E10obj_headerEv
Line
Count
Source
143
11
  static constexpr ObjHeader obj_header() {
144
11
    return ObjHeader::ClassFixed(field_mask(), sizeof(Dict));
145
11
  }
_ZN4DictIiP6BigStrE10obj_headerEv
Line
Count
Source
143
12
  static constexpr ObjHeader obj_header() {
144
12
    return ObjHeader::ClassFixed(field_mask(), sizeof(Dict));
145
12
  }
_ZN4DictIP6Tuple2IiiEiE10obj_headerEv
Line
Count
Source
143
2
  static constexpr ObjHeader obj_header() {
144
2
    return ObjHeader::ClassFixed(field_mask(), sizeof(Dict));
145
2
  }
_ZN4DictIP6Tuple2IP6BigStriEiE10obj_headerEv
Line
Count
Source
143
2
  static constexpr ObjHeader obj_header() {
144
2
    return ObjHeader::ClassFixed(field_mask(), sizeof(Dict));
145
2
  }
Unexecuted instantiation: _ZN4DictIiP6Tuple2IP4ListIPS1_IPS0_IiiEEEPS_IiiEEE10obj_headerEv
_ZN4DictIP6BigStrPN4args7_ActionEE10obj_headerEv
Line
Count
Source
143
6
  static constexpr ObjHeader obj_header() {
144
6
    return ObjHeader::ClassFixed(field_mask(), sizeof(Dict));
145
6
  }
_ZN4DictIP6BigStrPN10value_asdl7value_tEE10obj_headerEv
Line
Count
Source
143
3
  static constexpr ObjHeader obj_header() {
144
3
    return ObjHeader::ClassFixed(field_mask(), sizeof(Dict));
145
3
  }
146
147
  int len_;        // number of entries (keys and values, almost dense)
148
  int capacity_;   // number of k/v slots
149
  int index_len_;  // number of index slots
150
151
  // These 3 slabs are resized at the same time.
152
  Slab<int>* index_;  // kEmptyEntry, kDeletedEntry, or a valid index into
153
                      // keys_ and values_
154
  Slab<K>* keys_;     // Dict<K, int>
155
  Slab<V>* values_;   // Dict<int, V>
156
157
  // A dict has 3 pointers the GC needs to follow.
158
361
  static constexpr uint32_t field_mask() {
159
361
    return maskbit(offsetof(Dict, index_)) | maskbit(offsetof(Dict, keys_)) |
160
361
           maskbit(offsetof(Dict, values_));
161
361
  }
_ZN4DictIP6BigStriE10field_maskEv
Line
Count
Source
158
24
  static constexpr uint32_t field_mask() {
159
24
    return maskbit(offsetof(Dict, index_)) | maskbit(offsetof(Dict, keys_)) |
160
24
           maskbit(offsetof(Dict, values_));
161
24
  }
_ZN4DictIibE10field_maskEv
Line
Count
Source
158
9
  static constexpr uint32_t field_mask() {
159
9
    return maskbit(offsetof(Dict, index_)) | maskbit(offsetof(Dict, keys_)) |
160
9
           maskbit(offsetof(Dict, values_));
161
9
  }
_ZN4DictIiiE10field_maskEv
Line
Count
Source
158
292
  static constexpr uint32_t field_mask() {
159
292
    return maskbit(offsetof(Dict, index_)) | maskbit(offsetof(Dict, keys_)) |
160
292
           maskbit(offsetof(Dict, values_));
161
292
  }
_ZN4DictIP6BigStrS1_E10field_maskEv
Line
Count
Source
158
11
  static constexpr uint32_t field_mask() {
159
11
    return maskbit(offsetof(Dict, index_)) | maskbit(offsetof(Dict, keys_)) |
160
11
           maskbit(offsetof(Dict, values_));
161
11
  }
_ZN4DictIiP6BigStrE10field_maskEv
Line
Count
Source
158
12
  static constexpr uint32_t field_mask() {
159
12
    return maskbit(offsetof(Dict, index_)) | maskbit(offsetof(Dict, keys_)) |
160
12
           maskbit(offsetof(Dict, values_));
161
12
  }
_ZN4DictIP6Tuple2IiiEiE10field_maskEv
Line
Count
Source
158
2
  static constexpr uint32_t field_mask() {
159
2
    return maskbit(offsetof(Dict, index_)) | maskbit(offsetof(Dict, keys_)) |
160
2
           maskbit(offsetof(Dict, values_));
161
2
  }
_ZN4DictIP6Tuple2IP6BigStriEiE10field_maskEv
Line
Count
Source
158
2
  static constexpr uint32_t field_mask() {
159
2
    return maskbit(offsetof(Dict, index_)) | maskbit(offsetof(Dict, keys_)) |
160
2
           maskbit(offsetof(Dict, values_));
161
2
  }
Unexecuted instantiation: _ZN4DictIiP6Tuple2IP4ListIPS1_IPS0_IiiEEEPS_IiiEEE10field_maskEv
_ZN4DictIP6BigStrPN4args7_ActionEE10field_maskEv
Line
Count
Source
158
6
  static constexpr uint32_t field_mask() {
159
6
    return maskbit(offsetof(Dict, index_)) | maskbit(offsetof(Dict, keys_)) |
160
6
           maskbit(offsetof(Dict, values_));
161
6
  }
_ZN4DictIP6BigStrPN10value_asdl7value_tEE10field_maskEv
Line
Count
Source
158
3
  static constexpr uint32_t field_mask() {
159
3
    return maskbit(offsetof(Dict, index_)) | maskbit(offsetof(Dict, keys_)) |
160
3
           maskbit(offsetof(Dict, values_));
161
3
  }
162
163
  DISALLOW_COPY_AND_ASSIGN(Dict);
164
165
  // kItemSize is max of K and V size.  That is, on 64-bit machines, the RARE
166
  // Dict<int, int> is smaller than other dicts
167
  static constexpr int kItemSize = sizeof(K) > sizeof(V) ? sizeof(K)
168
                                                         : sizeof(V);
169
170
  // Matches mark_sweep_heap.h
171
  static constexpr int kPoolBytes2 = 48 - sizeof(ObjHeader);
172
  static_assert(kPoolBytes2 % kItemSize == 0,
173
                "An integral number of items should fit in second pool");
174
  static constexpr int kNumItems2 = kPoolBytes2 / kItemSize;
175
176
  static const int kHeaderFudge = sizeof(ObjHeader) / kItemSize;
177
  static_assert(sizeof(ObjHeader) % kItemSize == 0,
178
                "Slab header size should be multiple of key size");
179
180
#if 0
181
  static constexpr int kMinBytes2 = 128 - sizeof(ObjHeader);
182
  static_assert(kMinBytes2 % kItemSize == 0,
183
                "An integral number of items should fit");
184
  static constexpr int kMinItems2 = kMinBytes2 / kItemSize;
185
#endif
186
187
120
  int HowManyPairs(int num_desired) {
188
    // See gc_list.h for comments on nearly identical logic
189
190
120
    if (num_desired <= kNumItems2) {  // use full cell in pool 2
191
72
      return kNumItems2;
192
72
    }
193
#if 0
194
    if (num_desired <= kMinItems2) {  // 48 -> 128, not 48 -> 64
195
      return kMinItems2;
196
    }
197
#endif
198
48
    return RoundUp(num_desired + kHeaderFudge) - kHeaderFudge;
199
120
  }
_ZN4DictIP6BigStriE12HowManyPairsEi
Line
Count
Source
187
36
  int HowManyPairs(int num_desired) {
188
    // See gc_list.h for comments on nearly identical logic
189
190
36
    if (num_desired <= kNumItems2) {  // use full cell in pool 2
191
22
      return kNumItems2;
192
22
    }
193
#if 0
194
    if (num_desired <= kMinItems2) {  // 48 -> 128, not 48 -> 64
195
      return kMinItems2;
196
    }
197
#endif
198
14
    return RoundUp(num_desired + kHeaderFudge) - kHeaderFudge;
199
36
  }
_ZN4DictIibE12HowManyPairsEi
Line
Count
Source
187
9
  int HowManyPairs(int num_desired) {
188
    // See gc_list.h for comments on nearly identical logic
189
190
9
    if (num_desired <= kNumItems2) {  // use full cell in pool 2
191
9
      return kNumItems2;
192
9
    }
193
#if 0
194
    if (num_desired <= kMinItems2) {  // 48 -> 128, not 48 -> 64
195
      return kMinItems2;
196
    }
197
#endif
198
0
    return RoundUp(num_desired + kHeaderFudge) - kHeaderFudge;
199
9
  }
_ZN4DictIP6BigStrS1_E12HowManyPairsEi
Line
Count
Source
187
10
  int HowManyPairs(int num_desired) {
188
    // See gc_list.h for comments on nearly identical logic
189
190
10
    if (num_desired <= kNumItems2) {  // use full cell in pool 2
191
6
      return kNumItems2;
192
6
    }
193
#if 0
194
    if (num_desired <= kMinItems2) {  // 48 -> 128, not 48 -> 64
195
      return kMinItems2;
196
    }
197
#endif
198
4
    return RoundUp(num_desired + kHeaderFudge) - kHeaderFudge;
199
10
  }
_ZN4DictIiP6BigStrE12HowManyPairsEi
Line
Count
Source
187
12
  int HowManyPairs(int num_desired) {
188
    // See gc_list.h for comments on nearly identical logic
189
190
12
    if (num_desired <= kNumItems2) {  // use full cell in pool 2
191
10
      return kNumItems2;
192
10
    }
193
#if 0
194
    if (num_desired <= kMinItems2) {  // 48 -> 128, not 48 -> 64
195
      return kMinItems2;
196
    }
197
#endif
198
2
    return RoundUp(num_desired + kHeaderFudge) - kHeaderFudge;
199
12
  }
_ZN4DictIiiE12HowManyPairsEi
Line
Count
Source
187
34
  int HowManyPairs(int num_desired) {
188
    // See gc_list.h for comments on nearly identical logic
189
190
34
    if (num_desired <= kNumItems2) {  // use full cell in pool 2
191
16
      return kNumItems2;
192
16
    }
193
#if 0
194
    if (num_desired <= kMinItems2) {  // 48 -> 128, not 48 -> 64
195
      return kMinItems2;
196
    }
197
#endif
198
18
    return RoundUp(num_desired + kHeaderFudge) - kHeaderFudge;
199
34
  }
_ZN4DictIP6Tuple2IiiEiE12HowManyPairsEi
Line
Count
Source
187
2
  int HowManyPairs(int num_desired) {
188
    // See gc_list.h for comments on nearly identical logic
189
190
2
    if (num_desired <= kNumItems2) {  // use full cell in pool 2
191
2
      return kNumItems2;
192
2
    }
193
#if 0
194
    if (num_desired <= kMinItems2) {  // 48 -> 128, not 48 -> 64
195
      return kMinItems2;
196
    }
197
#endif
198
0
    return RoundUp(num_desired + kHeaderFudge) - kHeaderFudge;
199
2
  }
_ZN4DictIP6Tuple2IP6BigStriEiE12HowManyPairsEi
Line
Count
Source
187
2
  int HowManyPairs(int num_desired) {
188
    // See gc_list.h for comments on nearly identical logic
189
190
2
    if (num_desired <= kNumItems2) {  // use full cell in pool 2
191
2
      return kNumItems2;
192
2
    }
193
#if 0
194
    if (num_desired <= kMinItems2) {  // 48 -> 128, not 48 -> 64
195
      return kMinItems2;
196
    }
197
#endif
198
0
    return RoundUp(num_desired + kHeaderFudge) - kHeaderFudge;
199
2
  }
Unexecuted instantiation: _ZN4DictIiP6Tuple2IP4ListIPS1_IPS0_IiiEEEPS_IiiEEE12HowManyPairsEi
_ZN4DictIP6BigStrPN10value_asdl7value_tEE12HowManyPairsEi
Line
Count
Source
187
8
  int HowManyPairs(int num_desired) {
188
    // See gc_list.h for comments on nearly identical logic
189
190
8
    if (num_desired <= kNumItems2) {  // use full cell in pool 2
191
3
      return kNumItems2;
192
3
    }
193
#if 0
194
    if (num_desired <= kMinItems2) {  // 48 -> 128, not 48 -> 64
195
      return kMinItems2;
196
    }
197
#endif
198
5
    return RoundUp(num_desired + kHeaderFudge) - kHeaderFudge;
199
8
  }
_ZN4DictIP6BigStrPN4args7_ActionEE12HowManyPairsEi
Line
Count
Source
187
7
  int HowManyPairs(int num_desired) {
188
    // See gc_list.h for comments on nearly identical logic
189
190
7
    if (num_desired <= kNumItems2) {  // use full cell in pool 2
191
2
      return kNumItems2;
192
2
    }
193
#if 0
194
    if (num_desired <= kMinItems2) {  // 48 -> 128, not 48 -> 64
195
      return kMinItems2;
196
    }
197
#endif
198
5
    return RoundUp(num_desired + kHeaderFudge) - kHeaderFudge;
199
7
  }
200
};
201
202
template <typename K, typename V>
203
56
inline bool dict_contains(const Dict<K, V>* haystack, K needle) {
204
56
  return haystack->find_kv_index(needle) != kNotFound;
205
56
}
_Z13dict_containsIP6BigStriEbPK4DictIT_T0_ES3_
Line
Count
Source
203
5
inline bool dict_contains(const Dict<K, V>* haystack, K needle) {
204
5
  return haystack->find_kv_index(needle) != kNotFound;
205
5
}
_Z13dict_containsIibEbPK4DictIT_T0_ES1_
Line
Count
Source
203
37
inline bool dict_contains(const Dict<K, V>* haystack, K needle) {
204
37
  return haystack->find_kv_index(needle) != kNotFound;
205
37
}
_Z13dict_containsIiP6BigStrEbPK4DictIT_T0_ES3_
Line
Count
Source
203
4
inline bool dict_contains(const Dict<K, V>* haystack, K needle) {
204
4
  return haystack->find_kv_index(needle) != kNotFound;
205
4
}
_Z13dict_containsIiiEbPK4DictIT_T0_ES1_
Line
Count
Source
203
4
inline bool dict_contains(const Dict<K, V>* haystack, K needle) {
204
4
  return haystack->find_kv_index(needle) != kNotFound;
205
4
}
_Z13dict_containsIP6BigStrS1_EbPK4DictIT_T0_ES3_
Line
Count
Source
203
6
inline bool dict_contains(const Dict<K, V>* haystack, K needle) {
204
6
  return haystack->find_kv_index(needle) != kNotFound;
205
6
}
Unexecuted instantiation: _Z13dict_containsIP6BigStrPN4args7_ActionEEbPK4DictIT_T0_ES6_
206
207
template <typename K, typename V>
208
122
void Dict<K, V>::reserve(int num_desired) {
209
122
  if (capacity_ >= num_desired) {
210
2
    return;  // Don't do anything if there's already enough space.
211
2
  }
212
213
120
  int old_len = len_;
214
120
  Slab<K>* old_k = keys_;
215
120
  Slab<V>* old_v = values_;
216
217
  // Calculate the number of keys and values we should have
218
120
  capacity_ = HowManyPairs(num_desired);
219
220
  // 1) Ensure index len a power of 2, to avoid expensive modulus % operation
221
  // 2) Introduce hash table load factor.   Use capacity_+1 to simulate ceil()
222
  // div, not floor() div.
223
120
  index_len_ = RoundUp((capacity_ + 1) * 5 / 4);
224
120
  DCHECK(index_len_ > capacity_);
225
226
0
  index_ = NewSlab<int>(index_len_);
227
3.60k
  for (int i = 0; i < index_len_; ++i) {
228
3.48k
    index_->items_[i] = kEmptyEntry;
229
3.48k
  }
230
231
  // These are DENSE, while index_ is sparse.
232
120
  keys_ = NewSlab<K>(capacity_);
233
120
  values_ = NewSlab<V>(capacity_);
234
235
120
  if (old_k != nullptr) {  // rehash if there were any entries
236
48
    len_ = 0;
237
654
    for (int i = 0; i < old_len; ++i) {
238
606
      set(old_k->items_[i], old_v->items_[i]);
239
606
    }
240
48
  }
241
120
}
_ZN4DictIP6BigStriE7reserveEi
Line
Count
Source
208
36
void Dict<K, V>::reserve(int num_desired) {
209
36
  if (capacity_ >= num_desired) {
210
0
    return;  // Don't do anything if there's already enough space.
211
0
  }
212
213
36
  int old_len = len_;
214
36
  Slab<K>* old_k = keys_;
215
36
  Slab<V>* old_v = values_;
216
217
  // Calculate the number of keys and values we should have
218
36
  capacity_ = HowManyPairs(num_desired);
219
220
  // 1) Ensure index len a power of 2, to avoid expensive modulus % operation
221
  // 2) Introduce hash table load factor.   Use capacity_+1 to simulate ceil()
222
  // div, not floor() div.
223
36
  index_len_ = RoundUp((capacity_ + 1) * 5 / 4);
224
36
  DCHECK(index_len_ > capacity_);
225
226
0
  index_ = NewSlab<int>(index_len_);
227
916
  for (int i = 0; i < index_len_; ++i) {
228
880
    index_->items_[i] = kEmptyEntry;
229
880
  }
230
231
  // These are DENSE, while index_ is sparse.
232
36
  keys_ = NewSlab<K>(capacity_);
233
36
  values_ = NewSlab<V>(capacity_);
234
235
36
  if (old_k != nullptr) {  // rehash if there were any entries
236
14
    len_ = 0;
237
184
    for (int i = 0; i < old_len; ++i) {
238
170
      set(old_k->items_[i], old_v->items_[i]);
239
170
    }
240
14
  }
241
36
}
_ZN4DictIibE7reserveEi
Line
Count
Source
208
9
void Dict<K, V>::reserve(int num_desired) {
209
9
  if (capacity_ >= num_desired) {
210
0
    return;  // Don't do anything if there's already enough space.
211
0
  }
212
213
9
  int old_len = len_;
214
9
  Slab<K>* old_k = keys_;
215
9
  Slab<V>* old_v = values_;
216
217
  // Calculate the number of keys and values we should have
218
9
  capacity_ = HowManyPairs(num_desired);
219
220
  // 1) Ensure index len a power of 2, to avoid expensive modulus % operation
221
  // 2) Introduce hash table load factor.   Use capacity_+1 to simulate ceil()
222
  // div, not floor() div.
223
9
  index_len_ = RoundUp((capacity_ + 1) * 5 / 4);
224
9
  DCHECK(index_len_ > capacity_);
225
226
0
  index_ = NewSlab<int>(index_len_);
227
153
  for (int i = 0; i < index_len_; ++i) {
228
144
    index_->items_[i] = kEmptyEntry;
229
144
  }
230
231
  // These are DENSE, while index_ is sparse.
232
9
  keys_ = NewSlab<K>(capacity_);
233
9
  values_ = NewSlab<V>(capacity_);
234
235
9
  if (old_k != nullptr) {  // rehash if there were any entries
236
0
    len_ = 0;
237
0
    for (int i = 0; i < old_len; ++i) {
238
0
      set(old_k->items_[i], old_v->items_[i]);
239
0
    }
240
0
  }
241
9
}
_ZN4DictIP6BigStrS1_E7reserveEi
Line
Count
Source
208
10
void Dict<K, V>::reserve(int num_desired) {
209
10
  if (capacity_ >= num_desired) {
210
0
    return;  // Don't do anything if there's already enough space.
211
0
  }
212
213
10
  int old_len = len_;
214
10
  Slab<K>* old_k = keys_;
215
10
  Slab<V>* old_v = values_;
216
217
  // Calculate the number of keys and values we should have
218
10
  capacity_ = HowManyPairs(num_desired);
219
220
  // 1) Ensure index len a power of 2, to avoid expensive modulus % operation
221
  // 2) Introduce hash table load factor.   Use capacity_+1 to simulate ceil()
222
  // div, not floor() div.
223
10
  index_len_ = RoundUp((capacity_ + 1) * 5 / 4);
224
10
  DCHECK(index_len_ > capacity_);
225
226
0
  index_ = NewSlab<int>(index_len_);
227
298
  for (int i = 0; i < index_len_; ++i) {
228
288
    index_->items_[i] = kEmptyEntry;
229
288
  }
230
231
  // These are DENSE, while index_ is sparse.
232
10
  keys_ = NewSlab<K>(capacity_);
233
10
  values_ = NewSlab<V>(capacity_);
234
235
10
  if (old_k != nullptr) {  // rehash if there were any entries
236
4
    len_ = 0;
237
62
    for (int i = 0; i < old_len; ++i) {
238
58
      set(old_k->items_[i], old_v->items_[i]);
239
58
    }
240
4
  }
241
10
}
_ZN4DictIiP6BigStrE7reserveEi
Line
Count
Source
208
12
void Dict<K, V>::reserve(int num_desired) {
209
12
  if (capacity_ >= num_desired) {
210
0
    return;  // Don't do anything if there's already enough space.
211
0
  }
212
213
12
  int old_len = len_;
214
12
  Slab<K>* old_k = keys_;
215
12
  Slab<V>* old_v = values_;
216
217
  // Calculate the number of keys and values we should have
218
12
  capacity_ = HowManyPairs(num_desired);
219
220
  // 1) Ensure index len a power of 2, to avoid expensive modulus % operation
221
  // 2) Introduce hash table load factor.   Use capacity_+1 to simulate ceil()
222
  // div, not floor() div.
223
12
  index_len_ = RoundUp((capacity_ + 1) * 5 / 4);
224
12
  DCHECK(index_len_ > capacity_);
225
226
0
  index_ = NewSlab<int>(index_len_);
227
124
  for (int i = 0; i < index_len_; ++i) {
228
112
    index_->items_[i] = kEmptyEntry;
229
112
  }
230
231
  // These are DENSE, while index_ is sparse.
232
12
  keys_ = NewSlab<K>(capacity_);
233
12
  values_ = NewSlab<V>(capacity_);
234
235
12
  if (old_k != nullptr) {  // rehash if there were any entries
236
2
    len_ = 0;
237
12
    for (int i = 0; i < old_len; ++i) {
238
10
      set(old_k->items_[i], old_v->items_[i]);
239
10
    }
240
2
  }
241
12
}
_ZN4DictIiiE7reserveEi
Line
Count
Source
208
36
void Dict<K, V>::reserve(int num_desired) {
209
36
  if (capacity_ >= num_desired) {
210
2
    return;  // Don't do anything if there's already enough space.
211
2
  }
212
213
34
  int old_len = len_;
214
34
  Slab<K>* old_k = keys_;
215
34
  Slab<V>* old_v = values_;
216
217
  // Calculate the number of keys and values we should have
218
34
  capacity_ = HowManyPairs(num_desired);
219
220
  // 1) Ensure index len a power of 2, to avoid expensive modulus % operation
221
  // 2) Introduce hash table load factor.   Use capacity_+1 to simulate ceil()
222
  // div, not floor() div.
223
34
  index_len_ = RoundUp((capacity_ + 1) * 5 / 4);
224
34
  DCHECK(index_len_ > capacity_);
225
226
0
  index_ = NewSlab<int>(index_len_);
227
1.69k
  for (int i = 0; i < index_len_; ++i) {
228
1.66k
    index_->items_[i] = kEmptyEntry;
229
1.66k
  }
230
231
  // These are DENSE, while index_ is sparse.
232
34
  keys_ = NewSlab<K>(capacity_);
233
34
  values_ = NewSlab<V>(capacity_);
234
235
34
  if (old_k != nullptr) {  // rehash if there were any entries
236
18
    len_ = 0;
237
308
    for (int i = 0; i < old_len; ++i) {
238
290
      set(old_k->items_[i], old_v->items_[i]);
239
290
    }
240
18
  }
241
34
}
_ZN4DictIP6Tuple2IiiEiE7reserveEi
Line
Count
Source
208
2
void Dict<K, V>::reserve(int num_desired) {
209
2
  if (capacity_ >= num_desired) {
210
0
    return;  // Don't do anything if there's already enough space.
211
0
  }
212
213
2
  int old_len = len_;
214
2
  Slab<K>* old_k = keys_;
215
2
  Slab<V>* old_v = values_;
216
217
  // Calculate the number of keys and values we should have
218
2
  capacity_ = HowManyPairs(num_desired);
219
220
  // 1) Ensure index len a power of 2, to avoid expensive modulus % operation
221
  // 2) Introduce hash table load factor.   Use capacity_+1 to simulate ceil()
222
  // div, not floor() div.
223
2
  index_len_ = RoundUp((capacity_ + 1) * 5 / 4);
224
2
  DCHECK(index_len_ > capacity_);
225
226
0
  index_ = NewSlab<int>(index_len_);
227
18
  for (int i = 0; i < index_len_; ++i) {
228
16
    index_->items_[i] = kEmptyEntry;
229
16
  }
230
231
  // These are DENSE, while index_ is sparse.
232
2
  keys_ = NewSlab<K>(capacity_);
233
2
  values_ = NewSlab<V>(capacity_);
234
235
2
  if (old_k != nullptr) {  // rehash if there were any entries
236
0
    len_ = 0;
237
0
    for (int i = 0; i < old_len; ++i) {
238
0
      set(old_k->items_[i], old_v->items_[i]);
239
0
    }
240
0
  }
241
2
}
_ZN4DictIP6Tuple2IP6BigStriEiE7reserveEi
Line
Count
Source
208
2
void Dict<K, V>::reserve(int num_desired) {
209
2
  if (capacity_ >= num_desired) {
210
0
    return;  // Don't do anything if there's already enough space.
211
0
  }
212
213
2
  int old_len = len_;
214
2
  Slab<K>* old_k = keys_;
215
2
  Slab<V>* old_v = values_;
216
217
  // Calculate the number of keys and values we should have
218
2
  capacity_ = HowManyPairs(num_desired);
219
220
  // 1) Ensure index len a power of 2, to avoid expensive modulus % operation
221
  // 2) Introduce hash table load factor.   Use capacity_+1 to simulate ceil()
222
  // div, not floor() div.
223
2
  index_len_ = RoundUp((capacity_ + 1) * 5 / 4);
224
2
  DCHECK(index_len_ > capacity_);
225
226
0
  index_ = NewSlab<int>(index_len_);
227
18
  for (int i = 0; i < index_len_; ++i) {
228
16
    index_->items_[i] = kEmptyEntry;
229
16
  }
230
231
  // These are DENSE, while index_ is sparse.
232
2
  keys_ = NewSlab<K>(capacity_);
233
2
  values_ = NewSlab<V>(capacity_);
234
235
2
  if (old_k != nullptr) {  // rehash if there were any entries
236
0
    len_ = 0;
237
0
    for (int i = 0; i < old_len; ++i) {
238
0
      set(old_k->items_[i], old_v->items_[i]);
239
0
    }
240
0
  }
241
2
}
Unexecuted instantiation: _ZN4DictIiP6Tuple2IP4ListIPS1_IPS0_IiiEEEPS_IiiEEE7reserveEi
_ZN4DictIP6BigStrPN10value_asdl7value_tEE7reserveEi
Line
Count
Source
208
8
void Dict<K, V>::reserve(int num_desired) {
209
8
  if (capacity_ >= num_desired) {
210
0
    return;  // Don't do anything if there's already enough space.
211
0
  }
212
213
8
  int old_len = len_;
214
8
  Slab<K>* old_k = keys_;
215
8
  Slab<V>* old_v = values_;
216
217
  // Calculate the number of keys and values we should have
218
8
  capacity_ = HowManyPairs(num_desired);
219
220
  // 1) Ensure index len a power of 2, to avoid expensive modulus % operation
221
  // 2) Introduce hash table load factor.   Use capacity_+1 to simulate ceil()
222
  // div, not floor() div.
223
8
  index_len_ = RoundUp((capacity_ + 1) * 5 / 4);
224
8
  DCHECK(index_len_ > capacity_);
225
226
0
  index_ = NewSlab<int>(index_len_);
227
192
  for (int i = 0; i < index_len_; ++i) {
228
184
    index_->items_[i] = kEmptyEntry;
229
184
  }
230
231
  // These are DENSE, while index_ is sparse.
232
8
  keys_ = NewSlab<K>(capacity_);
233
8
  values_ = NewSlab<V>(capacity_);
234
235
8
  if (old_k != nullptr) {  // rehash if there were any entries
236
5
    len_ = 0;
237
44
    for (int i = 0; i < old_len; ++i) {
238
39
      set(old_k->items_[i], old_v->items_[i]);
239
39
    }
240
5
  }
241
8
}
_ZN4DictIP6BigStrPN4args7_ActionEE7reserveEi
Line
Count
Source
208
7
void Dict<K, V>::reserve(int num_desired) {
209
7
  if (capacity_ >= num_desired) {
210
0
    return;  // Don't do anything if there's already enough space.
211
0
  }
212
213
7
  int old_len = len_;
214
7
  Slab<K>* old_k = keys_;
215
7
  Slab<V>* old_v = values_;
216
217
  // Calculate the number of keys and values we should have
218
7
  capacity_ = HowManyPairs(num_desired);
219
220
  // 1) Ensure index len a power of 2, to avoid expensive modulus % operation
221
  // 2) Introduce hash table load factor.   Use capacity_+1 to simulate ceil()
222
  // div, not floor() div.
223
7
  index_len_ = RoundUp((capacity_ + 1) * 5 / 4);
224
7
  DCHECK(index_len_ > capacity_);
225
226
0
  index_ = NewSlab<int>(index_len_);
227
183
  for (int i = 0; i < index_len_; ++i) {
228
176
    index_->items_[i] = kEmptyEntry;
229
176
  }
230
231
  // These are DENSE, while index_ is sparse.
232
7
  keys_ = NewSlab<K>(capacity_);
233
7
  values_ = NewSlab<V>(capacity_);
234
235
7
  if (old_k != nullptr) {  // rehash if there were any entries
236
5
    len_ = 0;
237
44
    for (int i = 0; i < old_len; ++i) {
238
39
      set(old_k->items_[i], old_v->items_[i]);
239
39
    }
240
5
  }
241
7
}
242
243
template <typename K, typename V>
244
16.2k
V Dict<K, V>::at(K key) const {
245
16.2k
  int kv_index = find_kv_index(key);
246
16.2k
  if (kv_index == kNotFound) {
247
0
    throw Alloc<KeyError>();
248
16.2k
  } else {
249
16.2k
    return values_->items_[kv_index];
250
16.2k
  }
251
16.2k
}
_ZNK4DictIP6BigStriE2atES1_
Line
Count
Source
244
19
V Dict<K, V>::at(K key) const {
245
19
  int kv_index = find_kv_index(key);
246
19
  if (kv_index == kNotFound) {
247
0
    throw Alloc<KeyError>();
248
19
  } else {
249
19
    return values_->items_[kv_index];
250
19
  }
251
19
}
_ZNK4DictIiP6BigStrE2atEi
Line
Count
Source
244
7
V Dict<K, V>::at(K key) const {
245
7
  int kv_index = find_kv_index(key);
246
7
  if (kv_index == kNotFound) {
247
0
    throw Alloc<KeyError>();
248
7
  } else {
249
7
    return values_->items_[kv_index];
250
7
  }
251
7
}
_ZNK4DictIP6BigStrS1_E2atES1_
Line
Count
Source
244
8
V Dict<K, V>::at(K key) const {
245
8
  int kv_index = find_kv_index(key);
246
8
  if (kv_index == kNotFound) {
247
0
    throw Alloc<KeyError>();
248
8
  } else {
249
8
    return values_->items_[kv_index];
250
8
  }
251
8
}
_ZNK4DictIiiE2atEi
Line
Count
Source
244
16.1k
V Dict<K, V>::at(K key) const {
245
16.1k
  int kv_index = find_kv_index(key);
246
16.1k
  if (kv_index == kNotFound) {
247
0
    throw Alloc<KeyError>();
248
16.1k
  } else {
249
16.1k
    return values_->items_[kv_index];
250
16.1k
  }
251
16.1k
}
_ZNK4DictIP6Tuple2IiiEiE2atES2_
Line
Count
Source
244
4
V Dict<K, V>::at(K key) const {
245
4
  int kv_index = find_kv_index(key);
246
4
  if (kv_index == kNotFound) {
247
0
    throw Alloc<KeyError>();
248
4
  } else {
249
4
    return values_->items_[kv_index];
250
4
  }
251
4
}
_ZNK4DictIP6Tuple2IP6BigStriEiE2atES4_
Line
Count
Source
244
4
V Dict<K, V>::at(K key) const {
245
4
  int kv_index = find_kv_index(key);
246
4
  if (kv_index == kNotFound) {
247
0
    throw Alloc<KeyError>();
248
4
  } else {
249
4
    return values_->items_[kv_index];
250
4
  }
251
4
}
Unexecuted instantiation: _ZNK4DictIP6BigStrPN10value_asdl7value_tEE2atES1_
Unexecuted instantiation: _ZNK4DictIP6BigStrPN4args7_ActionEE2atES1_
252
253
template <typename K, typename V>
254
7
V Dict<K, V>::get(K key) const {
255
7
  int kv_index = find_kv_index(key);
256
7
  if (kv_index == kNotFound) {
257
4
    return nullptr;
258
4
  } else {
259
3
    return values_->items_[kv_index];
260
3
  }
261
7
}
_ZNK4DictIiP6BigStrE3getEi
Line
Count
Source
254
4
V Dict<K, V>::get(K key) const {
255
4
  int kv_index = find_kv_index(key);
256
4
  if (kv_index == kNotFound) {
257
2
    return nullptr;
258
2
  } else {
259
2
    return values_->items_[kv_index];
260
2
  }
261
4
}
_ZNK4DictIP6BigStrS1_E3getES1_
Line
Count
Source
254
3
V Dict<K, V>::get(K key) const {
255
3
  int kv_index = find_kv_index(key);
256
3
  if (kv_index == kNotFound) {
257
2
    return nullptr;
258
2
  } else {
259
1
    return values_->items_[kv_index];
260
1
  }
261
3
}
Unexecuted instantiation: _ZNK4DictIP6BigStrPN4args7_ActionEE3getES1_
262
263
template <typename K, typename V>
264
2
V Dict<K, V>::get(K key, V default_val) const {
265
2
  int kv_index = find_kv_index(key);
266
2
  if (kv_index == kNotFound) {
267
2
    return default_val;
268
2
  } else {
269
0
    return values_->items_[kv_index];
270
0
  }
271
2
}
_ZNK4DictIP6BigStrS1_E3getES1_S1_
Line
Count
Source
264
2
V Dict<K, V>::get(K key, V default_val) const {
265
2
  int kv_index = find_kv_index(key);
266
2
  if (kv_index == kNotFound) {
267
2
    return default_val;
268
2
  } else {
269
0
    return values_->items_[kv_index];
270
0
  }
271
2
}
Unexecuted instantiation: _ZNK4DictIiP6BigStrE3getEiS1_
Unexecuted instantiation: _ZNK4DictIP6BigStriE3getES1_i
272
273
template <typename K, typename V>
274
14
List<K>* Dict<K, V>::keys() const {
275
14
  return ListFromDictSlab<K>(keys_, len_);
276
14
}
_ZNK4DictIP6BigStriE4keysEv
Line
Count
Source
274
8
List<K>* Dict<K, V>::keys() const {
275
8
  return ListFromDictSlab<K>(keys_, len_);
276
8
}
_ZNK4DictIP6BigStrS1_E4keysEv
Line
Count
Source
274
2
List<K>* Dict<K, V>::keys() const {
275
2
  return ListFromDictSlab<K>(keys_, len_);
276
2
}
_ZNK4DictIiiE4keysEv
Line
Count
Source
274
4
List<K>* Dict<K, V>::keys() const {
275
4
  return ListFromDictSlab<K>(keys_, len_);
276
4
}
277
278
template <typename K, typename V>
279
4
List<V>* Dict<K, V>::values() const {
280
4
  return ListFromDictSlab<V>(values_, len_);
281
4
}
_ZNK4DictIP6BigStriE6valuesEv
Line
Count
Source
279
2
List<V>* Dict<K, V>::values() const {
280
2
  return ListFromDictSlab<V>(values_, len_);
281
2
}
_ZNK4DictIP6BigStrS1_E6valuesEv
Line
Count
Source
279
2
List<V>* Dict<K, V>::values() const {
280
2
  return ListFromDictSlab<V>(values_, len_);
281
2
}
282
283
template <typename K, typename V>
284
8
void Dict<K, V>::clear() {
285
  // Maintain invariant
286
792
  for (int i = 0; i < index_len_; ++i) {
287
784
    index_->items_[i] = kEmptyEntry;
288
784
  }
289
290
8
  if (keys_) {
291
6
    memset(keys_->items_, 0, len_ * sizeof(K));  // zero for GC scan
292
6
  }
293
8
  if (values_) {
294
6
    memset(values_->items_, 0, len_ * sizeof(V));  // zero for GC scan
295
6
  }
296
8
  len_ = 0;
297
8
}
_ZN4DictIiP6BigStrE5clearEv
Line
Count
Source
284
2
void Dict<K, V>::clear() {
285
  // Maintain invariant
286
2
  for (int i = 0; i < index_len_; ++i) {
287
0
    index_->items_[i] = kEmptyEntry;
288
0
  }
289
290
2
  if (keys_) {
291
0
    memset(keys_->items_, 0, len_ * sizeof(K));  // zero for GC scan
292
0
  }
293
2
  if (values_) {
294
0
    memset(values_->items_, 0, len_ * sizeof(V));  // zero for GC scan
295
0
  }
296
2
  len_ = 0;
297
2
}
_ZN4DictIP6BigStriE5clearEv
Line
Count
Source
284
2
void Dict<K, V>::clear() {
285
  // Maintain invariant
286
18
  for (int i = 0; i < index_len_; ++i) {
287
16
    index_->items_[i] = kEmptyEntry;
288
16
  }
289
290
2
  if (keys_) {
291
2
    memset(keys_->items_, 0, len_ * sizeof(K));  // zero for GC scan
292
2
  }
293
2
  if (values_) {
294
2
    memset(values_->items_, 0, len_ * sizeof(V));  // zero for GC scan
295
2
  }
296
2
  len_ = 0;
297
2
}
_ZN4DictIiiE5clearEv
Line
Count
Source
284
4
void Dict<K, V>::clear() {
285
  // Maintain invariant
286
772
  for (int i = 0; i < index_len_; ++i) {
287
768
    index_->items_[i] = kEmptyEntry;
288
768
  }
289
290
4
  if (keys_) {
291
4
    memset(keys_->items_, 0, len_ * sizeof(K));  // zero for GC scan
292
4
  }
293
4
  if (values_) {
294
4
    memset(values_->items_, 0, len_ * sizeof(V));  // zero for GC scan
295
4
  }
296
4
  len_ = 0;
297
4
}
298
299
// TODO:
300
// - Special case to intern BigStr* when it's hashed?  How?
301
//   - Should we have wrappers like:
302
//   - V GetAndIntern<V>(D, &string_key)
303
//   - SetAndIntern<V>(D, &string_key, value)
304
//   This will enable duplicate copies of the string to be garbage collected
305
template <typename K, typename V>
306
34.1k
int Dict<K, V>::hash_and_probe(K key) const {
307
34.1k
  if (capacity_ == 0) {
308
70
    return kTooSmall;
309
70
  }
310
311
  // Hash the key onto a slot in the index. If the first slot is occupied,
312
  // probe until an empty one is found.
313
34.0k
  unsigned h = hash_key(key);
314
  // faster % using & -- assuming index_len_ is power of 2
315
34.0k
  int init_bucket = h & (index_len_ - 1);
316
317
  // If we see a tombstone along the probing path, stash it.
318
34.0k
  int open_slot = -1;
319
320
37.7k
  for (int i = 0; i < index_len_; ++i) {
321
    // Start at init_bucket and wrap araound
322
323
    // faster % using & -- assuming index_len_ is power of 2
324
37.7k
    int slot = (i + init_bucket) & (index_len_ - 1);
325
326
37.7k
    int kv_index = index_->items_[slot];
327
37.7k
    DCHECK(kv_index < len_);
328
    // Optimistically this is the common case once the table has been populated.
329
37.7k
    if (kv_index >= 0) {
330
36.2k
      unsigned h2 = hash_key(keys_->items_[kv_index]);
331
36.2k
      if (h == h2 && keys_equal(keys_->items_[kv_index], key)) {
332
32.5k
        return slot;
333
32.5k
      }
334
36.2k
    }
335
336
5.23k
    if (kv_index == kEmptyEntry) {
337
1.54k
      if (open_slot != -1) {
338
6
        slot = open_slot;
339
6
      }
340
      // If there isn't room in the entry arrays, tell the caller to resize.
341
1.54k
      return len_ < capacity_ ? slot : kTooSmall;
342
1.54k
    }
343
344
    // Tombstone or collided keys unequal. Keep scanning.
345
3.69k
    DCHECK(kv_index >= 0 || kv_index == kDeletedEntry);
346
3.69k
    if (kv_index == kDeletedEntry && open_slot == -1) {
347
      // NOTE: We only record the open slot here. We DON'T return it. If we're
348
      // looking for a key that was writen before this tombstone was written to
349
      // the index we should continue probing until we get to that key. If we
350
      // get to an empty index slot or the end of the index then we know we are
351
      // dealing with a new key and can safely replace the tombstone without
352
      // disrupting any existing keys.
353
8
      open_slot = slot;
354
8
    }
355
3.69k
  }
356
357
2
  if (open_slot != -1) {
358
2
    return len_ < capacity_ ? open_slot : kTooSmall;
359
2
  }
360
361
0
  return kTooSmall;
362
2
}
_ZNK4DictIP6BigStriE14hash_and_probeES1_
Line
Count
Source
306
387
int Dict<K, V>::hash_and_probe(K key) const {
307
387
  if (capacity_ == 0) {
308
22
    return kTooSmall;
309
22
  }
310
311
  // Hash the key onto a slot in the index. If the first slot is occupied,
312
  // probe until an empty one is found.
313
365
  unsigned h = hash_key(key);
314
  // faster % using & -- assuming index_len_ is power of 2
315
365
  int init_bucket = h & (index_len_ - 1);
316
317
  // If we see a tombstone along the probing path, stash it.
318
365
  int open_slot = -1;
319
320
3.86k
  for (int i = 0; i < index_len_; ++i) {
321
    // Start at init_bucket and wrap araound
322
323
    // faster % using & -- assuming index_len_ is power of 2
324
3.86k
    int slot = (i + init_bucket) & (index_len_ - 1);
325
326
3.86k
    int kv_index = index_->items_[slot];
327
3.86k
    DCHECK(kv_index < len_);
328
    // Optimistically this is the common case once the table has been populated.
329
3.86k
    if (kv_index >= 0) {
330
3.52k
      unsigned h2 = hash_key(keys_->items_[kv_index]);
331
3.52k
      if (h == h2 && keys_equal(keys_->items_[kv_index], key)) {
332
24
        return slot;
333
24
      }
334
3.52k
    }
335
336
3.84k
    if (kv_index == kEmptyEntry) {
337
341
      if (open_slot != -1) {
338
2
        slot = open_slot;
339
2
      }
340
      // If there isn't room in the entry arrays, tell the caller to resize.
341
341
      return len_ < capacity_ ? slot : kTooSmall;
342
341
    }
343
344
    // Tombstone or collided keys unequal. Keep scanning.
345
3.50k
    DCHECK(kv_index >= 0 || kv_index == kDeletedEntry);
346
3.50k
    if (kv_index == kDeletedEntry && open_slot == -1) {
347
      // NOTE: We only record the open slot here. We DON'T return it. If we're
348
      // looking for a key that was writen before this tombstone was written to
349
      // the index we should continue probing until we get to that key. If we
350
      // get to an empty index slot or the end of the index then we know we are
351
      // dealing with a new key and can safely replace the tombstone without
352
      // disrupting any existing keys.
353
2
      open_slot = slot;
354
2
    }
355
3.50k
  }
356
357
0
  if (open_slot != -1) {
358
0
    return len_ < capacity_ ? open_slot : kTooSmall;
359
0
  }
360
361
0
  return kTooSmall;
362
0
}
_ZNK4DictIiP6BigStrE14hash_and_probeEi
Line
Count
Source
306
58
int Dict<K, V>::hash_and_probe(K key) const {
307
58
  if (capacity_ == 0) {
308
10
    return kTooSmall;
309
10
  }
310
311
  // Hash the key onto a slot in the index. If the first slot is occupied,
312
  // probe until an empty one is found.
313
48
  unsigned h = hash_key(key);
314
  // faster % using & -- assuming index_len_ is power of 2
315
48
  int init_bucket = h & (index_len_ - 1);
316
317
  // If we see a tombstone along the probing path, stash it.
318
48
  int open_slot = -1;
319
320
54
  for (int i = 0; i < index_len_; ++i) {
321
    // Start at init_bucket and wrap araound
322
323
    // faster % using & -- assuming index_len_ is power of 2
324
54
    int slot = (i + init_bucket) & (index_len_ - 1);
325
326
54
    int kv_index = index_->items_[slot];
327
54
    DCHECK(kv_index < len_);
328
    // Optimistically this is the common case once the table has been populated.
329
54
    if (kv_index >= 0) {
330
16
      unsigned h2 = hash_key(keys_->items_[kv_index]);
331
16
      if (h == h2 && keys_equal(keys_->items_[kv_index], key)) {
332
10
        return slot;
333
10
      }
334
16
    }
335
336
44
    if (kv_index == kEmptyEntry) {
337
38
      if (open_slot != -1) {
338
0
        slot = open_slot;
339
0
      }
340
      // If there isn't room in the entry arrays, tell the caller to resize.
341
38
      return len_ < capacity_ ? slot : kTooSmall;
342
38
    }
343
344
    // Tombstone or collided keys unequal. Keep scanning.
345
6
    DCHECK(kv_index >= 0 || kv_index == kDeletedEntry);
346
6
    if (kv_index == kDeletedEntry && open_slot == -1) {
347
      // NOTE: We only record the open slot here. We DON'T return it. If we're
348
      // looking for a key that was writen before this tombstone was written to
349
      // the index we should continue probing until we get to that key. If we
350
      // get to an empty index slot or the end of the index then we know we are
351
      // dealing with a new key and can safely replace the tombstone without
352
      // disrupting any existing keys.
353
0
      open_slot = slot;
354
0
    }
355
6
  }
356
357
0
  if (open_slot != -1) {
358
0
    return len_ < capacity_ ? open_slot : kTooSmall;
359
0
  }
360
361
0
  return kTooSmall;
362
0
}
_ZNK4DictIP6BigStrS1_E14hash_and_probeES1_
Line
Count
Source
306
112
int Dict<K, V>::hash_and_probe(K key) const {
307
112
  if (capacity_ == 0) {
308
6
    return kTooSmall;
309
6
  }
310
311
  // Hash the key onto a slot in the index. If the first slot is occupied,
312
  // probe until an empty one is found.
313
106
  unsigned h = hash_key(key);
314
  // faster % using & -- assuming index_len_ is power of 2
315
106
  int init_bucket = h & (index_len_ - 1);
316
317
  // If we see a tombstone along the probing path, stash it.
318
106
  int open_slot = -1;
319
320
160
  for (int i = 0; i < index_len_; ++i) {
321
    // Start at init_bucket and wrap araound
322
323
    // faster % using & -- assuming index_len_ is power of 2
324
160
    int slot = (i + init_bucket) & (index_len_ - 1);
325
326
160
    int kv_index = index_->items_[slot];
327
160
    DCHECK(kv_index < len_);
328
    // Optimistically this is the common case once the table has been populated.
329
160
    if (kv_index >= 0) {
330
60
      unsigned h2 = hash_key(keys_->items_[kv_index]);
331
60
      if (h == h2 && keys_equal(keys_->items_[kv_index], key)) {
332
6
        return slot;
333
6
      }
334
60
    }
335
336
154
    if (kv_index == kEmptyEntry) {
337
100
      if (open_slot != -1) {
338
0
        slot = open_slot;
339
0
      }
340
      // If there isn't room in the entry arrays, tell the caller to resize.
341
100
      return len_ < capacity_ ? slot : kTooSmall;
342
100
    }
343
344
    // Tombstone or collided keys unequal. Keep scanning.
345
54
    DCHECK(kv_index >= 0 || kv_index == kDeletedEntry);
346
54
    if (kv_index == kDeletedEntry && open_slot == -1) {
347
      // NOTE: We only record the open slot here. We DON'T return it. If we're
348
      // looking for a key that was writen before this tombstone was written to
349
      // the index we should continue probing until we get to that key. If we
350
      // get to an empty index slot or the end of the index then we know we are
351
      // dealing with a new key and can safely replace the tombstone without
352
      // disrupting any existing keys.
353
0
      open_slot = slot;
354
0
    }
355
54
  }
356
357
0
  if (open_slot != -1) {
358
0
    return len_ < capacity_ ? open_slot : kTooSmall;
359
0
  }
360
361
0
  return kTooSmall;
362
0
}
_ZNK4DictIibE14hash_and_probeEi
Line
Count
Source
306
74
int Dict<K, V>::hash_and_probe(K key) const {
307
74
  if (capacity_ == 0) {
308
9
    return kTooSmall;
309
9
  }
310
311
  // Hash the key onto a slot in the index. If the first slot is occupied,
312
  // probe until an empty one is found.
313
65
  unsigned h = hash_key(key);
314
  // faster % using & -- assuming index_len_ is power of 2
315
65
  int init_bucket = h & (index_len_ - 1);
316
317
  // If we see a tombstone along the probing path, stash it.
318
65
  int open_slot = -1;
319
320
69
  for (int i = 0; i < index_len_; ++i) {
321
    // Start at init_bucket and wrap araound
322
323
    // faster % using & -- assuming index_len_ is power of 2
324
69
    int slot = (i + init_bucket) & (index_len_ - 1);
325
326
69
    int kv_index = index_->items_[slot];
327
69
    DCHECK(kv_index < len_);
328
    // Optimistically this is the common case once the table has been populated.
329
69
    if (kv_index >= 0) {
330
4
      unsigned h2 = hash_key(keys_->items_[kv_index]);
331
4
      if (h == h2 && keys_equal(keys_->items_[kv_index], key)) {
332
0
        return slot;
333
0
      }
334
4
    }
335
336
69
    if (kv_index == kEmptyEntry) {
337
65
      if (open_slot != -1) {
338
0
        slot = open_slot;
339
0
      }
340
      // If there isn't room in the entry arrays, tell the caller to resize.
341
65
      return len_ < capacity_ ? slot : kTooSmall;
342
65
    }
343
344
    // Tombstone or collided keys unequal. Keep scanning.
345
4
    DCHECK(kv_index >= 0 || kv_index == kDeletedEntry);
346
4
    if (kv_index == kDeletedEntry && open_slot == -1) {
347
      // NOTE: We only record the open slot here. We DON'T return it. If we're
348
      // looking for a key that was writen before this tombstone was written to
349
      // the index we should continue probing until we get to that key. If we
350
      // get to an empty index slot or the end of the index then we know we are
351
      // dealing with a new key and can safely replace the tombstone without
352
      // disrupting any existing keys.
353
0
      open_slot = slot;
354
0
    }
355
4
  }
356
357
0
  if (open_slot != -1) {
358
0
    return len_ < capacity_ ? open_slot : kTooSmall;
359
0
  }
360
361
0
  return kTooSmall;
362
0
}
_ZNK4DictIiiE14hash_and_probeEi
Line
Count
Source
306
33.3k
int Dict<K, V>::hash_and_probe(K key) const {
307
33.3k
  if (capacity_ == 0) {
308
14
    return kTooSmall;
309
14
  }
310
311
  // Hash the key onto a slot in the index. If the first slot is occupied,
312
  // probe until an empty one is found.
313
33.3k
  unsigned h = hash_key(key);
314
  // faster % using & -- assuming index_len_ is power of 2
315
33.3k
  int init_bucket = h & (index_len_ - 1);
316
317
  // If we see a tombstone along the probing path, stash it.
318
33.3k
  int open_slot = -1;
319
320
33.3k
  for (int i = 0; i < index_len_; ++i) {
321
    // Start at init_bucket and wrap araound
322
323
    // faster % using & -- assuming index_len_ is power of 2
324
33.3k
    int slot = (i + init_bucket) & (index_len_ - 1);
325
326
33.3k
    int kv_index = index_->items_[slot];
327
33.3k
    DCHECK(kv_index < len_);
328
    // Optimistically this is the common case once the table has been populated.
329
33.3k
    if (kv_index >= 0) {
330
32.5k
      unsigned h2 = hash_key(keys_->items_[kv_index]);
331
32.5k
      if (h == h2 && keys_equal(keys_->items_[kv_index], key)) {
332
32.4k
        return slot;
333
32.4k
      }
334
32.5k
    }
335
336
902
    if (kv_index == kEmptyEntry) {
337
842
      if (open_slot != -1) {
338
4
        slot = open_slot;
339
4
      }
340
      // If there isn't room in the entry arrays, tell the caller to resize.
341
842
      return len_ < capacity_ ? slot : kTooSmall;
342
842
    }
343
344
    // Tombstone or collided keys unequal. Keep scanning.
345
60
    DCHECK(kv_index >= 0 || kv_index == kDeletedEntry);
346
60
    if (kv_index == kDeletedEntry && open_slot == -1) {
347
      // NOTE: We only record the open slot here. We DON'T return it. If we're
348
      // looking for a key that was writen before this tombstone was written to
349
      // the index we should continue probing until we get to that key. If we
350
      // get to an empty index slot or the end of the index then we know we are
351
      // dealing with a new key and can safely replace the tombstone without
352
      // disrupting any existing keys.
353
6
      open_slot = slot;
354
6
    }
355
60
  }
356
357
2
  if (open_slot != -1) {
358
2
    return len_ < capacity_ ? open_slot : kTooSmall;
359
2
  }
360
361
0
  return kTooSmall;
362
2
}
_ZNK4DictIP6Tuple2IiiEiE14hash_and_probeES2_
Line
Count
Source
306
10
int Dict<K, V>::hash_and_probe(K key) const {
307
10
  if (capacity_ == 0) {
308
2
    return kTooSmall;
309
2
  }
310
311
  // Hash the key onto a slot in the index. If the first slot is occupied,
312
  // probe until an empty one is found.
313
8
  unsigned h = hash_key(key);
314
  // faster % using & -- assuming index_len_ is power of 2
315
8
  int init_bucket = h & (index_len_ - 1);
316
317
  // If we see a tombstone along the probing path, stash it.
318
8
  int open_slot = -1;
319
320
8
  for (int i = 0; i < index_len_; ++i) {
321
    // Start at init_bucket and wrap araound
322
323
    // faster % using & -- assuming index_len_ is power of 2
324
8
    int slot = (i + init_bucket) & (index_len_ - 1);
325
326
8
    int kv_index = index_->items_[slot];
327
8
    DCHECK(kv_index < len_);
328
    // Optimistically this is the common case once the table has been populated.
329
8
    if (kv_index >= 0) {
330
4
      unsigned h2 = hash_key(keys_->items_[kv_index]);
331
4
      if (h == h2 && keys_equal(keys_->items_[kv_index], key)) {
332
4
        return slot;
333
4
      }
334
4
    }
335
336
4
    if (kv_index == kEmptyEntry) {
337
4
      if (open_slot != -1) {
338
0
        slot = open_slot;
339
0
      }
340
      // If there isn't room in the entry arrays, tell the caller to resize.
341
4
      return len_ < capacity_ ? slot : kTooSmall;
342
4
    }
343
344
    // Tombstone or collided keys unequal. Keep scanning.
345
0
    DCHECK(kv_index >= 0 || kv_index == kDeletedEntry);
346
0
    if (kv_index == kDeletedEntry && open_slot == -1) {
347
      // NOTE: We only record the open slot here. We DON'T return it. If we're
348
      // looking for a key that was writen before this tombstone was written to
349
      // the index we should continue probing until we get to that key. If we
350
      // get to an empty index slot or the end of the index then we know we are
351
      // dealing with a new key and can safely replace the tombstone without
352
      // disrupting any existing keys.
353
0
      open_slot = slot;
354
0
    }
355
0
  }
356
357
0
  if (open_slot != -1) {
358
0
    return len_ < capacity_ ? open_slot : kTooSmall;
359
0
  }
360
361
0
  return kTooSmall;
362
0
}
_ZNK4DictIP6Tuple2IP6BigStriEiE14hash_and_probeES4_
Line
Count
Source
306
10
int Dict<K, V>::hash_and_probe(K key) const {
307
10
  if (capacity_ == 0) {
308
2
    return kTooSmall;
309
2
  }
310
311
  // Hash the key onto a slot in the index. If the first slot is occupied,
312
  // probe until an empty one is found.
313
8
  unsigned h = hash_key(key);
314
  // faster % using & -- assuming index_len_ is power of 2
315
8
  int init_bucket = h & (index_len_ - 1);
316
317
  // If we see a tombstone along the probing path, stash it.
318
8
  int open_slot = -1;
319
320
8
  for (int i = 0; i < index_len_; ++i) {
321
    // Start at init_bucket and wrap araound
322
323
    // faster % using & -- assuming index_len_ is power of 2
324
8
    int slot = (i + init_bucket) & (index_len_ - 1);
325
326
8
    int kv_index = index_->items_[slot];
327
8
    DCHECK(kv_index < len_);
328
    // Optimistically this is the common case once the table has been populated.
329
8
    if (kv_index >= 0) {
330
4
      unsigned h2 = hash_key(keys_->items_[kv_index]);
331
4
      if (h == h2 && keys_equal(keys_->items_[kv_index], key)) {
332
4
        return slot;
333
4
      }
334
4
    }
335
336
4
    if (kv_index == kEmptyEntry) {
337
4
      if (open_slot != -1) {
338
0
        slot = open_slot;
339
0
      }
340
      // If there isn't room in the entry arrays, tell the caller to resize.
341
4
      return len_ < capacity_ ? slot : kTooSmall;
342
4
    }
343
344
    // Tombstone or collided keys unequal. Keep scanning.
345
0
    DCHECK(kv_index >= 0 || kv_index == kDeletedEntry);
346
0
    if (kv_index == kDeletedEntry && open_slot == -1) {
347
      // NOTE: We only record the open slot here. We DON'T return it. If we're
348
      // looking for a key that was writen before this tombstone was written to
349
      // the index we should continue probing until we get to that key. If we
350
      // get to an empty index slot or the end of the index then we know we are
351
      // dealing with a new key and can safely replace the tombstone without
352
      // disrupting any existing keys.
353
0
      open_slot = slot;
354
0
    }
355
0
  }
356
357
0
  if (open_slot != -1) {
358
0
    return len_ < capacity_ ? open_slot : kTooSmall;
359
0
  }
360
361
0
  return kTooSmall;
362
0
}
Unexecuted instantiation: _ZNK4DictIiP6Tuple2IP4ListIPS1_IPS0_IiiEEEPS_IiiEEE14hash_and_probeEi
_ZNK4DictIP6BigStrPN10value_asdl7value_tEE14hash_and_probeES1_
Line
Count
Source
306
80
int Dict<K, V>::hash_and_probe(K key) const {
307
80
  if (capacity_ == 0) {
308
3
    return kTooSmall;
309
3
  }
310
311
  // Hash the key onto a slot in the index. If the first slot is occupied,
312
  // probe until an empty one is found.
313
77
  unsigned h = hash_key(key);
314
  // faster % using & -- assuming index_len_ is power of 2
315
77
  int init_bucket = h & (index_len_ - 1);
316
317
  // If we see a tombstone along the probing path, stash it.
318
77
  int open_slot = -1;
319
320
99
  for (int i = 0; i < index_len_; ++i) {
321
    // Start at init_bucket and wrap araound
322
323
    // faster % using & -- assuming index_len_ is power of 2
324
99
    int slot = (i + init_bucket) & (index_len_ - 1);
325
326
99
    int kv_index = index_->items_[slot];
327
99
    DCHECK(kv_index < len_);
328
    // Optimistically this is the common case once the table has been populated.
329
99
    if (kv_index >= 0) {
330
22
      unsigned h2 = hash_key(keys_->items_[kv_index]);
331
22
      if (h == h2 && keys_equal(keys_->items_[kv_index], key)) {
332
0
        return slot;
333
0
      }
334
22
    }
335
336
99
    if (kv_index == kEmptyEntry) {
337
77
      if (open_slot != -1) {
338
0
        slot = open_slot;
339
0
      }
340
      // If there isn't room in the entry arrays, tell the caller to resize.
341
77
      return len_ < capacity_ ? slot : kTooSmall;
342
77
    }
343
344
    // Tombstone or collided keys unequal. Keep scanning.
345
22
    DCHECK(kv_index >= 0 || kv_index == kDeletedEntry);
346
22
    if (kv_index == kDeletedEntry && open_slot == -1) {
347
      // NOTE: We only record the open slot here. We DON'T return it. If we're
348
      // looking for a key that was writen before this tombstone was written to
349
      // the index we should continue probing until we get to that key. If we
350
      // get to an empty index slot or the end of the index then we know we are
351
      // dealing with a new key and can safely replace the tombstone without
352
      // disrupting any existing keys.
353
0
      open_slot = slot;
354
0
    }
355
22
  }
356
357
0
  if (open_slot != -1) {
358
0
    return len_ < capacity_ ? open_slot : kTooSmall;
359
0
  }
360
361
0
  return kTooSmall;
362
0
}
_ZNK4DictIP6BigStrPN4args7_ActionEE14hash_and_probeES1_
Line
Count
Source
306
76
int Dict<K, V>::hash_and_probe(K key) const {
307
76
  if (capacity_ == 0) {
308
2
    return kTooSmall;
309
2
  }
310
311
  // Hash the key onto a slot in the index. If the first slot is occupied,
312
  // probe until an empty one is found.
313
74
  unsigned h = hash_key(key);
314
  // faster % using & -- assuming index_len_ is power of 2
315
74
  int init_bucket = h & (index_len_ - 1);
316
317
  // If we see a tombstone along the probing path, stash it.
318
74
  int open_slot = -1;
319
320
120
  for (int i = 0; i < index_len_; ++i) {
321
    // Start at init_bucket and wrap araound
322
323
    // faster % using & -- assuming index_len_ is power of 2
324
120
    int slot = (i + init_bucket) & (index_len_ - 1);
325
326
120
    int kv_index = index_->items_[slot];
327
120
    DCHECK(kv_index < len_);
328
    // Optimistically this is the common case once the table has been populated.
329
120
    if (kv_index >= 0) {
330
46
      unsigned h2 = hash_key(keys_->items_[kv_index]);
331
46
      if (h == h2 && keys_equal(keys_->items_[kv_index], key)) {
332
0
        return slot;
333
0
      }
334
46
    }
335
336
120
    if (kv_index == kEmptyEntry) {
337
74
      if (open_slot != -1) {
338
0
        slot = open_slot;
339
0
      }
340
      // If there isn't room in the entry arrays, tell the caller to resize.
341
74
      return len_ < capacity_ ? slot : kTooSmall;
342
74
    }
343
344
    // Tombstone or collided keys unequal. Keep scanning.
345
46
    DCHECK(kv_index >= 0 || kv_index == kDeletedEntry);
346
46
    if (kv_index == kDeletedEntry && open_slot == -1) {
347
      // NOTE: We only record the open slot here. We DON'T return it. If we're
348
      // looking for a key that was writen before this tombstone was written to
349
      // the index we should continue probing until we get to that key. If we
350
      // get to an empty index slot or the end of the index then we know we are
351
      // dealing with a new key and can safely replace the tombstone without
352
      // disrupting any existing keys.
353
0
      open_slot = slot;
354
0
    }
355
46
  }
356
357
0
  if (open_slot != -1) {
358
0
    return len_ < capacity_ ? open_slot : kTooSmall;
359
0
  }
360
361
0
  return kTooSmall;
362
0
}
363
364
template <typename K, typename V>
365
16.2k
int Dict<K, V>::find_kv_index(K key) const {
366
16.2k
  if (index_ != nullptr) {  // Common case
367
16.2k
    int pos = hash_and_probe(key);
368
16.2k
    if (pos == kTooSmall) {
369
0
      return kNotFound;
370
0
    }
371
16.2k
    DCHECK(pos >= 0);
372
0
    int kv_index = index_->items_[pos];
373
16.2k
    if (kv_index < 0) {
374
38
      return kNotFound;
375
38
    }
376
16.2k
    return kv_index;
377
16.2k
  }
378
379
  // Linear search on GlobalDict instances.
380
  // TODO: Should we populate and compare their hash values?
381
40
  for (int i = 0; i < len_; ++i) {
382
25
    if (keys_equal(keys_->items_[i], key)) {
383
15
      return i;
384
15
    }
385
25
  }
386
387
15
  return kNotFound;
388
30
}
_ZNK4DictIP6BigStriE13find_kv_indexES1_
Line
Count
Source
365
24
int Dict<K, V>::find_kv_index(K key) const {
366
24
  if (index_ != nullptr) {  // Common case
367
23
    int pos = hash_and_probe(key);
368
23
    if (pos == kTooSmall) {
369
0
      return kNotFound;
370
0
    }
371
23
    DCHECK(pos >= 0);
372
0
    int kv_index = index_->items_[pos];
373
23
    if (kv_index < 0) {
374
2
      return kNotFound;
375
2
    }
376
21
    return kv_index;
377
23
  }
378
379
  // Linear search on GlobalDict instances.
380
  // TODO: Should we populate and compare their hash values?
381
1
  for (int i = 0; i < len_; ++i) {
382
1
    if (keys_equal(keys_->items_[i], key)) {
383
1
      return i;
384
1
    }
385
1
  }
386
387
0
  return kNotFound;
388
1
}
_ZNK4DictIiP6BigStrE13find_kv_indexEi
Line
Count
Source
365
15
int Dict<K, V>::find_kv_index(K key) const {
366
15
  if (index_ != nullptr) {  // Common case
367
14
    int pos = hash_and_probe(key);
368
14
    if (pos == kTooSmall) {
369
0
      return kNotFound;
370
0
    }
371
14
    DCHECK(pos >= 0);
372
0
    int kv_index = index_->items_[pos];
373
14
    if (kv_index < 0) {
374
4
      return kNotFound;
375
4
    }
376
10
    return kv_index;
377
14
  }
378
379
  // Linear search on GlobalDict instances.
380
  // TODO: Should we populate and compare their hash values?
381
1
  for (int i = 0; i < len_; ++i) {
382
1
    if (keys_equal(keys_->items_[i], key)) {
383
1
      return i;
384
1
    }
385
1
  }
386
387
0
  return kNotFound;
388
1
}
_ZNK4DictIP6BigStrS1_E13find_kv_indexES1_
Line
Count
Source
365
19
int Dict<K, V>::find_kv_index(K key) const {
366
19
  if (index_ != nullptr) {  // Common case
367
4
    int pos = hash_and_probe(key);
368
4
    if (pos == kTooSmall) {
369
0
      return kNotFound;
370
0
    }
371
4
    DCHECK(pos >= 0);
372
0
    int kv_index = index_->items_[pos];
373
4
    if (kv_index < 0) {
374
0
      return kNotFound;
375
0
    }
376
4
    return kv_index;
377
4
  }
378
379
  // Linear search on GlobalDict instances.
380
  // TODO: Should we populate and compare their hash values?
381
23
  for (int i = 0; i < len_; ++i) {
382
17
    if (keys_equal(keys_->items_[i], key)) {
383
9
      return i;
384
9
    }
385
17
  }
386
387
6
  return kNotFound;
388
15
}
_ZNK4DictIibE13find_kv_indexEi
Line
Count
Source
365
37
int Dict<K, V>::find_kv_index(K key) const {
366
37
  if (index_ != nullptr) {  // Common case
367
28
    int pos = hash_and_probe(key);
368
28
    if (pos == kTooSmall) {
369
0
      return kNotFound;
370
0
    }
371
28
    DCHECK(pos >= 0);
372
0
    int kv_index = index_->items_[pos];
373
28
    if (kv_index < 0) {
374
28
      return kNotFound;
375
28
    }
376
0
    return kv_index;
377
28
  }
378
379
  // Linear search on GlobalDict instances.
380
  // TODO: Should we populate and compare their hash values?
381
9
  for (int i = 0; i < len_; ++i) {
382
0
    if (keys_equal(keys_->items_[i], key)) {
383
0
      return i;
384
0
    }
385
0
  }
386
387
9
  return kNotFound;
388
9
}
_ZNK4DictIiiE13find_kv_indexEi
Line
Count
Source
365
16.1k
int Dict<K, V>::find_kv_index(K key) const {
366
16.1k
  if (index_ != nullptr) {  // Common case
367
16.1k
    int pos = hash_and_probe(key);
368
16.1k
    if (pos == kTooSmall) {
369
0
      return kNotFound;
370
0
    }
371
16.1k
    DCHECK(pos >= 0);
372
0
    int kv_index = index_->items_[pos];
373
16.1k
    if (kv_index < 0) {
374
4
      return kNotFound;
375
4
    }
376
16.1k
    return kv_index;
377
16.1k
  }
378
379
  // Linear search on GlobalDict instances.
380
  // TODO: Should we populate and compare their hash values?
381
6
  for (int i = 0; i < len_; ++i) {
382
6
    if (keys_equal(keys_->items_[i], key)) {
383
4
      return i;
384
4
    }
385
6
  }
386
387
0
  return kNotFound;
388
4
}
_ZNK4DictIP6Tuple2IiiEiE13find_kv_indexES2_
Line
Count
Source
365
4
int Dict<K, V>::find_kv_index(K key) const {
366
4
  if (index_ != nullptr) {  // Common case
367
4
    int pos = hash_and_probe(key);
368
4
    if (pos == kTooSmall) {
369
0
      return kNotFound;
370
0
    }
371
4
    DCHECK(pos >= 0);
372
0
    int kv_index = index_->items_[pos];
373
4
    if (kv_index < 0) {
374
0
      return kNotFound;
375
0
    }
376
4
    return kv_index;
377
4
  }
378
379
  // Linear search on GlobalDict instances.
380
  // TODO: Should we populate and compare their hash values?
381
0
  for (int i = 0; i < len_; ++i) {
382
0
    if (keys_equal(keys_->items_[i], key)) {
383
0
      return i;
384
0
    }
385
0
  }
386
387
0
  return kNotFound;
388
0
}
_ZNK4DictIP6Tuple2IP6BigStriEiE13find_kv_indexES4_
Line
Count
Source
365
4
int Dict<K, V>::find_kv_index(K key) const {
366
4
  if (index_ != nullptr) {  // Common case
367
4
    int pos = hash_and_probe(key);
368
4
    if (pos == kTooSmall) {
369
0
      return kNotFound;
370
0
    }
371
4
    DCHECK(pos >= 0);
372
0
    int kv_index = index_->items_[pos];
373
4
    if (kv_index < 0) {
374
0
      return kNotFound;
375
0
    }
376
4
    return kv_index;
377
4
  }
378
379
  // Linear search on GlobalDict instances.
380
  // TODO: Should we populate and compare their hash values?
381
0
  for (int i = 0; i < len_; ++i) {
382
0
    if (keys_equal(keys_->items_[i], key)) {
383
0
      return i;
384
0
    }
385
0
  }
386
387
0
  return kNotFound;
388
0
}
Unexecuted instantiation: _ZNK4DictIP6BigStrPN10value_asdl7value_tEE13find_kv_indexES1_
Unexecuted instantiation: _ZNK4DictIP6BigStrPN4args7_ActionEE13find_kv_indexES1_
389
390
template <typename K, typename V>
391
17.3k
void Dict<K, V>::set(K key, V val) {
392
17.3k
  DCHECK(obj_header().heap_tag != HeapTag::Global);
393
0
  int pos = hash_and_probe(key);
394
17.3k
  if (pos == kTooSmall) {
395
114
    reserve(len_ + 1);
396
114
    pos = hash_and_probe(key);
397
114
  }
398
17.3k
  DCHECK(pos >= 0);
399
400
0
  int kv_index = index_->items_[pos];
401
17.3k
  DCHECK(kv_index < len_);
402
17.3k
  if (kv_index < 0) {
403
    // Write new entries to the end of the k/v arrays. This allows us to recall
404
    // insertion order until the first deletion.
405
1.46k
    keys_->items_[len_] = key;
406
1.46k
    values_->items_[len_] = val;
407
1.46k
    index_->items_[pos] = len_;
408
1.46k
    len_++;
409
1.46k
    DCHECK(len_ <= capacity_);
410
15.8k
  } else {
411
15.8k
    values_->items_[kv_index] = val;
412
15.8k
  }
413
17.3k
}
_ZN4DictIP6BigStriE3setES1_i
Line
Count
Source
391
326
void Dict<K, V>::set(K key, V val) {
392
326
  DCHECK(obj_header().heap_tag != HeapTag::Global);
393
0
  int pos = hash_and_probe(key);
394
326
  if (pos == kTooSmall) {
395
36
    reserve(len_ + 1);
396
36
    pos = hash_and_probe(key);
397
36
  }
398
326
  DCHECK(pos >= 0);
399
400
0
  int kv_index = index_->items_[pos];
401
326
  DCHECK(kv_index < len_);
402
326
  if (kv_index < 0) {
403
    // Write new entries to the end of the k/v arrays. This allows us to recall
404
    // insertion order until the first deletion.
405
325
    keys_->items_[len_] = key;
406
325
    values_->items_[len_] = val;
407
325
    index_->items_[pos] = len_;
408
325
    len_++;
409
325
    DCHECK(len_ <= capacity_);
410
325
  } else {
411
1
    values_->items_[kv_index] = val;
412
1
  }
413
326
}
_ZN4DictIibE3setEib
Line
Count
Source
391
37
void Dict<K, V>::set(K key, V val) {
392
37
  DCHECK(obj_header().heap_tag != HeapTag::Global);
393
0
  int pos = hash_and_probe(key);
394
37
  if (pos == kTooSmall) {
395
9
    reserve(len_ + 1);
396
9
    pos = hash_and_probe(key);
397
9
  }
398
37
  DCHECK(pos >= 0);
399
400
0
  int kv_index = index_->items_[pos];
401
37
  DCHECK(kv_index < len_);
402
37
  if (kv_index < 0) {
403
    // Write new entries to the end of the k/v arrays. This allows us to recall
404
    // insertion order until the first deletion.
405
37
    keys_->items_[len_] = key;
406
37
    values_->items_[len_] = val;
407
37
    index_->items_[pos] = len_;
408
37
    len_++;
409
37
    DCHECK(len_ <= capacity_);
410
37
  } else {
411
0
    values_->items_[kv_index] = val;
412
0
  }
413
37
}
_ZN4DictIP6BigStrS1_E3setES1_S1_
Line
Count
Source
391
96
void Dict<K, V>::set(K key, V val) {
392
96
  DCHECK(obj_header().heap_tag != HeapTag::Global);
393
0
  int pos = hash_and_probe(key);
394
96
  if (pos == kTooSmall) {
395
10
    reserve(len_ + 1);
396
10
    pos = hash_and_probe(key);
397
10
  }
398
96
  DCHECK(pos >= 0);
399
400
0
  int kv_index = index_->items_[pos];
401
96
  DCHECK(kv_index < len_);
402
96
  if (kv_index < 0) {
403
    // Write new entries to the end of the k/v arrays. This allows us to recall
404
    // insertion order until the first deletion.
405
96
    keys_->items_[len_] = key;
406
96
    values_->items_[len_] = val;
407
96
    index_->items_[pos] = len_;
408
96
    len_++;
409
96
    DCHECK(len_ <= capacity_);
410
96
  } else {
411
0
    values_->items_[kv_index] = val;
412
0
  }
413
96
}
_ZN4DictIiP6BigStrE3setEiS1_
Line
Count
Source
391
30
void Dict<K, V>::set(K key, V val) {
392
30
  DCHECK(obj_header().heap_tag != HeapTag::Global);
393
0
  int pos = hash_and_probe(key);
394
30
  if (pos == kTooSmall) {
395
12
    reserve(len_ + 1);
396
12
    pos = hash_and_probe(key);
397
12
  }
398
30
  DCHECK(pos >= 0);
399
400
0
  int kv_index = index_->items_[pos];
401
30
  DCHECK(kv_index < len_);
402
30
  if (kv_index < 0) {
403
    // Write new entries to the end of the k/v arrays. This allows us to recall
404
    // insertion order until the first deletion.
405
30
    keys_->items_[len_] = key;
406
30
    values_->items_[len_] = val;
407
30
    index_->items_[pos] = len_;
408
30
    len_++;
409
30
    DCHECK(len_ <= capacity_);
410
30
  } else {
411
0
    values_->items_[kv_index] = val;
412
0
  }
413
30
}
_ZN4DictIiiE3setEii
Line
Count
Source
391
16.7k
void Dict<K, V>::set(K key, V val) {
392
16.7k
  DCHECK(obj_header().heap_tag != HeapTag::Global);
393
0
  int pos = hash_and_probe(key);
394
16.7k
  if (pos == kTooSmall) {
395
28
    reserve(len_ + 1);
396
28
    pos = hash_and_probe(key);
397
28
  }
398
16.7k
  DCHECK(pos >= 0);
399
400
0
  int kv_index = index_->items_[pos];
401
16.7k
  DCHECK(kv_index < len_);
402
16.7k
  if (kv_index < 0) {
403
    // Write new entries to the end of the k/v arrays. This allows us to recall
404
    // insertion order until the first deletion.
405
826
    keys_->items_[len_] = key;
406
826
    values_->items_[len_] = val;
407
826
    index_->items_[pos] = len_;
408
826
    len_++;
409
826
    DCHECK(len_ <= capacity_);
410
15.8k
  } else {
411
15.8k
    values_->items_[kv_index] = val;
412
15.8k
  }
413
16.7k
}
_ZN4DictIP6Tuple2IiiEiE3setES2_i
Line
Count
Source
391
4
void Dict<K, V>::set(K key, V val) {
392
4
  DCHECK(obj_header().heap_tag != HeapTag::Global);
393
0
  int pos = hash_and_probe(key);
394
4
  if (pos == kTooSmall) {
395
2
    reserve(len_ + 1);
396
2
    pos = hash_and_probe(key);
397
2
  }
398
4
  DCHECK(pos >= 0);
399
400
0
  int kv_index = index_->items_[pos];
401
4
  DCHECK(kv_index < len_);
402
4
  if (kv_index < 0) {
403
    // Write new entries to the end of the k/v arrays. This allows us to recall
404
    // insertion order until the first deletion.
405
4
    keys_->items_[len_] = key;
406
4
    values_->items_[len_] = val;
407
4
    index_->items_[pos] = len_;
408
4
    len_++;
409
4
    DCHECK(len_ <= capacity_);
410
4
  } else {
411
0
    values_->items_[kv_index] = val;
412
0
  }
413
4
}
_ZN4DictIP6Tuple2IP6BigStriEiE3setES4_i
Line
Count
Source
391
4
void Dict<K, V>::set(K key, V val) {
392
4
  DCHECK(obj_header().heap_tag != HeapTag::Global);
393
0
  int pos = hash_and_probe(key);
394
4
  if (pos == kTooSmall) {
395
2
    reserve(len_ + 1);
396
2
    pos = hash_and_probe(key);
397
2
  }
398
4
  DCHECK(pos >= 0);
399
400
0
  int kv_index = index_->items_[pos];
401
4
  DCHECK(kv_index < len_);
402
4
  if (kv_index < 0) {
403
    // Write new entries to the end of the k/v arrays. This allows us to recall
404
    // insertion order until the first deletion.
405
4
    keys_->items_[len_] = key;
406
4
    values_->items_[len_] = val;
407
4
    index_->items_[pos] = len_;
408
4
    len_++;
409
4
    DCHECK(len_ <= capacity_);
410
4
  } else {
411
0
    values_->items_[kv_index] = val;
412
0
  }
413
4
}
Unexecuted instantiation: _ZN4DictIiP6Tuple2IP4ListIPS1_IPS0_IiiEEEPS_IiiEEE3setEiSB_
_ZN4DictIP6BigStrPN10value_asdl7value_tEE3setES1_S4_
Line
Count
Source
391
72
void Dict<K, V>::set(K key, V val) {
392
72
  DCHECK(obj_header().heap_tag != HeapTag::Global);
393
0
  int pos = hash_and_probe(key);
394
72
  if (pos == kTooSmall) {
395
8
    reserve(len_ + 1);
396
8
    pos = hash_and_probe(key);
397
8
  }
398
72
  DCHECK(pos >= 0);
399
400
0
  int kv_index = index_->items_[pos];
401
72
  DCHECK(kv_index < len_);
402
72
  if (kv_index < 0) {
403
    // Write new entries to the end of the k/v arrays. This allows us to recall
404
    // insertion order until the first deletion.
405
72
    keys_->items_[len_] = key;
406
72
    values_->items_[len_] = val;
407
72
    index_->items_[pos] = len_;
408
72
    len_++;
409
72
    DCHECK(len_ <= capacity_);
410
72
  } else {
411
0
    values_->items_[kv_index] = val;
412
0
  }
413
72
}
_ZN4DictIP6BigStrPN4args7_ActionEE3setES1_S4_
Line
Count
Source
391
69
void Dict<K, V>::set(K key, V val) {
392
69
  DCHECK(obj_header().heap_tag != HeapTag::Global);
393
0
  int pos = hash_and_probe(key);
394
69
  if (pos == kTooSmall) {
395
7
    reserve(len_ + 1);
396
7
    pos = hash_and_probe(key);
397
7
  }
398
69
  DCHECK(pos >= 0);
399
400
0
  int kv_index = index_->items_[pos];
401
69
  DCHECK(kv_index < len_);
402
69
  if (kv_index < 0) {
403
    // Write new entries to the end of the k/v arrays. This allows us to recall
404
    // insertion order until the first deletion.
405
69
    keys_->items_[len_] = key;
406
69
    values_->items_[len_] = val;
407
69
    index_->items_[pos] = len_;
408
69
    len_++;
409
69
    DCHECK(len_ <= capacity_);
410
69
  } else {
411
0
    values_->items_[kv_index] = val;
412
0
  }
413
69
}
414
415
template <typename K, typename V>
416
53
inline int len(const Dict<K, V>* d) {
417
53
  return d->len_;
418
53
}
_Z3lenIP6BigStrS1_EiPK4DictIT_T0_E
Line
Count
Source
416
13
inline int len(const Dict<K, V>* d) {
417
13
  return d->len_;
418
13
}
_Z3lenIP6BigStriEiPK4DictIT_T0_E
Line
Count
Source
416
19
inline int len(const Dict<K, V>* d) {
417
19
  return d->len_;
418
19
}
_Z3lenIiP6BigStrEiPK4DictIT_T0_E
Line
Count
Source
416
7
inline int len(const Dict<K, V>* d) {
417
7
  return d->len_;
418
7
}
_Z3lenIiiEiPK4DictIT_T0_E
Line
Count
Source
416
14
inline int len(const Dict<K, V>* d) {
417
14
  return d->len_;
418
14
}
Unexecuted instantiation: _Z3lenIP6BigStrPN4args7_ActionEEiPK4DictIT_T0_E
419
420
template <class K, class V>
421
class DictIter {
422
 public:
423
11
  explicit DictIter(Dict<K, V>* D) : D_(D), pos_(0) {
424
11
  }
_ZN8DictIterIP6BigStriEC2EP4DictIS1_iE
Line
Count
Source
423
9
  explicit DictIter(Dict<K, V>* D) : D_(D), pos_(0) {
424
9
  }
Unexecuted instantiation: _ZN8DictIterIP6BigStrPN10value_asdl7value_tEEC2EP4DictIS1_S4_E
Unexecuted instantiation: _ZN8DictIterIP6BigStrPN12runtime_asdl7HayNodeEEC2EP4DictIS1_S4_E
_ZN8DictIterIP6BigStrS1_EC2EP4DictIS1_S1_E
Line
Count
Source
423
2
  explicit DictIter(Dict<K, V>* D) : D_(D), pos_(0) {
424
2
  }
Unexecuted instantiation: _ZN8DictIterIP6BigStrPN12runtime_asdl4CellEEC2EP4DictIS1_S4_E
425
17
  void Next() {
426
17
    pos_++;
427
17
  }
_ZN8DictIterIP6BigStriE4NextEv
Line
Count
Source
425
17
  void Next() {
426
17
    pos_++;
427
17
  }
Unexecuted instantiation: _ZN8DictIterIP6BigStrPN10value_asdl7value_tEE4NextEv
Unexecuted instantiation: _ZN8DictIterIP6BigStrPN12runtime_asdl7HayNodeEE4NextEv
Unexecuted instantiation: _ZN8DictIterIP6BigStrS1_E4NextEv
Unexecuted instantiation: _ZN8DictIterIP6BigStrPN12runtime_asdl4CellEE4NextEv
428
28
  bool Done() {
429
28
    return pos_ == D_->len_;
430
28
  }
_ZN8DictIterIP6BigStriE4DoneEv
Line
Count
Source
428
26
  bool Done() {
429
26
    return pos_ == D_->len_;
430
26
  }
Unexecuted instantiation: _ZN8DictIterIP6BigStrPN10value_asdl7value_tEE4DoneEv
Unexecuted instantiation: _ZN8DictIterIP6BigStrPN12runtime_asdl7HayNodeEE4DoneEv
_ZN8DictIterIP6BigStrS1_E4DoneEv
Line
Count
Source
428
2
  bool Done() {
429
2
    return pos_ == D_->len_;
430
2
  }
Unexecuted instantiation: _ZN8DictIterIP6BigStrPN12runtime_asdl4CellEE4DoneEv
431
17
  K Key() {
432
17
    return D_->keys_->items_[pos_];
433
17
  }
_ZN8DictIterIP6BigStriE3KeyEv
Line
Count
Source
431
17
  K Key() {
432
17
    return D_->keys_->items_[pos_];
433
17
  }
Unexecuted instantiation: _ZN8DictIterIP6BigStrPN10value_asdl7value_tEE3KeyEv
Unexecuted instantiation: _ZN8DictIterIP6BigStrPN12runtime_asdl7HayNodeEE3KeyEv
Unexecuted instantiation: _ZN8DictIterIP6BigStrS1_E3KeyEv
Unexecuted instantiation: _ZN8DictIterIP6BigStrPN12runtime_asdl4CellEE3KeyEv
434
10
  V Value() {
435
10
    return D_->values_->items_[pos_];
436
10
  }
_ZN8DictIterIP6BigStriE5ValueEv
Line
Count
Source
434
10
  V Value() {
435
10
    return D_->values_->items_[pos_];
436
10
  }
Unexecuted instantiation: _ZN8DictIterIP6BigStrPN10value_asdl7value_tEE5ValueEv
Unexecuted instantiation: _ZN8DictIterIP6BigStrPN12runtime_asdl7HayNodeEE5ValueEv
Unexecuted instantiation: _ZN8DictIterIP6BigStrS1_E5ValueEv
Unexecuted instantiation: _ZN8DictIterIP6BigStrPN12runtime_asdl4CellEE5ValueEv
437
438
 private:
439
  const Dict<K, V>* D_;
440
  int pos_;
441
};
442
443
// dict(mylist) converts a list of (k, v) tuples into a dict
444
template <typename K, typename V>
445
2
Dict<K, V>* dict(List<Tuple2<K, V>*>* l) {
446
2
  auto ret = Alloc<Dict<K, V>>();
447
2
  ret->reserve(len(l));
448
6
  for (ListIter<Tuple2<K, V>*> it(l); !it.Done(); it.Next()) {
449
4
    ret->set(it.Value()->at0(), it.Value()->at1());
450
4
  }
451
2
  return ret;
452
2
}
453
454
template <class K, class V>
455
2
void Dict<K, V>::update(List<Tuple2<K, V>*>* pairs) {
456
2
  reserve(len_ + len(pairs));
457
6
  for (ListIter<Tuple2<K, V>*> it(pairs); !it.Done(); it.Next()) {
458
4
    set(it.Value()->at0(), it.Value()->at1());
459
4
  }
460
2
}
461
462
template <class K, class V>
463
void Dict<K, V>::update(Dict<K, V>* other) {
464
  reserve(len_ + len(other));
465
  for (DictIter<K, V> it(other); !it.Done(); it.Next()) {
466
    set(it.Key(), it.Value());
467
  }
468
}
469
470
#endif  // MYCPP_GC_DICT_H