Branch data Line data Source code
1 : : /* Dictionary object implementation using a hash table */
2 : :
3 : : /* The distribution includes a separate file, Objects/dictnotes.txt,
4 : : describing explorations into dictionary design and optimization.
5 : : It covers typical dictionary use patterns, the parameters for
6 : : tuning dictionaries, and several ideas for possible optimizations.
7 : : */
8 : :
9 : : /* PyDictKeysObject
10 : :
11 : : This implements the dictionary's hashtable.
12 : :
13 : : As of Python 3.6, this is compact and ordered. Basic idea is described here:
14 : : * https://mail.python.org/pipermail/python-dev/2012-December/123028.html
15 : : * https://morepypy.blogspot.com/2015/01/faster-more-memory-efficient-and-more.html
16 : :
17 : : layout:
18 : :
19 : : +---------------------+
20 : : | dk_refcnt |
21 : : | dk_log2_size |
22 : : | dk_log2_index_bytes |
23 : : | dk_kind |
24 : : | dk_usable |
25 : : | dk_nentries |
26 : : +---------------------+
27 : : | dk_indices[] |
28 : : | |
29 : : +---------------------+
30 : : | dk_entries[] |
31 : : | |
32 : : +---------------------+
33 : :
34 : : dk_indices is actual hashtable. It holds index in entries, or DKIX_EMPTY(-1)
35 : : or DKIX_DUMMY(-2).
36 : : Size of indices is dk_size. Type of each index in indices is vary on dk_size:
37 : :
38 : : * int8 for dk_size <= 128
39 : : * int16 for 256 <= dk_size <= 2**15
40 : : * int32 for 2**16 <= dk_size <= 2**31
41 : : * int64 for 2**32 <= dk_size
42 : :
43 : : dk_entries is array of PyDictKeyEntry when dk_kind == DICT_KEYS_GENERAL or
44 : : PyDictUnicodeEntry otherwise. Its length is USABLE_FRACTION(dk_size).
45 : :
46 : : NOTE: Since negative value is used for DKIX_EMPTY and DKIX_DUMMY, type of
47 : : dk_indices entry is signed integer and int16 is used for table which
48 : : dk_size == 256.
49 : : */
50 : :
51 : :
52 : : /*
53 : : The DictObject can be in one of two forms.
54 : :
55 : : Either:
56 : : A combined table:
57 : : ma_values == NULL, dk_refcnt == 1.
58 : : Values are stored in the me_value field of the PyDictKeysObject.
59 : : Or:
60 : : A split table:
61 : : ma_values != NULL, dk_refcnt >= 1
62 : : Values are stored in the ma_values array.
63 : : Only string (unicode) keys are allowed.
64 : :
65 : : There are four kinds of slots in the table (slot is index, and
66 : : DK_ENTRIES(keys)[index] if index >= 0):
67 : :
68 : : 1. Unused. index == DKIX_EMPTY
69 : : Does not hold an active (key, value) pair now and never did. Unused can
70 : : transition to Active upon key insertion. This is each slot's initial state.
71 : :
72 : : 2. Active. index >= 0, me_key != NULL and me_value != NULL
73 : : Holds an active (key, value) pair. Active can transition to Dummy or
74 : : Pending upon key deletion (for combined and split tables respectively).
75 : : This is the only case in which me_value != NULL.
76 : :
77 : : 3. Dummy. index == DKIX_DUMMY (combined only)
78 : : Previously held an active (key, value) pair, but that was deleted and an
79 : : active pair has not yet overwritten the slot. Dummy can transition to
80 : : Active upon key insertion. Dummy slots cannot be made Unused again
81 : : else the probe sequence in case of collision would have no way to know
82 : : they were once active.
83 : :
84 : : 4. Pending. index >= 0, key != NULL, and value == NULL (split only)
85 : : Not yet inserted in split-table.
86 : : */
87 : :
88 : : /*
89 : : Preserving insertion order
90 : :
91 : : It's simple for combined table. Since dk_entries is mostly append only, we can
92 : : get insertion order by just iterating dk_entries.
93 : :
94 : : One exception is .popitem(). It removes last item in dk_entries and decrement
95 : : dk_nentries to achieve amortized O(1). Since there are DKIX_DUMMY remains in
96 : : dk_indices, we can't increment dk_usable even though dk_nentries is
97 : : decremented.
98 : :
99 : : To preserve the order in a split table, a bit vector is used to record the
100 : : insertion order. When a key is inserted the bit vector is shifted up by 4 bits
101 : : and the index of the key is stored in the low 4 bits.
102 : : As a consequence of this, split keys have a maximum size of 16.
103 : : */
104 : :
105 : : /* PyDict_MINSIZE is the starting size for any new dict.
106 : : * 8 allows dicts with no more than 5 active entries; experiments suggested
107 : : * this suffices for the majority of dicts (consisting mostly of usually-small
108 : : * dicts created to pass keyword arguments).
109 : : * Making this 8, rather than 4 reduces the number of resizes for most
110 : : * dictionaries, without any significant extra memory use.
111 : : */
112 : : #define PyDict_LOG_MINSIZE 3
113 : : #define PyDict_MINSIZE 8
114 : :
115 : : #include "Python.h"
116 : : #include "pycore_bitutils.h" // _Py_bit_length
117 : : #include "pycore_call.h" // _PyObject_CallNoArgs()
118 : : #include "pycore_code.h" // stats
119 : : #include "pycore_dict.h" // PyDictKeysObject
120 : : #include "pycore_gc.h" // _PyObject_GC_IS_TRACKED()
121 : : #include "pycore_object.h" // _PyObject_GC_TRACK()
122 : : #include "pycore_pyerrors.h" // _PyErr_GetRaisedException()
123 : : #include "pycore_pystate.h" // _PyThreadState_GET()
124 : : #include "stringlib/eq.h" // unicode_eq()
125 : :
126 : : #include <stdbool.h>
127 : :
128 : : /*[clinic input]
129 : : class dict "PyDictObject *" "&PyDict_Type"
130 : : [clinic start generated code]*/
131 : : /*[clinic end generated code: output=da39a3ee5e6b4b0d input=f157a5a0ce9589d6]*/
132 : :
133 : :
134 : : /*
135 : : To ensure the lookup algorithm terminates, there must be at least one Unused
136 : : slot (NULL key) in the table.
137 : : To avoid slowing down lookups on a near-full table, we resize the table when
138 : : it's USABLE_FRACTION (currently two-thirds) full.
139 : : */
140 : :
141 : : #define PERTURB_SHIFT 5
142 : :
143 : : /*
144 : : Major subtleties ahead: Most hash schemes depend on having a "good" hash
145 : : function, in the sense of simulating randomness. Python doesn't: its most
146 : : important hash functions (for ints) are very regular in common
147 : : cases:
148 : :
149 : : >>>[hash(i) for i in range(4)]
150 : : [0, 1, 2, 3]
151 : :
152 : : This isn't necessarily bad! To the contrary, in a table of size 2**i, taking
153 : : the low-order i bits as the initial table index is extremely fast, and there
154 : : are no collisions at all for dicts indexed by a contiguous range of ints. So
155 : : this gives better-than-random behavior in common cases, and that's very
156 : : desirable.
157 : :
158 : : OTOH, when collisions occur, the tendency to fill contiguous slices of the
159 : : hash table makes a good collision resolution strategy crucial. Taking only
160 : : the last i bits of the hash code is also vulnerable: for example, consider
161 : : the list [i << 16 for i in range(20000)] as a set of keys. Since ints are
162 : : their own hash codes, and this fits in a dict of size 2**15, the last 15 bits
163 : : of every hash code are all 0: they *all* map to the same table index.
164 : :
165 : : But catering to unusual cases should not slow the usual ones, so we just take
166 : : the last i bits anyway. It's up to collision resolution to do the rest. If
167 : : we *usually* find the key we're looking for on the first try (and, it turns
168 : : out, we usually do -- the table load factor is kept under 2/3, so the odds
169 : : are solidly in our favor), then it makes best sense to keep the initial index
170 : : computation dirt cheap.
171 : :
172 : : The first half of collision resolution is to visit table indices via this
173 : : recurrence:
174 : :
175 : : j = ((5*j) + 1) mod 2**i
176 : :
177 : : For any initial j in range(2**i), repeating that 2**i times generates each
178 : : int in range(2**i) exactly once (see any text on random-number generation for
179 : : proof). By itself, this doesn't help much: like linear probing (setting
180 : : j += 1, or j -= 1, on each loop trip), it scans the table entries in a fixed
181 : : order. This would be bad, except that's not the only thing we do, and it's
182 : : actually *good* in the common cases where hash keys are consecutive. In an
183 : : example that's really too small to make this entirely clear, for a table of
184 : : size 2**3 the order of indices is:
185 : :
186 : : 0 -> 1 -> 6 -> 7 -> 4 -> 5 -> 2 -> 3 -> 0 [and here it's repeating]
187 : :
188 : : If two things come in at index 5, the first place we look after is index 2,
189 : : not 6, so if another comes in at index 6 the collision at 5 didn't hurt it.
190 : : Linear probing is deadly in this case because there the fixed probe order
191 : : is the *same* as the order consecutive keys are likely to arrive. But it's
192 : : extremely unlikely hash codes will follow a 5*j+1 recurrence by accident,
193 : : and certain that consecutive hash codes do not.
194 : :
195 : : The other half of the strategy is to get the other bits of the hash code
196 : : into play. This is done by initializing a (unsigned) vrbl "perturb" to the
197 : : full hash code, and changing the recurrence to:
198 : :
199 : : perturb >>= PERTURB_SHIFT;
200 : : j = (5*j) + 1 + perturb;
201 : : use j % 2**i as the next table index;
202 : :
203 : : Now the probe sequence depends (eventually) on every bit in the hash code,
204 : : and the pseudo-scrambling property of recurring on 5*j+1 is more valuable,
205 : : because it quickly magnifies small differences in the bits that didn't affect
206 : : the initial index. Note that because perturb is unsigned, if the recurrence
207 : : is executed often enough perturb eventually becomes and remains 0. At that
208 : : point (very rarely reached) the recurrence is on (just) 5*j+1 again, and
209 : : that's certain to find an empty slot eventually (since it generates every int
210 : : in range(2**i), and we make sure there's always at least one empty slot).
211 : :
212 : : Selecting a good value for PERTURB_SHIFT is a balancing act. You want it
213 : : small so that the high bits of the hash code continue to affect the probe
214 : : sequence across iterations; but you want it large so that in really bad cases
215 : : the high-order hash bits have an effect on early iterations. 5 was "the
216 : : best" in minimizing total collisions across experiments Tim Peters ran (on
217 : : both normal and pathological cases), but 4 and 6 weren't significantly worse.
218 : :
219 : : Historical: Reimer Behrends contributed the idea of using a polynomial-based
220 : : approach, using repeated multiplication by x in GF(2**n) where an irreducible
221 : : polynomial for each table size was chosen such that x was a primitive root.
222 : : Christian Tismer later extended that to use division by x instead, as an
223 : : efficient way to get the high bits of the hash code into play. This scheme
224 : : also gave excellent collision statistics, but was more expensive: two
225 : : if-tests were required inside the loop; computing "the next" index took about
226 : : the same number of operations but without as much potential parallelism
227 : : (e.g., computing 5*j can go on at the same time as computing 1+perturb in the
228 : : above, and then shifting perturb can be done while the table index is being
229 : : masked); and the PyDictObject struct required a member to hold the table's
230 : : polynomial. In Tim's experiments the current scheme ran faster, produced
231 : : equally good collision statistics, needed less code & used less memory.
232 : :
233 : : */
234 : :
235 : : static int dictresize(PyInterpreterState *interp, PyDictObject *mp,
236 : : uint8_t log_newsize, int unicode);
237 : :
238 : : static PyObject* dict_iter(PyDictObject *dict);
239 : :
240 : : #include "clinic/dictobject.c.h"
241 : :
242 : :
243 : : #if PyDict_MAXFREELIST > 0
244 : : static struct _Py_dict_state *
245 : 3535921 : get_dict_state(PyInterpreterState *interp)
246 : : {
247 : 3535921 : return &interp->dict_state;
248 : : }
249 : : #endif
250 : :
251 : :
252 : : void
253 : 137 : _PyDict_ClearFreeList(PyInterpreterState *interp)
254 : : {
255 : : #if PyDict_MAXFREELIST > 0
256 : 137 : struct _Py_dict_state *state = &interp->dict_state;
257 [ + + ]: 9102 : while (state->numfree) {
258 : 8965 : PyDictObject *op = state->free_list[--state->numfree];
259 : : assert(PyDict_CheckExact(op));
260 : 8965 : PyObject_GC_Del(op);
261 : : }
262 [ + + ]: 8950 : while (state->keys_numfree) {
263 : 8813 : PyObject_Free(state->keys_free_list[--state->keys_numfree]);
264 : : }
265 : : #endif
266 : 137 : }
267 : :
268 : :
269 : : void
270 : 25 : _PyDict_Fini(PyInterpreterState *interp)
271 : : {
272 : 25 : _PyDict_ClearFreeList(interp);
273 : : #if defined(Py_DEBUG) && PyDict_MAXFREELIST > 0
274 : : struct _Py_dict_state *state = &interp->dict_state;
275 : : state->numfree = -1;
276 : : state->keys_numfree = -1;
277 : : #endif
278 : 25 : }
279 : :
280 : : static inline Py_hash_t
281 : 18883179 : unicode_get_hash(PyObject *o)
282 : : {
283 : : assert(PyUnicode_CheckExact(o));
284 : 18883179 : return _PyASCIIObject_CAST(o)->hash;
285 : : }
286 : :
287 : : /* Print summary info about the state of the optimized allocator */
288 : : void
289 : 0 : _PyDict_DebugMallocStats(FILE *out)
290 : : {
291 : : #if PyDict_MAXFREELIST > 0
292 : 0 : PyInterpreterState *interp = _PyInterpreterState_GET();
293 : 0 : struct _Py_dict_state *state = get_dict_state(interp);
294 : 0 : _PyDebugAllocatorStats(out, "free PyDictObject",
295 : : state->numfree, sizeof(PyDictObject));
296 : : #endif
297 : 0 : }
298 : :
299 : : #define DK_MASK(dk) (DK_SIZE(dk)-1)
300 : :
301 : : static void free_keys_object(PyInterpreterState *interp, PyDictKeysObject *keys);
302 : :
303 : : static inline void
304 : 745160 : dictkeys_incref(PyDictKeysObject *dk)
305 : : {
306 : : #ifdef Py_REF_DEBUG
307 : : _Py_IncRefTotal();
308 : : #endif
309 : 745160 : dk->dk_refcnt++;
310 : 745160 : }
311 : :
312 : : static inline void
313 : 1319832 : dictkeys_decref(PyInterpreterState *interp, PyDictKeysObject *dk)
314 : : {
315 : : assert(dk->dk_refcnt > 0);
316 : : #ifdef Py_REF_DEBUG
317 : : _Py_DecRefTotal();
318 : : #endif
319 [ + + ]: 1319832 : if (--dk->dk_refcnt == 0) {
320 : 576632 : free_keys_object(interp, dk);
321 : : }
322 : 1319832 : }
323 : :
324 : : /* lookup indices. returns DKIX_EMPTY, DKIX_DUMMY, or ix >=0 */
325 : : static inline Py_ssize_t
326 : 25872714 : dictkeys_get_index(const PyDictKeysObject *keys, Py_ssize_t i)
327 : : {
328 : 25872714 : int log2size = DK_LOG_SIZE(keys);
329 : : Py_ssize_t ix;
330 : :
331 [ + + ]: 25872714 : if (log2size < 8) {
332 : 23090746 : const int8_t *indices = (const int8_t*)(keys->dk_indices);
333 : 23090746 : ix = indices[i];
334 : : }
335 [ + - ]: 2781968 : else if (log2size < 16) {
336 : 2781968 : const int16_t *indices = (const int16_t*)(keys->dk_indices);
337 : 2781968 : ix = indices[i];
338 : : }
339 : : #if SIZEOF_VOID_P > 4
340 [ # # ]: 0 : else if (log2size >= 32) {
341 : 0 : const int64_t *indices = (const int64_t*)(keys->dk_indices);
342 : 0 : ix = indices[i];
343 : : }
344 : : #endif
345 : : else {
346 : 0 : const int32_t *indices = (const int32_t*)(keys->dk_indices);
347 : 0 : ix = indices[i];
348 : : }
349 : : assert(ix >= DKIX_DUMMY);
350 : 25872714 : return ix;
351 : : }
352 : :
353 : : /* write to indices. */
354 : : static inline void
355 : 6216532 : dictkeys_set_index(PyDictKeysObject *keys, Py_ssize_t i, Py_ssize_t ix)
356 : : {
357 : 6216532 : int log2size = DK_LOG_SIZE(keys);
358 : :
359 : : assert(ix >= DKIX_DUMMY);
360 : : assert(keys->dk_version == 0);
361 : :
362 [ + + ]: 6216532 : if (log2size < 8) {
363 : 5542218 : int8_t *indices = (int8_t*)(keys->dk_indices);
364 : : assert(ix <= 0x7f);
365 : 5542218 : indices[i] = (char)ix;
366 : : }
367 [ + - ]: 674314 : else if (log2size < 16) {
368 : 674314 : int16_t *indices = (int16_t*)(keys->dk_indices);
369 : : assert(ix <= 0x7fff);
370 : 674314 : indices[i] = (int16_t)ix;
371 : : }
372 : : #if SIZEOF_VOID_P > 4
373 [ # # ]: 0 : else if (log2size >= 32) {
374 : 0 : int64_t *indices = (int64_t*)(keys->dk_indices);
375 : 0 : indices[i] = ix;
376 : : }
377 : : #endif
378 : : else {
379 : 0 : int32_t *indices = (int32_t*)(keys->dk_indices);
380 : : assert(ix <= 0x7fffffff);
381 : 0 : indices[i] = (int32_t)ix;
382 : : }
383 : 6216532 : }
384 : :
385 : :
386 : : /* USABLE_FRACTION is the maximum dictionary load.
387 : : * Increasing this ratio makes dictionaries more dense resulting in more
388 : : * collisions. Decreasing it improves sparseness at the expense of spreading
389 : : * indices over more cache lines and at the cost of total memory consumed.
390 : : *
391 : : * USABLE_FRACTION must obey the following:
392 : : * (0 < USABLE_FRACTION(n) < n) for all n >= 2
393 : : *
394 : : * USABLE_FRACTION should be quick to calculate.
395 : : * Fractions around 1/2 to 2/3 seem to work well in practice.
396 : : */
397 : : #define USABLE_FRACTION(n) (((n) << 1)/3)
398 : :
399 : : /* Find the smallest dk_size >= minsize. */
400 : : static inline uint8_t
401 : 464552 : calculate_log2_keysize(Py_ssize_t minsize)
402 : : {
403 : : #if SIZEOF_LONG == SIZEOF_SIZE_T
404 : 464552 : minsize = (minsize | PyDict_MINSIZE) - 1;
405 : 464552 : return _Py_bit_length(minsize | (PyDict_MINSIZE-1));
406 : : #elif defined(_MSC_VER)
407 : : // On 64bit Windows, sizeof(long) == 4.
408 : : minsize = (minsize | PyDict_MINSIZE) - 1;
409 : : unsigned long msb;
410 : : _BitScanReverse64(&msb, (uint64_t)minsize);
411 : : return (uint8_t)(msb + 1);
412 : : #else
413 : : uint8_t log2_size;
414 : : for (log2_size = PyDict_LOG_MINSIZE;
415 : : (((Py_ssize_t)1) << log2_size) < minsize;
416 : : log2_size++)
417 : : ;
418 : : return log2_size;
419 : : #endif
420 : : }
421 : :
422 : : /* estimate_keysize is reverse function of USABLE_FRACTION.
423 : : *
424 : : * This can be used to reserve enough size to insert n entries without
425 : : * resizing.
426 : : */
427 : : static inline uint8_t
428 : 2106 : estimate_log2_keysize(Py_ssize_t n)
429 : : {
430 : 2106 : return calculate_log2_keysize((n*3 + 1) / 2);
431 : : }
432 : :
433 : :
434 : : /* GROWTH_RATE. Growth rate upon hitting maximum load.
435 : : * Currently set to used*3.
436 : : * This means that dicts double in size when growing without deletions,
437 : : * but have more head room when the number of deletions is on a par with the
438 : : * number of insertions. See also bpo-17563 and bpo-33205.
439 : : *
440 : : * GROWTH_RATE was set to used*4 up to version 3.2.
441 : : * GROWTH_RATE was set to used*2 in version 3.3.0
442 : : * GROWTH_RATE was set to used*2 + capacity/2 in 3.4.0-3.6.0.
443 : : */
444 : : #define GROWTH_RATE(d) ((d)->ma_used*3)
445 : :
446 : : /* This immutable, empty PyDictKeysObject is used for PyDict_Clear()
447 : : * (which cannot fail and thus can do no allocation).
448 : : */
449 : : static PyDictKeysObject empty_keys_struct = {
450 : : 1, /* dk_refcnt */
451 : : 0, /* dk_log2_size */
452 : : 0, /* dk_log2_index_bytes */
453 : : DICT_KEYS_UNICODE, /* dk_kind */
454 : : 1, /* dk_version */
455 : : 0, /* dk_usable (immutable) */
456 : : 0, /* dk_nentries */
457 : : {DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY,
458 : : DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY}, /* dk_indices */
459 : : };
460 : :
461 : : #define Py_EMPTY_KEYS &empty_keys_struct
462 : :
463 : : /* Uncomment to check the dict content in _PyDict_CheckConsistency() */
464 : : // #define DEBUG_PYDICT
465 : :
466 : : #ifdef DEBUG_PYDICT
467 : : # define ASSERT_CONSISTENT(op) assert(_PyDict_CheckConsistency((PyObject *)(op), 1))
468 : : #else
469 : : # define ASSERT_CONSISTENT(op) assert(_PyDict_CheckConsistency((PyObject *)(op), 0))
470 : : #endif
471 : :
472 : : static inline int
473 : 50010 : get_index_from_order(PyDictObject *mp, Py_ssize_t i)
474 : : {
475 : : assert(mp->ma_used <= SHARED_KEYS_MAX_SIZE);
476 : : assert(i < (((char *)mp->ma_values)[-2]));
477 : 50010 : return ((char *)mp->ma_values)[-3-i];
478 : : }
479 : :
480 : : #ifdef DEBUG_PYDICT
481 : : static void
482 : : dump_entries(PyDictKeysObject *dk)
483 : : {
484 : : for (Py_ssize_t i = 0; i < dk->dk_nentries; i++) {
485 : : if (DK_IS_UNICODE(dk)) {
486 : : PyDictUnicodeEntry *ep = &DK_UNICODE_ENTRIES(dk)[i];
487 : : printf("key=%p value=%p\n", ep->me_key, ep->me_value);
488 : : }
489 : : else {
490 : : PyDictKeyEntry *ep = &DK_ENTRIES(dk)[i];
491 : : printf("key=%p hash=%lx value=%p\n", ep->me_key, ep->me_hash, ep->me_value);
492 : : }
493 : : }
494 : : }
495 : : #endif
496 : :
497 : : int
498 : 0 : _PyDict_CheckConsistency(PyObject *op, int check_content)
499 : : {
500 : : #define CHECK(expr) \
501 : : do { if (!(expr)) { _PyObject_ASSERT_FAILED_MSG(op, Py_STRINGIFY(expr)); } } while (0)
502 : :
503 : : assert(op != NULL);
504 [ # # ]: 0 : CHECK(PyDict_Check(op));
505 : 0 : PyDictObject *mp = (PyDictObject *)op;
506 : :
507 : 0 : PyDictKeysObject *keys = mp->ma_keys;
508 : 0 : int splitted = _PyDict_HasSplitTable(mp);
509 : 0 : Py_ssize_t usable = USABLE_FRACTION(DK_SIZE(keys));
510 : :
511 [ # # # # ]: 0 : CHECK(0 <= mp->ma_used && mp->ma_used <= usable);
512 [ # # # # ]: 0 : CHECK(0 <= keys->dk_usable && keys->dk_usable <= usable);
513 [ # # # # ]: 0 : CHECK(0 <= keys->dk_nentries && keys->dk_nentries <= usable);
514 [ # # ]: 0 : CHECK(keys->dk_usable + keys->dk_nentries <= usable);
515 : :
516 [ # # ]: 0 : if (!splitted) {
517 : : /* combined table */
518 [ # # ]: 0 : CHECK(keys->dk_kind != DICT_KEYS_SPLIT);
519 [ # # # # ]: 0 : CHECK(keys->dk_refcnt == 1 || keys == Py_EMPTY_KEYS);
520 : : }
521 : : else {
522 [ # # ]: 0 : CHECK(keys->dk_kind == DICT_KEYS_SPLIT);
523 [ # # ]: 0 : CHECK(mp->ma_used <= SHARED_KEYS_MAX_SIZE);
524 : : }
525 : :
526 [ # # ]: 0 : if (check_content) {
527 [ # # ]: 0 : for (Py_ssize_t i=0; i < DK_SIZE(keys); i++) {
528 : 0 : Py_ssize_t ix = dictkeys_get_index(keys, i);
529 [ # # # # ]: 0 : CHECK(DKIX_DUMMY <= ix && ix <= usable);
530 : : }
531 : :
532 [ # # ]: 0 : if (keys->dk_kind == DICT_KEYS_GENERAL) {
533 : 0 : PyDictKeyEntry *entries = DK_ENTRIES(keys);
534 [ # # ]: 0 : for (Py_ssize_t i=0; i < usable; i++) {
535 : 0 : PyDictKeyEntry *entry = &entries[i];
536 : 0 : PyObject *key = entry->me_key;
537 : :
538 [ # # ]: 0 : if (key != NULL) {
539 : : /* test_dict fails if PyObject_Hash() is called again */
540 [ # # ]: 0 : CHECK(entry->me_hash != -1);
541 [ # # ]: 0 : CHECK(entry->me_value != NULL);
542 : :
543 [ # # ]: 0 : if (PyUnicode_CheckExact(key)) {
544 : 0 : Py_hash_t hash = unicode_get_hash(key);
545 [ # # ]: 0 : CHECK(entry->me_hash == hash);
546 : : }
547 : : }
548 : : }
549 : : }
550 : : else {
551 : 0 : PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(keys);
552 [ # # ]: 0 : for (Py_ssize_t i=0; i < usable; i++) {
553 : 0 : PyDictUnicodeEntry *entry = &entries[i];
554 : 0 : PyObject *key = entry->me_key;
555 : :
556 [ # # ]: 0 : if (key != NULL) {
557 [ # # ]: 0 : CHECK(PyUnicode_CheckExact(key));
558 : 0 : Py_hash_t hash = unicode_get_hash(key);
559 [ # # ]: 0 : CHECK(hash != -1);
560 [ # # ]: 0 : if (!splitted) {
561 [ # # ]: 0 : CHECK(entry->me_value != NULL);
562 : : }
563 : : }
564 : :
565 [ # # ]: 0 : if (splitted) {
566 [ # # ]: 0 : CHECK(entry->me_value == NULL);
567 : : }
568 : : }
569 : : }
570 : :
571 [ # # ]: 0 : if (splitted) {
572 [ # # ]: 0 : CHECK(mp->ma_used <= SHARED_KEYS_MAX_SIZE);
573 : : /* splitted table */
574 : 0 : int duplicate_check = 0;
575 [ # # ]: 0 : for (Py_ssize_t i=0; i < mp->ma_used; i++) {
576 : 0 : int index = get_index_from_order(mp, i);
577 [ # # ]: 0 : CHECK((duplicate_check & (1<<index)) == 0);
578 : 0 : duplicate_check |= (1<<index);
579 [ # # ]: 0 : CHECK(mp->ma_values->values[index] != NULL);
580 : : }
581 : : }
582 : : }
583 : 0 : return 1;
584 : :
585 : : #undef CHECK
586 : : }
587 : :
588 : :
589 : : static PyDictKeysObject*
590 : 998465 : new_keys_object(PyInterpreterState *interp, uint8_t log2_size, bool unicode)
591 : : {
592 : : PyDictKeysObject *dk;
593 : : Py_ssize_t usable;
594 : : int log2_bytes;
595 [ + + ]: 998465 : size_t entry_size = unicode ? sizeof(PyDictUnicodeEntry) : sizeof(PyDictKeyEntry);
596 : :
597 : : assert(log2_size >= PyDict_LOG_MINSIZE);
598 : :
599 : 998465 : usable = USABLE_FRACTION((size_t)1<<log2_size);
600 [ + + ]: 998465 : if (log2_size < 8) {
601 : 997291 : log2_bytes = log2_size;
602 : : }
603 [ + - ]: 1174 : else if (log2_size < 16) {
604 : 1174 : log2_bytes = log2_size + 1;
605 : : }
606 : : #if SIZEOF_VOID_P > 4
607 [ # # ]: 0 : else if (log2_size >= 32) {
608 : 0 : log2_bytes = log2_size + 3;
609 : : }
610 : : #endif
611 : : else {
612 : 0 : log2_bytes = log2_size + 2;
613 : : }
614 : :
615 : : #if PyDict_MAXFREELIST > 0
616 : 998465 : struct _Py_dict_state *state = get_dict_state(interp);
617 : : #ifdef Py_DEBUG
618 : : // new_keys_object() must not be called after _PyDict_Fini()
619 : : assert(state->keys_numfree != -1);
620 : : #endif
621 [ + + + + : 998465 : if (log2_size == PyDict_LOG_MINSIZE && unicode && state->keys_numfree > 0) {
+ + ]
622 : 504060 : dk = state->keys_free_list[--state->keys_numfree];
623 : 504060 : OBJECT_STAT_INC(from_freelist);
624 : : }
625 : : else
626 : : #endif
627 : : {
628 : 494405 : dk = PyObject_Malloc(sizeof(PyDictKeysObject)
629 : 494405 : + ((size_t)1 << log2_bytes)
630 : 494405 : + entry_size * usable);
631 [ - + ]: 494405 : if (dk == NULL) {
632 : 0 : PyErr_NoMemory();
633 : 0 : return NULL;
634 : : }
635 : : }
636 : : #ifdef Py_REF_DEBUG
637 : : _Py_IncRefTotal();
638 : : #endif
639 : 998465 : dk->dk_refcnt = 1;
640 : 998465 : dk->dk_log2_size = log2_size;
641 : 998465 : dk->dk_log2_index_bytes = log2_bytes;
642 : 998465 : dk->dk_kind = unicode ? DICT_KEYS_UNICODE : DICT_KEYS_GENERAL;
643 : 998465 : dk->dk_nentries = 0;
644 : 998465 : dk->dk_usable = usable;
645 : 998465 : dk->dk_version = 0;
646 : 998465 : memset(&dk->dk_indices[0], 0xff, ((size_t)1 << log2_bytes));
647 : 998465 : memset(&dk->dk_indices[(size_t)1 << log2_bytes], 0, entry_size * usable);
648 : 998465 : return dk;
649 : : }
650 : :
651 : : static void
652 : 576632 : free_keys_object(PyInterpreterState *interp, PyDictKeysObject *keys)
653 : : {
654 : : assert(keys != Py_EMPTY_KEYS);
655 [ + + ]: 576632 : if (DK_IS_UNICODE(keys)) {
656 : 549046 : PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(keys);
657 : : Py_ssize_t i, n;
658 [ + + ]: 3710050 : for (i = 0, n = keys->dk_nentries; i < n; i++) {
659 : 3161004 : Py_XDECREF(entries[i].me_key);
660 : 3161004 : Py_XDECREF(entries[i].me_value);
661 : : }
662 : : }
663 : : else {
664 : 27586 : PyDictKeyEntry *entries = DK_ENTRIES(keys);
665 : : Py_ssize_t i, n;
666 [ + + ]: 259696 : for (i = 0, n = keys->dk_nentries; i < n; i++) {
667 : 232110 : Py_XDECREF(entries[i].me_key);
668 : 232110 : Py_XDECREF(entries[i].me_value);
669 : : }
670 : : }
671 : : #if PyDict_MAXFREELIST > 0
672 : 576632 : struct _Py_dict_state *state = get_dict_state(interp);
673 : : #ifdef Py_DEBUG
674 : : // free_keys_object() must not be called after _PyDict_Fini()
675 : : assert(state->keys_numfree != -1);
676 : : #endif
677 [ + + ]: 576632 : if (DK_LOG_SIZE(keys) == PyDict_LOG_MINSIZE
678 [ + + ]: 123540 : && state->keys_numfree < PyDict_MAXFREELIST
679 [ + + ]: 89839 : && DK_IS_UNICODE(keys)) {
680 : 84425 : state->keys_free_list[state->keys_numfree++] = keys;
681 : : OBJECT_STAT_INC(to_freelist);
682 : 84425 : return;
683 : : }
684 : : #endif
685 : 492207 : PyObject_Free(keys);
686 : : }
687 : :
688 : : static inline PyDictValues*
689 : 139093 : new_values(size_t size)
690 : : {
691 : : assert(size >= 1);
692 : 139093 : size_t prefix_size = _Py_SIZE_ROUND_UP(size+2, sizeof(PyObject *));
693 : : assert(prefix_size < 256);
694 : 139093 : size_t n = prefix_size + size * sizeof(PyObject *);
695 : 139093 : uint8_t *mem = PyMem_Malloc(n);
696 [ - + ]: 139093 : if (mem == NULL) {
697 : 0 : return NULL;
698 : : }
699 : : assert(prefix_size % sizeof(PyObject *) == 0);
700 : 139093 : mem[prefix_size-1] = (uint8_t)prefix_size;
701 : 139093 : return (PyDictValues*)(mem + prefix_size);
702 : : }
703 : :
704 : : static inline void
705 : 139079 : free_values(PyDictValues *values)
706 : : {
707 : 139079 : int prefix_size = ((uint8_t *)values)[-1];
708 : 139079 : PyMem_Free(((char *)values)-prefix_size);
709 : 139079 : }
710 : :
711 : : /* Consumes a reference to the keys object */
712 : : static PyObject *
713 : 749393 : new_dict(PyInterpreterState *interp,
714 : : PyDictKeysObject *keys, PyDictValues *values,
715 : : Py_ssize_t used, int free_values_on_failure)
716 : : {
717 : : PyDictObject *mp;
718 : : assert(keys != NULL);
719 : : #if PyDict_MAXFREELIST > 0
720 : 749393 : struct _Py_dict_state *state = get_dict_state(interp);
721 : : #ifdef Py_DEBUG
722 : : // new_dict() must not be called after _PyDict_Fini()
723 : : assert(state->numfree != -1);
724 : : #endif
725 [ + + ]: 749393 : if (state->numfree) {
726 : 316365 : mp = state->free_list[--state->numfree];
727 : : assert (mp != NULL);
728 : : assert (Py_IS_TYPE(mp, &PyDict_Type));
729 : : OBJECT_STAT_INC(from_freelist);
730 : 316365 : _Py_NewReference((PyObject *)mp);
731 : : }
732 : : else
733 : : #endif
734 : : {
735 : 433028 : mp = PyObject_GC_New(PyDictObject, &PyDict_Type);
736 [ - + ]: 433028 : if (mp == NULL) {
737 : 0 : dictkeys_decref(interp, keys);
738 [ # # ]: 0 : if (free_values_on_failure) {
739 : 0 : free_values(values);
740 : : }
741 : 0 : return NULL;
742 : : }
743 : : }
744 : 749393 : mp->ma_keys = keys;
745 : 749393 : mp->ma_values = values;
746 : 749393 : mp->ma_used = used;
747 : 749393 : mp->ma_version_tag = DICT_NEXT_VERSION(interp);
748 : : ASSERT_CONSISTENT(mp);
749 : 749393 : return (PyObject *)mp;
750 : : }
751 : :
752 : : static inline size_t
753 : 139888 : shared_keys_usable_size(PyDictKeysObject *keys)
754 : : {
755 : 139888 : return (size_t)keys->dk_nentries + (size_t)keys->dk_usable;
756 : : }
757 : :
758 : : /* Consumes a reference to the keys object */
759 : : static PyObject *
760 : 826 : new_dict_with_shared_keys(PyInterpreterState *interp, PyDictKeysObject *keys)
761 : : {
762 : 826 : size_t size = shared_keys_usable_size(keys);
763 : 826 : PyDictValues *values = new_values(size);
764 [ - + ]: 826 : if (values == NULL) {
765 : 0 : dictkeys_decref(interp, keys);
766 : 0 : return PyErr_NoMemory();
767 : : }
768 : 826 : ((char *)values)[-2] = 0;
769 [ + + ]: 25606 : for (size_t i = 0; i < size; i++) {
770 : 24780 : values->values[i] = NULL;
771 : : }
772 : 826 : return new_dict(interp, keys, values, 0, 1);
773 : : }
774 : :
775 : :
776 : : static PyDictKeysObject *
777 : 42101 : clone_combined_dict_keys(PyDictObject *orig)
778 : : {
779 : : assert(PyDict_Check(orig));
780 : : assert(Py_TYPE(orig)->tp_iter == (getiterfunc)dict_iter);
781 : : assert(orig->ma_values == NULL);
782 : : assert(orig->ma_keys->dk_refcnt == 1);
783 : :
784 : 42101 : size_t keys_size = _PyDict_KeysSize(orig->ma_keys);
785 : 42101 : PyDictKeysObject *keys = PyObject_Malloc(keys_size);
786 [ - + ]: 42101 : if (keys == NULL) {
787 : 0 : PyErr_NoMemory();
788 : 0 : return NULL;
789 : : }
790 : :
791 : 42101 : memcpy(keys, orig->ma_keys, keys_size);
792 : :
793 : : /* After copying key/value pairs, we need to incref all
794 : : keys and values and they are about to be co-owned by a
795 : : new dict object. */
796 : : PyObject **pkey, **pvalue;
797 : : size_t offs;
798 [ + + ]: 42101 : if (DK_IS_UNICODE(orig->ma_keys)) {
799 : 41925 : PyDictUnicodeEntry *ep0 = DK_UNICODE_ENTRIES(keys);
800 : 41925 : pkey = &ep0->me_key;
801 : 41925 : pvalue = &ep0->me_value;
802 : 41925 : offs = sizeof(PyDictUnicodeEntry) / sizeof(PyObject*);
803 : : }
804 : : else {
805 : 176 : PyDictKeyEntry *ep0 = DK_ENTRIES(keys);
806 : 176 : pkey = &ep0->me_key;
807 : 176 : pvalue = &ep0->me_value;
808 : 176 : offs = sizeof(PyDictKeyEntry) / sizeof(PyObject*);
809 : : }
810 : :
811 : 42101 : Py_ssize_t n = keys->dk_nentries;
812 [ + + ]: 179595 : for (Py_ssize_t i = 0; i < n; i++) {
813 : 137494 : PyObject *value = *pvalue;
814 [ + + ]: 137494 : if (value != NULL) {
815 : 134625 : Py_INCREF(value);
816 : 134625 : Py_INCREF(*pkey);
817 : : }
818 : 137494 : pvalue += offs;
819 : 137494 : pkey += offs;
820 : : }
821 : :
822 : : /* Since we copied the keys table we now have an extra reference
823 : : in the system. Manually call increment _Py_RefTotal to signal that
824 : : we have it now; calling dictkeys_incref would be an error as
825 : : keys->dk_refcnt is already set to 1 (after memcpy). */
826 : : #ifdef Py_REF_DEBUG
827 : : _Py_IncRefTotal();
828 : : #endif
829 : 42101 : return keys;
830 : : }
831 : :
832 : : PyObject *
833 : 734656 : PyDict_New(void)
834 : : {
835 : 734656 : PyInterpreterState *interp = _PyInterpreterState_GET();
836 : 734656 : dictkeys_incref(Py_EMPTY_KEYS);
837 : 734656 : return new_dict(interp, Py_EMPTY_KEYS, NULL, 0, 0);
838 : : }
839 : :
840 : : /* Search index of hash table from offset of entry table */
841 : : static Py_ssize_t
842 : 111717 : lookdict_index(PyDictKeysObject *k, Py_hash_t hash, Py_ssize_t index)
843 : : {
844 : 111717 : size_t mask = DK_MASK(k);
845 : 111717 : size_t perturb = (size_t)hash;
846 : 111717 : size_t i = (size_t)hash & mask;
847 : :
848 : 49345 : for (;;) {
849 : 161062 : Py_ssize_t ix = dictkeys_get_index(k, i);
850 [ + + ]: 161062 : if (ix == index) {
851 : 111717 : return i;
852 : : }
853 [ - + ]: 49345 : if (ix == DKIX_EMPTY) {
854 : 0 : return DKIX_EMPTY;
855 : : }
856 : 49345 : perturb >>= PERTURB_SHIFT;
857 : 49345 : i = mask & (i*5 + perturb + 1);
858 : : }
859 : : Py_UNREACHABLE();
860 : : }
861 : :
862 : : // Search non-Unicode key from Unicode table
863 : : static Py_ssize_t
864 : 8121 : unicodekeys_lookup_generic(PyDictObject *mp, PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
865 : : {
866 : 8121 : PyDictUnicodeEntry *ep0 = DK_UNICODE_ENTRIES(dk);
867 : 8121 : size_t mask = DK_MASK(dk);
868 : 8121 : size_t perturb = hash;
869 : 8121 : size_t i = (size_t)hash & mask;
870 : : Py_ssize_t ix;
871 : : for (;;) {
872 : 8969 : ix = dictkeys_get_index(dk, i);
873 [ + + ]: 8969 : if (ix >= 0) {
874 : 848 : PyDictUnicodeEntry *ep = &ep0[ix];
875 : : assert(ep->me_key != NULL);
876 : : assert(PyUnicode_CheckExact(ep->me_key));
877 [ - + ]: 848 : if (ep->me_key == key) {
878 : 0 : return ix;
879 : : }
880 [ + + ]: 848 : if (unicode_get_hash(ep->me_key) == hash) {
881 : 5 : PyObject *startkey = ep->me_key;
882 : 5 : Py_INCREF(startkey);
883 : 5 : int cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
884 : 5 : Py_DECREF(startkey);
885 [ - + ]: 5 : if (cmp < 0) {
886 : 0 : return DKIX_ERROR;
887 : : }
888 [ + - + - ]: 5 : if (dk == mp->ma_keys && ep->me_key == startkey) {
889 [ - + ]: 5 : if (cmp > 0) {
890 : 0 : return ix;
891 : : }
892 : : }
893 : : else {
894 : : /* The dict was mutated, restart */
895 : 0 : return DKIX_KEY_CHANGED;
896 : : }
897 : : }
898 : : }
899 [ + - ]: 8121 : else if (ix == DKIX_EMPTY) {
900 : 8121 : return DKIX_EMPTY;
901 : : }
902 : 848 : perturb >>= PERTURB_SHIFT;
903 : 848 : i = mask & (i*5 + perturb + 1);
904 : : }
905 : : Py_UNREACHABLE();
906 : : }
907 : :
908 : : // Search Unicode key from Unicode table.
909 : : static Py_ssize_t _Py_HOT_FUNCTION
910 : 11978967 : unicodekeys_lookup_unicode(PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
911 : : {
912 : 11978967 : PyDictUnicodeEntry *ep0 = DK_UNICODE_ENTRIES(dk);
913 : 11978967 : size_t mask = DK_MASK(dk);
914 : 11978967 : size_t perturb = hash;
915 : 11978967 : size_t i = (size_t)hash & mask;
916 : : Py_ssize_t ix;
917 : : for (;;) {
918 : 13695953 : ix = dictkeys_get_index(dk, i);
919 [ + + ]: 13695953 : if (ix >= 0) {
920 : 7997806 : PyDictUnicodeEntry *ep = &ep0[ix];
921 : : assert(ep->me_key != NULL);
922 : : assert(PyUnicode_CheckExact(ep->me_key));
923 [ + + + + ]: 13089231 : if (ep->me_key == key ||
924 [ + - ]: 7110232 : (unicode_get_hash(ep->me_key) == hash && unicode_eq(ep->me_key, key))) {
925 : 4925188 : return ix;
926 : : }
927 : : }
928 [ + + ]: 5698147 : else if (ix == DKIX_EMPTY) {
929 : 5644460 : return DKIX_EMPTY;
930 : : }
931 : 3126305 : perturb >>= PERTURB_SHIFT;
932 : 3126305 : i = mask & (i*5 + perturb + 1);
933 : 3126305 : ix = dictkeys_get_index(dk, i);
934 [ + + ]: 3126305 : if (ix >= 0) {
935 : 1944170 : PyDictUnicodeEntry *ep = &ep0[ix];
936 : : assert(ep->me_key != NULL);
937 : : assert(PyUnicode_CheckExact(ep->me_key));
938 [ + + + + ]: 3720400 : if (ep->me_key == key ||
939 [ + - ]: 1862524 : (unicode_get_hash(ep->me_key) == hash && unicode_eq(ep->me_key, key))) {
940 : 254234 : return ix;
941 : : }
942 : : }
943 [ + + ]: 1182135 : else if (ix == DKIX_EMPTY) {
944 : 1155085 : return DKIX_EMPTY;
945 : : }
946 : 1716986 : perturb >>= PERTURB_SHIFT;
947 : 1716986 : i = mask & (i*5 + perturb + 1);
948 : : }
949 : : Py_UNREACHABLE();
950 : : }
951 : :
952 : : // Search key from Generic table.
953 : : static Py_ssize_t
954 : 478303 : dictkeys_generic_lookup(PyDictObject *mp, PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
955 : : {
956 : 478303 : PyDictKeyEntry *ep0 = DK_ENTRIES(dk);
957 : 478303 : size_t mask = DK_MASK(dk);
958 : 478303 : size_t perturb = hash;
959 : 478303 : size_t i = (size_t)hash & mask;
960 : : Py_ssize_t ix;
961 : : for (;;) {
962 : 953552 : ix = dictkeys_get_index(dk, i);
963 [ + + ]: 953552 : if (ix >= 0) {
964 : 579632 : PyDictKeyEntry *ep = &ep0[ix];
965 : : assert(ep->me_key != NULL);
966 [ + + ]: 579632 : if (ep->me_key == key) {
967 : 35733 : return ix;
968 : : }
969 [ + + ]: 543899 : if (ep->me_hash == hash) {
970 : 74717 : PyObject *startkey = ep->me_key;
971 : 74717 : Py_INCREF(startkey);
972 : 74717 : int cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
973 : 74717 : Py_DECREF(startkey);
974 [ - + ]: 74717 : if (cmp < 0) {
975 : 0 : return DKIX_ERROR;
976 : : }
977 [ + - + - ]: 74717 : if (dk == mp->ma_keys && ep->me_key == startkey) {
978 [ + + ]: 74717 : if (cmp > 0) {
979 : 73368 : return ix;
980 : : }
981 : : }
982 : : else {
983 : : /* The dict was mutated, restart */
984 : 0 : return DKIX_KEY_CHANGED;
985 : : }
986 : : }
987 : : }
988 [ + + ]: 373920 : else if (ix == DKIX_EMPTY) {
989 : 369202 : return DKIX_EMPTY;
990 : : }
991 : 475249 : perturb >>= PERTURB_SHIFT;
992 : 475249 : i = mask & (i*5 + perturb + 1);
993 : : }
994 : : Py_UNREACHABLE();
995 : : }
996 : :
997 : : /* Lookup a string in a (all unicode) dict keys.
998 : : * Returns DKIX_ERROR if key is not a string,
999 : : * or if the dict keys is not all strings.
1000 : : * If the keys is present then return the index of key.
1001 : : * If the key is not present then return DKIX_EMPTY.
1002 : : */
1003 : : Py_ssize_t
1004 : 223579 : _PyDictKeys_StringLookup(PyDictKeysObject* dk, PyObject *key)
1005 : : {
1006 : 223579 : DictKeysKind kind = dk->dk_kind;
1007 [ + - - + ]: 223579 : if (!PyUnicode_CheckExact(key) || kind == DICT_KEYS_GENERAL) {
1008 : 0 : return DKIX_ERROR;
1009 : : }
1010 : 223579 : Py_hash_t hash = unicode_get_hash(key);
1011 [ - + ]: 223579 : if (hash == -1) {
1012 : 0 : hash = PyUnicode_Type.tp_hash(key);
1013 [ # # ]: 0 : if (hash == -1) {
1014 : 0 : PyErr_Clear();
1015 : 0 : return DKIX_ERROR;
1016 : : }
1017 : : }
1018 : 223579 : return unicodekeys_lookup_unicode(dk, key, hash);
1019 : : }
1020 : :
1021 : : /*
1022 : : The basic lookup function used by all operations.
1023 : : This is based on Algorithm D from Knuth Vol. 3, Sec. 6.4.
1024 : : Open addressing is preferred over chaining since the link overhead for
1025 : : chaining would be substantial (100% with typical malloc overhead).
1026 : :
1027 : : The initial probe index is computed as hash mod the table size. Subsequent
1028 : : probe indices are computed as explained earlier.
1029 : :
1030 : : All arithmetic on hash should ignore overflow.
1031 : :
1032 : : _Py_dict_lookup() is general-purpose, and may return DKIX_ERROR if (and only if) a
1033 : : comparison raises an exception.
1034 : : When the key isn't found a DKIX_EMPTY is returned.
1035 : : */
1036 : : Py_ssize_t
1037 : 11831163 : _Py_dict_lookup(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **value_addr)
1038 : : {
1039 : : PyDictKeysObject *dk;
1040 : : DictKeysKind kind;
1041 : : Py_ssize_t ix;
1042 : :
1043 : 11831163 : start:
1044 : 11831163 : dk = mp->ma_keys;
1045 : 11831163 : kind = dk->dk_kind;
1046 : :
1047 [ + + ]: 11831163 : if (kind != DICT_KEYS_GENERAL) {
1048 [ + + ]: 11352860 : if (PyUnicode_CheckExact(key)) {
1049 : 11344739 : ix = unicodekeys_lookup_unicode(dk, key, hash);
1050 : : }
1051 : : else {
1052 : 8121 : ix = unicodekeys_lookup_generic(mp, dk, key, hash);
1053 [ - + ]: 8121 : if (ix == DKIX_KEY_CHANGED) {
1054 : 0 : goto start;
1055 : : }
1056 : : }
1057 : :
1058 [ + + ]: 11352860 : if (ix >= 0) {
1059 [ + + ]: 4736190 : if (kind == DICT_KEYS_SPLIT) {
1060 : 554192 : *value_addr = mp->ma_values->values[ix];
1061 : : }
1062 : : else {
1063 : 4181998 : *value_addr = DK_UNICODE_ENTRIES(dk)[ix].me_value;
1064 : : }
1065 : : }
1066 : : else {
1067 : 6616670 : *value_addr = NULL;
1068 : : }
1069 : : }
1070 : : else {
1071 : 478303 : ix = dictkeys_generic_lookup(mp, dk, key, hash);
1072 [ - + ]: 478303 : if (ix == DKIX_KEY_CHANGED) {
1073 : 0 : goto start;
1074 : : }
1075 [ + + ]: 478303 : if (ix >= 0) {
1076 : 109101 : *value_addr = DK_ENTRIES(dk)[ix].me_value;
1077 : : }
1078 : : else {
1079 : 369202 : *value_addr = NULL;
1080 : : }
1081 : : }
1082 : :
1083 : 11831163 : return ix;
1084 : : }
1085 : :
1086 : : int
1087 : 124 : _PyDict_HasOnlyStringKeys(PyObject *dict)
1088 : : {
1089 : 124 : Py_ssize_t pos = 0;
1090 : : PyObject *key, *value;
1091 : : assert(PyDict_Check(dict));
1092 : : /* Shortcut */
1093 [ + - ]: 124 : if (((PyDictObject *)dict)->ma_keys->dk_kind != DICT_KEYS_GENERAL)
1094 : 124 : return 1;
1095 [ # # ]: 0 : while (PyDict_Next(dict, &pos, &key, &value))
1096 [ # # ]: 0 : if (!PyUnicode_Check(key))
1097 : 0 : return 0;
1098 : 0 : return 1;
1099 : : }
1100 : :
1101 : : #define MAINTAIN_TRACKING(mp, key, value) \
1102 : : do { \
1103 : : if (!_PyObject_GC_IS_TRACKED(mp)) { \
1104 : : if (_PyObject_GC_MAY_BE_TRACKED(key) || \
1105 : : _PyObject_GC_MAY_BE_TRACKED(value)) { \
1106 : : _PyObject_GC_TRACK(mp); \
1107 : : } \
1108 : : } \
1109 : : } while(0)
1110 : :
1111 : : void
1112 : 61845 : _PyDict_MaybeUntrack(PyObject *op)
1113 : : {
1114 : : PyDictObject *mp;
1115 : : PyObject *value;
1116 : : Py_ssize_t i, numentries;
1117 : :
1118 [ + - - + ]: 61845 : if (!PyDict_CheckExact(op) || !_PyObject_GC_IS_TRACKED(op))
1119 : 0 : return;
1120 : :
1121 : 61845 : mp = (PyDictObject *) op;
1122 : 61845 : numentries = mp->ma_keys->dk_nentries;
1123 [ + + ]: 61845 : if (_PyDict_HasSplitTable(mp)) {
1124 [ + + ]: 6168 : for (i = 0; i < numentries; i++) {
1125 [ + + ]: 6167 : if ((value = mp->ma_values->values[i]) == NULL)
1126 : 1 : continue;
1127 [ + + ]: 6166 : if (_PyObject_GC_MAY_BE_TRACKED(value)) {
1128 : 2079 : return;
1129 : : }
1130 : : }
1131 : : }
1132 : : else {
1133 [ + + ]: 59765 : if (DK_IS_UNICODE(mp->ma_keys)) {
1134 : 49836 : PyDictUnicodeEntry *ep0 = DK_UNICODE_ENTRIES(mp->ma_keys);
1135 [ + + ]: 134415 : for (i = 0; i < numentries; i++) {
1136 [ + + ]: 132661 : if ((value = ep0[i].me_value) == NULL)
1137 : 7340 : continue;
1138 [ + + ]: 125321 : if (_PyObject_GC_MAY_BE_TRACKED(value))
1139 : 48082 : return;
1140 : : }
1141 : : }
1142 : : else {
1143 : 9929 : PyDictKeyEntry *ep0 = DK_ENTRIES(mp->ma_keys);
1144 [ + + ]: 13058 : for (i = 0; i < numentries; i++) {
1145 [ + + ]: 13026 : if ((value = ep0[i].me_value) == NULL)
1146 : 117 : continue;
1147 [ + + + + ]: 16043 : if (_PyObject_GC_MAY_BE_TRACKED(value) ||
1148 : 3134 : _PyObject_GC_MAY_BE_TRACKED(ep0[i].me_key))
1149 : 9897 : return;
1150 : : }
1151 : : }
1152 : : }
1153 : 1787 : _PyObject_GC_UNTRACK(op);
1154 : : }
1155 : :
1156 : : /* Internal function to find slot for an item from its hash
1157 : : when it is known that the key is not present in the dict.
1158 : :
1159 : : The dict must be combined. */
1160 : : static Py_ssize_t
1161 : 2751820 : find_empty_slot(PyDictKeysObject *keys, Py_hash_t hash)
1162 : : {
1163 : : assert(keys != NULL);
1164 : :
1165 : 2751820 : const size_t mask = DK_MASK(keys);
1166 : 2751820 : size_t i = hash & mask;
1167 : 2751820 : Py_ssize_t ix = dictkeys_get_index(keys, i);
1168 [ + + ]: 4121251 : for (size_t perturb = hash; ix >= 0;) {
1169 : 1369431 : perturb >>= PERTURB_SHIFT;
1170 : 1369431 : i = (i*5 + perturb + 1) & mask;
1171 : 1369431 : ix = dictkeys_get_index(keys, i);
1172 : : }
1173 : 2751820 : return i;
1174 : : }
1175 : :
1176 : : static int
1177 : 462446 : insertion_resize(PyInterpreterState *interp, PyDictObject *mp, int unicode)
1178 : : {
1179 : 462446 : return dictresize(interp, mp, calculate_log2_keysize(GROWTH_RATE(mp)), unicode);
1180 : : }
1181 : :
1182 : : static Py_ssize_t
1183 : 410649 : insert_into_dictkeys(PyDictKeysObject *keys, PyObject *name)
1184 : : {
1185 : : assert(PyUnicode_CheckExact(name));
1186 : 410649 : Py_hash_t hash = unicode_get_hash(name);
1187 [ - + ]: 410649 : if (hash == -1) {
1188 : 0 : hash = PyUnicode_Type.tp_hash(name);
1189 [ # # ]: 0 : if (hash == -1) {
1190 : 0 : PyErr_Clear();
1191 : 0 : return DKIX_EMPTY;
1192 : : }
1193 : : }
1194 : 410649 : Py_ssize_t ix = unicodekeys_lookup_unicode(keys, name, hash);
1195 [ + + ]: 410649 : if (ix == DKIX_EMPTY) {
1196 [ + + ]: 2063 : if (keys->dk_usable <= 0) {
1197 : 2 : return DKIX_EMPTY;
1198 : : }
1199 : : /* Insert into new slot. */
1200 : 2061 : keys->dk_version = 0;
1201 : 2061 : Py_ssize_t hashpos = find_empty_slot(keys, hash);
1202 : 2061 : ix = keys->dk_nentries;
1203 : 2061 : PyDictUnicodeEntry *ep = &DK_UNICODE_ENTRIES(keys)[ix];
1204 : 2061 : dictkeys_set_index(keys, hashpos, ix);
1205 : : assert(ep->me_key == NULL);
1206 : 2061 : ep->me_key = Py_NewRef(name);
1207 : 2061 : keys->dk_usable--;
1208 : 2061 : keys->dk_nentries++;
1209 : : }
1210 : : assert (ix < SHARED_KEYS_MAX_SIZE);
1211 : 410647 : return ix;
1212 : : }
1213 : :
1214 : : /*
1215 : : Internal routine to insert a new item into the table.
1216 : : Used both by the internal resize routine and by the public insert routine.
1217 : : Returns -1 if an error occurred, or 0 on success.
1218 : : Consumes key and value references.
1219 : : */
1220 : : static int
1221 : 3020461 : insertdict(PyInterpreterState *interp, PyDictObject *mp,
1222 : : PyObject *key, Py_hash_t hash, PyObject *value)
1223 : : {
1224 : : PyObject *old_value;
1225 : :
1226 [ + + + + ]: 3020461 : if (DK_IS_UNICODE(mp->ma_keys) && !PyUnicode_CheckExact(key)) {
1227 [ - + ]: 3532 : if (insertion_resize(interp, mp, 0) < 0)
1228 : 0 : goto Fail;
1229 : : assert(mp->ma_keys->dk_kind == DICT_KEYS_GENERAL);
1230 : : }
1231 : :
1232 : 3020461 : Py_ssize_t ix = _Py_dict_lookup(mp, key, hash, &old_value);
1233 [ - + ]: 3020461 : if (ix == DKIX_ERROR)
1234 : 0 : goto Fail;
1235 : :
1236 [ + + + + : 3020461 : MAINTAIN_TRACKING(mp, key, value);
+ + ]
1237 : :
1238 [ + + ]: 3020461 : if (ix == DKIX_EMPTY) {
1239 : 2526044 : uint64_t new_version = _PyDict_NotifyEvent(
1240 : : interp, PyDict_EVENT_ADDED, mp, key, value);
1241 : : /* Insert into new slot. */
1242 : 2526044 : mp->ma_keys->dk_version = 0;
1243 : : assert(old_value == NULL);
1244 [ + + ]: 2526044 : if (mp->ma_keys->dk_usable <= 0) {
1245 : : /* Need to resize. */
1246 [ - + ]: 452818 : if (insertion_resize(interp, mp, 1) < 0)
1247 : 0 : goto Fail;
1248 : : }
1249 : :
1250 : 2526044 : Py_ssize_t hashpos = find_empty_slot(mp->ma_keys, hash);
1251 : 2526044 : dictkeys_set_index(mp->ma_keys, hashpos, mp->ma_keys->dk_nentries);
1252 : :
1253 [ + + ]: 2526044 : if (DK_IS_UNICODE(mp->ma_keys)) {
1254 : : PyDictUnicodeEntry *ep;
1255 : 2387608 : ep = &DK_UNICODE_ENTRIES(mp->ma_keys)[mp->ma_keys->dk_nentries];
1256 : 2387608 : ep->me_key = key;
1257 [ + + ]: 2387608 : if (mp->ma_values) {
1258 : 383 : Py_ssize_t index = mp->ma_keys->dk_nentries;
1259 : 383 : _PyDictValues_AddToInsertionOrder(mp->ma_values, index);
1260 : : assert (mp->ma_values->values[index] == NULL);
1261 : 383 : mp->ma_values->values[index] = value;
1262 : : }
1263 : : else {
1264 : 2387225 : ep->me_value = value;
1265 : : }
1266 : : }
1267 : : else {
1268 : : PyDictKeyEntry *ep;
1269 : 138436 : ep = &DK_ENTRIES(mp->ma_keys)[mp->ma_keys->dk_nentries];
1270 : 138436 : ep->me_key = key;
1271 : 138436 : ep->me_hash = hash;
1272 : 138436 : ep->me_value = value;
1273 : : }
1274 : 2526044 : mp->ma_used++;
1275 : 2526044 : mp->ma_version_tag = new_version;
1276 : 2526044 : mp->ma_keys->dk_usable--;
1277 : 2526044 : mp->ma_keys->dk_nentries++;
1278 : : assert(mp->ma_keys->dk_usable >= 0);
1279 : : ASSERT_CONSISTENT(mp);
1280 : 2526044 : return 0;
1281 : : }
1282 : :
1283 [ + + ]: 494417 : if (old_value != value) {
1284 : 342561 : uint64_t new_version = _PyDict_NotifyEvent(
1285 : : interp, PyDict_EVENT_MODIFIED, mp, key, value);
1286 [ + + ]: 342561 : if (_PyDict_HasSplitTable(mp)) {
1287 : 214597 : mp->ma_values->values[ix] = value;
1288 [ + + ]: 214597 : if (old_value == NULL) {
1289 : 14584 : _PyDictValues_AddToInsertionOrder(mp->ma_values, ix);
1290 : 14584 : mp->ma_used++;
1291 : : }
1292 : : }
1293 : : else {
1294 : : assert(old_value != NULL);
1295 [ + + ]: 127964 : if (DK_IS_UNICODE(mp->ma_keys)) {
1296 : 127940 : DK_UNICODE_ENTRIES(mp->ma_keys)[ix].me_value = value;
1297 : : }
1298 : : else {
1299 : 24 : DK_ENTRIES(mp->ma_keys)[ix].me_value = value;
1300 : : }
1301 : : }
1302 : 342561 : mp->ma_version_tag = new_version;
1303 : : }
1304 : 494417 : Py_XDECREF(old_value); /* which **CAN** re-enter (see issue #22653) */
1305 : : ASSERT_CONSISTENT(mp);
1306 : 494417 : Py_DECREF(key);
1307 : 494417 : return 0;
1308 : :
1309 : 0 : Fail:
1310 : 0 : Py_DECREF(value);
1311 : 0 : Py_DECREF(key);
1312 : 0 : return -1;
1313 : : }
1314 : :
1315 : : // Same to insertdict but specialized for ma_keys = Py_EMPTY_KEYS.
1316 : : // Consumes key and value references.
1317 : : static int
1318 : 531972 : insert_to_emptydict(PyInterpreterState *interp, PyDictObject *mp,
1319 : : PyObject *key, Py_hash_t hash, PyObject *value)
1320 : : {
1321 : : assert(mp->ma_keys == Py_EMPTY_KEYS);
1322 : :
1323 : 531972 : uint64_t new_version = _PyDict_NotifyEvent(
1324 : : interp, PyDict_EVENT_ADDED, mp, key, value);
1325 : :
1326 : 531972 : int unicode = PyUnicode_CheckExact(key);
1327 : 531972 : PyDictKeysObject *newkeys = new_keys_object(
1328 : : interp, PyDict_LOG_MINSIZE, unicode);
1329 [ - + ]: 531972 : if (newkeys == NULL) {
1330 : 0 : Py_DECREF(key);
1331 : 0 : Py_DECREF(value);
1332 : 0 : return -1;
1333 : : }
1334 : 531972 : dictkeys_decref(interp, Py_EMPTY_KEYS);
1335 : 531972 : mp->ma_keys = newkeys;
1336 : 531972 : mp->ma_values = NULL;
1337 : :
1338 [ + + + + : 531972 : MAINTAIN_TRACKING(mp, key, value);
+ + ]
1339 : :
1340 : 531972 : size_t hashpos = (size_t)hash & (PyDict_MINSIZE-1);
1341 : 531972 : dictkeys_set_index(mp->ma_keys, hashpos, 0);
1342 [ + + ]: 531972 : if (unicode) {
1343 : 509890 : PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(mp->ma_keys);
1344 : 509890 : ep->me_key = key;
1345 : 509890 : ep->me_value = value;
1346 : : }
1347 : : else {
1348 : 22082 : PyDictKeyEntry *ep = DK_ENTRIES(mp->ma_keys);
1349 : 22082 : ep->me_key = key;
1350 : 22082 : ep->me_hash = hash;
1351 : 22082 : ep->me_value = value;
1352 : : }
1353 : 531972 : mp->ma_used++;
1354 : 531972 : mp->ma_version_tag = new_version;
1355 : 531972 : mp->ma_keys->dk_usable--;
1356 : 531972 : mp->ma_keys->dk_nentries++;
1357 : 531972 : return 0;
1358 : : }
1359 : :
1360 : : /*
1361 : : Internal routine used by dictresize() to build a hashtable of entries.
1362 : : */
1363 : : static void
1364 : 24355 : build_indices_generic(PyDictKeysObject *keys, PyDictKeyEntry *ep, Py_ssize_t n)
1365 : : {
1366 : 24355 : size_t mask = DK_MASK(keys);
1367 [ + + ]: 260111 : for (Py_ssize_t ix = 0; ix != n; ix++, ep++) {
1368 : 235756 : Py_hash_t hash = ep->me_hash;
1369 : 235756 : size_t i = hash & mask;
1370 [ + + ]: 301231 : for (size_t perturb = hash; dictkeys_get_index(keys, i) != DKIX_EMPTY;) {
1371 : 65475 : perturb >>= PERTURB_SHIFT;
1372 : 65475 : i = mask & (i*5 + perturb + 1);
1373 : : }
1374 : 235756 : dictkeys_set_index(keys, i, ix);
1375 : : }
1376 : 24355 : }
1377 : :
1378 : : static void
1379 : 439956 : build_indices_unicode(PyDictKeysObject *keys, PyDictUnicodeEntry *ep, Py_ssize_t n)
1380 : : {
1381 : 439956 : size_t mask = DK_MASK(keys);
1382 [ + + ]: 3025223 : for (Py_ssize_t ix = 0; ix != n; ix++, ep++) {
1383 : 2585267 : Py_hash_t hash = unicode_get_hash(ep->me_key);
1384 : : assert(hash != -1);
1385 : 2585267 : size_t i = hash & mask;
1386 [ + + ]: 3504391 : for (size_t perturb = hash; dictkeys_get_index(keys, i) != DKIX_EMPTY;) {
1387 : 919124 : perturb >>= PERTURB_SHIFT;
1388 : 919124 : i = mask & (i*5 + perturb + 1);
1389 : : }
1390 : 2585267 : dictkeys_set_index(keys, i, ix);
1391 : : }
1392 : 439956 : }
1393 : :
1394 : : /*
1395 : : Restructure the table by allocating a new table and reinserting all
1396 : : items again. When entries have been deleted, the new table may
1397 : : actually be smaller than the old one.
1398 : : If a table is split (its keys and hashes are shared, its values are not),
1399 : : then the values are temporarily copied into the table, it is resized as
1400 : : a combined table, then the me_value slots in the old table are NULLed out.
1401 : : After resizing a table is always combined.
1402 : :
1403 : : This function supports:
1404 : : - Unicode split -> Unicode combined or Generic
1405 : : - Unicode combined -> Unicode combined or Generic
1406 : : - Generic -> Generic
1407 : : */
1408 : : static int
1409 : 464311 : dictresize(PyInterpreterState *interp, PyDictObject *mp,
1410 : : uint8_t log2_newsize, int unicode)
1411 : : {
1412 : : PyDictKeysObject *oldkeys;
1413 : : PyDictValues *oldvalues;
1414 : :
1415 [ - + ]: 464311 : if (log2_newsize >= SIZEOF_SIZE_T*8) {
1416 : 0 : PyErr_NoMemory();
1417 : 0 : return -1;
1418 : : }
1419 : : assert(log2_newsize >= PyDict_LOG_MINSIZE);
1420 : :
1421 : 464311 : oldkeys = mp->ma_keys;
1422 : 464311 : oldvalues = mp->ma_values;
1423 : :
1424 [ + + ]: 464311 : if (!DK_IS_UNICODE(oldkeys)) {
1425 : 18882 : unicode = 0;
1426 : : }
1427 : :
1428 : : /* NOTE: Current odict checks mp->ma_keys to detect resize happen.
1429 : : * So we can't reuse oldkeys even if oldkeys->dk_size == newsize.
1430 : : * TODO: Try reusing oldkeys when reimplement odict.
1431 : : */
1432 : :
1433 : : /* Allocate a new table. */
1434 : 464311 : mp->ma_keys = new_keys_object(interp, log2_newsize, unicode);
1435 [ - + ]: 464311 : if (mp->ma_keys == NULL) {
1436 : 0 : mp->ma_keys = oldkeys;
1437 : 0 : return -1;
1438 : : }
1439 : : // New table must be large enough.
1440 : : assert(mp->ma_keys->dk_usable >= mp->ma_used);
1441 : :
1442 : 464311 : Py_ssize_t numentries = mp->ma_used;
1443 : :
1444 [ + + ]: 464311 : if (oldvalues != NULL) {
1445 : 2 : PyDictUnicodeEntry *oldentries = DK_UNICODE_ENTRIES(oldkeys);
1446 : : /* Convert split table into new combined table.
1447 : : * We must incref keys; we can transfer values.
1448 : : */
1449 [ - + ]: 2 : if (mp->ma_keys->dk_kind == DICT_KEYS_GENERAL) {
1450 : : // split -> generic
1451 : 0 : PyDictKeyEntry *newentries = DK_ENTRIES(mp->ma_keys);
1452 : :
1453 [ # # ]: 0 : for (Py_ssize_t i = 0; i < numentries; i++) {
1454 : 0 : int index = get_index_from_order(mp, i);
1455 : 0 : PyDictUnicodeEntry *ep = &oldentries[index];
1456 : : assert(oldvalues->values[index] != NULL);
1457 : 0 : newentries[i].me_key = Py_NewRef(ep->me_key);
1458 : 0 : newentries[i].me_hash = unicode_get_hash(ep->me_key);
1459 : 0 : newentries[i].me_value = oldvalues->values[index];
1460 : : }
1461 : 0 : build_indices_generic(mp->ma_keys, newentries, numentries);
1462 : : }
1463 : : else { // split -> combined unicode
1464 : 2 : PyDictUnicodeEntry *newentries = DK_UNICODE_ENTRIES(mp->ma_keys);
1465 : :
1466 [ + + ]: 60 : for (Py_ssize_t i = 0; i < numentries; i++) {
1467 : 58 : int index = get_index_from_order(mp, i);
1468 : 58 : PyDictUnicodeEntry *ep = &oldentries[index];
1469 : : assert(oldvalues->values[index] != NULL);
1470 : 58 : newentries[i].me_key = Py_NewRef(ep->me_key);
1471 : 58 : newentries[i].me_value = oldvalues->values[index];
1472 : : }
1473 : 2 : build_indices_unicode(mp->ma_keys, newentries, numentries);
1474 : : }
1475 : 2 : dictkeys_decref(interp, oldkeys);
1476 : 2 : mp->ma_values = NULL;
1477 : 2 : free_values(oldvalues);
1478 : : }
1479 : : else { // oldkeys is combined.
1480 [ + + ]: 464309 : if (oldkeys->dk_kind == DICT_KEYS_GENERAL) {
1481 : : // generic -> generic
1482 : : assert(mp->ma_keys->dk_kind == DICT_KEYS_GENERAL);
1483 : 18882 : PyDictKeyEntry *oldentries = DK_ENTRIES(oldkeys);
1484 : 18882 : PyDictKeyEntry *newentries = DK_ENTRIES(mp->ma_keys);
1485 [ + + ]: 18882 : if (oldkeys->dk_nentries == numentries) {
1486 : 18870 : memcpy(newentries, oldentries, numentries * sizeof(PyDictKeyEntry));
1487 : : }
1488 : : else {
1489 : 12 : PyDictKeyEntry *ep = oldentries;
1490 [ + + ]: 1345 : for (Py_ssize_t i = 0; i < numentries; i++) {
1491 [ + + ]: 1376 : while (ep->me_value == NULL)
1492 : 43 : ep++;
1493 : 1333 : newentries[i] = *ep++;
1494 : : }
1495 : : }
1496 : 18882 : build_indices_generic(mp->ma_keys, newentries, numentries);
1497 : : }
1498 : : else { // oldkeys is combined unicode
1499 : 445427 : PyDictUnicodeEntry *oldentries = DK_UNICODE_ENTRIES(oldkeys);
1500 [ + + ]: 445427 : if (unicode) { // combined unicode -> combined unicode
1501 : 439954 : PyDictUnicodeEntry *newentries = DK_UNICODE_ENTRIES(mp->ma_keys);
1502 [ + + + - ]: 439954 : if (oldkeys->dk_nentries == numentries && mp->ma_keys->dk_kind == DICT_KEYS_UNICODE) {
1503 : 438628 : memcpy(newentries, oldentries, numentries * sizeof(PyDictUnicodeEntry));
1504 : : }
1505 : : else {
1506 : 1326 : PyDictUnicodeEntry *ep = oldentries;
1507 [ + + ]: 121197 : for (Py_ssize_t i = 0; i < numentries; i++) {
1508 [ + + ]: 125854 : while (ep->me_value == NULL)
1509 : 5983 : ep++;
1510 : 119871 : newentries[i] = *ep++;
1511 : : }
1512 : : }
1513 : 439954 : build_indices_unicode(mp->ma_keys, newentries, numentries);
1514 : : }
1515 : : else { // combined unicode -> generic
1516 : 5473 : PyDictKeyEntry *newentries = DK_ENTRIES(mp->ma_keys);
1517 : 5473 : PyDictUnicodeEntry *ep = oldentries;
1518 [ + + ]: 11725 : for (Py_ssize_t i = 0; i < numentries; i++) {
1519 [ - + ]: 6252 : while (ep->me_value == NULL)
1520 : 0 : ep++;
1521 : 6252 : newentries[i].me_key = ep->me_key;
1522 : 6252 : newentries[i].me_hash = unicode_get_hash(ep->me_key);
1523 : 6252 : newentries[i].me_value = ep->me_value;
1524 : 6252 : ep++;
1525 : : }
1526 : 5473 : build_indices_generic(mp->ma_keys, newentries, numentries);
1527 : : }
1528 : : }
1529 : :
1530 : : // We can not use free_keys_object here because key's reference
1531 : : // are moved already.
1532 : : #ifdef Py_REF_DEBUG
1533 : : _Py_DecRefTotal();
1534 : : #endif
1535 [ + + ]: 464309 : if (oldkeys == Py_EMPTY_KEYS) {
1536 : 1859 : oldkeys->dk_refcnt--;
1537 : : assert(oldkeys->dk_refcnt > 0);
1538 : : }
1539 : : else {
1540 : : assert(oldkeys->dk_kind != DICT_KEYS_SPLIT);
1541 : : assert(oldkeys->dk_refcnt == 1);
1542 : : #if PyDict_MAXFREELIST > 0
1543 : 462450 : struct _Py_dict_state *state = get_dict_state(interp);
1544 : : #ifdef Py_DEBUG
1545 : : // dictresize() must not be called after _PyDict_Fini()
1546 : : assert(state->keys_numfree != -1);
1547 : : #endif
1548 [ + + ]: 462450 : if (DK_LOG_SIZE(oldkeys) == PyDict_LOG_MINSIZE &&
1549 [ + + ]: 444921 : DK_IS_UNICODE(oldkeys) &&
1550 [ + + ]: 429021 : state->keys_numfree < PyDict_MAXFREELIST)
1551 : : {
1552 : 428614 : state->keys_free_list[state->keys_numfree++] = oldkeys;
1553 : 428614 : OBJECT_STAT_INC(to_freelist);
1554 : : }
1555 : : else
1556 : : #endif
1557 : : {
1558 : 33836 : PyObject_Free(oldkeys);
1559 : : }
1560 : : }
1561 : : }
1562 : :
1563 : 464311 : mp->ma_keys->dk_usable -= numentries;
1564 : 464311 : mp->ma_keys->dk_nentries = numentries;
1565 : : ASSERT_CONSISTENT(mp);
1566 : 464311 : return 0;
1567 : : }
1568 : :
1569 : : static PyObject *
1570 : 124998 : dict_new_presized(PyInterpreterState *interp, Py_ssize_t minused, bool unicode)
1571 : : {
1572 : 124998 : const uint8_t log2_max_presize = 17;
1573 : 124998 : const Py_ssize_t max_presize = ((Py_ssize_t)1) << log2_max_presize;
1574 : : uint8_t log2_newsize;
1575 : : PyDictKeysObject *new_keys;
1576 : :
1577 [ + + ]: 124998 : if (minused <= USABLE_FRACTION(PyDict_MINSIZE)) {
1578 : 124757 : return PyDict_New();
1579 : : }
1580 : : /* There are no strict guarantee that returned dict can contain minused
1581 : : * items without resize. So we create medium size dict instead of very
1582 : : * large dict or MemoryError.
1583 : : */
1584 [ - + ]: 241 : if (minused > USABLE_FRACTION(max_presize)) {
1585 : 0 : log2_newsize = log2_max_presize;
1586 : : }
1587 : : else {
1588 : 241 : log2_newsize = estimate_log2_keysize(minused);
1589 : : }
1590 : :
1591 : 241 : new_keys = new_keys_object(interp, log2_newsize, unicode);
1592 [ - + ]: 241 : if (new_keys == NULL)
1593 : 0 : return NULL;
1594 : 241 : return new_dict(interp, new_keys, NULL, 0, 0);
1595 : : }
1596 : :
1597 : : PyObject *
1598 : 0 : _PyDict_NewPresized(Py_ssize_t minused)
1599 : : {
1600 : 0 : PyInterpreterState *interp = _PyInterpreterState_GET();
1601 : 0 : return dict_new_presized(interp, minused, false);
1602 : : }
1603 : :
1604 : : PyObject *
1605 : 124998 : _PyDict_FromItems(PyObject *const *keys, Py_ssize_t keys_offset,
1606 : : PyObject *const *values, Py_ssize_t values_offset,
1607 : : Py_ssize_t length)
1608 : : {
1609 : 124998 : bool unicode = true;
1610 : 124998 : PyObject *const *ks = keys;
1611 : 124998 : PyInterpreterState *interp = _PyInterpreterState_GET();
1612 : :
1613 [ + + ]: 134167 : for (Py_ssize_t i = 0; i < length; i++) {
1614 [ + + ]: 9232 : if (!PyUnicode_CheckExact(*ks)) {
1615 : 63 : unicode = false;
1616 : 63 : break;
1617 : : }
1618 : 9169 : ks += keys_offset;
1619 : : }
1620 : :
1621 : 124998 : PyObject *dict = dict_new_presized(interp, length, unicode);
1622 [ - + ]: 124998 : if (dict == NULL) {
1623 : 0 : return NULL;
1624 : : }
1625 : :
1626 : 124998 : ks = keys;
1627 : 124998 : PyObject *const *vs = values;
1628 : :
1629 [ + + ]: 134418 : for (Py_ssize_t i = 0; i < length; i++) {
1630 : 9420 : PyObject *key = *ks;
1631 : 9420 : PyObject *value = *vs;
1632 [ - + ]: 9420 : if (PyDict_SetItem(dict, key, value) < 0) {
1633 : 0 : Py_DECREF(dict);
1634 : 0 : return NULL;
1635 : : }
1636 : 9420 : ks += keys_offset;
1637 : 9420 : vs += values_offset;
1638 : : }
1639 : :
1640 : 124998 : return dict;
1641 : : }
1642 : :
1643 : : /* Note that, for historical reasons, PyDict_GetItem() suppresses all errors
1644 : : * that may occur (originally dicts supported only string keys, and exceptions
1645 : : * weren't possible). So, while the original intent was that a NULL return
1646 : : * meant the key wasn't present, in reality it can mean that, or that an error
1647 : : * (suppressed) occurred while computing the key's hash, or that some error
1648 : : * (suppressed) occurred when comparing keys in the dict's internal probe
1649 : : * sequence. A nasty example of the latter is when a Python-coded comparison
1650 : : * function hits a stack-depth error, which can cause this to return NULL
1651 : : * even if the key is present.
1652 : : */
1653 : : PyObject *
1654 : 25993 : PyDict_GetItem(PyObject *op, PyObject *key)
1655 : : {
1656 [ - + ]: 25993 : if (!PyDict_Check(op)) {
1657 : 0 : return NULL;
1658 : : }
1659 : 25993 : PyDictObject *mp = (PyDictObject *)op;
1660 : :
1661 : : Py_hash_t hash;
1662 [ + - - + ]: 25993 : if (!PyUnicode_CheckExact(key) || (hash = unicode_get_hash(key)) == -1) {
1663 : 0 : hash = PyObject_Hash(key);
1664 [ # # ]: 0 : if (hash == -1) {
1665 : 0 : PyErr_Clear();
1666 : 0 : return NULL;
1667 : : }
1668 : : }
1669 : :
1670 : 25993 : PyThreadState *tstate = _PyThreadState_GET();
1671 : : #ifdef Py_DEBUG
1672 : : // bpo-40839: Before Python 3.10, it was possible to call PyDict_GetItem()
1673 : : // with the GIL released.
1674 : : _Py_EnsureTstateNotNULL(tstate);
1675 : : #endif
1676 : :
1677 : : /* Preserve the existing exception */
1678 : : PyObject *value;
1679 : : Py_ssize_t ix; (void)ix;
1680 : :
1681 : :
1682 : 25993 : PyObject *exc = _PyErr_GetRaisedException(tstate);
1683 : 25993 : ix = _Py_dict_lookup(mp, key, hash, &value);
1684 : :
1685 : : /* Ignore any exception raised by the lookup */
1686 : 25993 : _PyErr_SetRaisedException(tstate, exc);
1687 : :
1688 : :
1689 : : assert(ix >= 0 || value == NULL);
1690 : 25993 : return value;
1691 : : }
1692 : :
1693 : : Py_ssize_t
1694 : 16518 : _PyDict_LookupIndex(PyDictObject *mp, PyObject *key)
1695 : : {
1696 : : PyObject *value;
1697 : : assert(PyDict_CheckExact((PyObject*)mp));
1698 : : assert(PyUnicode_CheckExact(key));
1699 : :
1700 : 16518 : Py_hash_t hash = unicode_get_hash(key);
1701 [ - + ]: 16518 : if (hash == -1) {
1702 : 0 : hash = PyObject_Hash(key);
1703 [ # # ]: 0 : if (hash == -1) {
1704 : 0 : return -1;
1705 : : }
1706 : : }
1707 : :
1708 : 16518 : return _Py_dict_lookup(mp, key, hash, &value);
1709 : : }
1710 : :
1711 : : /* Same as PyDict_GetItemWithError() but with hash supplied by caller.
1712 : : This returns NULL *with* an exception set if an exception occurred.
1713 : : It returns NULL *without* an exception set if the key wasn't present.
1714 : : */
1715 : : PyObject *
1716 : 3649594 : _PyDict_GetItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash)
1717 : : {
1718 : : Py_ssize_t ix; (void)ix;
1719 : 3649594 : PyDictObject *mp = (PyDictObject *)op;
1720 : : PyObject *value;
1721 : :
1722 [ - + ]: 3649594 : if (!PyDict_Check(op)) {
1723 : 0 : PyErr_BadInternalCall();
1724 : 0 : return NULL;
1725 : : }
1726 : :
1727 : 3649594 : ix = _Py_dict_lookup(mp, key, hash, &value);
1728 : : assert(ix >= 0 || value == NULL);
1729 : 3649594 : return value;
1730 : : }
1731 : :
1732 : : /* Variant of PyDict_GetItem() that doesn't suppress exceptions.
1733 : : This returns NULL *with* an exception set if an exception occurred.
1734 : : It returns NULL *without* an exception set if the key wasn't present.
1735 : : */
1736 : : PyObject *
1737 : 3752984 : PyDict_GetItemWithError(PyObject *op, PyObject *key)
1738 : : {
1739 : : Py_ssize_t ix; (void)ix;
1740 : : Py_hash_t hash;
1741 : 3752984 : PyDictObject*mp = (PyDictObject *)op;
1742 : : PyObject *value;
1743 : :
1744 [ - + ]: 3752984 : if (!PyDict_Check(op)) {
1745 : 0 : PyErr_BadInternalCall();
1746 : 0 : return NULL;
1747 : : }
1748 [ + + + + ]: 3752984 : if (!PyUnicode_CheckExact(key) || (hash = unicode_get_hash(key)) == -1)
1749 : : {
1750 : 80980 : hash = PyObject_Hash(key);
1751 [ - + ]: 80980 : if (hash == -1) {
1752 : 0 : return NULL;
1753 : : }
1754 : : }
1755 : :
1756 : 3752984 : ix = _Py_dict_lookup(mp, key, hash, &value);
1757 : : assert(ix >= 0 || value == NULL);
1758 : 3752984 : return value;
1759 : : }
1760 : :
1761 : : PyObject *
1762 : 6878 : _PyDict_GetItemWithError(PyObject *dp, PyObject *kv)
1763 : : {
1764 : : assert(PyUnicode_CheckExact(kv));
1765 : 6878 : Py_hash_t hash = kv->ob_type->tp_hash(kv);
1766 [ - + ]: 6878 : if (hash == -1) {
1767 : 0 : return NULL;
1768 : : }
1769 : 6878 : return _PyDict_GetItem_KnownHash(dp, kv, hash);
1770 : : }
1771 : :
1772 : : PyObject *
1773 : 0 : _PyDict_GetItemIdWithError(PyObject *dp, _Py_Identifier *key)
1774 : : {
1775 : : PyObject *kv;
1776 : 0 : kv = _PyUnicode_FromId(key); /* borrowed */
1777 [ # # ]: 0 : if (kv == NULL)
1778 : 0 : return NULL;
1779 : 0 : Py_hash_t hash = unicode_get_hash(kv);
1780 : : assert (hash != -1); /* interned strings have their hash value initialised */
1781 : 0 : return _PyDict_GetItem_KnownHash(dp, kv, hash);
1782 : : }
1783 : :
1784 : : PyObject *
1785 : 5848 : _PyDict_GetItemStringWithError(PyObject *v, const char *key)
1786 : : {
1787 : : PyObject *kv, *rv;
1788 : 5848 : kv = PyUnicode_FromString(key);
1789 [ - + ]: 5848 : if (kv == NULL) {
1790 : 0 : return NULL;
1791 : : }
1792 : 5848 : rv = PyDict_GetItemWithError(v, kv);
1793 : 5848 : Py_DECREF(kv);
1794 : 5848 : return rv;
1795 : : }
1796 : :
1797 : : /* Fast version of global value lookup (LOAD_GLOBAL).
1798 : : * Lookup in globals, then builtins.
1799 : : *
1800 : : *
1801 : : *
1802 : : *
1803 : : * Raise an exception and return NULL if an error occurred (ex: computing the
1804 : : * key hash failed, key comparison failed, ...). Return NULL if the key doesn't
1805 : : * exist. Return the value if the key exists.
1806 : : */
1807 : : PyObject *
1808 : 63803 : _PyDict_LoadGlobal(PyDictObject *globals, PyDictObject *builtins, PyObject *key)
1809 : : {
1810 : : Py_ssize_t ix;
1811 : : Py_hash_t hash;
1812 : : PyObject *value;
1813 : :
1814 [ + - - + ]: 63803 : if (!PyUnicode_CheckExact(key) || (hash = unicode_get_hash(key)) == -1) {
1815 : 0 : hash = PyObject_Hash(key);
1816 [ # # ]: 0 : if (hash == -1)
1817 : 0 : return NULL;
1818 : : }
1819 : :
1820 : : /* namespace 1: globals */
1821 : 63803 : ix = _Py_dict_lookup(globals, key, hash, &value);
1822 [ - + ]: 63803 : if (ix == DKIX_ERROR)
1823 : 0 : return NULL;
1824 [ + + + - ]: 63803 : if (ix != DKIX_EMPTY && value != NULL)
1825 : 30524 : return value;
1826 : :
1827 : : /* namespace 2: builtins */
1828 : 33279 : ix = _Py_dict_lookup(builtins, key, hash, &value);
1829 : : assert(ix >= 0 || value == NULL);
1830 : 33279 : return value;
1831 : : }
1832 : :
1833 : : /* Consumes references to key and value */
1834 : : int
1835 : 3534518 : _PyDict_SetItem_Take2(PyDictObject *mp, PyObject *key, PyObject *value)
1836 : : {
1837 : : assert(key);
1838 : : assert(value);
1839 : : assert(PyDict_Check(mp));
1840 : : Py_hash_t hash;
1841 [ + + + + ]: 3534518 : if (!PyUnicode_CheckExact(key) || (hash = unicode_get_hash(key)) == -1) {
1842 : 150120 : hash = PyObject_Hash(key);
1843 [ - + ]: 150120 : if (hash == -1) {
1844 : 0 : Py_DECREF(key);
1845 : 0 : Py_DECREF(value);
1846 : 0 : return -1;
1847 : : }
1848 : : }
1849 : 3534518 : PyInterpreterState *interp = _PyInterpreterState_GET();
1850 [ + + ]: 3534518 : if (mp->ma_keys == Py_EMPTY_KEYS) {
1851 : 531341 : return insert_to_emptydict(interp, mp, key, hash, value);
1852 : : }
1853 : : /* insertdict() handles any resizing that might be necessary */
1854 : 3003177 : return insertdict(interp, mp, key, hash, value);
1855 : : }
1856 : :
1857 : : /* CAUTION: PyDict_SetItem() must guarantee that it won't resize the
1858 : : * dictionary if it's merely replacing the value for an existing key.
1859 : : * This means that it's safe to loop over a dictionary with PyDict_Next()
1860 : : * and occasionally replace a value -- but you can't insert new keys or
1861 : : * remove them.
1862 : : */
1863 : : int
1864 : 3419051 : PyDict_SetItem(PyObject *op, PyObject *key, PyObject *value)
1865 : : {
1866 [ - + ]: 3419051 : if (!PyDict_Check(op)) {
1867 : 0 : PyErr_BadInternalCall();
1868 : 0 : return -1;
1869 : : }
1870 : : assert(key);
1871 : : assert(value);
1872 : 3419051 : return _PyDict_SetItem_Take2((PyDictObject *)op,
1873 : : Py_NewRef(key), Py_NewRef(value));
1874 : : }
1875 : :
1876 : : int
1877 : 61 : _PyDict_SetItem_KnownHash(PyObject *op, PyObject *key, PyObject *value,
1878 : : Py_hash_t hash)
1879 : : {
1880 : : PyDictObject *mp;
1881 : :
1882 [ - + ]: 61 : if (!PyDict_Check(op)) {
1883 : 0 : PyErr_BadInternalCall();
1884 : 0 : return -1;
1885 : : }
1886 : : assert(key);
1887 : : assert(value);
1888 : : assert(hash != -1);
1889 : 61 : mp = (PyDictObject *)op;
1890 : :
1891 : 61 : PyInterpreterState *interp = _PyInterpreterState_GET();
1892 [ + + ]: 61 : if (mp->ma_keys == Py_EMPTY_KEYS) {
1893 : 14 : return insert_to_emptydict(interp, mp, Py_NewRef(key), hash, Py_NewRef(value));
1894 : : }
1895 : : /* insertdict() handles any resizing that might be necessary */
1896 : 47 : return insertdict(interp, mp, Py_NewRef(key), hash, Py_NewRef(value));
1897 : : }
1898 : :
1899 : : static void
1900 : 292839 : delete_index_from_values(PyDictValues *values, Py_ssize_t ix)
1901 : : {
1902 : 292839 : uint8_t *size_ptr = ((uint8_t *)values)-2;
1903 : 292839 : int size = *size_ptr;
1904 : : int i;
1905 [ + + ]: 780904 : for (i = 1; size_ptr[-i] != ix; i++) {
1906 : : assert(i <= size);
1907 : : }
1908 : : assert(i <= size);
1909 [ + + ]: 683291 : for (; i < size; i++) {
1910 : 390452 : size_ptr[-i] = size_ptr[-i-1];
1911 : : }
1912 : 292839 : *size_ptr = size -1;
1913 : 292839 : }
1914 : :
1915 : : static int
1916 : 111717 : delitem_common(PyDictObject *mp, Py_hash_t hash, Py_ssize_t ix,
1917 : : PyObject *old_value, uint64_t new_version)
1918 : : {
1919 : : PyObject *old_key;
1920 : :
1921 : 111717 : Py_ssize_t hashpos = lookdict_index(mp->ma_keys, hash, ix);
1922 : : assert(hashpos >= 0);
1923 : :
1924 : 111717 : mp->ma_used--;
1925 : 111717 : mp->ma_version_tag = new_version;
1926 [ - + ]: 111717 : if (mp->ma_values) {
1927 : : assert(old_value == mp->ma_values->values[ix]);
1928 : 0 : mp->ma_values->values[ix] = NULL;
1929 : : assert(ix < SHARED_KEYS_MAX_SIZE);
1930 : : /* Update order */
1931 : 0 : delete_index_from_values(mp->ma_values, ix);
1932 : : ASSERT_CONSISTENT(mp);
1933 : : }
1934 : : else {
1935 : 111717 : mp->ma_keys->dk_version = 0;
1936 : 111717 : dictkeys_set_index(mp->ma_keys, hashpos, DKIX_DUMMY);
1937 [ + + ]: 111717 : if (DK_IS_UNICODE(mp->ma_keys)) {
1938 : 99271 : PyDictUnicodeEntry *ep = &DK_UNICODE_ENTRIES(mp->ma_keys)[ix];
1939 : 99271 : old_key = ep->me_key;
1940 : 99271 : ep->me_key = NULL;
1941 : 99271 : ep->me_value = NULL;
1942 : : }
1943 : : else {
1944 : 12446 : PyDictKeyEntry *ep = &DK_ENTRIES(mp->ma_keys)[ix];
1945 : 12446 : old_key = ep->me_key;
1946 : 12446 : ep->me_key = NULL;
1947 : 12446 : ep->me_value = NULL;
1948 : 12446 : ep->me_hash = 0;
1949 : : }
1950 : 111717 : Py_DECREF(old_key);
1951 : : }
1952 : 111717 : Py_DECREF(old_value);
1953 : :
1954 : : ASSERT_CONSISTENT(mp);
1955 : 111717 : return 0;
1956 : : }
1957 : :
1958 : : int
1959 : 110534 : PyDict_DelItem(PyObject *op, PyObject *key)
1960 : : {
1961 : : Py_hash_t hash;
1962 : : assert(key);
1963 [ + + + + ]: 110534 : if (!PyUnicode_CheckExact(key) || (hash = unicode_get_hash(key)) == -1) {
1964 : 12491 : hash = PyObject_Hash(key);
1965 [ - + ]: 12491 : if (hash == -1)
1966 : 0 : return -1;
1967 : : }
1968 : :
1969 : 110534 : return _PyDict_DelItem_KnownHash(op, key, hash);
1970 : : }
1971 : :
1972 : : int
1973 : 110534 : _PyDict_DelItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash)
1974 : : {
1975 : : Py_ssize_t ix;
1976 : : PyDictObject *mp;
1977 : : PyObject *old_value;
1978 : :
1979 [ - + ]: 110534 : if (!PyDict_Check(op)) {
1980 : 0 : PyErr_BadInternalCall();
1981 : 0 : return -1;
1982 : : }
1983 : : assert(key);
1984 : : assert(hash != -1);
1985 : 110534 : mp = (PyDictObject *)op;
1986 : 110534 : ix = _Py_dict_lookup(mp, key, hash, &old_value);
1987 [ - + ]: 110534 : if (ix == DKIX_ERROR)
1988 : 0 : return -1;
1989 [ + + - + ]: 110534 : if (ix == DKIX_EMPTY || old_value == NULL) {
1990 : 5 : _PyErr_SetKeyError(key);
1991 : 5 : return -1;
1992 : : }
1993 : :
1994 : 110529 : PyInterpreterState *interp = _PyInterpreterState_GET();
1995 : 110529 : uint64_t new_version = _PyDict_NotifyEvent(
1996 : : interp, PyDict_EVENT_DELETED, mp, key, NULL);
1997 : 110529 : return delitem_common(mp, hash, ix, old_value, new_version);
1998 : : }
1999 : :
2000 : : /* This function promises that the predicate -> deletion sequence is atomic
2001 : : * (i.e. protected by the GIL), assuming the predicate itself doesn't
2002 : : * release the GIL.
2003 : : */
2004 : : int
2005 : 0 : _PyDict_DelItemIf(PyObject *op, PyObject *key,
2006 : : int (*predicate)(PyObject *value))
2007 : : {
2008 : : Py_ssize_t hashpos, ix;
2009 : : PyDictObject *mp;
2010 : : Py_hash_t hash;
2011 : : PyObject *old_value;
2012 : : int res;
2013 : :
2014 [ # # ]: 0 : if (!PyDict_Check(op)) {
2015 : 0 : PyErr_BadInternalCall();
2016 : 0 : return -1;
2017 : : }
2018 : : assert(key);
2019 : 0 : hash = PyObject_Hash(key);
2020 [ # # ]: 0 : if (hash == -1)
2021 : 0 : return -1;
2022 : 0 : mp = (PyDictObject *)op;
2023 : 0 : ix = _Py_dict_lookup(mp, key, hash, &old_value);
2024 [ # # ]: 0 : if (ix == DKIX_ERROR)
2025 : 0 : return -1;
2026 [ # # # # ]: 0 : if (ix == DKIX_EMPTY || old_value == NULL) {
2027 : 0 : _PyErr_SetKeyError(key);
2028 : 0 : return -1;
2029 : : }
2030 : :
2031 : 0 : res = predicate(old_value);
2032 [ # # ]: 0 : if (res == -1)
2033 : 0 : return -1;
2034 : :
2035 : 0 : hashpos = lookdict_index(mp->ma_keys, hash, ix);
2036 : : assert(hashpos >= 0);
2037 : :
2038 [ # # ]: 0 : if (res > 0) {
2039 : 0 : PyInterpreterState *interp = _PyInterpreterState_GET();
2040 : 0 : uint64_t new_version = _PyDict_NotifyEvent(
2041 : : interp, PyDict_EVENT_DELETED, mp, key, NULL);
2042 : 0 : return delitem_common(mp, hashpos, ix, old_value, new_version);
2043 : : } else {
2044 : 0 : return 0;
2045 : : }
2046 : : }
2047 : :
2048 : :
2049 : : void
2050 : 8415 : PyDict_Clear(PyObject *op)
2051 : : {
2052 : : PyDictObject *mp;
2053 : : PyDictKeysObject *oldkeys;
2054 : : PyDictValues *oldvalues;
2055 : : Py_ssize_t i, n;
2056 : :
2057 [ - + ]: 8415 : if (!PyDict_Check(op))
2058 : 0 : return;
2059 : 8415 : mp = ((PyDictObject *)op);
2060 : 8415 : oldkeys = mp->ma_keys;
2061 : 8415 : oldvalues = mp->ma_values;
2062 [ + + ]: 8415 : if (oldkeys == Py_EMPTY_KEYS) {
2063 : 650 : return;
2064 : : }
2065 : : /* Empty the dict... */
2066 : 7765 : PyInterpreterState *interp = _PyInterpreterState_GET();
2067 : 7765 : uint64_t new_version = _PyDict_NotifyEvent(
2068 : : interp, PyDict_EVENT_CLEARED, mp, NULL, NULL);
2069 : 7765 : dictkeys_incref(Py_EMPTY_KEYS);
2070 : 7765 : mp->ma_keys = Py_EMPTY_KEYS;
2071 : 7765 : mp->ma_values = NULL;
2072 : 7765 : mp->ma_used = 0;
2073 : 7765 : mp->ma_version_tag = new_version;
2074 : : /* ...then clear the keys and values */
2075 [ - + ]: 7765 : if (oldvalues != NULL) {
2076 : 0 : n = oldkeys->dk_nentries;
2077 [ # # ]: 0 : for (i = 0; i < n; i++)
2078 [ # # ]: 0 : Py_CLEAR(oldvalues->values[i]);
2079 : 0 : free_values(oldvalues);
2080 : 0 : dictkeys_decref(interp, oldkeys);
2081 : : }
2082 : : else {
2083 : : assert(oldkeys->dk_refcnt == 1);
2084 : 7765 : dictkeys_decref(interp, oldkeys);
2085 : : }
2086 : : ASSERT_CONSISTENT(mp);
2087 : : }
2088 : :
2089 : : /* Internal version of PyDict_Next that returns a hash value in addition
2090 : : * to the key and value.
2091 : : * Return 1 on success, return 0 when the reached the end of the dictionary
2092 : : * (or if op is not a dictionary)
2093 : : */
2094 : : int
2095 : 758455 : _PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey,
2096 : : PyObject **pvalue, Py_hash_t *phash)
2097 : : {
2098 : : Py_ssize_t i;
2099 : : PyDictObject *mp;
2100 : : PyObject *key, *value;
2101 : : Py_hash_t hash;
2102 : :
2103 [ - + ]: 758455 : if (!PyDict_Check(op))
2104 : 0 : return 0;
2105 : 758455 : mp = (PyDictObject *)op;
2106 : 758455 : i = *ppos;
2107 [ + + ]: 758455 : if (mp->ma_values) {
2108 : : assert(mp->ma_used <= SHARED_KEYS_MAX_SIZE);
2109 [ + - + + ]: 53074 : if (i < 0 || i >= mp->ma_used)
2110 : 3122 : return 0;
2111 : 49952 : int index = get_index_from_order(mp, i);
2112 : 49952 : value = mp->ma_values->values[index];
2113 : :
2114 : 49952 : key = DK_UNICODE_ENTRIES(mp->ma_keys)[index].me_key;
2115 : 49952 : hash = unicode_get_hash(key);
2116 : : assert(value != NULL);
2117 : : }
2118 : : else {
2119 : 705381 : Py_ssize_t n = mp->ma_keys->dk_nentries;
2120 [ + - + + ]: 705381 : if (i < 0 || i >= n)
2121 : 126964 : return 0;
2122 [ + + ]: 578417 : if (DK_IS_UNICODE(mp->ma_keys)) {
2123 : 530258 : PyDictUnicodeEntry *entry_ptr = &DK_UNICODE_ENTRIES(mp->ma_keys)[i];
2124 [ + + + + ]: 621049 : while (i < n && entry_ptr->me_value == NULL) {
2125 : 90791 : entry_ptr++;
2126 : 90791 : i++;
2127 : : }
2128 [ + + ]: 530258 : if (i >= n)
2129 : 137 : return 0;
2130 : 530121 : key = entry_ptr->me_key;
2131 : 530121 : hash = unicode_get_hash(entry_ptr->me_key);
2132 : 530121 : value = entry_ptr->me_value;
2133 : : }
2134 : : else {
2135 : 48159 : PyDictKeyEntry *entry_ptr = &DK_ENTRIES(mp->ma_keys)[i];
2136 [ + + + + ]: 58475 : while (i < n && entry_ptr->me_value == NULL) {
2137 : 10316 : entry_ptr++;
2138 : 10316 : i++;
2139 : : }
2140 [ + + ]: 48159 : if (i >= n)
2141 : 1858 : return 0;
2142 : 46301 : key = entry_ptr->me_key;
2143 : 46301 : hash = entry_ptr->me_hash;
2144 : 46301 : value = entry_ptr->me_value;
2145 : : }
2146 : : }
2147 : 626374 : *ppos = i+1;
2148 [ + + ]: 626374 : if (pkey)
2149 : 625043 : *pkey = key;
2150 [ + + ]: 626374 : if (pvalue)
2151 : 500857 : *pvalue = value;
2152 [ + + ]: 626374 : if (phash)
2153 : 17300 : *phash = hash;
2154 : 626374 : return 1;
2155 : : }
2156 : :
2157 : : /*
2158 : : * Iterate over a dict. Use like so:
2159 : : *
2160 : : * Py_ssize_t i;
2161 : : * PyObject *key, *value;
2162 : : * i = 0; # important! i should not otherwise be changed by you
2163 : : * while (PyDict_Next(yourdict, &i, &key, &value)) {
2164 : : * Refer to borrowed references in key and value.
2165 : : * }
2166 : : *
2167 : : * Return 1 on success, return 0 when the reached the end of the dictionary
2168 : : * (or if op is not a dictionary)
2169 : : *
2170 : : * CAUTION: In general, it isn't safe to use PyDict_Next in a loop that
2171 : : * mutates the dict. One exception: it is safe if the loop merely changes
2172 : : * the values associated with the keys (but doesn't insert new keys or
2173 : : * delete keys), via PyDict_SetItem().
2174 : : */
2175 : : int
2176 : 596732 : PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey, PyObject **pvalue)
2177 : : {
2178 : 596732 : return _PyDict_Next(op, ppos, pkey, pvalue, NULL);
2179 : : }
2180 : :
2181 : : /* Internal version of dict.pop(). */
2182 : : PyObject *
2183 : 1361 : _PyDict_Pop_KnownHash(PyObject *dict, PyObject *key, Py_hash_t hash, PyObject *deflt)
2184 : : {
2185 : : Py_ssize_t ix;
2186 : : PyObject *old_value;
2187 : : PyDictObject *mp;
2188 : 1361 : PyInterpreterState *interp = _PyInterpreterState_GET();
2189 : :
2190 : : assert(PyDict_Check(dict));
2191 : 1361 : mp = (PyDictObject *)dict;
2192 : :
2193 [ - + ]: 1361 : if (mp->ma_used == 0) {
2194 [ # # ]: 0 : if (deflt) {
2195 : 0 : return Py_NewRef(deflt);
2196 : : }
2197 : 0 : _PyErr_SetKeyError(key);
2198 : 0 : return NULL;
2199 : : }
2200 : 1361 : ix = _Py_dict_lookup(mp, key, hash, &old_value);
2201 [ - + ]: 1361 : if (ix == DKIX_ERROR)
2202 : 0 : return NULL;
2203 [ + + - + ]: 1361 : if (ix == DKIX_EMPTY || old_value == NULL) {
2204 [ + - ]: 173 : if (deflt) {
2205 : 173 : return Py_NewRef(deflt);
2206 : : }
2207 : 0 : _PyErr_SetKeyError(key);
2208 : 0 : return NULL;
2209 : : }
2210 : : assert(old_value != NULL);
2211 : 1188 : uint64_t new_version = _PyDict_NotifyEvent(
2212 : : interp, PyDict_EVENT_DELETED, mp, key, NULL);
2213 : 1188 : delitem_common(mp, hash, ix, Py_NewRef(old_value), new_version);
2214 : :
2215 : : ASSERT_CONSISTENT(mp);
2216 : 1188 : return old_value;
2217 : : }
2218 : :
2219 : : PyObject *
2220 : 1428 : _PyDict_Pop(PyObject *dict, PyObject *key, PyObject *deflt)
2221 : : {
2222 : : Py_hash_t hash;
2223 : :
2224 [ + + ]: 1428 : if (((PyDictObject *)dict)->ma_used == 0) {
2225 [ + - ]: 67 : if (deflt) {
2226 : 67 : return Py_NewRef(deflt);
2227 : : }
2228 : 0 : _PyErr_SetKeyError(key);
2229 : 0 : return NULL;
2230 : : }
2231 [ + + - + ]: 1361 : if (!PyUnicode_CheckExact(key) || (hash = unicode_get_hash(key)) == -1) {
2232 : 67 : hash = PyObject_Hash(key);
2233 [ - + ]: 67 : if (hash == -1)
2234 : 0 : return NULL;
2235 : : }
2236 : 1361 : return _PyDict_Pop_KnownHash(dict, key, hash, deflt);
2237 : : }
2238 : :
2239 : : /* Internal version of dict.from_keys(). It is subclass-friendly. */
2240 : : PyObject *
2241 : 152 : _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value)
2242 : : {
2243 : : PyObject *it; /* iter(iterable) */
2244 : : PyObject *key;
2245 : : PyObject *d;
2246 : : int status;
2247 : 152 : PyInterpreterState *interp = _PyInterpreterState_GET();
2248 : :
2249 : 152 : d = _PyObject_CallNoArgs(cls);
2250 [ - + ]: 152 : if (d == NULL)
2251 : 0 : return NULL;
2252 : :
2253 [ + - + - ]: 152 : if (PyDict_CheckExact(d) && ((PyDictObject *)d)->ma_used == 0) {
2254 [ - + ]: 152 : if (PyDict_CheckExact(iterable)) {
2255 : 0 : PyDictObject *mp = (PyDictObject *)d;
2256 : : PyObject *oldvalue;
2257 : 0 : Py_ssize_t pos = 0;
2258 : : PyObject *key;
2259 : : Py_hash_t hash;
2260 : :
2261 : 0 : int unicode = DK_IS_UNICODE(((PyDictObject*)iterable)->ma_keys);
2262 [ # # ]: 0 : if (dictresize(interp, mp,
2263 : 0 : estimate_log2_keysize(PyDict_GET_SIZE(iterable)),
2264 : : unicode)) {
2265 : 0 : Py_DECREF(d);
2266 : 0 : return NULL;
2267 : : }
2268 : :
2269 [ # # ]: 0 : while (_PyDict_Next(iterable, &pos, &key, &oldvalue, &hash)) {
2270 [ # # ]: 0 : if (insertdict(interp, mp,
2271 : : Py_NewRef(key), hash, Py_NewRef(value))) {
2272 : 0 : Py_DECREF(d);
2273 : 0 : return NULL;
2274 : : }
2275 : : }
2276 : 0 : return d;
2277 : : }
2278 [ + - - + ]: 152 : if (PyAnySet_CheckExact(iterable)) {
2279 : 0 : PyDictObject *mp = (PyDictObject *)d;
2280 : 0 : Py_ssize_t pos = 0;
2281 : : PyObject *key;
2282 : : Py_hash_t hash;
2283 : :
2284 [ # # ]: 0 : if (dictresize(interp, mp,
2285 : 0 : estimate_log2_keysize(PySet_GET_SIZE(iterable)), 0)) {
2286 : 0 : Py_DECREF(d);
2287 : 0 : return NULL;
2288 : : }
2289 : :
2290 [ # # ]: 0 : while (_PySet_NextEntry(iterable, &pos, &key, &hash)) {
2291 [ # # ]: 0 : if (insertdict(interp, mp, Py_NewRef(key), hash, Py_NewRef(value))) {
2292 : 0 : Py_DECREF(d);
2293 : 0 : return NULL;
2294 : : }
2295 : : }
2296 : 0 : return d;
2297 : : }
2298 : : }
2299 : :
2300 : 152 : it = PyObject_GetIter(iterable);
2301 [ - + ]: 152 : if (it == NULL){
2302 : 0 : Py_DECREF(d);
2303 : 0 : return NULL;
2304 : : }
2305 : :
2306 [ + - ]: 152 : if (PyDict_CheckExact(d)) {
2307 [ + + ]: 677 : while ((key = PyIter_Next(it)) != NULL) {
2308 : 525 : status = PyDict_SetItem(d, key, value);
2309 : 525 : Py_DECREF(key);
2310 [ - + ]: 525 : if (status < 0)
2311 : 0 : goto Fail;
2312 : : }
2313 : : } else {
2314 [ # # ]: 0 : while ((key = PyIter_Next(it)) != NULL) {
2315 : 0 : status = PyObject_SetItem(d, key, value);
2316 : 0 : Py_DECREF(key);
2317 [ # # ]: 0 : if (status < 0)
2318 : 0 : goto Fail;
2319 : : }
2320 : : }
2321 : :
2322 [ - + ]: 152 : if (PyErr_Occurred())
2323 : 0 : goto Fail;
2324 : 152 : Py_DECREF(it);
2325 : 152 : return d;
2326 : :
2327 : 0 : Fail:
2328 : 0 : Py_DECREF(it);
2329 : 0 : Py_DECREF(d);
2330 : 0 : return NULL;
2331 : : }
2332 : :
2333 : : /* Methods */
2334 : :
2335 : : static void
2336 : 748981 : dict_dealloc(PyDictObject *mp)
2337 : : {
2338 : 748981 : PyInterpreterState *interp = _PyInterpreterState_GET();
2339 : : assert(Py_REFCNT(mp) == 0);
2340 : 748981 : Py_SET_REFCNT(mp, 1);
2341 : 748981 : _PyDict_NotifyEvent(interp, PyDict_EVENT_DEALLOCATED, mp, NULL, NULL);
2342 [ - + ]: 748981 : if (Py_REFCNT(mp) > 1) {
2343 : 0 : Py_SET_REFCNT(mp, Py_REFCNT(mp) - 1);
2344 : 0 : return;
2345 : : }
2346 : 748981 : Py_SET_REFCNT(mp, 0);
2347 : 748981 : PyDictValues *values = mp->ma_values;
2348 : 748981 : PyDictKeysObject *keys = mp->ma_keys;
2349 : : Py_ssize_t i, n;
2350 : :
2351 : : /* bpo-31095: UnTrack is needed before calling any callbacks */
2352 : 748981 : PyObject_GC_UnTrack(mp);
2353 [ + + - + ]: 748981 : Py_TRASHCAN_BEGIN(mp, dict_dealloc)
2354 [ + + ]: 748981 : if (values != NULL) {
2355 [ + + ]: 16762 : for (i = 0, n = mp->ma_keys->dk_nentries; i < n; i++) {
2356 : 15143 : Py_XDECREF(values->values[i]);
2357 : : }
2358 : 1619 : free_values(values);
2359 : 1619 : dictkeys_decref(interp, keys);
2360 : : }
2361 [ + - ]: 747362 : else if (keys != NULL) {
2362 : : assert(keys->dk_refcnt == 1 || keys == Py_EMPTY_KEYS);
2363 : 747362 : dictkeys_decref(interp, keys);
2364 : : }
2365 : : #if PyDict_MAXFREELIST > 0
2366 : 748981 : struct _Py_dict_state *state = get_dict_state(interp);
2367 : : #ifdef Py_DEBUG
2368 : : // new_dict() must not be called after _PyDict_Fini()
2369 : : assert(state->numfree != -1);
2370 : : #endif
2371 [ + + + + ]: 748981 : if (state->numfree < PyDict_MAXFREELIST && Py_IS_TYPE(mp, &PyDict_Type)) {
2372 : 325558 : state->free_list[state->numfree++] = mp;
2373 : 325558 : OBJECT_STAT_INC(to_freelist);
2374 : : }
2375 : : else
2376 : : #endif
2377 : : {
2378 : 423423 : Py_TYPE(mp)->tp_free((PyObject *)mp);
2379 : : }
2380 [ + + ]: 748981 : Py_TRASHCAN_END
2381 : : }
2382 : :
2383 : :
2384 : : static PyObject *
2385 : 3122 : dict_repr(PyDictObject *mp)
2386 : : {
2387 : : Py_ssize_t i;
2388 : 3122 : PyObject *key = NULL, *value = NULL;
2389 : : _PyUnicodeWriter writer;
2390 : : int first;
2391 : :
2392 : 3122 : i = Py_ReprEnter((PyObject *)mp);
2393 [ - + ]: 3122 : if (i != 0) {
2394 [ # # ]: 0 : return i > 0 ? PyUnicode_FromString("{...}") : NULL;
2395 : : }
2396 : :
2397 [ - + ]: 3122 : if (mp->ma_used == 0) {
2398 : 0 : Py_ReprLeave((PyObject *)mp);
2399 : 0 : return PyUnicode_FromString("{}");
2400 : : }
2401 : :
2402 : 3122 : _PyUnicodeWriter_Init(&writer);
2403 : 3122 : writer.overallocate = 1;
2404 : : /* "{" + "1: 2" + ", 3: 4" * (len - 1) + "}" */
2405 : 3122 : writer.min_length = 1 + 4 + (2 + 4) * (mp->ma_used - 1) + 1;
2406 : :
2407 [ - + ]: 3122 : if (_PyUnicodeWriter_WriteChar(&writer, '{') < 0)
2408 : 0 : goto error;
2409 : :
2410 : : /* Do repr() on each key+value pair, and insert ": " between them.
2411 : : Note that repr may mutate the dict. */
2412 : 3122 : i = 0;
2413 : 3122 : first = 1;
2414 [ + + ]: 53074 : while (PyDict_Next((PyObject *)mp, &i, &key, &value)) {
2415 : : PyObject *s;
2416 : : int res;
2417 : :
2418 : : /* Prevent repr from deleting key or value during key format. */
2419 : 49952 : Py_INCREF(key);
2420 : 49952 : Py_INCREF(value);
2421 : :
2422 [ + + ]: 49952 : if (!first) {
2423 [ - + ]: 46830 : if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0)
2424 : 0 : goto error;
2425 : : }
2426 : 49952 : first = 0;
2427 : :
2428 : 49952 : s = PyObject_Repr(key);
2429 [ - + ]: 49952 : if (s == NULL)
2430 : 0 : goto error;
2431 : 49952 : res = _PyUnicodeWriter_WriteStr(&writer, s);
2432 : 49952 : Py_DECREF(s);
2433 [ - + ]: 49952 : if (res < 0)
2434 : 0 : goto error;
2435 : :
2436 [ - + ]: 49952 : if (_PyUnicodeWriter_WriteASCIIString(&writer, ": ", 2) < 0)
2437 : 0 : goto error;
2438 : :
2439 : 49952 : s = PyObject_Repr(value);
2440 [ - + ]: 49952 : if (s == NULL)
2441 : 0 : goto error;
2442 : 49952 : res = _PyUnicodeWriter_WriteStr(&writer, s);
2443 : 49952 : Py_DECREF(s);
2444 [ - + ]: 49952 : if (res < 0)
2445 : 0 : goto error;
2446 : :
2447 [ + - ]: 49952 : Py_CLEAR(key);
2448 [ + - ]: 49952 : Py_CLEAR(value);
2449 : : }
2450 : :
2451 : 3122 : writer.overallocate = 0;
2452 [ - + ]: 3122 : if (_PyUnicodeWriter_WriteChar(&writer, '}') < 0)
2453 : 0 : goto error;
2454 : :
2455 : 3122 : Py_ReprLeave((PyObject *)mp);
2456 : :
2457 : 3122 : return _PyUnicodeWriter_Finish(&writer);
2458 : :
2459 : 0 : error:
2460 : 0 : Py_ReprLeave((PyObject *)mp);
2461 : 0 : _PyUnicodeWriter_Dealloc(&writer);
2462 : 0 : Py_XDECREF(key);
2463 : 0 : Py_XDECREF(value);
2464 : 0 : return NULL;
2465 : : }
2466 : :
2467 : : static Py_ssize_t
2468 : 754 : dict_length(PyDictObject *mp)
2469 : : {
2470 : 754 : return mp->ma_used;
2471 : : }
2472 : :
2473 : : static PyObject *
2474 : 7262 : dict_subscript(PyDictObject *mp, PyObject *key)
2475 : : {
2476 : : Py_ssize_t ix;
2477 : : Py_hash_t hash;
2478 : : PyObject *value;
2479 : :
2480 [ + + + + ]: 7262 : if (!PyUnicode_CheckExact(key) || (hash = unicode_get_hash(key)) == -1) {
2481 : 1255 : hash = PyObject_Hash(key);
2482 [ - + ]: 1255 : if (hash == -1)
2483 : 0 : return NULL;
2484 : : }
2485 : 7262 : ix = _Py_dict_lookup(mp, key, hash, &value);
2486 [ - + ]: 7262 : if (ix == DKIX_ERROR)
2487 : 0 : return NULL;
2488 [ + + - + ]: 7262 : if (ix == DKIX_EMPTY || value == NULL) {
2489 [ + + ]: 2564 : if (!PyDict_CheckExact(mp)) {
2490 : : /* Look up __missing__ method if we're a subclass. */
2491 : : PyObject *missing, *res;
2492 : 2323 : missing = _PyObject_LookupSpecial(
2493 : : (PyObject *)mp, &_Py_ID(__missing__));
2494 [ + + ]: 2323 : if (missing != NULL) {
2495 : 2233 : res = PyObject_CallOneArg(missing, key);
2496 : 2233 : Py_DECREF(missing);
2497 : 2233 : return res;
2498 : : }
2499 [ - + ]: 90 : else if (PyErr_Occurred())
2500 : 0 : return NULL;
2501 : : }
2502 : 331 : _PyErr_SetKeyError(key);
2503 : 331 : return NULL;
2504 : : }
2505 : 4698 : return Py_NewRef(value);
2506 : : }
2507 : :
2508 : : static int
2509 : 8810 : dict_ass_sub(PyDictObject *mp, PyObject *v, PyObject *w)
2510 : : {
2511 [ + + ]: 8810 : if (w == NULL)
2512 : 1609 : return PyDict_DelItem((PyObject *)mp, v);
2513 : : else
2514 : 7201 : return PyDict_SetItem((PyObject *)mp, v, w);
2515 : : }
2516 : :
2517 : : static PyMappingMethods dict_as_mapping = {
2518 : : (lenfunc)dict_length, /*mp_length*/
2519 : : (binaryfunc)dict_subscript, /*mp_subscript*/
2520 : : (objobjargproc)dict_ass_sub, /*mp_ass_subscript*/
2521 : : };
2522 : :
2523 : : static PyObject *
2524 : 16221 : dict_keys(PyDictObject *mp)
2525 : : {
2526 : : PyObject *v;
2527 : : Py_ssize_t n;
2528 : :
2529 : 16221 : again:
2530 : 16221 : n = mp->ma_used;
2531 : 16221 : v = PyList_New(n);
2532 [ - + ]: 16221 : if (v == NULL)
2533 : 0 : return NULL;
2534 [ - + ]: 16221 : if (n != mp->ma_used) {
2535 : : /* Durnit. The allocations caused the dict to resize.
2536 : : * Just start over, this shouldn't normally happen.
2537 : : */
2538 : 0 : Py_DECREF(v);
2539 : 0 : goto again;
2540 : : }
2541 : :
2542 : : /* Nothing we do below makes any function calls. */
2543 : 16221 : Py_ssize_t j = 0, pos = 0;
2544 : : PyObject *key;
2545 [ + + ]: 141738 : while (_PyDict_Next((PyObject*)mp, &pos, &key, NULL, NULL)) {
2546 : : assert(j < n);
2547 : 125517 : PyList_SET_ITEM(v, j, Py_NewRef(key));
2548 : 125517 : j++;
2549 : : }
2550 : : assert(j == n);
2551 : 16221 : return v;
2552 : : }
2553 : :
2554 : : static PyObject *
2555 : 0 : dict_values(PyDictObject *mp)
2556 : : {
2557 : : PyObject *v;
2558 : : Py_ssize_t n;
2559 : :
2560 : 0 : again:
2561 : 0 : n = mp->ma_used;
2562 : 0 : v = PyList_New(n);
2563 [ # # ]: 0 : if (v == NULL)
2564 : 0 : return NULL;
2565 [ # # ]: 0 : if (n != mp->ma_used) {
2566 : : /* Durnit. The allocations caused the dict to resize.
2567 : : * Just start over, this shouldn't normally happen.
2568 : : */
2569 : 0 : Py_DECREF(v);
2570 : 0 : goto again;
2571 : : }
2572 : :
2573 : : /* Nothing we do below makes any function calls. */
2574 : 0 : Py_ssize_t j = 0, pos = 0;
2575 : : PyObject *value;
2576 [ # # ]: 0 : while (_PyDict_Next((PyObject*)mp, &pos, NULL, &value, NULL)) {
2577 : : assert(j < n);
2578 : 0 : PyList_SET_ITEM(v, j, Py_NewRef(value));
2579 : 0 : j++;
2580 : : }
2581 : : assert(j == n);
2582 : 0 : return v;
2583 : : }
2584 : :
2585 : : static PyObject *
2586 : 0 : dict_items(PyDictObject *mp)
2587 : : {
2588 : : PyObject *v;
2589 : : Py_ssize_t i, n;
2590 : : PyObject *item;
2591 : :
2592 : : /* Preallocate the list of tuples, to avoid allocations during
2593 : : * the loop over the items, which could trigger GC, which
2594 : : * could resize the dict. :-(
2595 : : */
2596 : 0 : again:
2597 : 0 : n = mp->ma_used;
2598 : 0 : v = PyList_New(n);
2599 [ # # ]: 0 : if (v == NULL)
2600 : 0 : return NULL;
2601 [ # # ]: 0 : for (i = 0; i < n; i++) {
2602 : 0 : item = PyTuple_New(2);
2603 [ # # ]: 0 : if (item == NULL) {
2604 : 0 : Py_DECREF(v);
2605 : 0 : return NULL;
2606 : : }
2607 : 0 : PyList_SET_ITEM(v, i, item);
2608 : : }
2609 [ # # ]: 0 : if (n != mp->ma_used) {
2610 : : /* Durnit. The allocations caused the dict to resize.
2611 : : * Just start over, this shouldn't normally happen.
2612 : : */
2613 : 0 : Py_DECREF(v);
2614 : 0 : goto again;
2615 : : }
2616 : :
2617 : : /* Nothing we do below makes any function calls. */
2618 : 0 : Py_ssize_t j = 0, pos = 0;
2619 : : PyObject *key, *value;
2620 [ # # ]: 0 : while (_PyDict_Next((PyObject*)mp, &pos, &key, &value, NULL)) {
2621 : : assert(j < n);
2622 : 0 : PyObject *item = PyList_GET_ITEM(v, j);
2623 : 0 : PyTuple_SET_ITEM(item, 0, Py_NewRef(key));
2624 : 0 : PyTuple_SET_ITEM(item, 1, Py_NewRef(value));
2625 : 0 : j++;
2626 : : }
2627 : : assert(j == n);
2628 : 0 : return v;
2629 : : }
2630 : :
2631 : : /*[clinic input]
2632 : : @classmethod
2633 : : dict.fromkeys
2634 : : iterable: object
2635 : : value: object=None
2636 : : /
2637 : :
2638 : : Create a new dictionary with keys from iterable and values set to value.
2639 : : [clinic start generated code]*/
2640 : :
2641 : : static PyObject *
2642 : 152 : dict_fromkeys_impl(PyTypeObject *type, PyObject *iterable, PyObject *value)
2643 : : /*[clinic end generated code: output=8fb98e4b10384999 input=382ba4855d0f74c3]*/
2644 : : {
2645 : 152 : return _PyDict_FromKeys((PyObject *)type, iterable, value);
2646 : : }
2647 : :
2648 : : /* Single-arg dict update; used by dict_update_common and operators. */
2649 : : static int
2650 : 1329 : dict_update_arg(PyObject *self, PyObject *arg)
2651 : : {
2652 [ + + ]: 1329 : if (PyDict_CheckExact(arg)) {
2653 : 1215 : return PyDict_Merge(self, arg, 1);
2654 : : }
2655 : : PyObject *func;
2656 [ - + ]: 114 : if (_PyObject_LookupAttr(arg, &_Py_ID(keys), &func) < 0) {
2657 : 0 : return -1;
2658 : : }
2659 [ + + ]: 114 : if (func != NULL) {
2660 : 63 : Py_DECREF(func);
2661 : 63 : return PyDict_Merge(self, arg, 1);
2662 : : }
2663 : 51 : return PyDict_MergeFromSeq2(self, arg, 1);
2664 : : }
2665 : :
2666 : : static int
2667 : 2065 : dict_update_common(PyObject *self, PyObject *args, PyObject *kwds,
2668 : : const char *methname)
2669 : : {
2670 : 2065 : PyObject *arg = NULL;
2671 : 2065 : int result = 0;
2672 : :
2673 [ - + ]: 2065 : if (!PyArg_UnpackTuple(args, methname, 0, 1, &arg)) {
2674 : 0 : result = -1;
2675 : : }
2676 [ + + ]: 2065 : else if (arg != NULL) {
2677 : 1211 : result = dict_update_arg(self, arg);
2678 : : }
2679 : :
2680 [ + - + + ]: 2065 : if (result == 0 && kwds != NULL) {
2681 [ + - ]: 2 : if (PyArg_ValidateKeywordArguments(kwds))
2682 : 2 : result = PyDict_Merge(self, kwds, 1);
2683 : : else
2684 : 0 : result = -1;
2685 : : }
2686 : 2065 : return result;
2687 : : }
2688 : :
2689 : : /* Note: dict.update() uses the METH_VARARGS|METH_KEYWORDS calling convention.
2690 : : Using METH_FASTCALL|METH_KEYWORDS would make dict.update(**dict2) calls
2691 : : slower, see the issue #29312. */
2692 : : static PyObject *
2693 : 1213 : dict_update(PyObject *self, PyObject *args, PyObject *kwds)
2694 : : {
2695 [ + - ]: 1213 : if (dict_update_common(self, args, kwds, "update") != -1)
2696 : 1213 : Py_RETURN_NONE;
2697 : 0 : return NULL;
2698 : : }
2699 : :
2700 : : /* Update unconditionally replaces existing items.
2701 : : Merge has a 3rd argument 'override'; if set, it acts like Update,
2702 : : otherwise it leaves existing items unchanged.
2703 : :
2704 : : PyDict_{Update,Merge} update/merge from a mapping object.
2705 : :
2706 : : PyDict_MergeFromSeq2 updates/merges from any iterable object
2707 : : producing iterable objects of length 2.
2708 : : */
2709 : :
2710 : : int
2711 : 51 : PyDict_MergeFromSeq2(PyObject *d, PyObject *seq2, int override)
2712 : : {
2713 : : PyObject *it; /* iter(seq2) */
2714 : : Py_ssize_t i; /* index into seq2 of current element */
2715 : : PyObject *item; /* seq2[i] */
2716 : : PyObject *fast; /* item as a 2-tuple or 2-list */
2717 : :
2718 : : assert(d != NULL);
2719 : : assert(PyDict_Check(d));
2720 : : assert(seq2 != NULL);
2721 : :
2722 : 51 : it = PyObject_GetIter(seq2);
2723 [ - + ]: 51 : if (it == NULL)
2724 : 0 : return -1;
2725 : :
2726 : 540 : for (i = 0; ; ++i) {
2727 : : PyObject *key, *value;
2728 : : Py_ssize_t n;
2729 : :
2730 : 540 : fast = NULL;
2731 : 540 : item = PyIter_Next(it);
2732 [ + + ]: 540 : if (item == NULL) {
2733 [ - + ]: 51 : if (PyErr_Occurred())
2734 : 0 : goto Fail;
2735 : 51 : break;
2736 : : }
2737 : :
2738 : : /* Convert item to sequence, and verify length 2. */
2739 : 489 : fast = PySequence_Fast(item, "");
2740 [ - + ]: 489 : if (fast == NULL) {
2741 [ # # ]: 0 : if (PyErr_ExceptionMatches(PyExc_TypeError))
2742 : 0 : PyErr_Format(PyExc_TypeError,
2743 : : "cannot convert dictionary update "
2744 : : "sequence element #%zd to a sequence",
2745 : : i);
2746 : 0 : goto Fail;
2747 : : }
2748 [ - + ]: 489 : n = PySequence_Fast_GET_SIZE(fast);
2749 [ - + ]: 489 : if (n != 2) {
2750 : 0 : PyErr_Format(PyExc_ValueError,
2751 : : "dictionary update sequence element #%zd "
2752 : : "has length %zd; 2 is required",
2753 : : i, n);
2754 : 0 : goto Fail;
2755 : : }
2756 : :
2757 : : /* Update/merge with this (key, value) pair. */
2758 [ - + ]: 489 : key = PySequence_Fast_GET_ITEM(fast, 0);
2759 [ - + ]: 489 : value = PySequence_Fast_GET_ITEM(fast, 1);
2760 : 489 : Py_INCREF(key);
2761 : 489 : Py_INCREF(value);
2762 [ + - ]: 489 : if (override) {
2763 [ - + ]: 489 : if (PyDict_SetItem(d, key, value) < 0) {
2764 : 0 : Py_DECREF(key);
2765 : 0 : Py_DECREF(value);
2766 : 0 : goto Fail;
2767 : : }
2768 : : }
2769 : : else {
2770 [ # # ]: 0 : if (PyDict_SetDefault(d, key, value) == NULL) {
2771 : 0 : Py_DECREF(key);
2772 : 0 : Py_DECREF(value);
2773 : 0 : goto Fail;
2774 : : }
2775 : : }
2776 : :
2777 : 489 : Py_DECREF(key);
2778 : 489 : Py_DECREF(value);
2779 : 489 : Py_DECREF(fast);
2780 : 489 : Py_DECREF(item);
2781 : : }
2782 : :
2783 : 51 : i = 0;
2784 : : ASSERT_CONSISTENT(d);
2785 : 51 : goto Return;
2786 : 0 : Fail:
2787 : 0 : Py_XDECREF(item);
2788 : 0 : Py_XDECREF(fast);
2789 : 0 : i = -1;
2790 : 51 : Return:
2791 : 51 : Py_DECREF(it);
2792 : 51 : return Py_SAFE_DOWNCAST(i, Py_ssize_t, int);
2793 : : }
2794 : :
2795 : : static int
2796 : 106366 : dict_merge(PyInterpreterState *interp, PyObject *a, PyObject *b, int override)
2797 : : {
2798 : : PyDictObject *mp, *other;
2799 : :
2800 : : assert(0 <= override && override <= 2);
2801 : :
2802 : : /* We accept for the argument either a concrete dictionary object,
2803 : : * or an abstract "mapping" object. For the former, we can do
2804 : : * things quite efficiently. For the latter, we only require that
2805 : : * PyMapping_Keys() and PyObject_GetItem() be supported.
2806 : : */
2807 [ + - + - : 106366 : if (a == NULL || !PyDict_Check(a) || b == NULL) {
- + ]
2808 : 0 : PyErr_BadInternalCall();
2809 : 0 : return -1;
2810 : : }
2811 : 106366 : mp = (PyDictObject*)a;
2812 [ + + + - ]: 109012 : if (PyDict_Check(b) && (Py_TYPE(b)->tp_iter == (getiterfunc)dict_iter)) {
2813 : 106297 : other = (PyDictObject*)b;
2814 [ + - + + ]: 106297 : if (other == mp || other->ma_used == 0)
2815 : : /* a.update(a) or a.update({}); nothing to do */
2816 : 103651 : return 0;
2817 [ + + ]: 31872 : if (mp->ma_used == 0) {
2818 : : /* Since the target dict is empty, PyDict_GetItem()
2819 : : * always returns NULL. Setting override to 1
2820 : : * skips the unnecessary test.
2821 : : */
2822 : 31085 : override = 1;
2823 : 31085 : PyDictKeysObject *okeys = other->ma_keys;
2824 : :
2825 : : // If other is clean, combined, and just allocated, just clone it.
2826 [ + - ]: 31085 : if (other->ma_values == NULL &&
2827 [ + + ]: 31085 : other->ma_used == okeys->dk_nentries &&
2828 [ + + ]: 29254 : (DK_LOG_SIZE(okeys) == PyDict_LOG_MINSIZE ||
2829 [ + + ]: 70 : USABLE_FRACTION(DK_SIZE(okeys)/2) < other->ma_used)) {
2830 : 29226 : uint64_t new_version = _PyDict_NotifyEvent(
2831 : : interp, PyDict_EVENT_CLONED, mp, b, NULL);
2832 : 29226 : PyDictKeysObject *keys = clone_combined_dict_keys(other);
2833 [ - + ]: 29226 : if (keys == NULL) {
2834 : 0 : return -1;
2835 : : }
2836 : :
2837 : 29226 : dictkeys_decref(interp, mp->ma_keys);
2838 : 29226 : mp->ma_keys = keys;
2839 [ - + ]: 29226 : if (mp->ma_values != NULL) {
2840 : 0 : free_values(mp->ma_values);
2841 : 0 : mp->ma_values = NULL;
2842 : : }
2843 : :
2844 : 29226 : mp->ma_used = other->ma_used;
2845 : 29226 : mp->ma_version_tag = new_version;
2846 : : ASSERT_CONSISTENT(mp);
2847 : :
2848 [ + + + + ]: 29226 : if (_PyObject_GC_IS_TRACKED(other) && !_PyObject_GC_IS_TRACKED(mp)) {
2849 : : /* Maintain tracking. */
2850 : 70 : _PyObject_GC_TRACK(mp);
2851 : : }
2852 : :
2853 : 29226 : return 0;
2854 : : }
2855 : : }
2856 : : /* Do one big resize at the start, rather than
2857 : : * incrementally resizing as we insert new items. Expect
2858 : : * that there will be no (or few) overlapping keys.
2859 : : */
2860 [ + + ]: 2646 : if (USABLE_FRACTION(DK_SIZE(mp->ma_keys)) < other->ma_used) {
2861 : 1865 : int unicode = DK_IS_UNICODE(other->ma_keys);
2862 [ - + ]: 1865 : if (dictresize(interp, mp,
2863 : 1865 : estimate_log2_keysize(mp->ma_used + other->ma_used),
2864 : : unicode)) {
2865 : 0 : return -1;
2866 : : }
2867 : : }
2868 : :
2869 : 2646 : Py_ssize_t orig_size = other->ma_keys->dk_nentries;
2870 : 2646 : Py_ssize_t pos = 0;
2871 : : Py_hash_t hash;
2872 : : PyObject *key, *value;
2873 : :
2874 [ + + ]: 19883 : while (_PyDict_Next((PyObject*)other, &pos, &key, &value, &hash)) {
2875 : 17237 : int err = 0;
2876 : 17237 : Py_INCREF(key);
2877 : 17237 : Py_INCREF(value);
2878 [ + + ]: 17237 : if (override == 1) {
2879 : 17207 : err = insertdict(interp, mp,
2880 : : Py_NewRef(key), hash, Py_NewRef(value));
2881 : : }
2882 : : else {
2883 : 30 : err = _PyDict_Contains_KnownHash(a, key, hash);
2884 [ + - ]: 30 : if (err == 0) {
2885 : 30 : err = insertdict(interp, mp,
2886 : : Py_NewRef(key), hash, Py_NewRef(value));
2887 : : }
2888 [ # # ]: 0 : else if (err > 0) {
2889 [ # # ]: 0 : if (override != 0) {
2890 : 0 : _PyErr_SetKeyError(key);
2891 : 0 : Py_DECREF(value);
2892 : 0 : Py_DECREF(key);
2893 : 0 : return -1;
2894 : : }
2895 : 0 : err = 0;
2896 : : }
2897 : : }
2898 : 17237 : Py_DECREF(value);
2899 : 17237 : Py_DECREF(key);
2900 [ - + ]: 17237 : if (err != 0)
2901 : 0 : return -1;
2902 : :
2903 [ - + ]: 17237 : if (orig_size != other->ma_keys->dk_nentries) {
2904 : 0 : PyErr_SetString(PyExc_RuntimeError,
2905 : : "dict mutated during update");
2906 : 0 : return -1;
2907 : : }
2908 : : }
2909 : : }
2910 : : else {
2911 : : /* Do it the generic, slower way */
2912 : 69 : PyObject *keys = PyMapping_Keys(b);
2913 : : PyObject *iter;
2914 : : PyObject *key, *value;
2915 : : int status;
2916 : :
2917 [ - + ]: 69 : if (keys == NULL)
2918 : : /* Docstring says this is equivalent to E.keys() so
2919 : : * if E doesn't have a .keys() method we want
2920 : : * AttributeError to percolate up. Might as well
2921 : : * do the same for any other error.
2922 : : */
2923 : 0 : return -1;
2924 : :
2925 : 69 : iter = PyObject_GetIter(keys);
2926 : 69 : Py_DECREF(keys);
2927 [ - + ]: 69 : if (iter == NULL)
2928 : 0 : return -1;
2929 : :
2930 [ + + ]: 1743 : for (key = PyIter_Next(iter); key; key = PyIter_Next(iter)) {
2931 [ - + ]: 1674 : if (override != 1) {
2932 : 0 : status = PyDict_Contains(a, key);
2933 [ # # ]: 0 : if (status != 0) {
2934 [ # # ]: 0 : if (status > 0) {
2935 [ # # ]: 0 : if (override == 0) {
2936 : 0 : Py_DECREF(key);
2937 : 0 : continue;
2938 : : }
2939 : 0 : _PyErr_SetKeyError(key);
2940 : : }
2941 : 0 : Py_DECREF(key);
2942 : 0 : Py_DECREF(iter);
2943 : 0 : return -1;
2944 : : }
2945 : : }
2946 : 1674 : value = PyObject_GetItem(b, key);
2947 [ - + ]: 1674 : if (value == NULL) {
2948 : 0 : Py_DECREF(iter);
2949 : 0 : Py_DECREF(key);
2950 : 0 : return -1;
2951 : : }
2952 : 1674 : status = PyDict_SetItem(a, key, value);
2953 : 1674 : Py_DECREF(key);
2954 : 1674 : Py_DECREF(value);
2955 [ - + ]: 1674 : if (status < 0) {
2956 : 0 : Py_DECREF(iter);
2957 : 0 : return -1;
2958 : : }
2959 : : }
2960 : 69 : Py_DECREF(iter);
2961 [ - + ]: 69 : if (PyErr_Occurred())
2962 : : /* Iterator completed, via error */
2963 : 0 : return -1;
2964 : : }
2965 : : ASSERT_CONSISTENT(a);
2966 : 2715 : return 0;
2967 : : }
2968 : :
2969 : : int
2970 : 998 : PyDict_Update(PyObject *a, PyObject *b)
2971 : : {
2972 : 998 : PyInterpreterState *interp = _PyInterpreterState_GET();
2973 : 998 : return dict_merge(interp, a, b, 1);
2974 : : }
2975 : :
2976 : : int
2977 : 1280 : PyDict_Merge(PyObject *a, PyObject *b, int override)
2978 : : {
2979 : 1280 : PyInterpreterState *interp = _PyInterpreterState_GET();
2980 : : /* XXX Deprecate override not in (0, 1). */
2981 : 1280 : return dict_merge(interp, a, b, override != 0);
2982 : : }
2983 : :
2984 : : int
2985 : 102304 : _PyDict_MergeEx(PyObject *a, PyObject *b, int override)
2986 : : {
2987 : 102304 : PyInterpreterState *interp = _PyInterpreterState_GET();
2988 : 102304 : return dict_merge(interp, a, b, override);
2989 : : }
2990 : :
2991 : : static PyObject *
2992 : 1975 : dict_copy(PyDictObject *mp, PyObject *Py_UNUSED(ignored))
2993 : : {
2994 : 1975 : return PyDict_Copy((PyObject*)mp);
2995 : : }
2996 : :
2997 : : PyObject *
2998 : 14694 : PyDict_Copy(PyObject *o)
2999 : : {
3000 : : PyObject *copy;
3001 : : PyDictObject *mp;
3002 : 14694 : PyInterpreterState *interp = _PyInterpreterState_GET();
3003 : :
3004 [ + - - + ]: 14694 : if (o == NULL || !PyDict_Check(o)) {
3005 : 0 : PyErr_BadInternalCall();
3006 : 0 : return NULL;
3007 : : }
3008 : :
3009 : 14694 : mp = (PyDictObject *)o;
3010 [ + + ]: 14694 : if (mp->ma_used == 0) {
3011 : : /* The dict is empty; just return a new dict. */
3012 : 35 : return PyDict_New();
3013 : : }
3014 : :
3015 [ - + ]: 14659 : if (_PyDict_HasSplitTable(mp)) {
3016 : : PyDictObject *split_copy;
3017 : 0 : size_t size = shared_keys_usable_size(mp->ma_keys);
3018 : 0 : PyDictValues *newvalues = new_values(size);
3019 [ # # ]: 0 : if (newvalues == NULL)
3020 : 0 : return PyErr_NoMemory();
3021 : 0 : split_copy = PyObject_GC_New(PyDictObject, &PyDict_Type);
3022 [ # # ]: 0 : if (split_copy == NULL) {
3023 : 0 : free_values(newvalues);
3024 : 0 : return NULL;
3025 : : }
3026 : 0 : size_t prefix_size = ((uint8_t *)newvalues)[-1];
3027 : 0 : memcpy(((char *)newvalues)-prefix_size, ((char *)mp->ma_values)-prefix_size, prefix_size-1);
3028 : 0 : split_copy->ma_values = newvalues;
3029 : 0 : split_copy->ma_keys = mp->ma_keys;
3030 : 0 : split_copy->ma_used = mp->ma_used;
3031 : 0 : split_copy->ma_version_tag = DICT_NEXT_VERSION(interp);
3032 : 0 : dictkeys_incref(mp->ma_keys);
3033 [ # # ]: 0 : for (size_t i = 0; i < size; i++) {
3034 : 0 : PyObject *value = mp->ma_values->values[i];
3035 : 0 : split_copy->ma_values->values[i] = Py_XNewRef(value);
3036 : : }
3037 [ # # ]: 0 : if (_PyObject_GC_IS_TRACKED(mp))
3038 : 0 : _PyObject_GC_TRACK(split_copy);
3039 : 0 : return (PyObject *)split_copy;
3040 : : }
3041 : :
3042 [ + - ]: 14659 : if (Py_TYPE(mp)->tp_iter == (getiterfunc)dict_iter &&
3043 [ + - ]: 14659 : mp->ma_values == NULL &&
3044 [ + + ]: 14659 : (mp->ma_used >= (mp->ma_keys->dk_nentries * 2) / 3))
3045 : : {
3046 : : /* Use fast-copy if:
3047 : :
3048 : : (1) type(mp) doesn't override tp_iter; and
3049 : :
3050 : : (2) 'mp' is not a split-dict; and
3051 : :
3052 : : (3) if 'mp' is non-compact ('del' operation does not resize dicts),
3053 : : do fast-copy only if it has at most 1/3 non-used keys.
3054 : :
3055 : : The last condition (3) is important to guard against a pathological
3056 : : case when a large dict is almost emptied with multiple del/pop
3057 : : operations and copied after that. In cases like this, we defer to
3058 : : PyDict_Merge, which produces a compacted copy.
3059 : : */
3060 : 12875 : PyDictKeysObject *keys = clone_combined_dict_keys(mp);
3061 [ - + ]: 12875 : if (keys == NULL) {
3062 : 0 : return NULL;
3063 : : }
3064 : 12875 : PyDictObject *new = (PyDictObject *)new_dict(interp, keys, NULL, 0, 0);
3065 [ - + ]: 12875 : if (new == NULL) {
3066 : : /* In case of an error, `new_dict()` takes care of
3067 : : cleaning up `keys`. */
3068 : 0 : return NULL;
3069 : : }
3070 : :
3071 : 12875 : new->ma_used = mp->ma_used;
3072 : : ASSERT_CONSISTENT(new);
3073 [ + + ]: 12875 : if (_PyObject_GC_IS_TRACKED(mp)) {
3074 : : /* Maintain tracking. */
3075 : 9855 : _PyObject_GC_TRACK(new);
3076 : : }
3077 : :
3078 : 12875 : return (PyObject *)new;
3079 : : }
3080 : :
3081 : 1784 : copy = PyDict_New();
3082 [ - + ]: 1784 : if (copy == NULL)
3083 : 0 : return NULL;
3084 [ + - ]: 1784 : if (dict_merge(interp, copy, o, 1) == 0)
3085 : 1784 : return copy;
3086 : 0 : Py_DECREF(copy);
3087 : 0 : return NULL;
3088 : : }
3089 : :
3090 : : Py_ssize_t
3091 : 12404 : PyDict_Size(PyObject *mp)
3092 : : {
3093 [ + - - + ]: 12404 : if (mp == NULL || !PyDict_Check(mp)) {
3094 : 0 : PyErr_BadInternalCall();
3095 : 0 : return -1;
3096 : : }
3097 : 12404 : return ((PyDictObject *)mp)->ma_used;
3098 : : }
3099 : :
3100 : : PyObject *
3101 : 16221 : PyDict_Keys(PyObject *mp)
3102 : : {
3103 [ + - - + ]: 16221 : if (mp == NULL || !PyDict_Check(mp)) {
3104 : 0 : PyErr_BadInternalCall();
3105 : 0 : return NULL;
3106 : : }
3107 : 16221 : return dict_keys((PyDictObject *)mp);
3108 : : }
3109 : :
3110 : : PyObject *
3111 : 0 : PyDict_Values(PyObject *mp)
3112 : : {
3113 [ # # # # ]: 0 : if (mp == NULL || !PyDict_Check(mp)) {
3114 : 0 : PyErr_BadInternalCall();
3115 : 0 : return NULL;
3116 : : }
3117 : 0 : return dict_values((PyDictObject *)mp);
3118 : : }
3119 : :
3120 : : PyObject *
3121 : 0 : PyDict_Items(PyObject *mp)
3122 : : {
3123 [ # # # # ]: 0 : if (mp == NULL || !PyDict_Check(mp)) {
3124 : 0 : PyErr_BadInternalCall();
3125 : 0 : return NULL;
3126 : : }
3127 : 0 : return dict_items((PyDictObject *)mp);
3128 : : }
3129 : :
3130 : : /* Return 1 if dicts equal, 0 if not, -1 if error.
3131 : : * Gets out as soon as any difference is detected.
3132 : : * Uses only Py_EQ comparison.
3133 : : */
3134 : : static int
3135 : 13 : dict_equal(PyDictObject *a, PyDictObject *b)
3136 : : {
3137 : : Py_ssize_t i;
3138 : :
3139 [ - + ]: 13 : if (a->ma_used != b->ma_used)
3140 : : /* can't be equal if # of entries differ */
3141 : 0 : return 0;
3142 : : /* Same # of entries -- check all of 'em. Exit early on any diff. */
3143 [ + + ]: 2180 : for (i = 0; i < a->ma_keys->dk_nentries; i++) {
3144 : : PyObject *key, *aval;
3145 : : Py_hash_t hash;
3146 [ + + ]: 2167 : if (DK_IS_UNICODE(a->ma_keys)) {
3147 : 2166 : PyDictUnicodeEntry *ep = &DK_UNICODE_ENTRIES(a->ma_keys)[i];
3148 : 2166 : key = ep->me_key;
3149 [ - + ]: 2166 : if (key == NULL) {
3150 : 0 : continue;
3151 : : }
3152 : 2166 : hash = unicode_get_hash(key);
3153 [ - + ]: 2166 : if (a->ma_values)
3154 : 0 : aval = a->ma_values->values[i];
3155 : : else
3156 : 2166 : aval = ep->me_value;
3157 : : }
3158 : : else {
3159 : 1 : PyDictKeyEntry *ep = &DK_ENTRIES(a->ma_keys)[i];
3160 : 1 : key = ep->me_key;
3161 : 1 : aval = ep->me_value;
3162 : 1 : hash = ep->me_hash;
3163 : : }
3164 [ + - ]: 2167 : if (aval != NULL) {
3165 : : int cmp;
3166 : : PyObject *bval;
3167 : : /* temporarily bump aval's refcount to ensure it stays
3168 : : alive until we're done with it */
3169 : 2167 : Py_INCREF(aval);
3170 : : /* ditto for key */
3171 : 2167 : Py_INCREF(key);
3172 : : /* reuse the known hash value */
3173 : 2167 : _Py_dict_lookup(b, key, hash, &bval);
3174 [ - + ]: 2167 : if (bval == NULL) {
3175 : 0 : Py_DECREF(key);
3176 : 0 : Py_DECREF(aval);
3177 [ # # ]: 0 : if (PyErr_Occurred())
3178 : 0 : return -1;
3179 : 0 : return 0;
3180 : : }
3181 : 2167 : Py_INCREF(bval);
3182 : 2167 : cmp = PyObject_RichCompareBool(aval, bval, Py_EQ);
3183 : 2167 : Py_DECREF(key);
3184 : 2167 : Py_DECREF(aval);
3185 : 2167 : Py_DECREF(bval);
3186 [ - + ]: 2167 : if (cmp <= 0) /* error or not equal */
3187 : 0 : return cmp;
3188 : : }
3189 : : }
3190 : 13 : return 1;
3191 : : }
3192 : :
3193 : : static PyObject *
3194 : 13 : dict_richcompare(PyObject *v, PyObject *w, int op)
3195 : : {
3196 : : int cmp;
3197 : : PyObject *res;
3198 : :
3199 [ + - - + ]: 13 : if (!PyDict_Check(v) || !PyDict_Check(w)) {
3200 : 0 : res = Py_NotImplemented;
3201 : : }
3202 [ + + + - ]: 13 : else if (op == Py_EQ || op == Py_NE) {
3203 : 13 : cmp = dict_equal((PyDictObject *)v, (PyDictObject *)w);
3204 [ - + ]: 13 : if (cmp < 0)
3205 : 0 : return NULL;
3206 [ + + ]: 13 : res = (cmp == (op == Py_EQ)) ? Py_True : Py_False;
3207 : : }
3208 : : else
3209 : 0 : res = Py_NotImplemented;
3210 : 13 : return Py_NewRef(res);
3211 : : }
3212 : :
3213 : : /*[clinic input]
3214 : :
3215 : : @coexist
3216 : : dict.__contains__
3217 : :
3218 : : key: object
3219 : : /
3220 : :
3221 : : True if the dictionary has the specified key, else False.
3222 : : [clinic start generated code]*/
3223 : :
3224 : : static PyObject *
3225 : 63 : dict___contains__(PyDictObject *self, PyObject *key)
3226 : : /*[clinic end generated code: output=a3d03db709ed6e6b input=fe1cb42ad831e820]*/
3227 : : {
3228 : 63 : register PyDictObject *mp = self;
3229 : : Py_hash_t hash;
3230 : : Py_ssize_t ix;
3231 : : PyObject *value;
3232 : :
3233 [ + - - + ]: 63 : if (!PyUnicode_CheckExact(key) || (hash = unicode_get_hash(key)) == -1) {
3234 : 0 : hash = PyObject_Hash(key);
3235 [ # # ]: 0 : if (hash == -1)
3236 : 0 : return NULL;
3237 : : }
3238 : 63 : ix = _Py_dict_lookup(mp, key, hash, &value);
3239 [ - + ]: 63 : if (ix == DKIX_ERROR)
3240 : 0 : return NULL;
3241 [ - + - - ]: 63 : if (ix == DKIX_EMPTY || value == NULL)
3242 : 63 : Py_RETURN_FALSE;
3243 : 0 : Py_RETURN_TRUE;
3244 : : }
3245 : :
3246 : : /*[clinic input]
3247 : : dict.get
3248 : :
3249 : : key: object
3250 : : default: object = None
3251 : : /
3252 : :
3253 : : Return the value for key if key is in the dictionary, else default.
3254 : : [clinic start generated code]*/
3255 : :
3256 : : static PyObject *
3257 : 132694 : dict_get_impl(PyDictObject *self, PyObject *key, PyObject *default_value)
3258 : : /*[clinic end generated code: output=bba707729dee05bf input=279ddb5790b6b107]*/
3259 : : {
3260 : 132694 : PyObject *val = NULL;
3261 : : Py_hash_t hash;
3262 : : Py_ssize_t ix;
3263 : :
3264 [ + + + + ]: 132694 : if (!PyUnicode_CheckExact(key) || (hash = unicode_get_hash(key)) == -1) {
3265 : 127580 : hash = PyObject_Hash(key);
3266 [ - + ]: 127580 : if (hash == -1)
3267 : 0 : return NULL;
3268 : : }
3269 : 132694 : ix = _Py_dict_lookup(self, key, hash, &val);
3270 [ - + ]: 132694 : if (ix == DKIX_ERROR)
3271 : 0 : return NULL;
3272 [ + + - + ]: 132694 : if (ix == DKIX_EMPTY || val == NULL) {
3273 : 129968 : val = default_value;
3274 : : }
3275 : 132694 : return Py_NewRef(val);
3276 : : }
3277 : :
3278 : : PyObject *
3279 : 905324 : PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj)
3280 : : {
3281 : 905324 : PyDictObject *mp = (PyDictObject *)d;
3282 : : PyObject *value;
3283 : : Py_hash_t hash;
3284 : 905324 : PyInterpreterState *interp = _PyInterpreterState_GET();
3285 : :
3286 [ - + ]: 905324 : if (!PyDict_Check(d)) {
3287 : 0 : PyErr_BadInternalCall();
3288 : 0 : return NULL;
3289 : : }
3290 : :
3291 [ + + + + ]: 905324 : if (!PyUnicode_CheckExact(key) || (hash = unicode_get_hash(key)) == -1) {
3292 : 825259 : hash = PyObject_Hash(key);
3293 [ - + ]: 825259 : if (hash == -1)
3294 : 0 : return NULL;
3295 : : }
3296 : :
3297 [ + + ]: 905324 : if (mp->ma_keys == Py_EMPTY_KEYS) {
3298 [ - + ]: 617 : if (insert_to_emptydict(interp, mp, Py_NewRef(key), hash,
3299 : : Py_NewRef(defaultobj)) < 0) {
3300 : 0 : return NULL;
3301 : : }
3302 : 617 : return defaultobj;
3303 : : }
3304 : :
3305 [ + + + + ]: 904707 : if (!PyUnicode_CheckExact(key) && DK_IS_UNICODE(mp->ma_keys)) {
3306 [ - + ]: 157 : if (insertion_resize(interp, mp, 0) < 0) {
3307 : 0 : return NULL;
3308 : : }
3309 : : }
3310 : :
3311 : 904707 : Py_ssize_t ix = _Py_dict_lookup(mp, key, hash, &value);
3312 [ - + ]: 904707 : if (ix == DKIX_ERROR)
3313 : 0 : return NULL;
3314 : :
3315 [ + + ]: 904707 : if (ix == DKIX_EMPTY) {
3316 : 223715 : uint64_t new_version = _PyDict_NotifyEvent(
3317 : : interp, PyDict_EVENT_ADDED, mp, key, defaultobj);
3318 : 223715 : mp->ma_keys->dk_version = 0;
3319 : 223715 : value = defaultobj;
3320 [ + + ]: 223715 : if (mp->ma_keys->dk_usable <= 0) {
3321 [ - + ]: 5939 : if (insertion_resize(interp, mp, 1) < 0) {
3322 : 0 : return NULL;
3323 : : }
3324 : : }
3325 : 223715 : Py_ssize_t hashpos = find_empty_slot(mp->ma_keys, hash);
3326 : 223715 : dictkeys_set_index(mp->ma_keys, hashpos, mp->ma_keys->dk_nentries);
3327 [ + + ]: 223715 : if (DK_IS_UNICODE(mp->ma_keys)) {
3328 : : assert(PyUnicode_CheckExact(key));
3329 : 157601 : PyDictUnicodeEntry *ep = &DK_UNICODE_ENTRIES(mp->ma_keys)[mp->ma_keys->dk_nentries];
3330 : 157601 : ep->me_key = Py_NewRef(key);
3331 [ - + ]: 157601 : if (_PyDict_HasSplitTable(mp)) {
3332 : 0 : Py_ssize_t index = (int)mp->ma_keys->dk_nentries;
3333 : : assert(index < SHARED_KEYS_MAX_SIZE);
3334 : : assert(mp->ma_values->values[index] == NULL);
3335 : 0 : mp->ma_values->values[index] = Py_NewRef(value);
3336 : 0 : _PyDictValues_AddToInsertionOrder(mp->ma_values, index);
3337 : : }
3338 : : else {
3339 : 157601 : ep->me_value = Py_NewRef(value);
3340 : : }
3341 : : }
3342 : : else {
3343 : 66114 : PyDictKeyEntry *ep = &DK_ENTRIES(mp->ma_keys)[mp->ma_keys->dk_nentries];
3344 : 66114 : ep->me_key = Py_NewRef(key);
3345 : 66114 : ep->me_hash = hash;
3346 : 66114 : ep->me_value = Py_NewRef(value);
3347 : : }
3348 [ + + + + : 223715 : MAINTAIN_TRACKING(mp, key, value);
+ + ]
3349 : 223715 : mp->ma_used++;
3350 : 223715 : mp->ma_version_tag = new_version;
3351 : 223715 : mp->ma_keys->dk_usable--;
3352 : 223715 : mp->ma_keys->dk_nentries++;
3353 : : assert(mp->ma_keys->dk_usable >= 0);
3354 : : }
3355 [ - + ]: 680992 : else if (value == NULL) {
3356 : 0 : uint64_t new_version = _PyDict_NotifyEvent(
3357 : : interp, PyDict_EVENT_ADDED, mp, key, defaultobj);
3358 : 0 : value = defaultobj;
3359 : : assert(_PyDict_HasSplitTable(mp));
3360 : : assert(mp->ma_values->values[ix] == NULL);
3361 [ # # # # : 0 : MAINTAIN_TRACKING(mp, key, value);
# # ]
3362 : 0 : mp->ma_values->values[ix] = Py_NewRef(value);
3363 : 0 : _PyDictValues_AddToInsertionOrder(mp->ma_values, ix);
3364 : 0 : mp->ma_used++;
3365 : 0 : mp->ma_version_tag = new_version;
3366 : : }
3367 : :
3368 : : ASSERT_CONSISTENT(mp);
3369 : 904707 : return value;
3370 : : }
3371 : :
3372 : : /*[clinic input]
3373 : : dict.setdefault
3374 : :
3375 : : key: object
3376 : : default: object = None
3377 : : /
3378 : :
3379 : : Insert key with a value of default if key is not in the dictionary.
3380 : :
3381 : : Return the value for key if key is in the dictionary, else default.
3382 : : [clinic start generated code]*/
3383 : :
3384 : : static PyObject *
3385 : 1723 : dict_setdefault_impl(PyDictObject *self, PyObject *key,
3386 : : PyObject *default_value)
3387 : : /*[clinic end generated code: output=f8c1101ebf69e220 input=0f063756e815fd9d]*/
3388 : : {
3389 : : PyObject *val;
3390 : :
3391 : 1723 : val = PyDict_SetDefault((PyObject *)self, key, default_value);
3392 : 1723 : return Py_XNewRef(val);
3393 : : }
3394 : :
3395 : : static PyObject *
3396 : 11 : dict_clear(PyDictObject *mp, PyObject *Py_UNUSED(ignored))
3397 : : {
3398 : 11 : PyDict_Clear((PyObject *)mp);
3399 : 11 : Py_RETURN_NONE;
3400 : : }
3401 : :
3402 : : /*[clinic input]
3403 : : dict.pop
3404 : :
3405 : : key: object
3406 : : default: object = NULL
3407 : : /
3408 : :
3409 : : D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
3410 : :
3411 : : If the key is not found, return the default if given; otherwise,
3412 : : raise a KeyError.
3413 : : [clinic start generated code]*/
3414 : :
3415 : : static PyObject *
3416 : 1427 : dict_pop_impl(PyDictObject *self, PyObject *key, PyObject *default_value)
3417 : : /*[clinic end generated code: output=3abb47b89f24c21c input=e221baa01044c44c]*/
3418 : : {
3419 : 1427 : return _PyDict_Pop((PyObject*)self, key, default_value);
3420 : : }
3421 : :
3422 : : /*[clinic input]
3423 : : dict.popitem
3424 : :
3425 : : Remove and return a (key, value) pair as a 2-tuple.
3426 : :
3427 : : Pairs are returned in LIFO (last-in, first-out) order.
3428 : : Raises KeyError if the dict is empty.
3429 : : [clinic start generated code]*/
3430 : :
3431 : : static PyObject *
3432 : 0 : dict_popitem_impl(PyDictObject *self)
3433 : : /*[clinic end generated code: output=e65fcb04420d230d input=1c38a49f21f64941]*/
3434 : : {
3435 : : Py_ssize_t i, j;
3436 : : PyObject *res;
3437 : : uint64_t new_version;
3438 : 0 : PyInterpreterState *interp = _PyInterpreterState_GET();
3439 : :
3440 : : /* Allocate the result tuple before checking the size. Believe it
3441 : : * or not, this allocation could trigger a garbage collection which
3442 : : * could empty the dict, so if we checked the size first and that
3443 : : * happened, the result would be an infinite loop (searching for an
3444 : : * entry that no longer exists). Note that the usual popitem()
3445 : : * idiom is "while d: k, v = d.popitem()". so needing to throw the
3446 : : * tuple away if the dict *is* empty isn't a significant
3447 : : * inefficiency -- possible, but unlikely in practice.
3448 : : */
3449 : 0 : res = PyTuple_New(2);
3450 [ # # ]: 0 : if (res == NULL)
3451 : 0 : return NULL;
3452 [ # # ]: 0 : if (self->ma_used == 0) {
3453 : 0 : Py_DECREF(res);
3454 : 0 : PyErr_SetString(PyExc_KeyError, "popitem(): dictionary is empty");
3455 : 0 : return NULL;
3456 : : }
3457 : : /* Convert split table to combined table */
3458 [ # # ]: 0 : if (self->ma_keys->dk_kind == DICT_KEYS_SPLIT) {
3459 [ # # ]: 0 : if (dictresize(interp, self, DK_LOG_SIZE(self->ma_keys), 1)) {
3460 : 0 : Py_DECREF(res);
3461 : 0 : return NULL;
3462 : : }
3463 : : }
3464 : 0 : self->ma_keys->dk_version = 0;
3465 : :
3466 : : /* Pop last item */
3467 : : PyObject *key, *value;
3468 : : Py_hash_t hash;
3469 [ # # ]: 0 : if (DK_IS_UNICODE(self->ma_keys)) {
3470 : 0 : PyDictUnicodeEntry *ep0 = DK_UNICODE_ENTRIES(self->ma_keys);
3471 : 0 : i = self->ma_keys->dk_nentries - 1;
3472 [ # # # # ]: 0 : while (i >= 0 && ep0[i].me_value == NULL) {
3473 : 0 : i--;
3474 : : }
3475 : : assert(i >= 0);
3476 : :
3477 : 0 : key = ep0[i].me_key;
3478 : 0 : new_version = _PyDict_NotifyEvent(
3479 : : interp, PyDict_EVENT_DELETED, self, key, NULL);
3480 : 0 : hash = unicode_get_hash(key);
3481 : 0 : value = ep0[i].me_value;
3482 : 0 : ep0[i].me_key = NULL;
3483 : 0 : ep0[i].me_value = NULL;
3484 : : }
3485 : : else {
3486 : 0 : PyDictKeyEntry *ep0 = DK_ENTRIES(self->ma_keys);
3487 : 0 : i = self->ma_keys->dk_nentries - 1;
3488 [ # # # # ]: 0 : while (i >= 0 && ep0[i].me_value == NULL) {
3489 : 0 : i--;
3490 : : }
3491 : : assert(i >= 0);
3492 : :
3493 : 0 : key = ep0[i].me_key;
3494 : 0 : new_version = _PyDict_NotifyEvent(
3495 : : interp, PyDict_EVENT_DELETED, self, key, NULL);
3496 : 0 : hash = ep0[i].me_hash;
3497 : 0 : value = ep0[i].me_value;
3498 : 0 : ep0[i].me_key = NULL;
3499 : 0 : ep0[i].me_hash = -1;
3500 : 0 : ep0[i].me_value = NULL;
3501 : : }
3502 : :
3503 : 0 : j = lookdict_index(self->ma_keys, hash, i);
3504 : : assert(j >= 0);
3505 : : assert(dictkeys_get_index(self->ma_keys, j) == i);
3506 : 0 : dictkeys_set_index(self->ma_keys, j, DKIX_DUMMY);
3507 : :
3508 : 0 : PyTuple_SET_ITEM(res, 0, key);
3509 : 0 : PyTuple_SET_ITEM(res, 1, value);
3510 : : /* We can't dk_usable++ since there is DKIX_DUMMY in indices */
3511 : 0 : self->ma_keys->dk_nentries = i;
3512 : 0 : self->ma_used--;
3513 : 0 : self->ma_version_tag = new_version;
3514 : : ASSERT_CONSISTENT(self);
3515 : 0 : return res;
3516 : : }
3517 : :
3518 : : static int
3519 : 187680 : dict_traverse(PyObject *op, visitproc visit, void *arg)
3520 : : {
3521 : 187680 : PyDictObject *mp = (PyDictObject *)op;
3522 : 187680 : PyDictKeysObject *keys = mp->ma_keys;
3523 : 187680 : Py_ssize_t i, n = keys->dk_nentries;
3524 : :
3525 [ + + ]: 187680 : if (DK_IS_UNICODE(keys)) {
3526 [ + + ]: 161670 : if (mp->ma_values != NULL) {
3527 [ + + ]: 88600 : for (i = 0; i < n; i++) {
3528 [ + + - + ]: 78662 : Py_VISIT(mp->ma_values->values[i]);
3529 : : }
3530 : : }
3531 : : else {
3532 : 151732 : PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(keys);
3533 [ + + ]: 2342540 : for (i = 0; i < n; i++) {
3534 [ + + - + ]: 2190808 : Py_VISIT(entries[i].me_value);
3535 : : }
3536 : : }
3537 : : }
3538 : : else {
3539 : 26010 : PyDictKeyEntry *entries = DK_ENTRIES(keys);
3540 [ + + ]: 209834 : for (i = 0; i < n; i++) {
3541 [ + + ]: 183824 : if (entries[i].me_value != NULL) {
3542 [ + - - + ]: 177394 : Py_VISIT(entries[i].me_value);
3543 [ + - - + ]: 177394 : Py_VISIT(entries[i].me_key);
3544 : : }
3545 : : }
3546 : : }
3547 : 187680 : return 0;
3548 : : }
3549 : :
3550 : : static int
3551 : 1165 : dict_tp_clear(PyObject *op)
3552 : : {
3553 : 1165 : PyDict_Clear(op);
3554 : 1165 : return 0;
3555 : : }
3556 : :
3557 : : static PyObject *dictiter_new(PyDictObject *, PyTypeObject *);
3558 : :
3559 : : Py_ssize_t
3560 : 0 : _PyDict_SizeOf(PyDictObject *mp)
3561 : : {
3562 : 0 : size_t res = _PyObject_SIZE(Py_TYPE(mp));
3563 [ # # ]: 0 : if (mp->ma_values) {
3564 : 0 : res += shared_keys_usable_size(mp->ma_keys) * sizeof(PyObject*);
3565 : : }
3566 : : /* If the dictionary is split, the keys portion is accounted-for
3567 : : in the type object. */
3568 [ # # ]: 0 : if (mp->ma_keys->dk_refcnt == 1) {
3569 : 0 : res += _PyDict_KeysSize(mp->ma_keys);
3570 : : }
3571 : : assert(res <= (size_t)PY_SSIZE_T_MAX);
3572 : 0 : return (Py_ssize_t)res;
3573 : : }
3574 : :
3575 : : size_t
3576 : 42101 : _PyDict_KeysSize(PyDictKeysObject *keys)
3577 : : {
3578 : 84202 : size_t es = (keys->dk_kind == DICT_KEYS_GENERAL
3579 [ + + ]: 42101 : ? sizeof(PyDictKeyEntry) : sizeof(PyDictUnicodeEntry));
3580 : 42101 : size_t size = sizeof(PyDictKeysObject);
3581 : 42101 : size += (size_t)1 << keys->dk_log2_index_bytes;
3582 : 42101 : size += USABLE_FRACTION((size_t)DK_SIZE(keys)) * es;
3583 : 42101 : return size;
3584 : : }
3585 : :
3586 : : static PyObject *
3587 : 0 : dict_sizeof(PyDictObject *mp, PyObject *Py_UNUSED(ignored))
3588 : : {
3589 : 0 : return PyLong_FromSsize_t(_PyDict_SizeOf(mp));
3590 : : }
3591 : :
3592 : : static PyObject *
3593 : 0 : dict_or(PyObject *self, PyObject *other)
3594 : : {
3595 [ # # # # ]: 0 : if (!PyDict_Check(self) || !PyDict_Check(other)) {
3596 : 0 : Py_RETURN_NOTIMPLEMENTED;
3597 : : }
3598 : 0 : PyObject *new = PyDict_Copy(self);
3599 [ # # ]: 0 : if (new == NULL) {
3600 : 0 : return NULL;
3601 : : }
3602 [ # # ]: 0 : if (dict_update_arg(new, other)) {
3603 : 0 : Py_DECREF(new);
3604 : 0 : return NULL;
3605 : : }
3606 : 0 : return new;
3607 : : }
3608 : :
3609 : : static PyObject *
3610 : 4 : dict_ior(PyObject *self, PyObject *other)
3611 : : {
3612 [ - + ]: 4 : if (dict_update_arg(self, other)) {
3613 : 0 : return NULL;
3614 : : }
3615 : 4 : return Py_NewRef(self);
3616 : : }
3617 : :
3618 : : PyDoc_STRVAR(getitem__doc__,
3619 : : "__getitem__($self, key, /)\n--\n\nReturn self[key].");
3620 : :
3621 : : PyDoc_STRVAR(sizeof__doc__,
3622 : : "D.__sizeof__() -> size of D in memory, in bytes");
3623 : :
3624 : : PyDoc_STRVAR(update__doc__,
3625 : : "D.update([E, ]**F) -> None. Update D from dict/iterable E and F.\n\
3626 : : If E is present and has a .keys() method, then does: for k in E: D[k] = E[k]\n\
3627 : : If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v\n\
3628 : : In either case, this is followed by: for k in F: D[k] = F[k]");
3629 : :
3630 : : PyDoc_STRVAR(clear__doc__,
3631 : : "D.clear() -> None. Remove all items from D.");
3632 : :
3633 : : PyDoc_STRVAR(copy__doc__,
3634 : : "D.copy() -> a shallow copy of D");
3635 : :
3636 : : /* Forward */
3637 : : static PyObject *dictkeys_new(PyObject *, PyObject *);
3638 : : static PyObject *dictitems_new(PyObject *, PyObject *);
3639 : : static PyObject *dictvalues_new(PyObject *, PyObject *);
3640 : :
3641 : : PyDoc_STRVAR(keys__doc__,
3642 : : "D.keys() -> a set-like object providing a view on D's keys");
3643 : : PyDoc_STRVAR(items__doc__,
3644 : : "D.items() -> a set-like object providing a view on D's items");
3645 : : PyDoc_STRVAR(values__doc__,
3646 : : "D.values() -> an object providing a view on D's values");
3647 : :
3648 : : static PyMethodDef mapp_methods[] = {
3649 : : DICT___CONTAINS___METHODDEF
3650 : : {"__getitem__", _PyCFunction_CAST(dict_subscript), METH_O | METH_COEXIST,
3651 : : getitem__doc__},
3652 : : {"__sizeof__", _PyCFunction_CAST(dict_sizeof), METH_NOARGS,
3653 : : sizeof__doc__},
3654 : : DICT_GET_METHODDEF
3655 : : DICT_SETDEFAULT_METHODDEF
3656 : : DICT_POP_METHODDEF
3657 : : DICT_POPITEM_METHODDEF
3658 : : {"keys", dictkeys_new, METH_NOARGS,
3659 : : keys__doc__},
3660 : : {"items", dictitems_new, METH_NOARGS,
3661 : : items__doc__},
3662 : : {"values", dictvalues_new, METH_NOARGS,
3663 : : values__doc__},
3664 : : {"update", _PyCFunction_CAST(dict_update), METH_VARARGS | METH_KEYWORDS,
3665 : : update__doc__},
3666 : : DICT_FROMKEYS_METHODDEF
3667 : : {"clear", (PyCFunction)dict_clear, METH_NOARGS,
3668 : : clear__doc__},
3669 : : {"copy", (PyCFunction)dict_copy, METH_NOARGS,
3670 : : copy__doc__},
3671 : : DICT___REVERSED___METHODDEF
3672 : : {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")},
3673 : : {NULL, NULL} /* sentinel */
3674 : : };
3675 : :
3676 : : /* Return 1 if `key` is in dict `op`, 0 if not, and -1 on error. */
3677 : : int
3678 : 109713 : PyDict_Contains(PyObject *op, PyObject *key)
3679 : : {
3680 : : Py_hash_t hash;
3681 : : Py_ssize_t ix;
3682 : 109713 : PyDictObject *mp = (PyDictObject *)op;
3683 : : PyObject *value;
3684 : :
3685 [ + + + + ]: 109713 : if (!PyUnicode_CheckExact(key) || (hash = unicode_get_hash(key)) == -1) {
3686 : 20256 : hash = PyObject_Hash(key);
3687 [ - + ]: 20256 : if (hash == -1)
3688 : 0 : return -1;
3689 : : }
3690 : 109713 : ix = _Py_dict_lookup(mp, key, hash, &value);
3691 [ - + ]: 109713 : if (ix == DKIX_ERROR)
3692 : 0 : return -1;
3693 [ + + + - ]: 109713 : return (ix != DKIX_EMPTY && value != NULL);
3694 : : }
3695 : :
3696 : : /* Internal version of PyDict_Contains used when the hash value is already known */
3697 : : int
3698 : 30 : _PyDict_Contains_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash)
3699 : : {
3700 : 30 : PyDictObject *mp = (PyDictObject *)op;
3701 : : PyObject *value;
3702 : : Py_ssize_t ix;
3703 : :
3704 : 30 : ix = _Py_dict_lookup(mp, key, hash, &value);
3705 [ - + ]: 30 : if (ix == DKIX_ERROR)
3706 : 0 : return -1;
3707 [ - + - - ]: 30 : return (ix != DKIX_EMPTY && value != NULL);
3708 : : }
3709 : :
3710 : : int
3711 : 0 : _PyDict_ContainsId(PyObject *op, _Py_Identifier *key)
3712 : : {
3713 : 0 : PyObject *kv = _PyUnicode_FromId(key); /* borrowed */
3714 [ # # ]: 0 : if (kv == NULL) {
3715 : 0 : return -1;
3716 : : }
3717 : 0 : return PyDict_Contains(op, kv);
3718 : : }
3719 : :
3720 : : /* Hack to implement "key in dict" */
3721 : : static PySequenceMethods dict_as_sequence = {
3722 : : 0, /* sq_length */
3723 : : 0, /* sq_concat */
3724 : : 0, /* sq_repeat */
3725 : : 0, /* sq_item */
3726 : : 0, /* sq_slice */
3727 : : 0, /* sq_ass_item */
3728 : : 0, /* sq_ass_slice */
3729 : : PyDict_Contains, /* sq_contains */
3730 : : 0, /* sq_inplace_concat */
3731 : : 0, /* sq_inplace_repeat */
3732 : : };
3733 : :
3734 : : static PyNumberMethods dict_as_number = {
3735 : : .nb_or = dict_or,
3736 : : .nb_inplace_or = dict_ior,
3737 : : };
3738 : :
3739 : : static PyObject *
3740 : 1118 : dict_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
3741 : : {
3742 : : assert(type != NULL);
3743 : : assert(type->tp_alloc != NULL);
3744 : : // dict subclasses must implement the GC protocol
3745 : : assert(_PyType_IS_GC(type));
3746 : :
3747 : 1118 : PyObject *self = type->tp_alloc(type, 0);
3748 [ - + ]: 1118 : if (self == NULL) {
3749 : 0 : return NULL;
3750 : : }
3751 : 1118 : PyDictObject *d = (PyDictObject *)self;
3752 : :
3753 : 1118 : d->ma_used = 0;
3754 : 1118 : d->ma_version_tag = DICT_NEXT_VERSION(
3755 : : _PyInterpreterState_GET());
3756 : 1118 : dictkeys_incref(Py_EMPTY_KEYS);
3757 : 1118 : d->ma_keys = Py_EMPTY_KEYS;
3758 : 1118 : d->ma_values = NULL;
3759 : : ASSERT_CONSISTENT(d);
3760 : :
3761 [ + + ]: 1118 : if (type != &PyDict_Type) {
3762 : : // Don't track if a subclass tp_alloc is PyType_GenericAlloc()
3763 [ + + ]: 852 : if (!_PyObject_GC_IS_TRACKED(d)) {
3764 : 38 : _PyObject_GC_TRACK(d);
3765 : : }
3766 : : }
3767 : : else {
3768 : : // _PyType_AllocNoTrack() does not track the created object
3769 : : assert(!_PyObject_GC_IS_TRACKED(d));
3770 : : }
3771 : 1118 : return self;
3772 : : }
3773 : :
3774 : : static int
3775 : 852 : dict_init(PyObject *self, PyObject *args, PyObject *kwds)
3776 : : {
3777 : 852 : return dict_update_common(self, args, kwds, "dict");
3778 : : }
3779 : :
3780 : : static PyObject *
3781 : 266 : dict_vectorcall(PyObject *type, PyObject * const*args,
3782 : : size_t nargsf, PyObject *kwnames)
3783 : : {
3784 : 266 : Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
3785 [ + - - + : 266 : if (!_PyArg_CheckPositional("dict", nargs, 0, 1)) {
- - ]
3786 : 0 : return NULL;
3787 : : }
3788 : :
3789 : 266 : PyObject *self = dict_new(_PyType_CAST(type), NULL, NULL);
3790 [ - + ]: 266 : if (self == NULL) {
3791 : 0 : return NULL;
3792 : : }
3793 [ + + ]: 266 : if (nargs == 1) {
3794 [ - + ]: 114 : if (dict_update_arg(self, args[0]) < 0) {
3795 : 0 : Py_DECREF(self);
3796 : 0 : return NULL;
3797 : : }
3798 : 114 : args++;
3799 : : }
3800 [ + + ]: 266 : if (kwnames != NULL) {
3801 [ + + ]: 156 : for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(kwnames); i++) {
3802 [ - + ]: 104 : if (PyDict_SetItem(self, PyTuple_GET_ITEM(kwnames, i), args[i]) < 0) {
3803 : 0 : Py_DECREF(self);
3804 : 0 : return NULL;
3805 : : }
3806 : : }
3807 : : }
3808 : 266 : return self;
3809 : : }
3810 : :
3811 : : static PyObject *
3812 : 292 : dict_iter(PyDictObject *dict)
3813 : : {
3814 : 292 : return dictiter_new(dict, &PyDictIterKey_Type);
3815 : : }
3816 : :
3817 : : PyDoc_STRVAR(dictionary_doc,
3818 : : "dict() -> new empty dictionary\n"
3819 : : "dict(mapping) -> new dictionary initialized from a mapping object's\n"
3820 : : " (key, value) pairs\n"
3821 : : "dict(iterable) -> new dictionary initialized as if via:\n"
3822 : : " d = {}\n"
3823 : : " for k, v in iterable:\n"
3824 : : " d[k] = v\n"
3825 : : "dict(**kwargs) -> new dictionary initialized with the name=value pairs\n"
3826 : : " in the keyword argument list. For example: dict(one=1, two=2)");
3827 : :
3828 : : PyTypeObject PyDict_Type = {
3829 : : PyVarObject_HEAD_INIT(&PyType_Type, 0)
3830 : : "dict",
3831 : : sizeof(PyDictObject),
3832 : : 0,
3833 : : (destructor)dict_dealloc, /* tp_dealloc */
3834 : : 0, /* tp_vectorcall_offset */
3835 : : 0, /* tp_getattr */
3836 : : 0, /* tp_setattr */
3837 : : 0, /* tp_as_async */
3838 : : (reprfunc)dict_repr, /* tp_repr */
3839 : : &dict_as_number, /* tp_as_number */
3840 : : &dict_as_sequence, /* tp_as_sequence */
3841 : : &dict_as_mapping, /* tp_as_mapping */
3842 : : PyObject_HashNotImplemented, /* tp_hash */
3843 : : 0, /* tp_call */
3844 : : 0, /* tp_str */
3845 : : PyObject_GenericGetAttr, /* tp_getattro */
3846 : : 0, /* tp_setattro */
3847 : : 0, /* tp_as_buffer */
3848 : : Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
3849 : : Py_TPFLAGS_BASETYPE | Py_TPFLAGS_DICT_SUBCLASS |
3850 : : _Py_TPFLAGS_MATCH_SELF | Py_TPFLAGS_MAPPING, /* tp_flags */
3851 : : dictionary_doc, /* tp_doc */
3852 : : dict_traverse, /* tp_traverse */
3853 : : dict_tp_clear, /* tp_clear */
3854 : : dict_richcompare, /* tp_richcompare */
3855 : : 0, /* tp_weaklistoffset */
3856 : : (getiterfunc)dict_iter, /* tp_iter */
3857 : : 0, /* tp_iternext */
3858 : : mapp_methods, /* tp_methods */
3859 : : 0, /* tp_members */
3860 : : 0, /* tp_getset */
3861 : : 0, /* tp_base */
3862 : : 0, /* tp_dict */
3863 : : 0, /* tp_descr_get */
3864 : : 0, /* tp_descr_set */
3865 : : 0, /* tp_dictoffset */
3866 : : dict_init, /* tp_init */
3867 : : _PyType_AllocNoTrack, /* tp_alloc */
3868 : : dict_new, /* tp_new */
3869 : : PyObject_GC_Del, /* tp_free */
3870 : : .tp_vectorcall = dict_vectorcall,
3871 : : };
3872 : :
3873 : : /* For backward compatibility with old dictionary interface */
3874 : :
3875 : : PyObject *
3876 : 0 : PyDict_GetItemString(PyObject *v, const char *key)
3877 : : {
3878 : : PyObject *kv, *rv;
3879 : 0 : kv = PyUnicode_FromString(key);
3880 [ # # ]: 0 : if (kv == NULL) {
3881 : 0 : PyErr_Clear();
3882 : 0 : return NULL;
3883 : : }
3884 : 0 : rv = PyDict_GetItem(v, kv);
3885 : 0 : Py_DECREF(kv);
3886 : 0 : return rv;
3887 : : }
3888 : :
3889 : : int
3890 : 0 : _PyDict_SetItemId(PyObject *v, _Py_Identifier *key, PyObject *item)
3891 : : {
3892 : : PyObject *kv;
3893 : 0 : kv = _PyUnicode_FromId(key); /* borrowed */
3894 [ # # ]: 0 : if (kv == NULL)
3895 : 0 : return -1;
3896 : 0 : return PyDict_SetItem(v, kv, item);
3897 : : }
3898 : :
3899 : : int
3900 : 25199 : PyDict_SetItemString(PyObject *v, const char *key, PyObject *item)
3901 : : {
3902 : : PyObject *kv;
3903 : : int err;
3904 : 25199 : kv = PyUnicode_FromString(key);
3905 [ - + ]: 25199 : if (kv == NULL)
3906 : 0 : return -1;
3907 : 25199 : PyUnicode_InternInPlace(&kv); /* XXX Should we really? */
3908 : 25199 : err = PyDict_SetItem(v, kv, item);
3909 : 25199 : Py_DECREF(kv);
3910 : 25199 : return err;
3911 : : }
3912 : :
3913 : : int
3914 : 0 : _PyDict_DelItemId(PyObject *v, _Py_Identifier *key)
3915 : : {
3916 : 0 : PyObject *kv = _PyUnicode_FromId(key); /* borrowed */
3917 [ # # ]: 0 : if (kv == NULL)
3918 : 0 : return -1;
3919 : 0 : return PyDict_DelItem(v, kv);
3920 : : }
3921 : :
3922 : : int
3923 : 44 : PyDict_DelItemString(PyObject *v, const char *key)
3924 : : {
3925 : : PyObject *kv;
3926 : : int err;
3927 : 44 : kv = PyUnicode_FromString(key);
3928 [ - + ]: 44 : if (kv == NULL)
3929 : 0 : return -1;
3930 : 44 : err = PyDict_DelItem(v, kv);
3931 : 44 : Py_DECREF(kv);
3932 : 44 : return err;
3933 : : }
3934 : :
3935 : : /* Dictionary iterator types */
3936 : :
3937 : : typedef struct {
3938 : : PyObject_HEAD
3939 : : PyDictObject *di_dict; /* Set to NULL when iterator is exhausted */
3940 : : Py_ssize_t di_used;
3941 : : Py_ssize_t di_pos;
3942 : : PyObject* di_result; /* reusable result tuple for iteritems */
3943 : : Py_ssize_t len;
3944 : : } dictiterobject;
3945 : :
3946 : : static PyObject *
3947 : 3987 : dictiter_new(PyDictObject *dict, PyTypeObject *itertype)
3948 : : {
3949 : : dictiterobject *di;
3950 : 3987 : di = PyObject_GC_New(dictiterobject, itertype);
3951 [ - + ]: 3987 : if (di == NULL) {
3952 : 0 : return NULL;
3953 : : }
3954 : 3987 : di->di_dict = (PyDictObject*)Py_NewRef(dict);
3955 : 3987 : di->di_used = dict->ma_used;
3956 : 3987 : di->len = dict->ma_used;
3957 [ + - + - ]: 3987 : if (itertype == &PyDictRevIterKey_Type ||
3958 [ - + ]: 3987 : itertype == &PyDictRevIterItem_Type ||
3959 : : itertype == &PyDictRevIterValue_Type) {
3960 [ # # ]: 0 : if (dict->ma_values) {
3961 : 0 : di->di_pos = dict->ma_used - 1;
3962 : : }
3963 : : else {
3964 : 0 : di->di_pos = dict->ma_keys->dk_nentries - 1;
3965 : : }
3966 : : }
3967 : : else {
3968 : 3987 : di->di_pos = 0;
3969 : : }
3970 [ + + - + ]: 3987 : if (itertype == &PyDictIterItem_Type ||
3971 : : itertype == &PyDictRevIterItem_Type) {
3972 : 1238 : di->di_result = PyTuple_Pack(2, Py_None, Py_None);
3973 [ - + ]: 1238 : if (di->di_result == NULL) {
3974 : 0 : Py_DECREF(di);
3975 : 0 : return NULL;
3976 : : }
3977 : : }
3978 : : else {
3979 : 2749 : di->di_result = NULL;
3980 : : }
3981 : 3987 : _PyObject_GC_TRACK(di);
3982 : 3987 : return (PyObject *)di;
3983 : : }
3984 : :
3985 : : static void
3986 : 3987 : dictiter_dealloc(dictiterobject *di)
3987 : : {
3988 : : /* bpo-31095: UnTrack is needed before calling any callbacks */
3989 : 3987 : _PyObject_GC_UNTRACK(di);
3990 : 3987 : Py_XDECREF(di->di_dict);
3991 : 3987 : Py_XDECREF(di->di_result);
3992 : 3987 : PyObject_GC_Del(di);
3993 : 3987 : }
3994 : :
3995 : : static int
3996 : 0 : dictiter_traverse(dictiterobject *di, visitproc visit, void *arg)
3997 : : {
3998 [ # # # # ]: 0 : Py_VISIT(di->di_dict);
3999 [ # # # # ]: 0 : Py_VISIT(di->di_result);
4000 : 0 : return 0;
4001 : : }
4002 : :
4003 : : static PyObject *
4004 : 1027 : dictiter_len(dictiterobject *di, PyObject *Py_UNUSED(ignored))
4005 : : {
4006 : 1027 : Py_ssize_t len = 0;
4007 [ + - + - ]: 1027 : if (di->di_dict != NULL && di->di_used == di->di_dict->ma_used)
4008 : 1027 : len = di->len;
4009 : 1027 : return PyLong_FromSize_t(len);
4010 : : }
4011 : :
4012 : : PyDoc_STRVAR(length_hint_doc,
4013 : : "Private method returning an estimate of len(list(it)).");
4014 : :
4015 : : static PyObject *
4016 : : dictiter_reduce(dictiterobject *di, PyObject *Py_UNUSED(ignored));
4017 : :
4018 : : PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
4019 : :
4020 : : static PyMethodDef dictiter_methods[] = {
4021 : : {"__length_hint__", _PyCFunction_CAST(dictiter_len), METH_NOARGS,
4022 : : length_hint_doc},
4023 : : {"__reduce__", _PyCFunction_CAST(dictiter_reduce), METH_NOARGS,
4024 : : reduce_doc},
4025 : : {NULL, NULL} /* sentinel */
4026 : : };
4027 : :
4028 : : static PyObject*
4029 : 6252 : dictiter_iternextkey(dictiterobject *di)
4030 : : {
4031 : : PyObject *key;
4032 : : Py_ssize_t i;
4033 : : PyDictKeysObject *k;
4034 : 6252 : PyDictObject *d = di->di_dict;
4035 : :
4036 [ - + ]: 6252 : if (d == NULL)
4037 : 0 : return NULL;
4038 : : assert (PyDict_Check(d));
4039 : :
4040 [ - + ]: 6252 : if (di->di_used != d->ma_used) {
4041 : 0 : PyErr_SetString(PyExc_RuntimeError,
4042 : : "dictionary changed size during iteration");
4043 : 0 : di->di_used = -1; /* Make this state sticky */
4044 : 0 : return NULL;
4045 : : }
4046 : :
4047 : 6252 : i = di->di_pos;
4048 : 6252 : k = d->ma_keys;
4049 : : assert(i >= 0);
4050 [ - + ]: 6252 : if (d->ma_values) {
4051 [ # # ]: 0 : if (i >= d->ma_used)
4052 : 0 : goto fail;
4053 : 0 : int index = get_index_from_order(d, i);
4054 : 0 : key = DK_UNICODE_ENTRIES(k)[index].me_key;
4055 : : assert(d->ma_values->values[index] != NULL);
4056 : : }
4057 : : else {
4058 : 6252 : Py_ssize_t n = k->dk_nentries;
4059 [ + + ]: 6252 : if (DK_IS_UNICODE(k)) {
4060 : 5291 : PyDictUnicodeEntry *entry_ptr = &DK_UNICODE_ENTRIES(k)[i];
4061 [ + + + + ]: 5416 : while (i < n && entry_ptr->me_value == NULL) {
4062 : 125 : entry_ptr++;
4063 : 125 : i++;
4064 : : }
4065 [ + + ]: 5291 : if (i >= n)
4066 : 976 : goto fail;
4067 : 4315 : key = entry_ptr->me_key;
4068 : : }
4069 : : else {
4070 : 961 : PyDictKeyEntry *entry_ptr = &DK_ENTRIES(k)[i];
4071 [ + + - + ]: 961 : while (i < n && entry_ptr->me_value == NULL) {
4072 : 0 : entry_ptr++;
4073 : 0 : i++;
4074 : : }
4075 [ + + ]: 961 : if (i >= n)
4076 : 157 : goto fail;
4077 : 804 : key = entry_ptr->me_key;
4078 : : }
4079 : : }
4080 : : // We found an element (key), but did not expect it
4081 [ - + ]: 5119 : if (di->len == 0) {
4082 : 0 : PyErr_SetString(PyExc_RuntimeError,
4083 : : "dictionary keys changed during iteration");
4084 : 0 : goto fail;
4085 : : }
4086 : 5119 : di->di_pos = i+1;
4087 : 5119 : di->len--;
4088 : 5119 : return Py_NewRef(key);
4089 : :
4090 : 1133 : fail:
4091 : 1133 : di->di_dict = NULL;
4092 : 1133 : Py_DECREF(d);
4093 : 1133 : return NULL;
4094 : : }
4095 : :
4096 : : PyTypeObject PyDictIterKey_Type = {
4097 : : PyVarObject_HEAD_INIT(&PyType_Type, 0)
4098 : : "dict_keyiterator", /* tp_name */
4099 : : sizeof(dictiterobject), /* tp_basicsize */
4100 : : 0, /* tp_itemsize */
4101 : : /* methods */
4102 : : (destructor)dictiter_dealloc, /* tp_dealloc */
4103 : : 0, /* tp_vectorcall_offset */
4104 : : 0, /* tp_getattr */
4105 : : 0, /* tp_setattr */
4106 : : 0, /* tp_as_async */
4107 : : 0, /* tp_repr */
4108 : : 0, /* tp_as_number */
4109 : : 0, /* tp_as_sequence */
4110 : : 0, /* tp_as_mapping */
4111 : : 0, /* tp_hash */
4112 : : 0, /* tp_call */
4113 : : 0, /* tp_str */
4114 : : PyObject_GenericGetAttr, /* tp_getattro */
4115 : : 0, /* tp_setattro */
4116 : : 0, /* tp_as_buffer */
4117 : : Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
4118 : : 0, /* tp_doc */
4119 : : (traverseproc)dictiter_traverse, /* tp_traverse */
4120 : : 0, /* tp_clear */
4121 : : 0, /* tp_richcompare */
4122 : : 0, /* tp_weaklistoffset */
4123 : : PyObject_SelfIter, /* tp_iter */
4124 : : (iternextfunc)dictiter_iternextkey, /* tp_iternext */
4125 : : dictiter_methods, /* tp_methods */
4126 : : 0,
4127 : : };
4128 : :
4129 : : static PyObject *
4130 : 4732 : dictiter_iternextvalue(dictiterobject *di)
4131 : : {
4132 : : PyObject *value;
4133 : : Py_ssize_t i;
4134 : 4732 : PyDictObject *d = di->di_dict;
4135 : :
4136 [ - + ]: 4732 : if (d == NULL)
4137 : 0 : return NULL;
4138 : : assert (PyDict_Check(d));
4139 : :
4140 [ - + ]: 4732 : if (di->di_used != d->ma_used) {
4141 : 0 : PyErr_SetString(PyExc_RuntimeError,
4142 : : "dictionary changed size during iteration");
4143 : 0 : di->di_used = -1; /* Make this state sticky */
4144 : 0 : return NULL;
4145 : : }
4146 : :
4147 : 4732 : i = di->di_pos;
4148 : : assert(i >= 0);
4149 [ - + ]: 4732 : if (d->ma_values) {
4150 [ # # ]: 0 : if (i >= d->ma_used)
4151 : 0 : goto fail;
4152 : 0 : int index = get_index_from_order(d, i);
4153 : 0 : value = d->ma_values->values[index];
4154 : : assert(value != NULL);
4155 : : }
4156 : : else {
4157 : 4732 : Py_ssize_t n = d->ma_keys->dk_nentries;
4158 [ + + ]: 4732 : if (DK_IS_UNICODE(d->ma_keys)) {
4159 : 4531 : PyDictUnicodeEntry *entry_ptr = &DK_UNICODE_ENTRIES(d->ma_keys)[i];
4160 [ + + + + ]: 4593 : while (i < n && entry_ptr->me_value == NULL) {
4161 : 62 : entry_ptr++;
4162 : 62 : i++;
4163 : : }
4164 [ + + ]: 4531 : if (i >= n)
4165 : 1563 : goto fail;
4166 : 2968 : value = entry_ptr->me_value;
4167 : : }
4168 : : else {
4169 : 201 : PyDictKeyEntry *entry_ptr = &DK_ENTRIES(d->ma_keys)[i];
4170 [ + + - + ]: 201 : while (i < n && entry_ptr->me_value == NULL) {
4171 : 0 : entry_ptr++;
4172 : 0 : i++;
4173 : : }
4174 [ + + ]: 201 : if (i >= n)
4175 : 3 : goto fail;
4176 : 198 : value = entry_ptr->me_value;
4177 : : }
4178 : : }
4179 : : // We found an element, but did not expect it
4180 [ - + ]: 3166 : if (di->len == 0) {
4181 : 0 : PyErr_SetString(PyExc_RuntimeError,
4182 : : "dictionary keys changed during iteration");
4183 : 0 : goto fail;
4184 : : }
4185 : 3166 : di->di_pos = i+1;
4186 : 3166 : di->len--;
4187 : 3166 : return Py_NewRef(value);
4188 : :
4189 : 1566 : fail:
4190 : 1566 : di->di_dict = NULL;
4191 : 1566 : Py_DECREF(d);
4192 : 1566 : return NULL;
4193 : : }
4194 : :
4195 : : PyTypeObject PyDictIterValue_Type = {
4196 : : PyVarObject_HEAD_INIT(&PyType_Type, 0)
4197 : : "dict_valueiterator", /* tp_name */
4198 : : sizeof(dictiterobject), /* tp_basicsize */
4199 : : 0, /* tp_itemsize */
4200 : : /* methods */
4201 : : (destructor)dictiter_dealloc, /* tp_dealloc */
4202 : : 0, /* tp_vectorcall_offset */
4203 : : 0, /* tp_getattr */
4204 : : 0, /* tp_setattr */
4205 : : 0, /* tp_as_async */
4206 : : 0, /* tp_repr */
4207 : : 0, /* tp_as_number */
4208 : : 0, /* tp_as_sequence */
4209 : : 0, /* tp_as_mapping */
4210 : : 0, /* tp_hash */
4211 : : 0, /* tp_call */
4212 : : 0, /* tp_str */
4213 : : PyObject_GenericGetAttr, /* tp_getattro */
4214 : : 0, /* tp_setattro */
4215 : : 0, /* tp_as_buffer */
4216 : : Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
4217 : : 0, /* tp_doc */
4218 : : (traverseproc)dictiter_traverse, /* tp_traverse */
4219 : : 0, /* tp_clear */
4220 : : 0, /* tp_richcompare */
4221 : : 0, /* tp_weaklistoffset */
4222 : : PyObject_SelfIter, /* tp_iter */
4223 : : (iternextfunc)dictiter_iternextvalue, /* tp_iternext */
4224 : : dictiter_methods, /* tp_methods */
4225 : : 0,
4226 : : };
4227 : :
4228 : : static PyObject *
4229 : 17595 : dictiter_iternextitem(dictiterobject *di)
4230 : : {
4231 : : PyObject *key, *value, *result;
4232 : : Py_ssize_t i;
4233 : 17595 : PyDictObject *d = di->di_dict;
4234 : :
4235 [ - + ]: 17595 : if (d == NULL)
4236 : 0 : return NULL;
4237 : : assert (PyDict_Check(d));
4238 : :
4239 [ - + ]: 17595 : if (di->di_used != d->ma_used) {
4240 : 0 : PyErr_SetString(PyExc_RuntimeError,
4241 : : "dictionary changed size during iteration");
4242 : 0 : di->di_used = -1; /* Make this state sticky */
4243 : 0 : return NULL;
4244 : : }
4245 : :
4246 : 17595 : i = di->di_pos;
4247 : : assert(i >= 0);
4248 [ - + ]: 17595 : if (d->ma_values) {
4249 [ # # ]: 0 : if (i >= d->ma_used)
4250 : 0 : goto fail;
4251 : 0 : int index = get_index_from_order(d, i);
4252 : 0 : key = DK_UNICODE_ENTRIES(d->ma_keys)[index].me_key;
4253 : 0 : value = d->ma_values->values[index];
4254 : : assert(value != NULL);
4255 : : }
4256 : : else {
4257 : 17595 : Py_ssize_t n = d->ma_keys->dk_nentries;
4258 [ + + ]: 17595 : if (DK_IS_UNICODE(d->ma_keys)) {
4259 : 17477 : PyDictUnicodeEntry *entry_ptr = &DK_UNICODE_ENTRIES(d->ma_keys)[i];
4260 [ + + + + ]: 18367 : while (i < n && entry_ptr->me_value == NULL) {
4261 : 890 : entry_ptr++;
4262 : 890 : i++;
4263 : : }
4264 [ + + ]: 17477 : if (i >= n)
4265 : 1209 : goto fail;
4266 : 16268 : key = entry_ptr->me_key;
4267 : 16268 : value = entry_ptr->me_value;
4268 : : }
4269 : : else {
4270 : 118 : PyDictKeyEntry *entry_ptr = &DK_ENTRIES(d->ma_keys)[i];
4271 [ + + - + ]: 118 : while (i < n && entry_ptr->me_value == NULL) {
4272 : 0 : entry_ptr++;
4273 : 0 : i++;
4274 : : }
4275 [ + + ]: 118 : if (i >= n)
4276 : 4 : goto fail;
4277 : 114 : key = entry_ptr->me_key;
4278 : 114 : value = entry_ptr->me_value;
4279 : : }
4280 : : }
4281 : : // We found an element, but did not expect it
4282 [ - + ]: 16382 : if (di->len == 0) {
4283 : 0 : PyErr_SetString(PyExc_RuntimeError,
4284 : : "dictionary keys changed during iteration");
4285 : 0 : goto fail;
4286 : : }
4287 : 16382 : di->di_pos = i+1;
4288 : 16382 : di->len--;
4289 : 16382 : result = di->di_result;
4290 [ + + ]: 16382 : if (Py_REFCNT(result) == 1) {
4291 : 7586 : PyObject *oldkey = PyTuple_GET_ITEM(result, 0);
4292 : 7586 : PyObject *oldvalue = PyTuple_GET_ITEM(result, 1);
4293 : 7586 : PyTuple_SET_ITEM(result, 0, Py_NewRef(key));
4294 : 7586 : PyTuple_SET_ITEM(result, 1, Py_NewRef(value));
4295 : 7586 : Py_INCREF(result);
4296 : 7586 : Py_DECREF(oldkey);
4297 : 7586 : Py_DECREF(oldvalue);
4298 : : // bpo-42536: The GC may have untracked this result tuple. Since we're
4299 : : // recycling it, make sure it's tracked again:
4300 [ - + ]: 7586 : if (!_PyObject_GC_IS_TRACKED(result)) {
4301 : 0 : _PyObject_GC_TRACK(result);
4302 : : }
4303 : : }
4304 : : else {
4305 : 8796 : result = PyTuple_New(2);
4306 [ - + ]: 8796 : if (result == NULL)
4307 : 0 : return NULL;
4308 : 8796 : PyTuple_SET_ITEM(result, 0, Py_NewRef(key));
4309 : 8796 : PyTuple_SET_ITEM(result, 1, Py_NewRef(value));
4310 : : }
4311 : 16382 : return result;
4312 : :
4313 : 1213 : fail:
4314 : 1213 : di->di_dict = NULL;
4315 : 1213 : Py_DECREF(d);
4316 : 1213 : return NULL;
4317 : : }
4318 : :
4319 : : PyTypeObject PyDictIterItem_Type = {
4320 : : PyVarObject_HEAD_INIT(&PyType_Type, 0)
4321 : : "dict_itemiterator", /* tp_name */
4322 : : sizeof(dictiterobject), /* tp_basicsize */
4323 : : 0, /* tp_itemsize */
4324 : : /* methods */
4325 : : (destructor)dictiter_dealloc, /* tp_dealloc */
4326 : : 0, /* tp_vectorcall_offset */
4327 : : 0, /* tp_getattr */
4328 : : 0, /* tp_setattr */
4329 : : 0, /* tp_as_async */
4330 : : 0, /* tp_repr */
4331 : : 0, /* tp_as_number */
4332 : : 0, /* tp_as_sequence */
4333 : : 0, /* tp_as_mapping */
4334 : : 0, /* tp_hash */
4335 : : 0, /* tp_call */
4336 : : 0, /* tp_str */
4337 : : PyObject_GenericGetAttr, /* tp_getattro */
4338 : : 0, /* tp_setattro */
4339 : : 0, /* tp_as_buffer */
4340 : : Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
4341 : : 0, /* tp_doc */
4342 : : (traverseproc)dictiter_traverse, /* tp_traverse */
4343 : : 0, /* tp_clear */
4344 : : 0, /* tp_richcompare */
4345 : : 0, /* tp_weaklistoffset */
4346 : : PyObject_SelfIter, /* tp_iter */
4347 : : (iternextfunc)dictiter_iternextitem, /* tp_iternext */
4348 : : dictiter_methods, /* tp_methods */
4349 : : 0,
4350 : : };
4351 : :
4352 : :
4353 : : /* dictreviter */
4354 : :
4355 : : static PyObject *
4356 : 0 : dictreviter_iternext(dictiterobject *di)
4357 : : {
4358 : 0 : PyDictObject *d = di->di_dict;
4359 : :
4360 [ # # ]: 0 : if (d == NULL) {
4361 : 0 : return NULL;
4362 : : }
4363 : : assert (PyDict_Check(d));
4364 : :
4365 [ # # ]: 0 : if (di->di_used != d->ma_used) {
4366 : 0 : PyErr_SetString(PyExc_RuntimeError,
4367 : : "dictionary changed size during iteration");
4368 : 0 : di->di_used = -1; /* Make this state sticky */
4369 : 0 : return NULL;
4370 : : }
4371 : :
4372 : 0 : Py_ssize_t i = di->di_pos;
4373 : 0 : PyDictKeysObject *k = d->ma_keys;
4374 : : PyObject *key, *value, *result;
4375 : :
4376 [ # # ]: 0 : if (i < 0) {
4377 : 0 : goto fail;
4378 : : }
4379 [ # # ]: 0 : if (d->ma_values) {
4380 : 0 : int index = get_index_from_order(d, i);
4381 : 0 : key = DK_UNICODE_ENTRIES(k)[index].me_key;
4382 : 0 : value = d->ma_values->values[index];
4383 : : assert (value != NULL);
4384 : : }
4385 : : else {
4386 [ # # ]: 0 : if (DK_IS_UNICODE(k)) {
4387 : 0 : PyDictUnicodeEntry *entry_ptr = &DK_UNICODE_ENTRIES(k)[i];
4388 [ # # ]: 0 : while (entry_ptr->me_value == NULL) {
4389 [ # # ]: 0 : if (--i < 0) {
4390 : 0 : goto fail;
4391 : : }
4392 : 0 : entry_ptr--;
4393 : : }
4394 : 0 : key = entry_ptr->me_key;
4395 : 0 : value = entry_ptr->me_value;
4396 : : }
4397 : : else {
4398 : 0 : PyDictKeyEntry *entry_ptr = &DK_ENTRIES(k)[i];
4399 [ # # ]: 0 : while (entry_ptr->me_value == NULL) {
4400 [ # # ]: 0 : if (--i < 0) {
4401 : 0 : goto fail;
4402 : : }
4403 : 0 : entry_ptr--;
4404 : : }
4405 : 0 : key = entry_ptr->me_key;
4406 : 0 : value = entry_ptr->me_value;
4407 : : }
4408 : : }
4409 : 0 : di->di_pos = i-1;
4410 : 0 : di->len--;
4411 : :
4412 [ # # ]: 0 : if (Py_IS_TYPE(di, &PyDictRevIterKey_Type)) {
4413 : 0 : return Py_NewRef(key);
4414 : : }
4415 [ # # ]: 0 : else if (Py_IS_TYPE(di, &PyDictRevIterValue_Type)) {
4416 : 0 : return Py_NewRef(value);
4417 : : }
4418 [ # # ]: 0 : else if (Py_IS_TYPE(di, &PyDictRevIterItem_Type)) {
4419 : 0 : result = di->di_result;
4420 [ # # ]: 0 : if (Py_REFCNT(result) == 1) {
4421 : 0 : PyObject *oldkey = PyTuple_GET_ITEM(result, 0);
4422 : 0 : PyObject *oldvalue = PyTuple_GET_ITEM(result, 1);
4423 : 0 : PyTuple_SET_ITEM(result, 0, Py_NewRef(key));
4424 : 0 : PyTuple_SET_ITEM(result, 1, Py_NewRef(value));
4425 : 0 : Py_INCREF(result);
4426 : 0 : Py_DECREF(oldkey);
4427 : 0 : Py_DECREF(oldvalue);
4428 : : // bpo-42536: The GC may have untracked this result tuple. Since
4429 : : // we're recycling it, make sure it's tracked again:
4430 [ # # ]: 0 : if (!_PyObject_GC_IS_TRACKED(result)) {
4431 : 0 : _PyObject_GC_TRACK(result);
4432 : : }
4433 : : }
4434 : : else {
4435 : 0 : result = PyTuple_New(2);
4436 [ # # ]: 0 : if (result == NULL) {
4437 : 0 : return NULL;
4438 : : }
4439 : 0 : PyTuple_SET_ITEM(result, 0, Py_NewRef(key));
4440 : 0 : PyTuple_SET_ITEM(result, 1, Py_NewRef(value));
4441 : : }
4442 : 0 : return result;
4443 : : }
4444 : : else {
4445 : 0 : Py_UNREACHABLE();
4446 : : }
4447 : :
4448 : 0 : fail:
4449 : 0 : di->di_dict = NULL;
4450 : 0 : Py_DECREF(d);
4451 : 0 : return NULL;
4452 : : }
4453 : :
4454 : : PyTypeObject PyDictRevIterKey_Type = {
4455 : : PyVarObject_HEAD_INIT(&PyType_Type, 0)
4456 : : "dict_reversekeyiterator",
4457 : : sizeof(dictiterobject),
4458 : : .tp_dealloc = (destructor)dictiter_dealloc,
4459 : : .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
4460 : : .tp_traverse = (traverseproc)dictiter_traverse,
4461 : : .tp_iter = PyObject_SelfIter,
4462 : : .tp_iternext = (iternextfunc)dictreviter_iternext,
4463 : : .tp_methods = dictiter_methods
4464 : : };
4465 : :
4466 : :
4467 : : /*[clinic input]
4468 : : dict.__reversed__
4469 : :
4470 : : Return a reverse iterator over the dict keys.
4471 : : [clinic start generated code]*/
4472 : :
4473 : : static PyObject *
4474 : 0 : dict___reversed___impl(PyDictObject *self)
4475 : : /*[clinic end generated code: output=e674483336d1ed51 input=23210ef3477d8c4d]*/
4476 : : {
4477 : : assert (PyDict_Check(self));
4478 : 0 : return dictiter_new(self, &PyDictRevIterKey_Type);
4479 : : }
4480 : :
4481 : : static PyObject *
4482 : 0 : dictiter_reduce(dictiterobject *di, PyObject *Py_UNUSED(ignored))
4483 : : {
4484 : : /* copy the iterator state */
4485 : 0 : dictiterobject tmp = *di;
4486 : 0 : Py_XINCREF(tmp.di_dict);
4487 : 0 : PyObject *list = PySequence_List((PyObject*)&tmp);
4488 : 0 : Py_XDECREF(tmp.di_dict);
4489 [ # # ]: 0 : if (list == NULL) {
4490 : 0 : return NULL;
4491 : : }
4492 : 0 : return Py_BuildValue("N(N)", _PyEval_GetBuiltin(&_Py_ID(iter)), list);
4493 : : }
4494 : :
4495 : : PyTypeObject PyDictRevIterItem_Type = {
4496 : : PyVarObject_HEAD_INIT(&PyType_Type, 0)
4497 : : "dict_reverseitemiterator",
4498 : : sizeof(dictiterobject),
4499 : : .tp_dealloc = (destructor)dictiter_dealloc,
4500 : : .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
4501 : : .tp_traverse = (traverseproc)dictiter_traverse,
4502 : : .tp_iter = PyObject_SelfIter,
4503 : : .tp_iternext = (iternextfunc)dictreviter_iternext,
4504 : : .tp_methods = dictiter_methods
4505 : : };
4506 : :
4507 : : PyTypeObject PyDictRevIterValue_Type = {
4508 : : PyVarObject_HEAD_INIT(&PyType_Type, 0)
4509 : : "dict_reversevalueiterator",
4510 : : sizeof(dictiterobject),
4511 : : .tp_dealloc = (destructor)dictiter_dealloc,
4512 : : .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
4513 : : .tp_traverse = (traverseproc)dictiter_traverse,
4514 : : .tp_iter = PyObject_SelfIter,
4515 : : .tp_iternext = (iternextfunc)dictreviter_iternext,
4516 : : .tp_methods = dictiter_methods
4517 : : };
4518 : :
4519 : : /***********************************************/
4520 : : /* View objects for keys(), items(), values(). */
4521 : : /***********************************************/
4522 : :
4523 : : /* The instance lay-out is the same for all three; but the type differs. */
4524 : :
4525 : : static void
4526 : 3771 : dictview_dealloc(_PyDictViewObject *dv)
4527 : : {
4528 : : /* bpo-31095: UnTrack is needed before calling any callbacks */
4529 : 3771 : _PyObject_GC_UNTRACK(dv);
4530 : 3771 : Py_XDECREF(dv->dv_dict);
4531 : 3771 : PyObject_GC_Del(dv);
4532 : 3771 : }
4533 : :
4534 : : static int
4535 : 28 : dictview_traverse(_PyDictViewObject *dv, visitproc visit, void *arg)
4536 : : {
4537 [ + - - + ]: 28 : Py_VISIT(dv->dv_dict);
4538 : 28 : return 0;
4539 : : }
4540 : :
4541 : : static Py_ssize_t
4542 : 1564 : dictview_len(_PyDictViewObject *dv)
4543 : : {
4544 : 1564 : Py_ssize_t len = 0;
4545 [ + - ]: 1564 : if (dv->dv_dict != NULL)
4546 : 1564 : len = dv->dv_dict->ma_used;
4547 : 1564 : return len;
4548 : : }
4549 : :
4550 : : PyObject *
4551 : 3771 : _PyDictView_New(PyObject *dict, PyTypeObject *type)
4552 : : {
4553 : : _PyDictViewObject *dv;
4554 [ - + ]: 3771 : if (dict == NULL) {
4555 : 0 : PyErr_BadInternalCall();
4556 : 0 : return NULL;
4557 : : }
4558 [ - + ]: 3771 : if (!PyDict_Check(dict)) {
4559 : : /* XXX Get rid of this restriction later */
4560 : 0 : PyErr_Format(PyExc_TypeError,
4561 : : "%s() requires a dict argument, not '%s'",
4562 : 0 : type->tp_name, Py_TYPE(dict)->tp_name);
4563 : 0 : return NULL;
4564 : : }
4565 : 3771 : dv = PyObject_GC_New(_PyDictViewObject, type);
4566 [ - + ]: 3771 : if (dv == NULL)
4567 : 0 : return NULL;
4568 : 3771 : dv->dv_dict = (PyDictObject *)Py_NewRef(dict);
4569 : 3771 : _PyObject_GC_TRACK(dv);
4570 : 3771 : return (PyObject *)dv;
4571 : : }
4572 : :
4573 : : static PyObject *
4574 : 0 : dictview_mapping(PyObject *view, void *Py_UNUSED(ignored)) {
4575 : : assert(view != NULL);
4576 : : assert(PyDictKeys_Check(view)
4577 : : || PyDictValues_Check(view)
4578 : : || PyDictItems_Check(view));
4579 : 0 : PyObject *mapping = (PyObject *)((_PyDictViewObject *)view)->dv_dict;
4580 : 0 : return PyDictProxy_New(mapping);
4581 : : }
4582 : :
4583 : : static PyGetSetDef dictview_getset[] = {
4584 : : {"mapping", dictview_mapping, (setter)NULL,
4585 : : "dictionary that this view refers to", NULL},
4586 : : {0}
4587 : : };
4588 : :
4589 : : /* TODO(guido): The views objects are not complete:
4590 : :
4591 : : * support more set operations
4592 : : * support arbitrary mappings?
4593 : : - either these should be static or exported in dictobject.h
4594 : : - if public then they should probably be in builtins
4595 : : */
4596 : :
4597 : : /* Return 1 if self is a subset of other, iterating over self;
4598 : : 0 if not; -1 if an error occurred. */
4599 : : static int
4600 : 0 : all_contained_in(PyObject *self, PyObject *other)
4601 : : {
4602 : 0 : PyObject *iter = PyObject_GetIter(self);
4603 : 0 : int ok = 1;
4604 : :
4605 [ # # ]: 0 : if (iter == NULL)
4606 : 0 : return -1;
4607 : 0 : for (;;) {
4608 : 0 : PyObject *next = PyIter_Next(iter);
4609 [ # # ]: 0 : if (next == NULL) {
4610 [ # # ]: 0 : if (PyErr_Occurred())
4611 : 0 : ok = -1;
4612 : 0 : break;
4613 : : }
4614 : 0 : ok = PySequence_Contains(other, next);
4615 : 0 : Py_DECREF(next);
4616 [ # # ]: 0 : if (ok <= 0)
4617 : 0 : break;
4618 : : }
4619 : 0 : Py_DECREF(iter);
4620 : 0 : return ok;
4621 : : }
4622 : :
4623 : : static PyObject *
4624 : 0 : dictview_richcompare(PyObject *self, PyObject *other, int op)
4625 : : {
4626 : : Py_ssize_t len_self, len_other;
4627 : : int ok;
4628 : : PyObject *result;
4629 : :
4630 : : assert(self != NULL);
4631 : : assert(PyDictViewSet_Check(self));
4632 : : assert(other != NULL);
4633 : :
4634 [ # # # # : 0 : if (!PyAnySet_Check(other) && !PyDictViewSet_Check(other))
# # # # #
# # # ]
4635 : 0 : Py_RETURN_NOTIMPLEMENTED;
4636 : :
4637 : 0 : len_self = PyObject_Size(self);
4638 [ # # ]: 0 : if (len_self < 0)
4639 : 0 : return NULL;
4640 : 0 : len_other = PyObject_Size(other);
4641 [ # # ]: 0 : if (len_other < 0)
4642 : 0 : return NULL;
4643 : :
4644 : 0 : ok = 0;
4645 [ # # # # : 0 : switch(op) {
# # ]
4646 : :
4647 : 0 : case Py_NE:
4648 : : case Py_EQ:
4649 [ # # ]: 0 : if (len_self == len_other)
4650 : 0 : ok = all_contained_in(self, other);
4651 [ # # # # ]: 0 : if (op == Py_NE && ok >= 0)
4652 : 0 : ok = !ok;
4653 : 0 : break;
4654 : :
4655 : 0 : case Py_LT:
4656 [ # # ]: 0 : if (len_self < len_other)
4657 : 0 : ok = all_contained_in(self, other);
4658 : 0 : break;
4659 : :
4660 : 0 : case Py_LE:
4661 [ # # ]: 0 : if (len_self <= len_other)
4662 : 0 : ok = all_contained_in(self, other);
4663 : 0 : break;
4664 : :
4665 : 0 : case Py_GT:
4666 [ # # ]: 0 : if (len_self > len_other)
4667 : 0 : ok = all_contained_in(other, self);
4668 : 0 : break;
4669 : :
4670 : 0 : case Py_GE:
4671 [ # # ]: 0 : if (len_self >= len_other)
4672 : 0 : ok = all_contained_in(other, self);
4673 : 0 : break;
4674 : :
4675 : : }
4676 [ # # ]: 0 : if (ok < 0)
4677 : 0 : return NULL;
4678 [ # # ]: 0 : result = ok ? Py_True : Py_False;
4679 : 0 : return Py_NewRef(result);
4680 : : }
4681 : :
4682 : : static PyObject *
4683 : 0 : dictview_repr(_PyDictViewObject *dv)
4684 : : {
4685 : : PyObject *seq;
4686 : 0 : PyObject *result = NULL;
4687 : : Py_ssize_t rc;
4688 : :
4689 : 0 : rc = Py_ReprEnter((PyObject *)dv);
4690 [ # # ]: 0 : if (rc != 0) {
4691 [ # # ]: 0 : return rc > 0 ? PyUnicode_FromString("...") : NULL;
4692 : : }
4693 : 0 : seq = PySequence_List((PyObject *)dv);
4694 [ # # ]: 0 : if (seq == NULL) {
4695 : 0 : goto Done;
4696 : : }
4697 : 0 : result = PyUnicode_FromFormat("%s(%R)", Py_TYPE(dv)->tp_name, seq);
4698 : 0 : Py_DECREF(seq);
4699 : :
4700 : 0 : Done:
4701 : 0 : Py_ReprLeave((PyObject *)dv);
4702 : 0 : return result;
4703 : : }
4704 : :
4705 : : /*** dict_keys ***/
4706 : :
4707 : : static PyObject *
4708 : 866 : dictkeys_iter(_PyDictViewObject *dv)
4709 : : {
4710 [ - + ]: 866 : if (dv->dv_dict == NULL) {
4711 : 0 : Py_RETURN_NONE;
4712 : : }
4713 : 866 : return dictiter_new(dv->dv_dict, &PyDictIterKey_Type);
4714 : : }
4715 : :
4716 : : static int
4717 : 161 : dictkeys_contains(_PyDictViewObject *dv, PyObject *obj)
4718 : : {
4719 [ - + ]: 161 : if (dv->dv_dict == NULL)
4720 : 0 : return 0;
4721 : 161 : return PyDict_Contains((PyObject *)dv->dv_dict, obj);
4722 : : }
4723 : :
4724 : : static PySequenceMethods dictkeys_as_sequence = {
4725 : : (lenfunc)dictview_len, /* sq_length */
4726 : : 0, /* sq_concat */
4727 : : 0, /* sq_repeat */
4728 : : 0, /* sq_item */
4729 : : 0, /* sq_slice */
4730 : : 0, /* sq_ass_item */
4731 : : 0, /* sq_ass_slice */
4732 : : (objobjproc)dictkeys_contains, /* sq_contains */
4733 : : };
4734 : :
4735 : : // Create a set object from dictviews object.
4736 : : // Returns a new reference.
4737 : : // This utility function is used by set operations.
4738 : : static PyObject*
4739 : 0 : dictviews_to_set(PyObject *self)
4740 : : {
4741 : 0 : PyObject *left = self;
4742 [ # # ]: 0 : if (PyDictKeys_Check(self)) {
4743 : : // PySet_New() has fast path for the dict object.
4744 : 0 : PyObject *dict = (PyObject *)((_PyDictViewObject *)self)->dv_dict;
4745 [ # # ]: 0 : if (PyDict_CheckExact(dict)) {
4746 : 0 : left = dict;
4747 : : }
4748 : : }
4749 : 0 : return PySet_New(left);
4750 : : }
4751 : :
4752 : : static PyObject*
4753 : 0 : dictviews_sub(PyObject *self, PyObject *other)
4754 : : {
4755 : 0 : PyObject *result = dictviews_to_set(self);
4756 [ # # ]: 0 : if (result == NULL) {
4757 : 0 : return NULL;
4758 : : }
4759 : :
4760 : 0 : PyObject *tmp = PyObject_CallMethodOneArg(
4761 : : result, &_Py_ID(difference_update), other);
4762 [ # # ]: 0 : if (tmp == NULL) {
4763 : 0 : Py_DECREF(result);
4764 : 0 : return NULL;
4765 : : }
4766 : :
4767 : 0 : Py_DECREF(tmp);
4768 : 0 : return result;
4769 : : }
4770 : :
4771 : : static int
4772 : : dictitems_contains(_PyDictViewObject *dv, PyObject *obj);
4773 : :
4774 : : PyObject *
4775 : 0 : _PyDictView_Intersect(PyObject* self, PyObject *other)
4776 : : {
4777 : : PyObject *result;
4778 : : PyObject *it;
4779 : : PyObject *key;
4780 : : Py_ssize_t len_self;
4781 : : int rv;
4782 : : int (*dict_contains)(_PyDictViewObject *, PyObject *);
4783 : :
4784 : : /* Python interpreter swaps parameters when dict view
4785 : : is on right side of & */
4786 [ # # # # ]: 0 : if (!PyDictViewSet_Check(self)) {
4787 : 0 : PyObject *tmp = other;
4788 : 0 : other = self;
4789 : 0 : self = tmp;
4790 : : }
4791 : :
4792 : 0 : len_self = dictview_len((_PyDictViewObject *)self);
4793 : :
4794 : : /* if other is a set and self is smaller than other,
4795 : : reuse set intersection logic */
4796 [ # # # # ]: 0 : if (PySet_CheckExact(other) && len_self <= PyObject_Size(other)) {
4797 : 0 : return PyObject_CallMethodObjArgs(
4798 : : other, &_Py_ID(intersection), self, NULL);
4799 : : }
4800 : :
4801 : : /* if other is another dict view, and it is bigger than self,
4802 : : swap them */
4803 [ # # # # ]: 0 : if (PyDictViewSet_Check(other)) {
4804 : 0 : Py_ssize_t len_other = dictview_len((_PyDictViewObject *)other);
4805 [ # # ]: 0 : if (len_other > len_self) {
4806 : 0 : PyObject *tmp = other;
4807 : 0 : other = self;
4808 : 0 : self = tmp;
4809 : : }
4810 : : }
4811 : :
4812 : : /* at this point, two things should be true
4813 : : 1. self is a dictview
4814 : : 2. if other is a dictview then it is smaller than self */
4815 : 0 : result = PySet_New(NULL);
4816 [ # # ]: 0 : if (result == NULL)
4817 : 0 : return NULL;
4818 : :
4819 : 0 : it = PyObject_GetIter(other);
4820 [ # # ]: 0 : if (it == NULL) {
4821 : 0 : Py_DECREF(result);
4822 : 0 : return NULL;
4823 : : }
4824 : :
4825 [ # # ]: 0 : if (PyDictKeys_Check(self)) {
4826 : 0 : dict_contains = dictkeys_contains;
4827 : : }
4828 : : /* else PyDictItems_Check(self) */
4829 : : else {
4830 : 0 : dict_contains = dictitems_contains;
4831 : : }
4832 : :
4833 [ # # ]: 0 : while ((key = PyIter_Next(it)) != NULL) {
4834 : 0 : rv = dict_contains((_PyDictViewObject *)self, key);
4835 [ # # ]: 0 : if (rv < 0) {
4836 : 0 : goto error;
4837 : : }
4838 [ # # ]: 0 : if (rv) {
4839 [ # # ]: 0 : if (PySet_Add(result, key)) {
4840 : 0 : goto error;
4841 : : }
4842 : : }
4843 : 0 : Py_DECREF(key);
4844 : : }
4845 : 0 : Py_DECREF(it);
4846 [ # # ]: 0 : if (PyErr_Occurred()) {
4847 : 0 : Py_DECREF(result);
4848 : 0 : return NULL;
4849 : : }
4850 : 0 : return result;
4851 : :
4852 : 0 : error:
4853 : 0 : Py_DECREF(it);
4854 : 0 : Py_DECREF(result);
4855 : 0 : Py_DECREF(key);
4856 : 0 : return NULL;
4857 : : }
4858 : :
4859 : : static PyObject*
4860 : 0 : dictviews_or(PyObject* self, PyObject *other)
4861 : : {
4862 : 0 : PyObject *result = dictviews_to_set(self);
4863 [ # # ]: 0 : if (result == NULL) {
4864 : 0 : return NULL;
4865 : : }
4866 : :
4867 [ # # ]: 0 : if (_PySet_Update(result, other) < 0) {
4868 : 0 : Py_DECREF(result);
4869 : 0 : return NULL;
4870 : : }
4871 : 0 : return result;
4872 : : }
4873 : :
4874 : : static PyObject *
4875 : 0 : dictitems_xor(PyObject *self, PyObject *other)
4876 : : {
4877 : : assert(PyDictItems_Check(self));
4878 : : assert(PyDictItems_Check(other));
4879 : 0 : PyObject *d1 = (PyObject *)((_PyDictViewObject *)self)->dv_dict;
4880 : 0 : PyObject *d2 = (PyObject *)((_PyDictViewObject *)other)->dv_dict;
4881 : :
4882 : 0 : PyObject *temp_dict = PyDict_Copy(d1);
4883 [ # # ]: 0 : if (temp_dict == NULL) {
4884 : 0 : return NULL;
4885 : : }
4886 : 0 : PyObject *result_set = PySet_New(NULL);
4887 [ # # ]: 0 : if (result_set == NULL) {
4888 [ # # ]: 0 : Py_CLEAR(temp_dict);
4889 : 0 : return NULL;
4890 : : }
4891 : :
4892 : 0 : PyObject *key = NULL, *val1 = NULL, *val2 = NULL;
4893 : 0 : Py_ssize_t pos = 0;
4894 : : Py_hash_t hash;
4895 : :
4896 [ # # ]: 0 : while (_PyDict_Next(d2, &pos, &key, &val2, &hash)) {
4897 : 0 : Py_INCREF(key);
4898 : 0 : Py_INCREF(val2);
4899 : 0 : val1 = _PyDict_GetItem_KnownHash(temp_dict, key, hash);
4900 : :
4901 : : int to_delete;
4902 [ # # ]: 0 : if (val1 == NULL) {
4903 [ # # ]: 0 : if (PyErr_Occurred()) {
4904 : 0 : goto error;
4905 : : }
4906 : 0 : to_delete = 0;
4907 : : }
4908 : : else {
4909 : 0 : Py_INCREF(val1);
4910 : 0 : to_delete = PyObject_RichCompareBool(val1, val2, Py_EQ);
4911 [ # # ]: 0 : if (to_delete < 0) {
4912 : 0 : goto error;
4913 : : }
4914 : : }
4915 : :
4916 [ # # ]: 0 : if (to_delete) {
4917 [ # # ]: 0 : if (_PyDict_DelItem_KnownHash(temp_dict, key, hash) < 0) {
4918 : 0 : goto error;
4919 : : }
4920 : : }
4921 : : else {
4922 : 0 : PyObject *pair = PyTuple_Pack(2, key, val2);
4923 [ # # ]: 0 : if (pair == NULL) {
4924 : 0 : goto error;
4925 : : }
4926 [ # # ]: 0 : if (PySet_Add(result_set, pair) < 0) {
4927 : 0 : Py_DECREF(pair);
4928 : 0 : goto error;
4929 : : }
4930 : 0 : Py_DECREF(pair);
4931 : : }
4932 : 0 : Py_DECREF(key);
4933 : 0 : Py_XDECREF(val1);
4934 : 0 : Py_DECREF(val2);
4935 : : }
4936 : 0 : key = val1 = val2 = NULL;
4937 : :
4938 : 0 : PyObject *remaining_pairs = PyObject_CallMethodNoArgs(
4939 : : temp_dict, &_Py_ID(items));
4940 [ # # ]: 0 : if (remaining_pairs == NULL) {
4941 : 0 : goto error;
4942 : : }
4943 [ # # ]: 0 : if (_PySet_Update(result_set, remaining_pairs) < 0) {
4944 : 0 : Py_DECREF(remaining_pairs);
4945 : 0 : goto error;
4946 : : }
4947 : 0 : Py_DECREF(temp_dict);
4948 : 0 : Py_DECREF(remaining_pairs);
4949 : 0 : return result_set;
4950 : :
4951 : 0 : error:
4952 : 0 : Py_XDECREF(temp_dict);
4953 : 0 : Py_XDECREF(result_set);
4954 : 0 : Py_XDECREF(key);
4955 : 0 : Py_XDECREF(val1);
4956 : 0 : Py_XDECREF(val2);
4957 : 0 : return NULL;
4958 : : }
4959 : :
4960 : : static PyObject*
4961 : 0 : dictviews_xor(PyObject* self, PyObject *other)
4962 : : {
4963 [ # # # # ]: 0 : if (PyDictItems_Check(self) && PyDictItems_Check(other)) {
4964 : 0 : return dictitems_xor(self, other);
4965 : : }
4966 : 0 : PyObject *result = dictviews_to_set(self);
4967 [ # # ]: 0 : if (result == NULL) {
4968 : 0 : return NULL;
4969 : : }
4970 : :
4971 : 0 : PyObject *tmp = PyObject_CallMethodOneArg(
4972 : : result, &_Py_ID(symmetric_difference_update), other);
4973 [ # # ]: 0 : if (tmp == NULL) {
4974 : 0 : Py_DECREF(result);
4975 : 0 : return NULL;
4976 : : }
4977 : :
4978 : 0 : Py_DECREF(tmp);
4979 : 0 : return result;
4980 : : }
4981 : :
4982 : : static PyNumberMethods dictviews_as_number = {
4983 : : 0, /*nb_add*/
4984 : : (binaryfunc)dictviews_sub, /*nb_subtract*/
4985 : : 0, /*nb_multiply*/
4986 : : 0, /*nb_remainder*/
4987 : : 0, /*nb_divmod*/
4988 : : 0, /*nb_power*/
4989 : : 0, /*nb_negative*/
4990 : : 0, /*nb_positive*/
4991 : : 0, /*nb_absolute*/
4992 : : 0, /*nb_bool*/
4993 : : 0, /*nb_invert*/
4994 : : 0, /*nb_lshift*/
4995 : : 0, /*nb_rshift*/
4996 : : (binaryfunc)_PyDictView_Intersect, /*nb_and*/
4997 : : (binaryfunc)dictviews_xor, /*nb_xor*/
4998 : : (binaryfunc)dictviews_or, /*nb_or*/
4999 : : };
5000 : :
5001 : : static PyObject*
5002 : 0 : dictviews_isdisjoint(PyObject *self, PyObject *other)
5003 : : {
5004 : : PyObject *it;
5005 : 0 : PyObject *item = NULL;
5006 : :
5007 [ # # ]: 0 : if (self == other) {
5008 [ # # ]: 0 : if (dictview_len((_PyDictViewObject *)self) == 0)
5009 : 0 : Py_RETURN_TRUE;
5010 : : else
5011 : 0 : Py_RETURN_FALSE;
5012 : : }
5013 : :
5014 : : /* Iterate over the shorter object (only if other is a set,
5015 : : * because PySequence_Contains may be expensive otherwise): */
5016 [ # # # # : 0 : if (PyAnySet_Check(other) || PyDictViewSet_Check(other)) {
# # # # #
# # # ]
5017 : 0 : Py_ssize_t len_self = dictview_len((_PyDictViewObject *)self);
5018 : 0 : Py_ssize_t len_other = PyObject_Size(other);
5019 [ # # ]: 0 : if (len_other == -1)
5020 : 0 : return NULL;
5021 : :
5022 [ # # ]: 0 : if ((len_other > len_self)) {
5023 : 0 : PyObject *tmp = other;
5024 : 0 : other = self;
5025 : 0 : self = tmp;
5026 : : }
5027 : : }
5028 : :
5029 : 0 : it = PyObject_GetIter(other);
5030 [ # # ]: 0 : if (it == NULL)
5031 : 0 : return NULL;
5032 : :
5033 [ # # ]: 0 : while ((item = PyIter_Next(it)) != NULL) {
5034 : 0 : int contains = PySequence_Contains(self, item);
5035 : 0 : Py_DECREF(item);
5036 [ # # ]: 0 : if (contains == -1) {
5037 : 0 : Py_DECREF(it);
5038 : 0 : return NULL;
5039 : : }
5040 : :
5041 [ # # ]: 0 : if (contains) {
5042 : 0 : Py_DECREF(it);
5043 : 0 : Py_RETURN_FALSE;
5044 : : }
5045 : : }
5046 : 0 : Py_DECREF(it);
5047 [ # # ]: 0 : if (PyErr_Occurred())
5048 : 0 : return NULL; /* PyIter_Next raised an exception. */
5049 : 0 : Py_RETURN_TRUE;
5050 : : }
5051 : :
5052 : : PyDoc_STRVAR(isdisjoint_doc,
5053 : : "Return True if the view and the given iterable have a null intersection.");
5054 : :
5055 : : static PyObject* dictkeys_reversed(_PyDictViewObject *dv, PyObject *Py_UNUSED(ignored));
5056 : :
5057 : : PyDoc_STRVAR(reversed_keys_doc,
5058 : : "Return a reverse iterator over the dict keys.");
5059 : :
5060 : : static PyMethodDef dictkeys_methods[] = {
5061 : : {"isdisjoint", (PyCFunction)dictviews_isdisjoint, METH_O,
5062 : : isdisjoint_doc},
5063 : : {"__reversed__", _PyCFunction_CAST(dictkeys_reversed), METH_NOARGS,
5064 : : reversed_keys_doc},
5065 : : {NULL, NULL} /* sentinel */
5066 : : };
5067 : :
5068 : : PyTypeObject PyDictKeys_Type = {
5069 : : PyVarObject_HEAD_INIT(&PyType_Type, 0)
5070 : : "dict_keys", /* tp_name */
5071 : : sizeof(_PyDictViewObject), /* tp_basicsize */
5072 : : 0, /* tp_itemsize */
5073 : : /* methods */
5074 : : (destructor)dictview_dealloc, /* tp_dealloc */
5075 : : 0, /* tp_vectorcall_offset */
5076 : : 0, /* tp_getattr */
5077 : : 0, /* tp_setattr */
5078 : : 0, /* tp_as_async */
5079 : : (reprfunc)dictview_repr, /* tp_repr */
5080 : : &dictviews_as_number, /* tp_as_number */
5081 : : &dictkeys_as_sequence, /* tp_as_sequence */
5082 : : 0, /* tp_as_mapping */
5083 : : 0, /* tp_hash */
5084 : : 0, /* tp_call */
5085 : : 0, /* tp_str */
5086 : : PyObject_GenericGetAttr, /* tp_getattro */
5087 : : 0, /* tp_setattro */
5088 : : 0, /* tp_as_buffer */
5089 : : Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
5090 : : 0, /* tp_doc */
5091 : : (traverseproc)dictview_traverse, /* tp_traverse */
5092 : : 0, /* tp_clear */
5093 : : dictview_richcompare, /* tp_richcompare */
5094 : : 0, /* tp_weaklistoffset */
5095 : : (getiterfunc)dictkeys_iter, /* tp_iter */
5096 : : 0, /* tp_iternext */
5097 : : dictkeys_methods, /* tp_methods */
5098 : : .tp_getset = dictview_getset,
5099 : : };
5100 : :
5101 : : static PyObject *
5102 : 892 : dictkeys_new(PyObject *dict, PyObject *Py_UNUSED(ignored))
5103 : : {
5104 : 892 : return _PyDictView_New(dict, &PyDictKeys_Type);
5105 : : }
5106 : :
5107 : : static PyObject *
5108 : 0 : dictkeys_reversed(_PyDictViewObject *dv, PyObject *Py_UNUSED(ignored))
5109 : : {
5110 [ # # ]: 0 : if (dv->dv_dict == NULL) {
5111 : 0 : Py_RETURN_NONE;
5112 : : }
5113 : 0 : return dictiter_new(dv->dv_dict, &PyDictRevIterKey_Type);
5114 : : }
5115 : :
5116 : : /*** dict_items ***/
5117 : :
5118 : : static PyObject *
5119 : 1238 : dictitems_iter(_PyDictViewObject *dv)
5120 : : {
5121 [ - + ]: 1238 : if (dv->dv_dict == NULL) {
5122 : 0 : Py_RETURN_NONE;
5123 : : }
5124 : 1238 : return dictiter_new(dv->dv_dict, &PyDictIterItem_Type);
5125 : : }
5126 : :
5127 : : static int
5128 : 0 : dictitems_contains(_PyDictViewObject *dv, PyObject *obj)
5129 : : {
5130 : : int result;
5131 : : PyObject *key, *value, *found;
5132 [ # # ]: 0 : if (dv->dv_dict == NULL)
5133 : 0 : return 0;
5134 [ # # # # ]: 0 : if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 2)
5135 : 0 : return 0;
5136 : 0 : key = PyTuple_GET_ITEM(obj, 0);
5137 : 0 : value = PyTuple_GET_ITEM(obj, 1);
5138 : 0 : found = PyDict_GetItemWithError((PyObject *)dv->dv_dict, key);
5139 [ # # ]: 0 : if (found == NULL) {
5140 [ # # ]: 0 : if (PyErr_Occurred())
5141 : 0 : return -1;
5142 : 0 : return 0;
5143 : : }
5144 : 0 : Py_INCREF(found);
5145 : 0 : result = PyObject_RichCompareBool(found, value, Py_EQ);
5146 : 0 : Py_DECREF(found);
5147 : 0 : return result;
5148 : : }
5149 : :
5150 : : static PySequenceMethods dictitems_as_sequence = {
5151 : : (lenfunc)dictview_len, /* sq_length */
5152 : : 0, /* sq_concat */
5153 : : 0, /* sq_repeat */
5154 : : 0, /* sq_item */
5155 : : 0, /* sq_slice */
5156 : : 0, /* sq_ass_item */
5157 : : 0, /* sq_ass_slice */
5158 : : (objobjproc)dictitems_contains, /* sq_contains */
5159 : : };
5160 : :
5161 : : static PyObject* dictitems_reversed(_PyDictViewObject *dv, PyObject *Py_UNUSED(ignored));
5162 : :
5163 : : PyDoc_STRVAR(reversed_items_doc,
5164 : : "Return a reverse iterator over the dict items.");
5165 : :
5166 : : static PyMethodDef dictitems_methods[] = {
5167 : : {"isdisjoint", (PyCFunction)dictviews_isdisjoint, METH_O,
5168 : : isdisjoint_doc},
5169 : : {"__reversed__", (PyCFunction)dictitems_reversed, METH_NOARGS,
5170 : : reversed_items_doc},
5171 : : {NULL, NULL} /* sentinel */
5172 : : };
5173 : :
5174 : : PyTypeObject PyDictItems_Type = {
5175 : : PyVarObject_HEAD_INIT(&PyType_Type, 0)
5176 : : "dict_items", /* tp_name */
5177 : : sizeof(_PyDictViewObject), /* tp_basicsize */
5178 : : 0, /* tp_itemsize */
5179 : : /* methods */
5180 : : (destructor)dictview_dealloc, /* tp_dealloc */
5181 : : 0, /* tp_vectorcall_offset */
5182 : : 0, /* tp_getattr */
5183 : : 0, /* tp_setattr */
5184 : : 0, /* tp_as_async */
5185 : : (reprfunc)dictview_repr, /* tp_repr */
5186 : : &dictviews_as_number, /* tp_as_number */
5187 : : &dictitems_as_sequence, /* tp_as_sequence */
5188 : : 0, /* tp_as_mapping */
5189 : : 0, /* tp_hash */
5190 : : 0, /* tp_call */
5191 : : 0, /* tp_str */
5192 : : PyObject_GenericGetAttr, /* tp_getattro */
5193 : : 0, /* tp_setattro */
5194 : : 0, /* tp_as_buffer */
5195 : : Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
5196 : : 0, /* tp_doc */
5197 : : (traverseproc)dictview_traverse, /* tp_traverse */
5198 : : 0, /* tp_clear */
5199 : : dictview_richcompare, /* tp_richcompare */
5200 : : 0, /* tp_weaklistoffset */
5201 : : (getiterfunc)dictitems_iter, /* tp_iter */
5202 : : 0, /* tp_iternext */
5203 : : dictitems_methods, /* tp_methods */
5204 : : .tp_getset = dictview_getset,
5205 : : };
5206 : :
5207 : : static PyObject *
5208 : 1263 : dictitems_new(PyObject *dict, PyObject *Py_UNUSED(ignored))
5209 : : {
5210 : 1263 : return _PyDictView_New(dict, &PyDictItems_Type);
5211 : : }
5212 : :
5213 : : static PyObject *
5214 : 0 : dictitems_reversed(_PyDictViewObject *dv, PyObject *Py_UNUSED(ignored))
5215 : : {
5216 [ # # ]: 0 : if (dv->dv_dict == NULL) {
5217 : 0 : Py_RETURN_NONE;
5218 : : }
5219 : 0 : return dictiter_new(dv->dv_dict, &PyDictRevIterItem_Type);
5220 : : }
5221 : :
5222 : : /*** dict_values ***/
5223 : :
5224 : : static PyObject *
5225 : 1591 : dictvalues_iter(_PyDictViewObject *dv)
5226 : : {
5227 [ - + ]: 1591 : if (dv->dv_dict == NULL) {
5228 : 0 : Py_RETURN_NONE;
5229 : : }
5230 : 1591 : return dictiter_new(dv->dv_dict, &PyDictIterValue_Type);
5231 : : }
5232 : :
5233 : : static PySequenceMethods dictvalues_as_sequence = {
5234 : : (lenfunc)dictview_len, /* sq_length */
5235 : : 0, /* sq_concat */
5236 : : 0, /* sq_repeat */
5237 : : 0, /* sq_item */
5238 : : 0, /* sq_slice */
5239 : : 0, /* sq_ass_item */
5240 : : 0, /* sq_ass_slice */
5241 : : (objobjproc)0, /* sq_contains */
5242 : : };
5243 : :
5244 : : static PyObject* dictvalues_reversed(_PyDictViewObject *dv, PyObject *Py_UNUSED(ignored));
5245 : :
5246 : : PyDoc_STRVAR(reversed_values_doc,
5247 : : "Return a reverse iterator over the dict values.");
5248 : :
5249 : : static PyMethodDef dictvalues_methods[] = {
5250 : : {"__reversed__", (PyCFunction)dictvalues_reversed, METH_NOARGS,
5251 : : reversed_values_doc},
5252 : : {NULL, NULL} /* sentinel */
5253 : : };
5254 : :
5255 : : PyTypeObject PyDictValues_Type = {
5256 : : PyVarObject_HEAD_INIT(&PyType_Type, 0)
5257 : : "dict_values", /* tp_name */
5258 : : sizeof(_PyDictViewObject), /* tp_basicsize */
5259 : : 0, /* tp_itemsize */
5260 : : /* methods */
5261 : : (destructor)dictview_dealloc, /* tp_dealloc */
5262 : : 0, /* tp_vectorcall_offset */
5263 : : 0, /* tp_getattr */
5264 : : 0, /* tp_setattr */
5265 : : 0, /* tp_as_async */
5266 : : (reprfunc)dictview_repr, /* tp_repr */
5267 : : 0, /* tp_as_number */
5268 : : &dictvalues_as_sequence, /* tp_as_sequence */
5269 : : 0, /* tp_as_mapping */
5270 : : 0, /* tp_hash */
5271 : : 0, /* tp_call */
5272 : : 0, /* tp_str */
5273 : : PyObject_GenericGetAttr, /* tp_getattro */
5274 : : 0, /* tp_setattro */
5275 : : 0, /* tp_as_buffer */
5276 : : Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
5277 : : 0, /* tp_doc */
5278 : : (traverseproc)dictview_traverse, /* tp_traverse */
5279 : : 0, /* tp_clear */
5280 : : 0, /* tp_richcompare */
5281 : : 0, /* tp_weaklistoffset */
5282 : : (getiterfunc)dictvalues_iter, /* tp_iter */
5283 : : 0, /* tp_iternext */
5284 : : dictvalues_methods, /* tp_methods */
5285 : : .tp_getset = dictview_getset,
5286 : : };
5287 : :
5288 : : static PyObject *
5289 : 1616 : dictvalues_new(PyObject *dict, PyObject *Py_UNUSED(ignored))
5290 : : {
5291 : 1616 : return _PyDictView_New(dict, &PyDictValues_Type);
5292 : : }
5293 : :
5294 : : static PyObject *
5295 : 0 : dictvalues_reversed(_PyDictViewObject *dv, PyObject *Py_UNUSED(ignored))
5296 : : {
5297 [ # # ]: 0 : if (dv->dv_dict == NULL) {
5298 : 0 : Py_RETURN_NONE;
5299 : : }
5300 : 0 : return dictiter_new(dv->dv_dict, &PyDictRevIterValue_Type);
5301 : : }
5302 : :
5303 : :
5304 : : /* Returns NULL if cannot allocate a new PyDictKeysObject,
5305 : : but does not set an error */
5306 : : PyDictKeysObject *
5307 : 1941 : _PyDict_NewKeysForClass(void)
5308 : : {
5309 : 1941 : PyInterpreterState *interp = _PyInterpreterState_GET();
5310 : 1941 : PyDictKeysObject *keys = new_keys_object(
5311 : : interp, NEXT_LOG2_SHARED_KEYS_MAX_SIZE, 1);
5312 [ - + ]: 1941 : if (keys == NULL) {
5313 : 0 : PyErr_Clear();
5314 : : }
5315 : : else {
5316 : : assert(keys->dk_nentries == 0);
5317 : : /* Set to max size+1 as it will shrink by one before each new object */
5318 : 1941 : keys->dk_usable = SHARED_KEYS_MAX_SIZE;
5319 : 1941 : keys->dk_kind = DICT_KEYS_SPLIT;
5320 : : }
5321 : 1941 : return keys;
5322 : : }
5323 : :
5324 : : #define CACHED_KEYS(tp) (((PyHeapTypeObject*)tp)->ht_cached_keys)
5325 : :
5326 : : static int
5327 : 138267 : init_inline_values(PyObject *obj, PyTypeObject *tp)
5328 : : {
5329 : : assert(tp->tp_flags & Py_TPFLAGS_HEAPTYPE);
5330 : : // assert(type->tp_dictoffset > 0); -- TO DO Update this assert.
5331 : : assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
5332 : 138267 : PyDictKeysObject *keys = CACHED_KEYS(tp);
5333 : : assert(keys != NULL);
5334 [ + + ]: 138267 : if (keys->dk_usable > 1) {
5335 : 5240 : keys->dk_usable--;
5336 : : }
5337 : 138267 : size_t size = shared_keys_usable_size(keys);
5338 : 138267 : PyDictValues *values = new_values(size);
5339 [ - + ]: 138267 : if (values == NULL) {
5340 : 0 : PyErr_NoMemory();
5341 : 0 : return -1;
5342 : : }
5343 : : assert(((uint8_t *)values)[-1] >= (size + 2));
5344 : 138267 : ((uint8_t *)values)[-2] = 0;
5345 [ + + ]: 1051934 : for (size_t i = 0; i < size; i++) {
5346 : 913667 : values->values[i] = NULL;
5347 : : }
5348 : 138267 : _PyDictOrValues_SetValues(_PyObject_DictOrValuesPointer(obj), values);
5349 : 138267 : return 0;
5350 : : }
5351 : :
5352 : : int
5353 : 273167 : _PyObject_InitializeDict(PyObject *obj)
5354 : : {
5355 : 273167 : PyInterpreterState *interp = _PyInterpreterState_GET();
5356 : 273167 : PyTypeObject *tp = Py_TYPE(obj);
5357 [ + + ]: 273167 : if (tp->tp_dictoffset == 0) {
5358 : 134900 : return 0;
5359 : : }
5360 [ + - ]: 138267 : if (tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
5361 : : OBJECT_STAT_INC(new_values);
5362 : 138267 : return init_inline_values(obj, tp);
5363 : : }
5364 : : PyObject *dict;
5365 [ # # # # ]: 0 : if (_PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE) && CACHED_KEYS(tp)) {
5366 : 0 : dictkeys_incref(CACHED_KEYS(tp));
5367 : 0 : dict = new_dict_with_shared_keys(interp, CACHED_KEYS(tp));
5368 : : }
5369 : : else {
5370 : 0 : dict = PyDict_New();
5371 : : }
5372 [ # # ]: 0 : if (dict == NULL) {
5373 : 0 : return -1;
5374 : : }
5375 : 0 : PyObject **dictptr = _PyObject_ComputedDictPointer(obj);
5376 : 0 : *dictptr = dict;
5377 : 0 : return 0;
5378 : : }
5379 : :
5380 : : static PyObject *
5381 : 795 : make_dict_from_instance_attributes(PyInterpreterState *interp,
5382 : : PyDictKeysObject *keys, PyDictValues *values)
5383 : : {
5384 : 795 : dictkeys_incref(keys);
5385 : 795 : Py_ssize_t used = 0;
5386 : 795 : Py_ssize_t track = 0;
5387 : 795 : size_t size = shared_keys_usable_size(keys);
5388 [ + + ]: 14580 : for (size_t i = 0; i < size; i++) {
5389 : 13785 : PyObject *val = values->values[i];
5390 [ + + ]: 13785 : if (val != NULL) {
5391 : 216 : used += 1;
5392 : 216 : track += _PyObject_GC_MAY_BE_TRACKED(val);
5393 : : }
5394 : : }
5395 : 795 : PyObject *res = new_dict(interp, keys, values, used, 0);
5396 [ + + + - ]: 795 : if (track && res) {
5397 : 23 : _PyObject_GC_TRACK(res);
5398 : : }
5399 : 795 : return res;
5400 : : }
5401 : :
5402 : : PyObject *
5403 : 0 : _PyObject_MakeDictFromInstanceAttributes(PyObject *obj, PyDictValues *values)
5404 : : {
5405 : 0 : PyInterpreterState *interp = _PyInterpreterState_GET();
5406 : 0 : PyDictKeysObject *keys = CACHED_KEYS(Py_TYPE(obj));
5407 : : OBJECT_STAT_INC(dict_materialized_on_request);
5408 : 0 : return make_dict_from_instance_attributes(interp, keys, values);
5409 : : }
5410 : :
5411 : : int
5412 : 410649 : _PyObject_StoreInstanceAttribute(PyObject *obj, PyDictValues *values,
5413 : : PyObject *name, PyObject *value)
5414 : : {
5415 : 410649 : PyInterpreterState *interp = _PyInterpreterState_GET();
5416 : 410649 : PyDictKeysObject *keys = CACHED_KEYS(Py_TYPE(obj));
5417 : : assert(keys != NULL);
5418 : : assert(values != NULL);
5419 : : assert(Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
5420 : 410649 : Py_ssize_t ix = DKIX_EMPTY;
5421 [ + - ]: 410649 : if (PyUnicode_CheckExact(name)) {
5422 : 410649 : ix = insert_into_dictkeys(keys, name);
5423 : : }
5424 [ + + ]: 410649 : if (ix == DKIX_EMPTY) {
5425 : : #ifdef Py_STATS
5426 : : if (PyUnicode_CheckExact(name)) {
5427 : : if (shared_keys_usable_size(keys) == SHARED_KEYS_MAX_SIZE) {
5428 : : OBJECT_STAT_INC(dict_materialized_too_big);
5429 : : }
5430 : : else {
5431 : : OBJECT_STAT_INC(dict_materialized_new_key);
5432 : : }
5433 : : }
5434 : : else {
5435 : : OBJECT_STAT_INC(dict_materialized_str_subclass);
5436 : : }
5437 : : #endif
5438 : 2 : PyObject *dict = make_dict_from_instance_attributes(
5439 : : interp, keys, values);
5440 [ - + ]: 2 : if (dict == NULL) {
5441 : 0 : return -1;
5442 : : }
5443 : 2 : _PyObject_DictOrValuesPointer(obj)->dict = dict;
5444 [ - + ]: 2 : if (value == NULL) {
5445 : 0 : return PyDict_DelItem(dict, name);
5446 : : }
5447 : : else {
5448 : 2 : return PyDict_SetItem(dict, name, value);
5449 : : }
5450 : : }
5451 : 410647 : PyObject *old_value = values->values[ix];
5452 : 410647 : values->values[ix] = Py_XNewRef(value);
5453 [ + + ]: 410647 : if (old_value == NULL) {
5454 [ - + ]: 116995 : if (value == NULL) {
5455 : 0 : PyErr_Format(PyExc_AttributeError,
5456 : : "'%.100s' object has no attribute '%U'",
5457 : 0 : Py_TYPE(obj)->tp_name, name);
5458 : 0 : return -1;
5459 : : }
5460 : 116995 : _PyDictValues_AddToInsertionOrder(values, ix);
5461 : : }
5462 : : else {
5463 [ + + ]: 293652 : if (value == NULL) {
5464 : 292839 : delete_index_from_values(values, ix);
5465 : : }
5466 : 293652 : Py_DECREF(old_value);
5467 : : }
5468 : 410647 : return 0;
5469 : : }
5470 : :
5471 : : /* Sanity check for managed dicts */
5472 : : #if 0
5473 : : #define CHECK(val) assert(val); if (!(val)) { return 0; }
5474 : :
5475 : : int
5476 : : _PyObject_ManagedDictValidityCheck(PyObject *obj)
5477 : : {
5478 : : PyTypeObject *tp = Py_TYPE(obj);
5479 : : CHECK(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
5480 : : PyDictOrValues *dorv_ptr = _PyObject_DictOrValuesPointer(obj);
5481 : : if (_PyDictOrValues_IsValues(*dorv_ptr)) {
5482 : : PyDictValues *values = _PyDictOrValues_GetValues(*dorv_ptr);
5483 : : int size = ((uint8_t *)values)[-2];
5484 : : int count = 0;
5485 : : PyDictKeysObject *keys = CACHED_KEYS(tp);
5486 : : for (Py_ssize_t i = 0; i < keys->dk_nentries; i++) {
5487 : : if (values->values[i] != NULL) {
5488 : : count++;
5489 : : }
5490 : : }
5491 : : CHECK(size == count);
5492 : : }
5493 : : else {
5494 : : if (dorv_ptr->dict != NULL) {
5495 : : CHECK(PyDict_Check(dorv_ptr->dict));
5496 : : }
5497 : : }
5498 : : return 1;
5499 : : }
5500 : : #endif
5501 : :
5502 : : PyObject *
5503 : 203615 : _PyObject_GetInstanceAttribute(PyObject *obj, PyDictValues *values,
5504 : : PyObject *name)
5505 : : {
5506 : : assert(PyUnicode_CheckExact(name));
5507 : 203615 : PyDictKeysObject *keys = CACHED_KEYS(Py_TYPE(obj));
5508 : : assert(keys != NULL);
5509 : 203615 : Py_ssize_t ix = _PyDictKeys_StringLookup(keys, name);
5510 [ + + ]: 203615 : if (ix == DKIX_EMPTY) {
5511 : 183973 : return NULL;
5512 : : }
5513 : 19642 : PyObject *value = values->values[ix];
5514 : 19642 : return Py_XNewRef(value);
5515 : : }
5516 : :
5517 : : int
5518 : 0 : _PyObject_IsInstanceDictEmpty(PyObject *obj)
5519 : : {
5520 : 0 : PyTypeObject *tp = Py_TYPE(obj);
5521 [ # # ]: 0 : if (tp->tp_dictoffset == 0) {
5522 : 0 : return 1;
5523 : : }
5524 : : PyObject *dict;
5525 [ # # ]: 0 : if (tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
5526 : 0 : PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(obj);
5527 [ # # ]: 0 : if (_PyDictOrValues_IsValues(dorv)) {
5528 : 0 : PyDictKeysObject *keys = CACHED_KEYS(tp);
5529 [ # # ]: 0 : for (Py_ssize_t i = 0; i < keys->dk_nentries; i++) {
5530 [ # # ]: 0 : if (_PyDictOrValues_GetValues(dorv)->values[i] != NULL) {
5531 : 0 : return 0;
5532 : : }
5533 : : }
5534 : 0 : return 1;
5535 : : }
5536 : 0 : dict = _PyDictOrValues_GetDict(dorv);
5537 : : }
5538 : : else {
5539 : 0 : PyObject **dictptr = _PyObject_ComputedDictPointer(obj);
5540 : 0 : dict = *dictptr;
5541 : : }
5542 [ # # ]: 0 : if (dict == NULL) {
5543 : 0 : return 1;
5544 : : }
5545 : 0 : return ((PyDictObject *)dict)->ma_used == 0;
5546 : : }
5547 : :
5548 : : void
5549 : 137332 : _PyObject_FreeInstanceAttributes(PyObject *self)
5550 : : {
5551 : 137332 : PyTypeObject *tp = Py_TYPE(self);
5552 : : assert(Py_TYPE(self)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
5553 : 137332 : PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(self);
5554 [ - + ]: 137332 : if (!_PyDictOrValues_IsValues(dorv)) {
5555 : 0 : return;
5556 : : }
5557 : 137332 : PyDictValues *values = _PyDictOrValues_GetValues(dorv);
5558 : 137332 : PyDictKeysObject *keys = CACHED_KEYS(tp);
5559 [ + + ]: 823076 : for (Py_ssize_t i = 0; i < keys->dk_nentries; i++) {
5560 : 685744 : Py_XDECREF(values->values[i]);
5561 : : }
5562 : 137332 : free_values(values);
5563 : : }
5564 : :
5565 : : int
5566 : 50728 : _PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg)
5567 : : {
5568 : 50728 : PyTypeObject *tp = Py_TYPE(obj);
5569 [ - + ]: 50728 : if((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {
5570 : 0 : return 0;
5571 : : }
5572 : : assert(tp->tp_dictoffset);
5573 : 50728 : PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(obj);
5574 [ + + ]: 50728 : if (_PyDictOrValues_IsValues(dorv)) {
5575 : 35542 : PyDictValues *values = _PyDictOrValues_GetValues(dorv);
5576 : 35542 : PyDictKeysObject *keys = CACHED_KEYS(tp);
5577 [ + + ]: 263098 : for (Py_ssize_t i = 0; i < keys->dk_nentries; i++) {
5578 [ + + - + ]: 227556 : Py_VISIT(values->values[i]);
5579 : : }
5580 : : }
5581 : : else {
5582 : 15186 : PyObject *dict = _PyDictOrValues_GetDict(dorv);
5583 [ + + - + ]: 15186 : Py_VISIT(dict);
5584 : : }
5585 : 50728 : return 0;
5586 : : }
5587 : :
5588 : : void
5589 : 416 : _PyObject_ClearManagedDict(PyObject *obj)
5590 : : {
5591 : 416 : PyTypeObject *tp = Py_TYPE(obj);
5592 [ - + ]: 416 : if((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {
5593 : 0 : return;
5594 : : }
5595 : 416 : PyDictOrValues *dorv_ptr = _PyObject_DictOrValuesPointer(obj);
5596 [ + + ]: 416 : if (_PyDictOrValues_IsValues(*dorv_ptr)) {
5597 : 126 : PyDictValues *values = _PyDictOrValues_GetValues(*dorv_ptr);
5598 : 126 : PyDictKeysObject *keys = CACHED_KEYS(tp);
5599 [ + + ]: 615 : for (Py_ssize_t i = 0; i < keys->dk_nentries; i++) {
5600 [ + + ]: 489 : Py_CLEAR(values->values[i]);
5601 : : }
5602 : 126 : dorv_ptr->dict = NULL;
5603 : 126 : free_values(values);
5604 : : }
5605 : : else {
5606 : 290 : PyObject *dict = dorv_ptr->dict;
5607 [ + - ]: 290 : if (dict) {
5608 : 290 : dorv_ptr->dict = NULL;
5609 : 290 : Py_DECREF(dict);
5610 : : }
5611 : : }
5612 : : }
5613 : :
5614 : : PyObject *
5615 : 4636 : PyObject_GenericGetDict(PyObject *obj, void *context)
5616 : : {
5617 : : PyObject *dict;
5618 : 4636 : PyInterpreterState *interp = _PyInterpreterState_GET();
5619 : 4636 : PyTypeObject *tp = Py_TYPE(obj);
5620 [ + + ]: 4636 : if (_PyType_HasFeature(tp, Py_TPFLAGS_MANAGED_DICT)) {
5621 : 3919 : PyDictOrValues *dorv_ptr = _PyObject_DictOrValuesPointer(obj);
5622 [ + + ]: 3919 : if (_PyDictOrValues_IsValues(*dorv_ptr)) {
5623 : 793 : PyDictValues *values = _PyDictOrValues_GetValues(*dorv_ptr);
5624 : : OBJECT_STAT_INC(dict_materialized_on_request);
5625 : 793 : dict = make_dict_from_instance_attributes(
5626 : 793 : interp, CACHED_KEYS(tp), values);
5627 [ + - ]: 793 : if (dict != NULL) {
5628 : 793 : dorv_ptr->dict = dict;
5629 : : }
5630 : : }
5631 : : else {
5632 : 3126 : dict = _PyDictOrValues_GetDict(*dorv_ptr);
5633 [ - + ]: 3126 : if (dict == NULL) {
5634 : 0 : dictkeys_incref(CACHED_KEYS(tp));
5635 : 0 : dict = new_dict_with_shared_keys(interp, CACHED_KEYS(tp));
5636 : 0 : dorv_ptr->dict = dict;
5637 : : }
5638 : : }
5639 : : }
5640 : : else {
5641 : 717 : PyObject **dictptr = _PyObject_ComputedDictPointer(obj);
5642 [ - + ]: 717 : if (dictptr == NULL) {
5643 : 0 : PyErr_SetString(PyExc_AttributeError,
5644 : : "This object has no __dict__");
5645 : 0 : return NULL;
5646 : : }
5647 : 717 : dict = *dictptr;
5648 [ + + ]: 717 : if (dict == NULL) {
5649 : 655 : PyTypeObject *tp = Py_TYPE(obj);
5650 [ - + - - ]: 655 : if (_PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE) && CACHED_KEYS(tp)) {
5651 : 0 : dictkeys_incref(CACHED_KEYS(tp));
5652 : 0 : *dictptr = dict = new_dict_with_shared_keys(
5653 : 0 : interp, CACHED_KEYS(tp));
5654 : : }
5655 : : else {
5656 : 655 : *dictptr = dict = PyDict_New();
5657 : : }
5658 : : }
5659 : : }
5660 : 4636 : return Py_XNewRef(dict);
5661 : : }
5662 : :
5663 : : int
5664 : 2788515 : _PyObjectDict_SetItem(PyTypeObject *tp, PyObject **dictptr,
5665 : : PyObject *key, PyObject *value)
5666 : : {
5667 : : PyObject *dict;
5668 : : int res;
5669 : : PyDictKeysObject *cached;
5670 : 2788515 : PyInterpreterState *interp = _PyInterpreterState_GET();
5671 : :
5672 : : assert(dictptr != NULL);
5673 [ + + + + ]: 2788515 : if ((tp->tp_flags & Py_TPFLAGS_HEAPTYPE) && (cached = CACHED_KEYS(tp))) {
5674 : : assert(dictptr != NULL);
5675 : 315012 : dict = *dictptr;
5676 [ + + ]: 315012 : if (dict == NULL) {
5677 : 826 : dictkeys_incref(cached);
5678 : 826 : dict = new_dict_with_shared_keys(interp, cached);
5679 [ - + ]: 826 : if (dict == NULL)
5680 : 0 : return -1;
5681 : 826 : *dictptr = dict;
5682 : : }
5683 [ - + ]: 315012 : if (value == NULL) {
5684 : 0 : res = PyDict_DelItem(dict, key);
5685 : : }
5686 : : else {
5687 : 315012 : res = PyDict_SetItem(dict, key, value);
5688 : : }
5689 : : } else {
5690 : 2473503 : dict = *dictptr;
5691 [ + + ]: 2473503 : if (dict == NULL) {
5692 : 411123 : dict = PyDict_New();
5693 [ - + ]: 411123 : if (dict == NULL)
5694 : 0 : return -1;
5695 : 411123 : *dictptr = dict;
5696 : : }
5697 [ + + ]: 2473503 : if (value == NULL) {
5698 : 187 : res = PyDict_DelItem(dict, key);
5699 : : } else {
5700 : 2473316 : res = PyDict_SetItem(dict, key, value);
5701 : : }
5702 : : }
5703 : : ASSERT_CONSISTENT(dict);
5704 : 2788515 : return res;
5705 : : }
5706 : :
5707 : : void
5708 : 1886 : _PyDictKeys_DecRef(PyDictKeysObject *keys)
5709 : : {
5710 : 1886 : PyInterpreterState *interp = _PyInterpreterState_GET();
5711 : 1886 : dictkeys_decref(interp, keys);
5712 : 1886 : }
5713 : :
5714 : 18693 : uint32_t _PyDictKeys_GetVersionForCurrentState(PyInterpreterState *interp,
5715 : : PyDictKeysObject *dictkeys)
5716 : : {
5717 [ + + ]: 18693 : if (dictkeys->dk_version != 0) {
5718 : 17354 : return dictkeys->dk_version;
5719 : : }
5720 [ - + ]: 1339 : if (interp->dict_state.next_keys_version == 0) {
5721 : 0 : return 0;
5722 : : }
5723 : 1339 : uint32_t v = interp->dict_state.next_keys_version++;
5724 : 1339 : dictkeys->dk_version = v;
5725 : 1339 : return v;
5726 : : }
5727 : :
5728 : : static inline int
5729 : 0 : validate_watcher_id(PyInterpreterState *interp, int watcher_id)
5730 : : {
5731 [ # # # # ]: 0 : if (watcher_id < 0 || watcher_id >= DICT_MAX_WATCHERS) {
5732 : 0 : PyErr_Format(PyExc_ValueError, "Invalid dict watcher ID %d", watcher_id);
5733 : 0 : return -1;
5734 : : }
5735 [ # # ]: 0 : if (!interp->dict_state.watchers[watcher_id]) {
5736 : 0 : PyErr_Format(PyExc_ValueError, "No dict watcher set for ID %d", watcher_id);
5737 : 0 : return -1;
5738 : : }
5739 : 0 : return 0;
5740 : : }
5741 : :
5742 : : int
5743 : 0 : PyDict_Watch(int watcher_id, PyObject* dict)
5744 : : {
5745 [ # # ]: 0 : if (!PyDict_Check(dict)) {
5746 : 0 : PyErr_SetString(PyExc_ValueError, "Cannot watch non-dictionary");
5747 : 0 : return -1;
5748 : : }
5749 : 0 : PyInterpreterState *interp = _PyInterpreterState_GET();
5750 [ # # ]: 0 : if (validate_watcher_id(interp, watcher_id)) {
5751 : 0 : return -1;
5752 : : }
5753 : 0 : ((PyDictObject*)dict)->ma_version_tag |= (1LL << watcher_id);
5754 : 0 : return 0;
5755 : : }
5756 : :
5757 : : int
5758 : 0 : PyDict_Unwatch(int watcher_id, PyObject* dict)
5759 : : {
5760 [ # # ]: 0 : if (!PyDict_Check(dict)) {
5761 : 0 : PyErr_SetString(PyExc_ValueError, "Cannot watch non-dictionary");
5762 : 0 : return -1;
5763 : : }
5764 : 0 : PyInterpreterState *interp = _PyInterpreterState_GET();
5765 [ # # ]: 0 : if (validate_watcher_id(interp, watcher_id)) {
5766 : 0 : return -1;
5767 : : }
5768 : 0 : ((PyDictObject*)dict)->ma_version_tag &= ~(1LL << watcher_id);
5769 : 0 : return 0;
5770 : : }
5771 : :
5772 : : int
5773 : 0 : PyDict_AddWatcher(PyDict_WatchCallback callback)
5774 : : {
5775 : 0 : PyInterpreterState *interp = _PyInterpreterState_GET();
5776 : :
5777 [ # # ]: 0 : for (int i = 0; i < DICT_MAX_WATCHERS; i++) {
5778 [ # # ]: 0 : if (!interp->dict_state.watchers[i]) {
5779 : 0 : interp->dict_state.watchers[i] = callback;
5780 : 0 : return i;
5781 : : }
5782 : : }
5783 : :
5784 : 0 : PyErr_SetString(PyExc_RuntimeError, "no more dict watcher IDs available");
5785 : 0 : return -1;
5786 : : }
5787 : :
5788 : : int
5789 : 0 : PyDict_ClearWatcher(int watcher_id)
5790 : : {
5791 : 0 : PyInterpreterState *interp = _PyInterpreterState_GET();
5792 [ # # ]: 0 : if (validate_watcher_id(interp, watcher_id)) {
5793 : 0 : return -1;
5794 : : }
5795 : 0 : interp->dict_state.watchers[watcher_id] = NULL;
5796 : 0 : return 0;
5797 : : }
5798 : :
5799 : : static const char *
5800 : 0 : dict_event_name(PyDict_WatchEvent event) {
5801 [ # # # # : 0 : switch (event) {
# # # ]
5802 : : #define CASE(op) \
5803 : : case PyDict_EVENT_##op: \
5804 : : return "PyDict_EVENT_" #op;
5805 : 0 : PY_FOREACH_DICT_EVENT(CASE)
5806 : : #undef CASE
5807 : : }
5808 : 0 : Py_UNREACHABLE();
5809 : : }
5810 : :
5811 : : void
5812 : 0 : _PyDict_SendEvent(int watcher_bits,
5813 : : PyDict_WatchEvent event,
5814 : : PyDictObject *mp,
5815 : : PyObject *key,
5816 : : PyObject *value)
5817 : : {
5818 : 0 : PyInterpreterState *interp = _PyInterpreterState_GET();
5819 [ # # ]: 0 : for (int i = 0; i < DICT_MAX_WATCHERS; i++) {
5820 [ # # ]: 0 : if (watcher_bits & 1) {
5821 : 0 : PyDict_WatchCallback cb = interp->dict_state.watchers[i];
5822 [ # # # # ]: 0 : if (cb && (cb(event, (PyObject*)mp, key, value) < 0)) {
5823 : : // We don't want to resurrect the dict by potentially having an
5824 : : // unraisablehook keep a reference to it, so we don't pass the
5825 : : // dict as context, just an informative string message. Dict
5826 : : // repr can call arbitrary code, so we invent a simpler version.
5827 : 0 : PyObject *context = PyUnicode_FromFormat(
5828 : : "%s watcher callback for <dict at %p>",
5829 : : dict_event_name(event), mp);
5830 [ # # ]: 0 : if (context == NULL) {
5831 : 0 : context = Py_NewRef(Py_None);
5832 : : }
5833 : 0 : PyErr_WriteUnraisable(context);
5834 : 0 : Py_DECREF(context);
5835 : : }
5836 : : }
5837 : 0 : watcher_bits >>= 1;
5838 : : }
5839 : 0 : }
|