Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
allendowney
GitHub Repository: allendowney/cpython
Path: blob/main/Objects/odictobject.c
12 views
1
/* Ordered Dictionary object implementation.
2
3
This implementation is necessarily explicitly equivalent to the pure Python
4
OrderedDict class in Lib/collections/__init__.py. The strategy there
5
involves using a doubly-linked-list to capture the order. We keep to that
6
strategy, using a lower-level linked-list.
7
8
About the Linked-List
9
=====================
10
11
For the linked list we use a basic doubly-linked-list. Using a circularly-
12
linked-list does have some benefits, but they don't apply so much here
13
since OrderedDict is focused on the ends of the list (for the most part).
14
Furthermore, there are some features of generic linked-lists that we simply
15
don't need for OrderedDict. Thus a simple custom implementation meets our
16
needs. Alternatives to our simple approach include the QCIRCLE_*
17
macros from BSD's queue.h, and the linux's list.h.
18
19
Getting O(1) Node Lookup
20
------------------------
21
22
One invariant of Python's OrderedDict is that it preserves time complexity
23
of dict's methods, particularly the O(1) operations. Simply adding a
24
linked-list on top of dict is not sufficient here; operations for nodes in
25
the middle of the linked-list implicitly require finding the node first.
26
With a simple linked-list like we're using, that is an O(n) operation.
27
Consequently, methods like __delitem__() would change from O(1) to O(n),
28
which is unacceptable.
29
30
In order to preserve O(1) performance for node removal (finding nodes), we
31
must do better than just looping through the linked-list. Here are options
32
we've considered:
33
34
1. use a second dict to map keys to nodes (a la the pure Python version).
35
2. keep a simple hash table mirroring the order of dict's, mapping each key
36
to the corresponding node in the linked-list.
37
3. use a version of shared keys (split dict) that allows non-unicode keys.
38
4. have the value stored for each key be a (value, node) pair, and adjust
39
__getitem__(), get(), etc. accordingly.
40
41
The approach with the least performance impact (time and space) is #2,
42
mirroring the key order of dict's dk_entries with an array of node pointers.
43
While _Py_dict_lookup() does not give us the index into the array,
44
we make use of pointer arithmetic to get that index. An alternative would
45
be to refactor _Py_dict_lookup() to provide the index, explicitly exposing
46
the implementation detail. We could even just use a custom lookup function
47
for OrderedDict that facilitates our need. However, both approaches are
48
significantly more complicated than just using pointer arithmetic.
49
50
The catch with mirroring the hash table ordering is that we have to keep
51
the ordering in sync through any dict resizes. However, that order only
52
matters during node lookup. We can simply defer any potential resizing
53
until we need to do a lookup.
54
55
Linked-List Nodes
56
-----------------
57
58
The current implementation stores a pointer to the associated key only.
59
One alternative would be to store a pointer to the PyDictKeyEntry instead.
60
This would save one pointer de-reference per item, which is nice during
61
calls to values() and items(). However, it adds unnecessary overhead
62
otherwise, so we stick with just the key.
63
64
Linked-List API
65
---------------
66
67
As noted, the linked-list implemented here does not have all the bells and
68
whistles. However, we recognize that the implementation may need to
69
change to accommodate performance improvements or extra functionality. To
70
that end, we use a simple API to interact with the linked-list. Here's a
71
summary of the methods/macros:
72
73
Node info:
74
75
* _odictnode_KEY(node)
76
* _odictnode_VALUE(od, node)
77
* _odictnode_PREV(node)
78
* _odictnode_NEXT(node)
79
80
Linked-List info:
81
82
* _odict_FIRST(od)
83
* _odict_LAST(od)
84
* _odict_EMPTY(od)
85
* _odict_FOREACH(od, node) - used in place of `for (node=...)`
86
87
For adding nodes:
88
89
* _odict_add_head(od, node)
90
* _odict_add_tail(od, node)
91
* _odict_add_new_node(od, key, hash)
92
93
For removing nodes:
94
95
* _odict_clear_node(od, node, key, hash)
96
* _odict_clear_nodes(od, clear_each)
97
98
Others:
99
100
* _odict_find_node_hash(od, key, hash)
101
* _odict_find_node(od, key)
102
* _odict_keys_equal(od1, od2)
103
104
And here's a look at how the linked-list relates to the OrderedDict API:
105
106
============ === === ==== ==== ==== === ==== ===== ==== ==== === ==== === ===
107
method key val prev next mem 1st last empty iter find add rmv clr keq
108
============ === === ==== ==== ==== === ==== ===== ==== ==== === ==== === ===
109
__del__ ~ X
110
__delitem__ free ~ node
111
__eq__ ~ X
112
__iter__ X X
113
__new__ X X
114
__reduce__ X ~ X
115
__repr__ X X X
116
__reversed__ X X
117
__setitem__ key
118
__sizeof__ size X
119
clear ~ ~ X
120
copy X X X
121
items X X X
122
keys X X
123
move_to_end X X X ~ h/t key
124
pop free key
125
popitem X X free X X node
126
setdefault ~ ? ~
127
values X X
128
============ === === ==== ==== ==== === ==== ===== ==== ==== === ==== === ===
129
130
__delitem__ is the only method that directly relies on finding an arbitrary
131
node in the linked-list. Everything else is iteration or relates to the
132
ends of the linked-list.
133
134
Situation that Endangers Consistency
135
------------------------------------
136
Using a raw linked-list for OrderedDict exposes a key situation that can
137
cause problems. If a node is stored in a variable, there is a chance that
138
the node may have been deallocated before the variable gets used, thus
139
potentially leading to a segmentation fault. A key place where this shows
140
up is during iteration through the linked list (via _odict_FOREACH or
141
otherwise).
142
143
A number of solutions are available to resolve this situation:
144
145
* defer looking up the node until as late as possible and certainly after
146
any code that could possibly result in a deletion;
147
* if the node is needed both before and after a point where the node might
148
be removed, do a check before using the node at the "after" location to
149
see if the node is still valid;
150
* like the last one, but simply pull the node again to ensure it's right;
151
* keep the key in the variable instead of the node and then look up the
152
node using the key at the point where the node is needed (this is what
153
we do for the iterators).
154
155
Another related problem, preserving consistent ordering during iteration,
156
is described below. That one is not exclusive to using linked-lists.
157
158
159
Challenges from Subclassing dict
160
================================
161
162
OrderedDict subclasses dict, which is an unusual relationship between two
163
builtin types (other than the base object type). Doing so results in
164
some complication and deserves further explanation. There are two things
165
to consider here. First, in what circumstances or with what adjustments
166
can OrderedDict be used as a drop-in replacement for dict (at the C level)?
167
Second, how can the OrderedDict implementation leverage the dict
168
implementation effectively without introducing unnecessary coupling or
169
inefficiencies?
170
171
This second point is reflected here and in the implementation, so the
172
further focus is on the first point. It is worth noting that for
173
overridden methods, the dict implementation is deferred to as much as
174
possible. Furthermore, coupling is limited to as little as is reasonable.
175
176
Concrete API Compatibility
177
--------------------------
178
179
Use of the concrete C-API for dict (PyDict_*) with OrderedDict is
180
problematic. (See http://bugs.python.org/issue10977.) The concrete API
181
has a number of hard-coded assumptions tied to the dict implementation.
182
This is, in part, due to performance reasons, which is understandable
183
given the part dict plays in Python.
184
185
Any attempt to replace dict with OrderedDict for any role in the
186
interpreter (e.g. **kwds) faces a challenge. Such any effort must
187
recognize that the instances in affected locations currently interact with
188
the concrete API.
189
190
Here are some ways to address this challenge:
191
192
1. Change the relevant usage of the concrete API in CPython and add
193
PyDict_CheckExact() calls to each of the concrete API functions.
194
2. Adjust the relevant concrete API functions to explicitly accommodate
195
OrderedDict.
196
3. As with #1, add the checks, but improve the abstract API with smart fast
197
paths for dict and OrderedDict, and refactor CPython to use the abstract
198
API. Improvements to the abstract API would be valuable regardless.
199
200
Adding the checks to the concrete API would help make any interpreter
201
switch to OrderedDict less painful for extension modules. However, this
202
won't work. The equivalent C API call to `dict.__setitem__(obj, k, v)`
203
is 'PyDict_SetItem(obj, k, v)`. This illustrates how subclasses in C call
204
the base class's methods, since there is no equivalent of super() in the
205
C API. Calling into Python for parent class API would work, but some
206
extension modules already rely on this feature of the concrete API.
207
208
For reference, here is a breakdown of some of the dict concrete API:
209
210
========================== ============= =======================
211
concrete API uses abstract API
212
========================== ============= =======================
213
PyDict_Check PyMapping_Check
214
(PyDict_CheckExact) -
215
(PyDict_New) -
216
(PyDictProxy_New) -
217
PyDict_Clear -
218
PyDict_Contains PySequence_Contains
219
PyDict_Copy -
220
PyDict_SetItem PyObject_SetItem
221
PyDict_SetItemString PyMapping_SetItemString
222
PyDict_DelItem PyMapping_DelItem
223
PyDict_DelItemString PyMapping_DelItemString
224
PyDict_GetItem -
225
PyDict_GetItemWithError PyObject_GetItem
226
_PyDict_GetItemIdWithError -
227
PyDict_GetItemString PyMapping_GetItemString
228
PyDict_Items PyMapping_Items
229
PyDict_Keys PyMapping_Keys
230
PyDict_Values PyMapping_Values
231
PyDict_Size PyMapping_Size
232
PyMapping_Length
233
PyDict_Next PyIter_Next
234
_PyDict_Next -
235
PyDict_Merge -
236
PyDict_Update -
237
PyDict_MergeFromSeq2 -
238
PyDict_ClearFreeList -
239
- PyMapping_HasKeyString
240
- PyMapping_HasKey
241
========================== ============= =======================
242
243
244
The dict Interface Relative to OrderedDict
245
==========================================
246
247
Since OrderedDict subclasses dict, understanding the various methods and
248
attributes of dict is important for implementing OrderedDict.
249
250
Relevant Type Slots
251
-------------------
252
253
================= ================ =================== ================
254
slot attribute object dict
255
================= ================ =================== ================
256
tp_dealloc - object_dealloc dict_dealloc
257
tp_repr __repr__ object_repr dict_repr
258
sq_contains __contains__ - dict_contains
259
mp_length __len__ - dict_length
260
mp_subscript __getitem__ - dict_subscript
261
mp_ass_subscript __setitem__ - dict_ass_sub
262
__delitem__
263
tp_hash __hash__ _Py_HashPointer ..._HashNotImpl
264
tp_str __str__ object_str -
265
tp_getattro __getattribute__ ..._GenericGetAttr (repeated)
266
__getattr__
267
tp_setattro __setattr__ ..._GenericSetAttr (disabled)
268
tp_doc __doc__ (literal) dictionary_doc
269
tp_traverse - - dict_traverse
270
tp_clear - - dict_tp_clear
271
tp_richcompare __eq__ object_richcompare dict_richcompare
272
__ne__
273
tp_weaklistoffset (__weakref__) - -
274
tp_iter __iter__ - dict_iter
275
tp_dictoffset (__dict__) - -
276
tp_init __init__ object_init dict_init
277
tp_alloc - PyType_GenericAlloc (repeated)
278
tp_new __new__ object_new dict_new
279
tp_free - PyObject_Del PyObject_GC_Del
280
================= ================ =================== ================
281
282
Relevant Methods
283
----------------
284
285
================ =================== ===============
286
method object dict
287
================ =================== ===============
288
__reduce__ object_reduce -
289
__sizeof__ object_sizeof dict_sizeof
290
clear - dict_clear
291
copy - dict_copy
292
fromkeys - dict_fromkeys
293
get - dict_get
294
items - dictitems_new
295
keys - dictkeys_new
296
pop - dict_pop
297
popitem - dict_popitem
298
setdefault - dict_setdefault
299
update - dict_update
300
values - dictvalues_new
301
================ =================== ===============
302
303
304
Pure Python OrderedDict
305
=======================
306
307
As already noted, compatibility with the pure Python OrderedDict
308
implementation is a key goal of this C implementation. To further that
309
goal, here's a summary of how OrderedDict-specific methods are implemented
310
in collections/__init__.py. Also provided is an indication of which
311
methods directly mutate or iterate the object, as well as any relationship
312
with the underlying linked-list.
313
314
============= ============== == ================ === === ====
315
method impl used ll uses inq mut iter
316
============= ============== == ================ === === ====
317
__contains__ dict - - X
318
__delitem__ OrderedDict Y dict.__delitem__ X
319
__eq__ OrderedDict N OrderedDict ~
320
dict.__eq__
321
__iter__
322
__getitem__ dict - - X
323
__iter__ OrderedDict Y - X
324
__init__ OrderedDict N update
325
__len__ dict - - X
326
__ne__ MutableMapping - __eq__ ~
327
__reduce__ OrderedDict N OrderedDict ~
328
__iter__
329
__getitem__
330
__repr__ OrderedDict N __class__ ~
331
items
332
__reversed__ OrderedDict Y - X
333
__setitem__ OrderedDict Y __contains__ X
334
dict.__setitem__
335
__sizeof__ OrderedDict Y __len__ ~
336
__dict__
337
clear OrderedDict Y dict.clear X
338
copy OrderedDict N __class__
339
__init__
340
fromkeys OrderedDict N __setitem__
341
get dict - - ~
342
items MutableMapping - ItemsView X
343
keys MutableMapping - KeysView X
344
move_to_end OrderedDict Y - X
345
pop OrderedDict N __contains__ X
346
__getitem__
347
__delitem__
348
popitem OrderedDict Y dict.pop X
349
setdefault OrderedDict N __contains__ ~
350
__getitem__
351
__setitem__
352
update MutableMapping - __setitem__ ~
353
values MutableMapping - ValuesView X
354
============= ============== == ================ === === ====
355
356
__reversed__ and move_to_end are both exclusive to OrderedDict.
357
358
359
C OrderedDict Implementation
360
============================
361
362
================= ================
363
slot impl
364
================= ================
365
tp_dealloc odict_dealloc
366
tp_repr odict_repr
367
mp_ass_subscript odict_ass_sub
368
tp_doc odict_doc
369
tp_traverse odict_traverse
370
tp_clear odict_tp_clear
371
tp_richcompare odict_richcompare
372
tp_weaklistoffset (offset)
373
tp_iter odict_iter
374
tp_dictoffset (offset)
375
tp_init odict_init
376
tp_alloc (repeated)
377
================= ================
378
379
================= ================
380
method impl
381
================= ================
382
__reduce__ odict_reduce
383
__sizeof__ odict_sizeof
384
clear odict_clear
385
copy odict_copy
386
fromkeys odict_fromkeys
387
items odictitems_new
388
keys odictkeys_new
389
pop odict_pop
390
popitem odict_popitem
391
setdefault odict_setdefault
392
update odict_update
393
values odictvalues_new
394
================= ================
395
396
Inherited unchanged from object/dict:
397
398
================ ==========================
399
method type field
400
================ ==========================
401
- tp_free
402
__contains__ tp_as_sequence.sq_contains
403
__getattr__ tp_getattro
404
__getattribute__ tp_getattro
405
__getitem__ tp_as_mapping.mp_subscript
406
__hash__ tp_hash
407
__len__ tp_as_mapping.mp_length
408
__setattr__ tp_setattro
409
__str__ tp_str
410
get -
411
================ ==========================
412
413
414
Other Challenges
415
================
416
417
Preserving Ordering During Iteration
418
------------------------------------
419
During iteration through an OrderedDict, it is possible that items could
420
get added, removed, or reordered. For a linked-list implementation, as
421
with some other implementations, that situation may lead to undefined
422
behavior. The documentation for dict mentions this in the `iter()` section
423
of http://docs.python.org/3.4/library/stdtypes.html#dictionary-view-objects.
424
In this implementation we follow dict's lead (as does the pure Python
425
implementation) for __iter__(), keys(), values(), and items().
426
427
For internal iteration (using _odict_FOREACH or not), there is still the
428
risk that not all nodes that we expect to be seen in the loop actually get
429
seen. Thus, we are careful in each of those places to ensure that they
430
are. This comes, of course, at a small price at each location. The
431
solutions are much the same as those detailed in the `Situation that
432
Endangers Consistency` section above.
433
434
435
Potential Optimizations
436
=======================
437
438
* Allocate the nodes as a block via od_fast_nodes instead of individually.
439
- Set node->key to NULL to indicate the node is not-in-use.
440
- Add _odict_EXISTS()?
441
- How to maintain consistency across resizes? Existing node pointers
442
would be invalidated after a resize, which is particularly problematic
443
for the iterators.
444
* Use a more stream-lined implementation of update() and, likely indirectly,
445
__init__().
446
447
*/
448
449
/* TODO
450
451
sooner:
452
- reentrancy (make sure everything is at a thread-safe state when calling
453
into Python). I've already checked this multiple times, but want to
454
make one more pass.
455
- add unit tests for reentrancy?
456
457
later:
458
- make the dict views support the full set API (the pure Python impl does)
459
- implement a fuller MutableMapping API in C?
460
- move the MutableMapping implementation to abstract.c?
461
- optimize mutablemapping_update
462
- use PyObject_Malloc (small object allocator) for odict nodes?
463
- support subclasses better (e.g. in odict_richcompare)
464
465
*/
466
467
#include "Python.h"
468
#include "pycore_call.h" // _PyObject_CallNoArgs()
469
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
470
#include "pycore_dict.h" // _Py_dict_lookup()
471
#include <stddef.h> // offsetof()
472
473
#include "clinic/odictobject.c.h"
474
475
/*[clinic input]
476
class OrderedDict "PyODictObject *" "&PyODict_Type"
477
[clinic start generated code]*/
478
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=ca0641cf6143d4af]*/
479
480
481
typedef struct _odictnode _ODictNode;
482
483
/* PyODictObject */
484
struct _odictobject {
485
PyDictObject od_dict; /* the underlying dict */
486
_ODictNode *od_first; /* first node in the linked list, if any */
487
_ODictNode *od_last; /* last node in the linked list, if any */
488
/* od_fast_nodes, od_fast_nodes_size and od_resize_sentinel are managed
489
* by _odict_resize().
490
* Note that we rely on implementation details of dict for both. */
491
_ODictNode **od_fast_nodes; /* hash table that mirrors the dict table */
492
Py_ssize_t od_fast_nodes_size;
493
void *od_resize_sentinel; /* changes if odict should be resized */
494
495
size_t od_state; /* incremented whenever the LL changes */
496
PyObject *od_inst_dict; /* OrderedDict().__dict__ */
497
PyObject *od_weakreflist; /* holds weakrefs to the odict */
498
};
499
500
501
/* ----------------------------------------------
502
* odict keys (a simple doubly-linked list)
503
*/
504
505
struct _odictnode {
506
PyObject *key;
507
Py_hash_t hash;
508
_ODictNode *next;
509
_ODictNode *prev;
510
};
511
512
#define _odictnode_KEY(node) \
513
(node->key)
514
#define _odictnode_HASH(node) \
515
(node->hash)
516
/* borrowed reference */
517
#define _odictnode_VALUE(node, od) \
518
PyODict_GetItemWithError((PyObject *)od, _odictnode_KEY(node))
519
#define _odictnode_PREV(node) (node->prev)
520
#define _odictnode_NEXT(node) (node->next)
521
522
#define _odict_FIRST(od) (((PyODictObject *)od)->od_first)
523
#define _odict_LAST(od) (((PyODictObject *)od)->od_last)
524
#define _odict_EMPTY(od) (_odict_FIRST(od) == NULL)
525
#define _odict_FOREACH(od, node) \
526
for (node = _odict_FIRST(od); node != NULL; node = _odictnode_NEXT(node))
527
528
/* Return the index into the hash table, regardless of a valid node. */
529
static Py_ssize_t
530
_odict_get_index_raw(PyODictObject *od, PyObject *key, Py_hash_t hash)
531
{
532
PyObject *value = NULL;
533
PyDictKeysObject *keys = ((PyDictObject *)od)->ma_keys;
534
Py_ssize_t ix;
535
536
ix = _Py_dict_lookup((PyDictObject *)od, key, hash, &value);
537
if (ix == DKIX_EMPTY) {
538
return keys->dk_nentries; /* index of new entry */
539
}
540
if (ix < 0)
541
return -1;
542
/* We use pointer arithmetic to get the entry's index into the table. */
543
return ix;
544
}
545
546
#define ONE ((Py_ssize_t)1)
547
548
/* Replace od->od_fast_nodes with a new table matching the size of dict's. */
549
static int
550
_odict_resize(PyODictObject *od)
551
{
552
Py_ssize_t size, i;
553
_ODictNode **fast_nodes, *node;
554
555
/* Initialize a new "fast nodes" table. */
556
size = ONE << (((PyDictObject *)od)->ma_keys->dk_log2_size);
557
fast_nodes = PyMem_NEW(_ODictNode *, size);
558
if (fast_nodes == NULL) {
559
PyErr_NoMemory();
560
return -1;
561
}
562
for (i = 0; i < size; i++)
563
fast_nodes[i] = NULL;
564
565
/* Copy the current nodes into the table. */
566
_odict_FOREACH(od, node) {
567
i = _odict_get_index_raw(od, _odictnode_KEY(node),
568
_odictnode_HASH(node));
569
if (i < 0) {
570
PyMem_Free(fast_nodes);
571
return -1;
572
}
573
fast_nodes[i] = node;
574
}
575
576
/* Replace the old fast nodes table. */
577
PyMem_Free(od->od_fast_nodes);
578
od->od_fast_nodes = fast_nodes;
579
od->od_fast_nodes_size = size;
580
od->od_resize_sentinel = ((PyDictObject *)od)->ma_keys;
581
return 0;
582
}
583
584
/* Return the index into the hash table, regardless of a valid node. */
585
static Py_ssize_t
586
_odict_get_index(PyODictObject *od, PyObject *key, Py_hash_t hash)
587
{
588
PyDictKeysObject *keys;
589
590
assert(key != NULL);
591
keys = ((PyDictObject *)od)->ma_keys;
592
593
/* Ensure od_fast_nodes and dk_entries are in sync. */
594
if (od->od_resize_sentinel != keys ||
595
od->od_fast_nodes_size != (ONE << (keys->dk_log2_size))) {
596
int resize_res = _odict_resize(od);
597
if (resize_res < 0)
598
return -1;
599
}
600
601
return _odict_get_index_raw(od, key, hash);
602
}
603
604
/* Returns NULL if there was some error or the key was not found. */
605
static _ODictNode *
606
_odict_find_node_hash(PyODictObject *od, PyObject *key, Py_hash_t hash)
607
{
608
Py_ssize_t index;
609
610
if (_odict_EMPTY(od))
611
return NULL;
612
index = _odict_get_index(od, key, hash);
613
if (index < 0)
614
return NULL;
615
assert(od->od_fast_nodes != NULL);
616
return od->od_fast_nodes[index];
617
}
618
619
static _ODictNode *
620
_odict_find_node(PyODictObject *od, PyObject *key)
621
{
622
Py_ssize_t index;
623
Py_hash_t hash;
624
625
if (_odict_EMPTY(od))
626
return NULL;
627
hash = PyObject_Hash(key);
628
if (hash == -1)
629
return NULL;
630
index = _odict_get_index(od, key, hash);
631
if (index < 0)
632
return NULL;
633
assert(od->od_fast_nodes != NULL);
634
return od->od_fast_nodes[index];
635
}
636
637
static void
638
_odict_add_head(PyODictObject *od, _ODictNode *node)
639
{
640
_odictnode_PREV(node) = NULL;
641
_odictnode_NEXT(node) = _odict_FIRST(od);
642
if (_odict_FIRST(od) == NULL)
643
_odict_LAST(od) = node;
644
else
645
_odictnode_PREV(_odict_FIRST(od)) = node;
646
_odict_FIRST(od) = node;
647
od->od_state++;
648
}
649
650
static void
651
_odict_add_tail(PyODictObject *od, _ODictNode *node)
652
{
653
_odictnode_PREV(node) = _odict_LAST(od);
654
_odictnode_NEXT(node) = NULL;
655
if (_odict_LAST(od) == NULL)
656
_odict_FIRST(od) = node;
657
else
658
_odictnode_NEXT(_odict_LAST(od)) = node;
659
_odict_LAST(od) = node;
660
od->od_state++;
661
}
662
663
/* adds the node to the end of the list */
664
static int
665
_odict_add_new_node(PyODictObject *od, PyObject *key, Py_hash_t hash)
666
{
667
Py_ssize_t i;
668
_ODictNode *node;
669
670
Py_INCREF(key);
671
i = _odict_get_index(od, key, hash);
672
if (i < 0) {
673
if (!PyErr_Occurred())
674
PyErr_SetObject(PyExc_KeyError, key);
675
Py_DECREF(key);
676
return -1;
677
}
678
assert(od->od_fast_nodes != NULL);
679
if (od->od_fast_nodes[i] != NULL) {
680
/* We already have a node for the key so there's no need to add one. */
681
Py_DECREF(key);
682
return 0;
683
}
684
685
/* must not be added yet */
686
node = (_ODictNode *)PyMem_Malloc(sizeof(_ODictNode));
687
if (node == NULL) {
688
Py_DECREF(key);
689
PyErr_NoMemory();
690
return -1;
691
}
692
693
_odictnode_KEY(node) = key;
694
_odictnode_HASH(node) = hash;
695
_odict_add_tail(od, node);
696
od->od_fast_nodes[i] = node;
697
return 0;
698
}
699
700
/* Putting the decref after the free causes problems. */
701
#define _odictnode_DEALLOC(node) \
702
do { \
703
Py_DECREF(_odictnode_KEY(node)); \
704
PyMem_Free((void *)node); \
705
} while (0)
706
707
/* Repeated calls on the same node are no-ops. */
708
static void
709
_odict_remove_node(PyODictObject *od, _ODictNode *node)
710
{
711
if (_odict_FIRST(od) == node)
712
_odict_FIRST(od) = _odictnode_NEXT(node);
713
else if (_odictnode_PREV(node) != NULL)
714
_odictnode_NEXT(_odictnode_PREV(node)) = _odictnode_NEXT(node);
715
716
if (_odict_LAST(od) == node)
717
_odict_LAST(od) = _odictnode_PREV(node);
718
else if (_odictnode_NEXT(node) != NULL)
719
_odictnode_PREV(_odictnode_NEXT(node)) = _odictnode_PREV(node);
720
721
_odictnode_PREV(node) = NULL;
722
_odictnode_NEXT(node) = NULL;
723
od->od_state++;
724
}
725
726
/* If someone calls PyDict_DelItem() directly on an OrderedDict, we'll
727
get all sorts of problems here. In PyODict_DelItem we make sure to
728
call _odict_clear_node first.
729
730
This matters in the case of colliding keys. Suppose we add 3 keys:
731
[A, B, C], where the hash of C collides with A and the next possible
732
index in the hash table is occupied by B. If we remove B then for C
733
the dict's looknode func will give us the old index of B instead of
734
the index we got before deleting B. However, the node for C in
735
od_fast_nodes is still at the old dict index of C. Thus to be sure
736
things don't get out of sync, we clear the node in od_fast_nodes
737
*before* calling PyDict_DelItem.
738
739
The same must be done for any other OrderedDict operations where
740
we modify od_fast_nodes.
741
*/
742
static int
743
_odict_clear_node(PyODictObject *od, _ODictNode *node, PyObject *key,
744
Py_hash_t hash)
745
{
746
Py_ssize_t i;
747
748
assert(key != NULL);
749
if (_odict_EMPTY(od)) {
750
/* Let later code decide if this is a KeyError. */
751
return 0;
752
}
753
754
i = _odict_get_index(od, key, hash);
755
if (i < 0)
756
return PyErr_Occurred() ? -1 : 0;
757
758
assert(od->od_fast_nodes != NULL);
759
if (node == NULL)
760
node = od->od_fast_nodes[i];
761
assert(node == od->od_fast_nodes[i]);
762
if (node == NULL) {
763
/* Let later code decide if this is a KeyError. */
764
return 0;
765
}
766
767
// Now clear the node.
768
od->od_fast_nodes[i] = NULL;
769
_odict_remove_node(od, node);
770
_odictnode_DEALLOC(node);
771
return 0;
772
}
773
774
static void
775
_odict_clear_nodes(PyODictObject *od)
776
{
777
_ODictNode *node, *next;
778
779
PyMem_Free(od->od_fast_nodes);
780
od->od_fast_nodes = NULL;
781
od->od_fast_nodes_size = 0;
782
od->od_resize_sentinel = NULL;
783
784
node = _odict_FIRST(od);
785
_odict_FIRST(od) = NULL;
786
_odict_LAST(od) = NULL;
787
while (node != NULL) {
788
next = _odictnode_NEXT(node);
789
_odictnode_DEALLOC(node);
790
node = next;
791
}
792
}
793
794
/* There isn't any memory management of nodes past this point. */
795
#undef _odictnode_DEALLOC
796
797
static int
798
_odict_keys_equal(PyODictObject *a, PyODictObject *b)
799
{
800
_ODictNode *node_a, *node_b;
801
802
node_a = _odict_FIRST(a);
803
node_b = _odict_FIRST(b);
804
while (1) {
805
if (node_a == NULL && node_b == NULL)
806
/* success: hit the end of each at the same time */
807
return 1;
808
else if (node_a == NULL || node_b == NULL)
809
/* unequal length */
810
return 0;
811
else {
812
int res = PyObject_RichCompareBool(
813
(PyObject *)_odictnode_KEY(node_a),
814
(PyObject *)_odictnode_KEY(node_b),
815
Py_EQ);
816
if (res < 0)
817
return res;
818
else if (res == 0)
819
return 0;
820
821
/* otherwise it must match, so move on to the next one */
822
node_a = _odictnode_NEXT(node_a);
823
node_b = _odictnode_NEXT(node_b);
824
}
825
}
826
}
827
828
829
/* ----------------------------------------------
830
* OrderedDict mapping methods
831
*/
832
833
/* mp_ass_subscript: __setitem__() and __delitem__() */
834
835
static int
836
odict_mp_ass_sub(PyODictObject *od, PyObject *v, PyObject *w)
837
{
838
if (w == NULL)
839
return PyODict_DelItem((PyObject *)od, v);
840
else
841
return PyODict_SetItem((PyObject *)od, v, w);
842
}
843
844
/* tp_as_mapping */
845
846
static PyMappingMethods odict_as_mapping = {
847
0, /*mp_length*/
848
0, /*mp_subscript*/
849
(objobjargproc)odict_mp_ass_sub, /*mp_ass_subscript*/
850
};
851
852
853
/* ----------------------------------------------
854
* OrderedDict number methods
855
*/
856
857
static int mutablemapping_update_arg(PyObject*, PyObject*);
858
859
static PyObject *
860
odict_or(PyObject *left, PyObject *right)
861
{
862
PyTypeObject *type;
863
PyObject *other;
864
if (PyODict_Check(left)) {
865
type = Py_TYPE(left);
866
other = right;
867
}
868
else {
869
type = Py_TYPE(right);
870
other = left;
871
}
872
if (!PyDict_Check(other)) {
873
Py_RETURN_NOTIMPLEMENTED;
874
}
875
PyObject *new = PyObject_CallOneArg((PyObject*)type, left);
876
if (!new) {
877
return NULL;
878
}
879
if (mutablemapping_update_arg(new, right) < 0) {
880
Py_DECREF(new);
881
return NULL;
882
}
883
return new;
884
}
885
886
static PyObject *
887
odict_inplace_or(PyObject *self, PyObject *other)
888
{
889
if (mutablemapping_update_arg(self, other) < 0) {
890
return NULL;
891
}
892
return Py_NewRef(self);
893
}
894
895
/* tp_as_number */
896
897
static PyNumberMethods odict_as_number = {
898
.nb_or = odict_or,
899
.nb_inplace_or = odict_inplace_or,
900
};
901
902
903
/* ----------------------------------------------
904
* OrderedDict methods
905
*/
906
907
/* fromkeys() */
908
909
/*[clinic input]
910
@classmethod
911
OrderedDict.fromkeys
912
913
iterable as seq: object
914
value: object = None
915
916
Create a new ordered dictionary with keys from iterable and values set to value.
917
[clinic start generated code]*/
918
919
static PyObject *
920
OrderedDict_fromkeys_impl(PyTypeObject *type, PyObject *seq, PyObject *value)
921
/*[clinic end generated code: output=c10390d452d78d6d input=1a0476c229c597b3]*/
922
{
923
return _PyDict_FromKeys((PyObject *)type, seq, value);
924
}
925
926
/* __sizeof__() */
927
928
/* OrderedDict.__sizeof__() does not have a docstring. */
929
PyDoc_STRVAR(odict_sizeof__doc__, "");
930
931
static PyObject *
932
odict_sizeof(PyODictObject *od, PyObject *Py_UNUSED(ignored))
933
{
934
Py_ssize_t res = _PyDict_SizeOf((PyDictObject *)od);
935
res += sizeof(_ODictNode *) * od->od_fast_nodes_size; /* od_fast_nodes */
936
if (!_odict_EMPTY(od)) {
937
res += sizeof(_ODictNode) * PyODict_SIZE(od); /* linked-list */
938
}
939
return PyLong_FromSsize_t(res);
940
}
941
942
/* __reduce__() */
943
944
PyDoc_STRVAR(odict_reduce__doc__, "Return state information for pickling");
945
946
static PyObject *
947
odict_reduce(register PyODictObject *od, PyObject *Py_UNUSED(ignored))
948
{
949
PyObject *state, *result = NULL;
950
PyObject *items_iter, *items, *args = NULL;
951
952
/* capture any instance state */
953
state = _PyObject_GetState((PyObject *)od);
954
if (state == NULL)
955
goto Done;
956
957
/* build the result */
958
args = PyTuple_New(0);
959
if (args == NULL)
960
goto Done;
961
962
items = PyObject_CallMethodNoArgs((PyObject *)od, &_Py_ID(items));
963
if (items == NULL)
964
goto Done;
965
966
items_iter = PyObject_GetIter(items);
967
Py_DECREF(items);
968
if (items_iter == NULL)
969
goto Done;
970
971
result = PyTuple_Pack(5, Py_TYPE(od), args, state, Py_None, items_iter);
972
Py_DECREF(items_iter);
973
974
Done:
975
Py_XDECREF(state);
976
Py_XDECREF(args);
977
978
return result;
979
}
980
981
/* setdefault(): Skips __missing__() calls. */
982
983
984
/*[clinic input]
985
OrderedDict.setdefault
986
987
key: object
988
default: object = None
989
990
Insert key with a value of default if key is not in the dictionary.
991
992
Return the value for key if key is in the dictionary, else default.
993
[clinic start generated code]*/
994
995
static PyObject *
996
OrderedDict_setdefault_impl(PyODictObject *self, PyObject *key,
997
PyObject *default_value)
998
/*[clinic end generated code: output=97537cb7c28464b6 input=38e098381c1efbc6]*/
999
{
1000
PyObject *result = NULL;
1001
1002
if (PyODict_CheckExact(self)) {
1003
result = PyODict_GetItemWithError(self, key); /* borrowed */
1004
if (result == NULL) {
1005
if (PyErr_Occurred())
1006
return NULL;
1007
assert(_odict_find_node(self, key) == NULL);
1008
if (PyODict_SetItem((PyObject *)self, key, default_value) >= 0) {
1009
result = Py_NewRef(default_value);
1010
}
1011
}
1012
else {
1013
Py_INCREF(result);
1014
}
1015
}
1016
else {
1017
int exists = PySequence_Contains((PyObject *)self, key);
1018
if (exists < 0) {
1019
return NULL;
1020
}
1021
else if (exists) {
1022
result = PyObject_GetItem((PyObject *)self, key);
1023
}
1024
else if (PyObject_SetItem((PyObject *)self, key, default_value) >= 0) {
1025
result = Py_NewRef(default_value);
1026
}
1027
}
1028
1029
return result;
1030
}
1031
1032
/* pop() */
1033
1034
static PyObject *
1035
_odict_popkey_hash(PyObject *od, PyObject *key, PyObject *failobj,
1036
Py_hash_t hash)
1037
{
1038
PyObject *value = NULL;
1039
1040
_ODictNode *node = _odict_find_node_hash((PyODictObject *)od, key, hash);
1041
if (node != NULL) {
1042
/* Pop the node first to avoid a possible dict resize (due to
1043
eval loop reentrancy) and complications due to hash collision
1044
resolution. */
1045
int res = _odict_clear_node((PyODictObject *)od, node, key, hash);
1046
if (res < 0) {
1047
return NULL;
1048
}
1049
/* Now delete the value from the dict. */
1050
value = _PyDict_Pop_KnownHash(od, key, hash, failobj);
1051
}
1052
else if (value == NULL && !PyErr_Occurred()) {
1053
/* Apply the fallback value, if necessary. */
1054
if (failobj) {
1055
value = Py_NewRef(failobj);
1056
}
1057
else {
1058
PyErr_SetObject(PyExc_KeyError, key);
1059
}
1060
}
1061
1062
return value;
1063
}
1064
1065
/* Skips __missing__() calls. */
1066
/*[clinic input]
1067
OrderedDict.pop
1068
1069
key: object
1070
default: object = NULL
1071
1072
od.pop(key[,default]) -> v, remove specified key and return the corresponding value.
1073
1074
If the key is not found, return the default if given; otherwise,
1075
raise a KeyError.
1076
[clinic start generated code]*/
1077
1078
static PyObject *
1079
OrderedDict_pop_impl(PyODictObject *self, PyObject *key,
1080
PyObject *default_value)
1081
/*[clinic end generated code: output=7a6447d104e7494b input=7efe36601007dff7]*/
1082
{
1083
Py_hash_t hash = PyObject_Hash(key);
1084
if (hash == -1)
1085
return NULL;
1086
return _odict_popkey_hash((PyObject *)self, key, default_value, hash);
1087
}
1088
1089
1090
/* popitem() */
1091
1092
/*[clinic input]
1093
OrderedDict.popitem
1094
1095
last: bool = True
1096
1097
Remove and return a (key, value) pair from the dictionary.
1098
1099
Pairs are returned in LIFO order if last is true or FIFO order if false.
1100
[clinic start generated code]*/
1101
1102
static PyObject *
1103
OrderedDict_popitem_impl(PyODictObject *self, int last)
1104
/*[clinic end generated code: output=98e7d986690d49eb input=d992ac5ee8305e1a]*/
1105
{
1106
PyObject *key, *value, *item = NULL;
1107
_ODictNode *node;
1108
1109
/* pull the item */
1110
1111
if (_odict_EMPTY(self)) {
1112
PyErr_SetString(PyExc_KeyError, "dictionary is empty");
1113
return NULL;
1114
}
1115
1116
node = last ? _odict_LAST(self) : _odict_FIRST(self);
1117
key = Py_NewRef(_odictnode_KEY(node));
1118
value = _odict_popkey_hash((PyObject *)self, key, NULL, _odictnode_HASH(node));
1119
if (value == NULL)
1120
return NULL;
1121
item = PyTuple_Pack(2, key, value);
1122
Py_DECREF(key);
1123
Py_DECREF(value);
1124
return item;
1125
}
1126
1127
/* keys() */
1128
1129
/* MutableMapping.keys() does not have a docstring. */
1130
PyDoc_STRVAR(odict_keys__doc__, "");
1131
1132
static PyObject * odictkeys_new(PyObject *od, PyObject *Py_UNUSED(ignored)); /* forward */
1133
1134
/* values() */
1135
1136
/* MutableMapping.values() does not have a docstring. */
1137
PyDoc_STRVAR(odict_values__doc__, "");
1138
1139
static PyObject * odictvalues_new(PyObject *od, PyObject *Py_UNUSED(ignored)); /* forward */
1140
1141
/* items() */
1142
1143
/* MutableMapping.items() does not have a docstring. */
1144
PyDoc_STRVAR(odict_items__doc__, "");
1145
1146
static PyObject * odictitems_new(PyObject *od, PyObject *Py_UNUSED(ignored)); /* forward */
1147
1148
/* update() */
1149
1150
/* MutableMapping.update() does not have a docstring. */
1151
PyDoc_STRVAR(odict_update__doc__, "");
1152
1153
/* forward */
1154
static PyObject * mutablemapping_update(PyObject *, PyObject *, PyObject *);
1155
1156
#define odict_update mutablemapping_update
1157
1158
/* clear() */
1159
1160
PyDoc_STRVAR(odict_clear__doc__,
1161
"od.clear() -> None. Remove all items from od.");
1162
1163
static PyObject *
1164
odict_clear(register PyODictObject *od, PyObject *Py_UNUSED(ignored))
1165
{
1166
PyDict_Clear((PyObject *)od);
1167
_odict_clear_nodes(od);
1168
Py_RETURN_NONE;
1169
}
1170
1171
/* copy() */
1172
1173
/* forward */
1174
static int _PyODict_SetItem_KnownHash(PyObject *, PyObject *, PyObject *,
1175
Py_hash_t);
1176
1177
PyDoc_STRVAR(odict_copy__doc__, "od.copy() -> a shallow copy of od");
1178
1179
static PyObject *
1180
odict_copy(register PyODictObject *od, PyObject *Py_UNUSED(ignored))
1181
{
1182
_ODictNode *node;
1183
PyObject *od_copy;
1184
1185
if (PyODict_CheckExact(od))
1186
od_copy = PyODict_New();
1187
else
1188
od_copy = _PyObject_CallNoArgs((PyObject *)Py_TYPE(od));
1189
if (od_copy == NULL)
1190
return NULL;
1191
1192
if (PyODict_CheckExact(od)) {
1193
_odict_FOREACH(od, node) {
1194
PyObject *key = _odictnode_KEY(node);
1195
PyObject *value = _odictnode_VALUE(node, od);
1196
if (value == NULL) {
1197
if (!PyErr_Occurred())
1198
PyErr_SetObject(PyExc_KeyError, key);
1199
goto fail;
1200
}
1201
if (_PyODict_SetItem_KnownHash((PyObject *)od_copy, key, value,
1202
_odictnode_HASH(node)) != 0)
1203
goto fail;
1204
}
1205
}
1206
else {
1207
_odict_FOREACH(od, node) {
1208
int res;
1209
PyObject *value = PyObject_GetItem((PyObject *)od,
1210
_odictnode_KEY(node));
1211
if (value == NULL)
1212
goto fail;
1213
res = PyObject_SetItem((PyObject *)od_copy,
1214
_odictnode_KEY(node), value);
1215
Py_DECREF(value);
1216
if (res != 0)
1217
goto fail;
1218
}
1219
}
1220
return od_copy;
1221
1222
fail:
1223
Py_DECREF(od_copy);
1224
return NULL;
1225
}
1226
1227
/* __reversed__() */
1228
1229
PyDoc_STRVAR(odict_reversed__doc__, "od.__reversed__() <==> reversed(od)");
1230
1231
#define _odict_ITER_REVERSED 1
1232
#define _odict_ITER_KEYS 2
1233
#define _odict_ITER_VALUES 4
1234
#define _odict_ITER_ITEMS (_odict_ITER_KEYS|_odict_ITER_VALUES)
1235
1236
/* forward */
1237
static PyObject * odictiter_new(PyODictObject *, int);
1238
1239
static PyObject *
1240
odict_reversed(PyODictObject *od, PyObject *Py_UNUSED(ignored))
1241
{
1242
return odictiter_new(od, _odict_ITER_KEYS|_odict_ITER_REVERSED);
1243
}
1244
1245
1246
/* move_to_end() */
1247
1248
/*[clinic input]
1249
OrderedDict.move_to_end
1250
1251
key: object
1252
last: bool = True
1253
1254
Move an existing element to the end (or beginning if last is false).
1255
1256
Raise KeyError if the element does not exist.
1257
[clinic start generated code]*/
1258
1259
static PyObject *
1260
OrderedDict_move_to_end_impl(PyODictObject *self, PyObject *key, int last)
1261
/*[clinic end generated code: output=fafa4c5cc9b92f20 input=d6ceff7132a2fcd7]*/
1262
{
1263
_ODictNode *node;
1264
1265
if (_odict_EMPTY(self)) {
1266
PyErr_SetObject(PyExc_KeyError, key);
1267
return NULL;
1268
}
1269
node = last ? _odict_LAST(self) : _odict_FIRST(self);
1270
if (key != _odictnode_KEY(node)) {
1271
node = _odict_find_node(self, key);
1272
if (node == NULL) {
1273
if (!PyErr_Occurred())
1274
PyErr_SetObject(PyExc_KeyError, key);
1275
return NULL;
1276
}
1277
if (last) {
1278
/* Only move if not already the last one. */
1279
if (node != _odict_LAST(self)) {
1280
_odict_remove_node(self, node);
1281
_odict_add_tail(self, node);
1282
}
1283
}
1284
else {
1285
/* Only move if not already the first one. */
1286
if (node != _odict_FIRST(self)) {
1287
_odict_remove_node(self, node);
1288
_odict_add_head(self, node);
1289
}
1290
}
1291
}
1292
Py_RETURN_NONE;
1293
}
1294
1295
1296
/* tp_methods */
1297
1298
static PyMethodDef odict_methods[] = {
1299
1300
/* overridden dict methods */
1301
ORDEREDDICT_FROMKEYS_METHODDEF
1302
{"__sizeof__", (PyCFunction)odict_sizeof, METH_NOARGS,
1303
odict_sizeof__doc__},
1304
{"__reduce__", (PyCFunction)odict_reduce, METH_NOARGS,
1305
odict_reduce__doc__},
1306
ORDEREDDICT_SETDEFAULT_METHODDEF
1307
ORDEREDDICT_POP_METHODDEF
1308
ORDEREDDICT_POPITEM_METHODDEF
1309
{"keys", odictkeys_new, METH_NOARGS,
1310
odict_keys__doc__},
1311
{"values", odictvalues_new, METH_NOARGS,
1312
odict_values__doc__},
1313
{"items", odictitems_new, METH_NOARGS,
1314
odict_items__doc__},
1315
{"update", _PyCFunction_CAST(odict_update), METH_VARARGS | METH_KEYWORDS,
1316
odict_update__doc__},
1317
{"clear", (PyCFunction)odict_clear, METH_NOARGS,
1318
odict_clear__doc__},
1319
{"copy", (PyCFunction)odict_copy, METH_NOARGS,
1320
odict_copy__doc__},
1321
1322
/* new methods */
1323
{"__reversed__", (PyCFunction)odict_reversed, METH_NOARGS,
1324
odict_reversed__doc__},
1325
ORDEREDDICT_MOVE_TO_END_METHODDEF
1326
1327
{NULL, NULL} /* sentinel */
1328
};
1329
1330
1331
/* ----------------------------------------------
1332
* OrderedDict members
1333
*/
1334
1335
/* tp_getset */
1336
1337
static PyGetSetDef odict_getset[] = {
1338
{"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
1339
{NULL}
1340
};
1341
1342
/* ----------------------------------------------
1343
* OrderedDict type slot methods
1344
*/
1345
1346
/* tp_dealloc */
1347
1348
static void
1349
odict_dealloc(PyODictObject *self)
1350
{
1351
PyObject_GC_UnTrack(self);
1352
Py_TRASHCAN_BEGIN(self, odict_dealloc)
1353
1354
Py_XDECREF(self->od_inst_dict);
1355
if (self->od_weakreflist != NULL)
1356
PyObject_ClearWeakRefs((PyObject *)self);
1357
1358
_odict_clear_nodes(self);
1359
PyDict_Type.tp_dealloc((PyObject *)self);
1360
1361
Py_TRASHCAN_END
1362
}
1363
1364
/* tp_repr */
1365
1366
static PyObject *
1367
odict_repr(PyODictObject *self)
1368
{
1369
int i;
1370
PyObject *result = NULL, *dcopy = NULL;
1371
1372
if (PyODict_SIZE(self) == 0)
1373
return PyUnicode_FromFormat("%s()", _PyType_Name(Py_TYPE(self)));
1374
1375
i = Py_ReprEnter((PyObject *)self);
1376
if (i != 0) {
1377
return i > 0 ? PyUnicode_FromString("...") : NULL;
1378
}
1379
1380
dcopy = PyDict_Copy((PyObject *)self);
1381
if (dcopy == NULL) {
1382
goto Done;
1383
}
1384
1385
result = PyUnicode_FromFormat("%s(%R)",
1386
_PyType_Name(Py_TYPE(self)),
1387
dcopy);
1388
Py_DECREF(dcopy);
1389
1390
Done:
1391
Py_ReprLeave((PyObject *)self);
1392
return result;
1393
}
1394
1395
/* tp_doc */
1396
1397
PyDoc_STRVAR(odict_doc,
1398
"Dictionary that remembers insertion order");
1399
1400
/* tp_traverse */
1401
1402
static int
1403
odict_traverse(PyODictObject *od, visitproc visit, void *arg)
1404
{
1405
_ODictNode *node;
1406
1407
Py_VISIT(od->od_inst_dict);
1408
_odict_FOREACH(od, node) {
1409
Py_VISIT(_odictnode_KEY(node));
1410
}
1411
return PyDict_Type.tp_traverse((PyObject *)od, visit, arg);
1412
}
1413
1414
/* tp_clear */
1415
1416
static int
1417
odict_tp_clear(PyODictObject *od)
1418
{
1419
Py_CLEAR(od->od_inst_dict);
1420
PyDict_Clear((PyObject *)od);
1421
_odict_clear_nodes(od);
1422
return 0;
1423
}
1424
1425
/* tp_richcompare */
1426
1427
static PyObject *
1428
odict_richcompare(PyObject *v, PyObject *w, int op)
1429
{
1430
if (!PyODict_Check(v) || !PyDict_Check(w)) {
1431
Py_RETURN_NOTIMPLEMENTED;
1432
}
1433
1434
if (op == Py_EQ || op == Py_NE) {
1435
PyObject *res, *cmp;
1436
int eq;
1437
1438
cmp = PyDict_Type.tp_richcompare(v, w, op);
1439
if (cmp == NULL)
1440
return NULL;
1441
if (!PyODict_Check(w))
1442
return cmp;
1443
if (op == Py_EQ && cmp == Py_False)
1444
return cmp;
1445
if (op == Py_NE && cmp == Py_True)
1446
return cmp;
1447
Py_DECREF(cmp);
1448
1449
/* Try comparing odict keys. */
1450
eq = _odict_keys_equal((PyODictObject *)v, (PyODictObject *)w);
1451
if (eq < 0)
1452
return NULL;
1453
1454
res = (eq == (op == Py_EQ)) ? Py_True : Py_False;
1455
return Py_NewRef(res);
1456
} else {
1457
Py_RETURN_NOTIMPLEMENTED;
1458
}
1459
}
1460
1461
/* tp_iter */
1462
1463
static PyObject *
1464
odict_iter(PyODictObject *od)
1465
{
1466
return odictiter_new(od, _odict_ITER_KEYS);
1467
}
1468
1469
/* tp_init */
1470
1471
static int
1472
odict_init(PyObject *self, PyObject *args, PyObject *kwds)
1473
{
1474
PyObject *res;
1475
Py_ssize_t len = PyObject_Length(args);
1476
1477
if (len == -1)
1478
return -1;
1479
if (len > 1) {
1480
const char *msg = "expected at most 1 arguments, got %zd";
1481
PyErr_Format(PyExc_TypeError, msg, len);
1482
return -1;
1483
}
1484
1485
/* __init__() triggering update() is just the way things are! */
1486
res = odict_update(self, args, kwds);
1487
if (res == NULL) {
1488
return -1;
1489
} else {
1490
Py_DECREF(res);
1491
return 0;
1492
}
1493
}
1494
1495
/* PyODict_Type */
1496
1497
PyTypeObject PyODict_Type = {
1498
PyVarObject_HEAD_INIT(&PyType_Type, 0)
1499
"collections.OrderedDict", /* tp_name */
1500
sizeof(PyODictObject), /* tp_basicsize */
1501
0, /* tp_itemsize */
1502
(destructor)odict_dealloc, /* tp_dealloc */
1503
0, /* tp_vectorcall_offset */
1504
0, /* tp_getattr */
1505
0, /* tp_setattr */
1506
0, /* tp_as_async */
1507
(reprfunc)odict_repr, /* tp_repr */
1508
&odict_as_number, /* tp_as_number */
1509
0, /* tp_as_sequence */
1510
&odict_as_mapping, /* tp_as_mapping */
1511
0, /* tp_hash */
1512
0, /* tp_call */
1513
0, /* tp_str */
1514
0, /* tp_getattro */
1515
0, /* tp_setattro */
1516
0, /* tp_as_buffer */
1517
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,/* tp_flags */
1518
odict_doc, /* tp_doc */
1519
(traverseproc)odict_traverse, /* tp_traverse */
1520
(inquiry)odict_tp_clear, /* tp_clear */
1521
(richcmpfunc)odict_richcompare, /* tp_richcompare */
1522
offsetof(PyODictObject, od_weakreflist), /* tp_weaklistoffset */
1523
(getiterfunc)odict_iter, /* tp_iter */
1524
0, /* tp_iternext */
1525
odict_methods, /* tp_methods */
1526
0, /* tp_members */
1527
odict_getset, /* tp_getset */
1528
&PyDict_Type, /* tp_base */
1529
0, /* tp_dict */
1530
0, /* tp_descr_get */
1531
0, /* tp_descr_set */
1532
offsetof(PyODictObject, od_inst_dict), /* tp_dictoffset */
1533
(initproc)odict_init, /* tp_init */
1534
PyType_GenericAlloc, /* tp_alloc */
1535
0, /* tp_new */
1536
0, /* tp_free */
1537
};
1538
1539
1540
/* ----------------------------------------------
1541
* the public OrderedDict API
1542
*/
1543
1544
PyObject *
1545
PyODict_New(void)
1546
{
1547
return PyDict_Type.tp_new(&PyODict_Type, NULL, NULL);
1548
}
1549
1550
static int
1551
_PyODict_SetItem_KnownHash(PyObject *od, PyObject *key, PyObject *value,
1552
Py_hash_t hash)
1553
{
1554
int res = _PyDict_SetItem_KnownHash(od, key, value, hash);
1555
if (res == 0) {
1556
res = _odict_add_new_node((PyODictObject *)od, key, hash);
1557
if (res < 0) {
1558
/* Revert setting the value on the dict */
1559
PyObject *exc = PyErr_GetRaisedException();
1560
(void) _PyDict_DelItem_KnownHash(od, key, hash);
1561
_PyErr_ChainExceptions1(exc);
1562
}
1563
}
1564
return res;
1565
}
1566
1567
int
1568
PyODict_SetItem(PyObject *od, PyObject *key, PyObject *value)
1569
{
1570
Py_hash_t hash = PyObject_Hash(key);
1571
if (hash == -1)
1572
return -1;
1573
return _PyODict_SetItem_KnownHash(od, key, value, hash);
1574
}
1575
1576
int
1577
PyODict_DelItem(PyObject *od, PyObject *key)
1578
{
1579
int res;
1580
Py_hash_t hash = PyObject_Hash(key);
1581
if (hash == -1)
1582
return -1;
1583
res = _odict_clear_node((PyODictObject *)od, NULL, key, hash);
1584
if (res < 0)
1585
return -1;
1586
return _PyDict_DelItem_KnownHash(od, key, hash);
1587
}
1588
1589
1590
/* -------------------------------------------
1591
* The OrderedDict views (keys/values/items)
1592
*/
1593
1594
typedef struct {
1595
PyObject_HEAD
1596
int kind;
1597
PyODictObject *di_odict;
1598
Py_ssize_t di_size;
1599
size_t di_state;
1600
PyObject *di_current;
1601
PyObject *di_result; /* reusable result tuple for iteritems */
1602
} odictiterobject;
1603
1604
static void
1605
odictiter_dealloc(odictiterobject *di)
1606
{
1607
_PyObject_GC_UNTRACK(di);
1608
Py_XDECREF(di->di_odict);
1609
Py_XDECREF(di->di_current);
1610
if ((di->kind & _odict_ITER_ITEMS) == _odict_ITER_ITEMS) {
1611
Py_DECREF(di->di_result);
1612
}
1613
PyObject_GC_Del(di);
1614
}
1615
1616
static int
1617
odictiter_traverse(odictiterobject *di, visitproc visit, void *arg)
1618
{
1619
Py_VISIT(di->di_odict);
1620
Py_VISIT(di->di_current); /* A key could be any type, not just str. */
1621
Py_VISIT(di->di_result);
1622
return 0;
1623
}
1624
1625
/* In order to protect against modifications during iteration, we track
1626
* the current key instead of the current node. */
1627
static PyObject *
1628
odictiter_nextkey(odictiterobject *di)
1629
{
1630
PyObject *key = NULL;
1631
_ODictNode *node;
1632
int reversed = di->kind & _odict_ITER_REVERSED;
1633
1634
if (di->di_odict == NULL)
1635
return NULL;
1636
if (di->di_current == NULL)
1637
goto done; /* We're already done. */
1638
1639
/* Check for unsupported changes. */
1640
if (di->di_odict->od_state != di->di_state) {
1641
PyErr_SetString(PyExc_RuntimeError,
1642
"OrderedDict mutated during iteration");
1643
goto done;
1644
}
1645
if (di->di_size != PyODict_SIZE(di->di_odict)) {
1646
PyErr_SetString(PyExc_RuntimeError,
1647
"OrderedDict changed size during iteration");
1648
di->di_size = -1; /* Make this state sticky */
1649
return NULL;
1650
}
1651
1652
/* Get the key. */
1653
node = _odict_find_node(di->di_odict, di->di_current);
1654
if (node == NULL) {
1655
if (!PyErr_Occurred())
1656
PyErr_SetObject(PyExc_KeyError, di->di_current);
1657
/* Must have been deleted. */
1658
Py_CLEAR(di->di_current);
1659
return NULL;
1660
}
1661
key = di->di_current;
1662
1663
/* Advance to the next key. */
1664
node = reversed ? _odictnode_PREV(node) : _odictnode_NEXT(node);
1665
if (node == NULL) {
1666
/* Reached the end. */
1667
di->di_current = NULL;
1668
}
1669
else {
1670
di->di_current = Py_NewRef(_odictnode_KEY(node));
1671
}
1672
1673
return key;
1674
1675
done:
1676
Py_CLEAR(di->di_odict);
1677
return key;
1678
}
1679
1680
static PyObject *
1681
odictiter_iternext(odictiterobject *di)
1682
{
1683
PyObject *result, *value;
1684
PyObject *key = odictiter_nextkey(di); /* new reference */
1685
1686
if (key == NULL)
1687
return NULL;
1688
1689
/* Handle the keys case. */
1690
if (! (di->kind & _odict_ITER_VALUES)) {
1691
return key;
1692
}
1693
1694
value = PyODict_GetItem((PyObject *)di->di_odict, key); /* borrowed */
1695
if (value == NULL) {
1696
if (!PyErr_Occurred())
1697
PyErr_SetObject(PyExc_KeyError, key);
1698
Py_DECREF(key);
1699
goto done;
1700
}
1701
Py_INCREF(value);
1702
1703
/* Handle the values case. */
1704
if (!(di->kind & _odict_ITER_KEYS)) {
1705
Py_DECREF(key);
1706
return value;
1707
}
1708
1709
/* Handle the items case. */
1710
result = di->di_result;
1711
1712
if (Py_REFCNT(result) == 1) {
1713
/* not in use so we can reuse it
1714
* (the common case during iteration) */
1715
Py_INCREF(result);
1716
Py_DECREF(PyTuple_GET_ITEM(result, 0)); /* borrowed */
1717
Py_DECREF(PyTuple_GET_ITEM(result, 1)); /* borrowed */
1718
// bpo-42536: The GC may have untracked this result tuple. Since we're
1719
// recycling it, make sure it's tracked again:
1720
if (!_PyObject_GC_IS_TRACKED(result)) {
1721
_PyObject_GC_TRACK(result);
1722
}
1723
}
1724
else {
1725
result = PyTuple_New(2);
1726
if (result == NULL) {
1727
Py_DECREF(key);
1728
Py_DECREF(value);
1729
goto done;
1730
}
1731
}
1732
1733
PyTuple_SET_ITEM(result, 0, key); /* steals reference */
1734
PyTuple_SET_ITEM(result, 1, value); /* steals reference */
1735
return result;
1736
1737
done:
1738
Py_CLEAR(di->di_current);
1739
Py_CLEAR(di->di_odict);
1740
return NULL;
1741
}
1742
1743
/* No need for tp_clear because odictiterobject is not mutable. */
1744
1745
PyDoc_STRVAR(reduce_doc, "Return state information for pickling");
1746
1747
static PyObject *
1748
odictiter_reduce(odictiterobject *di, PyObject *Py_UNUSED(ignored))
1749
{
1750
/* copy the iterator state */
1751
odictiterobject tmp = *di;
1752
Py_XINCREF(tmp.di_odict);
1753
Py_XINCREF(tmp.di_current);
1754
1755
/* iterate the temporary into a list */
1756
PyObject *list = PySequence_List((PyObject*)&tmp);
1757
Py_XDECREF(tmp.di_odict);
1758
Py_XDECREF(tmp.di_current);
1759
if (list == NULL) {
1760
return NULL;
1761
}
1762
return Py_BuildValue("N(N)", _PyEval_GetBuiltin(&_Py_ID(iter)), list);
1763
}
1764
1765
static PyMethodDef odictiter_methods[] = {
1766
{"__reduce__", (PyCFunction)odictiter_reduce, METH_NOARGS, reduce_doc},
1767
{NULL, NULL} /* sentinel */
1768
};
1769
1770
PyTypeObject PyODictIter_Type = {
1771
PyVarObject_HEAD_INIT(&PyType_Type, 0)
1772
"odict_iterator", /* tp_name */
1773
sizeof(odictiterobject), /* tp_basicsize */
1774
0, /* tp_itemsize */
1775
/* methods */
1776
(destructor)odictiter_dealloc, /* tp_dealloc */
1777
0, /* tp_vectorcall_offset */
1778
0, /* tp_getattr */
1779
0, /* tp_setattr */
1780
0, /* tp_as_async */
1781
0, /* tp_repr */
1782
0, /* tp_as_number */
1783
0, /* tp_as_sequence */
1784
0, /* tp_as_mapping */
1785
0, /* tp_hash */
1786
0, /* tp_call */
1787
0, /* tp_str */
1788
PyObject_GenericGetAttr, /* tp_getattro */
1789
0, /* tp_setattro */
1790
0, /* tp_as_buffer */
1791
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
1792
0, /* tp_doc */
1793
(traverseproc)odictiter_traverse, /* tp_traverse */
1794
0, /* tp_clear */
1795
0, /* tp_richcompare */
1796
0, /* tp_weaklistoffset */
1797
PyObject_SelfIter, /* tp_iter */
1798
(iternextfunc)odictiter_iternext, /* tp_iternext */
1799
odictiter_methods, /* tp_methods */
1800
0,
1801
};
1802
1803
static PyObject *
1804
odictiter_new(PyODictObject *od, int kind)
1805
{
1806
odictiterobject *di;
1807
_ODictNode *node;
1808
int reversed = kind & _odict_ITER_REVERSED;
1809
1810
di = PyObject_GC_New(odictiterobject, &PyODictIter_Type);
1811
if (di == NULL)
1812
return NULL;
1813
1814
if ((kind & _odict_ITER_ITEMS) == _odict_ITER_ITEMS) {
1815
di->di_result = PyTuple_Pack(2, Py_None, Py_None);
1816
if (di->di_result == NULL) {
1817
Py_DECREF(di);
1818
return NULL;
1819
}
1820
}
1821
else {
1822
di->di_result = NULL;
1823
}
1824
1825
di->kind = kind;
1826
node = reversed ? _odict_LAST(od) : _odict_FIRST(od);
1827
di->di_current = node ? Py_NewRef(_odictnode_KEY(node)) : NULL;
1828
di->di_size = PyODict_SIZE(od);
1829
di->di_state = od->od_state;
1830
di->di_odict = (PyODictObject*)Py_NewRef(od);
1831
1832
_PyObject_GC_TRACK(di);
1833
return (PyObject *)di;
1834
}
1835
1836
/* keys() */
1837
1838
static PyObject *
1839
odictkeys_iter(_PyDictViewObject *dv)
1840
{
1841
if (dv->dv_dict == NULL) {
1842
Py_RETURN_NONE;
1843
}
1844
return odictiter_new((PyODictObject *)dv->dv_dict,
1845
_odict_ITER_KEYS);
1846
}
1847
1848
static PyObject *
1849
odictkeys_reversed(_PyDictViewObject *dv, PyObject *Py_UNUSED(ignored))
1850
{
1851
if (dv->dv_dict == NULL) {
1852
Py_RETURN_NONE;
1853
}
1854
return odictiter_new((PyODictObject *)dv->dv_dict,
1855
_odict_ITER_KEYS|_odict_ITER_REVERSED);
1856
}
1857
1858
static PyMethodDef odictkeys_methods[] = {
1859
{"__reversed__", (PyCFunction)odictkeys_reversed, METH_NOARGS, NULL},
1860
{NULL, NULL} /* sentinel */
1861
};
1862
1863
PyTypeObject PyODictKeys_Type = {
1864
PyVarObject_HEAD_INIT(&PyType_Type, 0)
1865
"odict_keys", /* tp_name */
1866
0, /* tp_basicsize */
1867
0, /* tp_itemsize */
1868
0, /* tp_dealloc */
1869
0, /* tp_vectorcall_offset */
1870
0, /* tp_getattr */
1871
0, /* tp_setattr */
1872
0, /* tp_as_async */
1873
0, /* tp_repr */
1874
0, /* tp_as_number */
1875
0, /* tp_as_sequence */
1876
0, /* tp_as_mapping */
1877
0, /* tp_hash */
1878
0, /* tp_call */
1879
0, /* tp_str */
1880
0, /* tp_getattro */
1881
0, /* tp_setattro */
1882
0, /* tp_as_buffer */
1883
0, /* tp_flags */
1884
0, /* tp_doc */
1885
0, /* tp_traverse */
1886
0, /* tp_clear */
1887
0, /* tp_richcompare */
1888
0, /* tp_weaklistoffset */
1889
(getiterfunc)odictkeys_iter, /* tp_iter */
1890
0, /* tp_iternext */
1891
odictkeys_methods, /* tp_methods */
1892
0, /* tp_members */
1893
0, /* tp_getset */
1894
&PyDictKeys_Type, /* tp_base */
1895
};
1896
1897
static PyObject *
1898
odictkeys_new(PyObject *od, PyObject *Py_UNUSED(ignored))
1899
{
1900
return _PyDictView_New(od, &PyODictKeys_Type);
1901
}
1902
1903
/* items() */
1904
1905
static PyObject *
1906
odictitems_iter(_PyDictViewObject *dv)
1907
{
1908
if (dv->dv_dict == NULL) {
1909
Py_RETURN_NONE;
1910
}
1911
return odictiter_new((PyODictObject *)dv->dv_dict,
1912
_odict_ITER_KEYS|_odict_ITER_VALUES);
1913
}
1914
1915
static PyObject *
1916
odictitems_reversed(_PyDictViewObject *dv, PyObject *Py_UNUSED(ignored))
1917
{
1918
if (dv->dv_dict == NULL) {
1919
Py_RETURN_NONE;
1920
}
1921
return odictiter_new((PyODictObject *)dv->dv_dict,
1922
_odict_ITER_KEYS|_odict_ITER_VALUES|_odict_ITER_REVERSED);
1923
}
1924
1925
static PyMethodDef odictitems_methods[] = {
1926
{"__reversed__", (PyCFunction)odictitems_reversed, METH_NOARGS, NULL},
1927
{NULL, NULL} /* sentinel */
1928
};
1929
1930
PyTypeObject PyODictItems_Type = {
1931
PyVarObject_HEAD_INIT(&PyType_Type, 0)
1932
"odict_items", /* tp_name */
1933
0, /* tp_basicsize */
1934
0, /* tp_itemsize */
1935
0, /* tp_dealloc */
1936
0, /* tp_vectorcall_offset */
1937
0, /* tp_getattr */
1938
0, /* tp_setattr */
1939
0, /* tp_as_async */
1940
0, /* tp_repr */
1941
0, /* tp_as_number */
1942
0, /* tp_as_sequence */
1943
0, /* tp_as_mapping */
1944
0, /* tp_hash */
1945
0, /* tp_call */
1946
0, /* tp_str */
1947
0, /* tp_getattro */
1948
0, /* tp_setattro */
1949
0, /* tp_as_buffer */
1950
0, /* tp_flags */
1951
0, /* tp_doc */
1952
0, /* tp_traverse */
1953
0, /* tp_clear */
1954
0, /* tp_richcompare */
1955
0, /* tp_weaklistoffset */
1956
(getiterfunc)odictitems_iter, /* tp_iter */
1957
0, /* tp_iternext */
1958
odictitems_methods, /* tp_methods */
1959
0, /* tp_members */
1960
0, /* tp_getset */
1961
&PyDictItems_Type, /* tp_base */
1962
};
1963
1964
static PyObject *
1965
odictitems_new(PyObject *od, PyObject *Py_UNUSED(ignored))
1966
{
1967
return _PyDictView_New(od, &PyODictItems_Type);
1968
}
1969
1970
/* values() */
1971
1972
static PyObject *
1973
odictvalues_iter(_PyDictViewObject *dv)
1974
{
1975
if (dv->dv_dict == NULL) {
1976
Py_RETURN_NONE;
1977
}
1978
return odictiter_new((PyODictObject *)dv->dv_dict,
1979
_odict_ITER_VALUES);
1980
}
1981
1982
static PyObject *
1983
odictvalues_reversed(_PyDictViewObject *dv, PyObject *Py_UNUSED(ignored))
1984
{
1985
if (dv->dv_dict == NULL) {
1986
Py_RETURN_NONE;
1987
}
1988
return odictiter_new((PyODictObject *)dv->dv_dict,
1989
_odict_ITER_VALUES|_odict_ITER_REVERSED);
1990
}
1991
1992
static PyMethodDef odictvalues_methods[] = {
1993
{"__reversed__", (PyCFunction)odictvalues_reversed, METH_NOARGS, NULL},
1994
{NULL, NULL} /* sentinel */
1995
};
1996
1997
PyTypeObject PyODictValues_Type = {
1998
PyVarObject_HEAD_INIT(&PyType_Type, 0)
1999
"odict_values", /* tp_name */
2000
0, /* tp_basicsize */
2001
0, /* tp_itemsize */
2002
0, /* tp_dealloc */
2003
0, /* tp_vectorcall_offset */
2004
0, /* tp_getattr */
2005
0, /* tp_setattr */
2006
0, /* tp_as_async */
2007
0, /* tp_repr */
2008
0, /* tp_as_number */
2009
0, /* tp_as_sequence */
2010
0, /* tp_as_mapping */
2011
0, /* tp_hash */
2012
0, /* tp_call */
2013
0, /* tp_str */
2014
0, /* tp_getattro */
2015
0, /* tp_setattro */
2016
0, /* tp_as_buffer */
2017
0, /* tp_flags */
2018
0, /* tp_doc */
2019
0, /* tp_traverse */
2020
0, /* tp_clear */
2021
0, /* tp_richcompare */
2022
0, /* tp_weaklistoffset */
2023
(getiterfunc)odictvalues_iter, /* tp_iter */
2024
0, /* tp_iternext */
2025
odictvalues_methods, /* tp_methods */
2026
0, /* tp_members */
2027
0, /* tp_getset */
2028
&PyDictValues_Type, /* tp_base */
2029
};
2030
2031
static PyObject *
2032
odictvalues_new(PyObject *od, PyObject *Py_UNUSED(ignored))
2033
{
2034
return _PyDictView_New(od, &PyODictValues_Type);
2035
}
2036
2037
2038
/* ----------------------------------------------
2039
MutableMapping implementations
2040
2041
Mapping:
2042
2043
============ ===========
2044
method uses
2045
============ ===========
2046
__contains__ __getitem__
2047
__eq__ items
2048
__getitem__ +
2049
__iter__ +
2050
__len__ +
2051
__ne__ __eq__
2052
get __getitem__
2053
items ItemsView
2054
keys KeysView
2055
values ValuesView
2056
============ ===========
2057
2058
ItemsView uses __len__, __iter__, and __getitem__.
2059
KeysView uses __len__, __iter__, and __contains__.
2060
ValuesView uses __len__, __iter__, and __getitem__.
2061
2062
MutableMapping:
2063
2064
============ ===========
2065
method uses
2066
============ ===========
2067
__delitem__ +
2068
__setitem__ +
2069
clear popitem
2070
pop __getitem__
2071
__delitem__
2072
popitem __iter__
2073
_getitem__
2074
__delitem__
2075
setdefault __getitem__
2076
__setitem__
2077
update __setitem__
2078
============ ===========
2079
*/
2080
2081
static int
2082
mutablemapping_add_pairs(PyObject *self, PyObject *pairs)
2083
{
2084
PyObject *pair, *iterator, *unexpected;
2085
int res = 0;
2086
2087
iterator = PyObject_GetIter(pairs);
2088
if (iterator == NULL)
2089
return -1;
2090
PyErr_Clear();
2091
2092
while ((pair = PyIter_Next(iterator)) != NULL) {
2093
/* could be more efficient (see UNPACK_SEQUENCE in ceval.c) */
2094
PyObject *key = NULL, *value = NULL;
2095
PyObject *pair_iterator = PyObject_GetIter(pair);
2096
if (pair_iterator == NULL)
2097
goto Done;
2098
2099
key = PyIter_Next(pair_iterator);
2100
if (key == NULL) {
2101
if (!PyErr_Occurred())
2102
PyErr_SetString(PyExc_ValueError,
2103
"need more than 0 values to unpack");
2104
goto Done;
2105
}
2106
2107
value = PyIter_Next(pair_iterator);
2108
if (value == NULL) {
2109
if (!PyErr_Occurred())
2110
PyErr_SetString(PyExc_ValueError,
2111
"need more than 1 value to unpack");
2112
goto Done;
2113
}
2114
2115
unexpected = PyIter_Next(pair_iterator);
2116
if (unexpected != NULL) {
2117
Py_DECREF(unexpected);
2118
PyErr_SetString(PyExc_ValueError,
2119
"too many values to unpack (expected 2)");
2120
goto Done;
2121
}
2122
else if (PyErr_Occurred())
2123
goto Done;
2124
2125
res = PyObject_SetItem(self, key, value);
2126
2127
Done:
2128
Py_DECREF(pair);
2129
Py_XDECREF(pair_iterator);
2130
Py_XDECREF(key);
2131
Py_XDECREF(value);
2132
if (PyErr_Occurred())
2133
break;
2134
}
2135
Py_DECREF(iterator);
2136
2137
if (res < 0 || PyErr_Occurred() != NULL)
2138
return -1;
2139
else
2140
return 0;
2141
}
2142
2143
static int
2144
mutablemapping_update_arg(PyObject *self, PyObject *arg)
2145
{
2146
int res = 0;
2147
if (PyDict_CheckExact(arg)) {
2148
PyObject *items = PyDict_Items(arg);
2149
if (items == NULL) {
2150
return -1;
2151
}
2152
res = mutablemapping_add_pairs(self, items);
2153
Py_DECREF(items);
2154
return res;
2155
}
2156
PyObject *func;
2157
if (_PyObject_LookupAttr(arg, &_Py_ID(keys), &func) < 0) {
2158
return -1;
2159
}
2160
if (func != NULL) {
2161
PyObject *keys = _PyObject_CallNoArgs(func);
2162
Py_DECREF(func);
2163
if (keys == NULL) {
2164
return -1;
2165
}
2166
PyObject *iterator = PyObject_GetIter(keys);
2167
Py_DECREF(keys);
2168
if (iterator == NULL) {
2169
return -1;
2170
}
2171
PyObject *key;
2172
while (res == 0 && (key = PyIter_Next(iterator))) {
2173
PyObject *value = PyObject_GetItem(arg, key);
2174
if (value != NULL) {
2175
res = PyObject_SetItem(self, key, value);
2176
Py_DECREF(value);
2177
}
2178
else {
2179
res = -1;
2180
}
2181
Py_DECREF(key);
2182
}
2183
Py_DECREF(iterator);
2184
if (res != 0 || PyErr_Occurred()) {
2185
return -1;
2186
}
2187
return 0;
2188
}
2189
if (_PyObject_LookupAttr(arg, &_Py_ID(items), &func) < 0) {
2190
return -1;
2191
}
2192
if (func != NULL) {
2193
PyObject *items = _PyObject_CallNoArgs(func);
2194
Py_DECREF(func);
2195
if (items == NULL) {
2196
return -1;
2197
}
2198
res = mutablemapping_add_pairs(self, items);
2199
Py_DECREF(items);
2200
return res;
2201
}
2202
res = mutablemapping_add_pairs(self, arg);
2203
return res;
2204
}
2205
2206
static PyObject *
2207
mutablemapping_update(PyObject *self, PyObject *args, PyObject *kwargs)
2208
{
2209
int res;
2210
/* first handle args, if any */
2211
assert(args == NULL || PyTuple_Check(args));
2212
Py_ssize_t len = (args != NULL) ? PyTuple_GET_SIZE(args) : 0;
2213
if (len > 1) {
2214
const char *msg = "update() takes at most 1 positional argument (%zd given)";
2215
PyErr_Format(PyExc_TypeError, msg, len);
2216
return NULL;
2217
}
2218
2219
if (len) {
2220
PyObject *other = PyTuple_GET_ITEM(args, 0); /* borrowed reference */
2221
assert(other != NULL);
2222
Py_INCREF(other);
2223
res = mutablemapping_update_arg(self, other);
2224
Py_DECREF(other);
2225
if (res < 0) {
2226
return NULL;
2227
}
2228
}
2229
2230
/* now handle kwargs */
2231
assert(kwargs == NULL || PyDict_Check(kwargs));
2232
if (kwargs != NULL && PyDict_GET_SIZE(kwargs)) {
2233
PyObject *items = PyDict_Items(kwargs);
2234
if (items == NULL)
2235
return NULL;
2236
res = mutablemapping_add_pairs(self, items);
2237
Py_DECREF(items);
2238
if (res == -1)
2239
return NULL;
2240
}
2241
2242
Py_RETURN_NONE;
2243
}
2244
2245