omextra 0.0.0.dev509__py3-none-any.whl → 0.0.0.dev510__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3656 +0,0 @@
1
- // @omlish-cext
2
- //
3
- // PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
4
- // --------------------------------------------
5
- //
6
- // 1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and the Individual or Organization
7
- // ("Licensee") accessing and otherwise using this software ("Python") in source or binary form and its associated
8
- // documentation.
9
- //
10
- // 2. Subject to the terms and conditions of this License Agreement, PSF hereby grants Licensee a nonexclusive,
11
- // royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative
12
- // works, distribute, and otherwise use Python alone or in any derivative version, provided, however, that PSF's License
13
- // Agreement and PSF's notice of copyright, i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
14
- // 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Python Software Foundation; All Rights Reserved" are retained in
15
- // Python alone or in any derivative version prepared by Licensee.
16
- //
17
- // 3. In the event Licensee prepares a derivative work that is based on or incorporates Python or any part thereof, and
18
- // wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in
19
- // any such work a brief summary of the changes made to Python.
20
- //
21
- // 4. PSF is making Python available to Licensee on an "AS IS" basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES,
22
- // EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY
23
- // OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT INFRINGE ANY THIRD PARTY
24
- // RIGHTS.
25
- //
26
- // 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL
27
- // DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, OR ANY DERIVATIVE THEREOF, EVEN IF
28
- // ADVISED OF THE POSSIBILITY THEREOF.
29
- //
30
- // 6. This License Agreement will automatically terminate upon a material breach of its terms and conditions.
31
- //
32
- // 7. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint
33
- // venture between PSF and Licensee. This License Agreement does not grant permission to use PSF trademarks or trade
34
- // name in a trademark sense to endorse or promote products or services of Licensee, or any third party.
35
- //
36
- // 8. By copying, installing or otherwise using Python, Licensee agrees to be bound by the terms and conditions of this
37
- // License Agreement.
38
- //
39
- // https://github.com/python/cpython/blob/main/Python/hamt.c
40
- //
41
- // original: https://github.com/python/cpython/commit/aa18fd55d575a04e3aa782fedcd08dced26676e0
42
- //
43
- #define PY_SSIZE_T_CLEAN
44
-
45
- #include "Python.h"
46
-
47
- #include <stddef.h> // offsetof()
48
-
49
- #if PY_VERSION_HEX < 0x030D0000
50
- # error "This extension requires CPython 3.13+"
51
- #endif
52
-
53
- ////
54
-
55
- /*
56
- HAMT tree is shaped by hashes of keys. Every group of 5 bits of a hash denotes
57
- the exact position of the key in one level of the tree. Since we're using
58
- 32 bit hashes, we can have at most 7 such levels. Although if there are
59
- two distinct keys with equal hashes, they will have to occupy the same
60
- cell in the 7th level of the tree -- so we'd put them in a "collision" node.
61
- Which brings the total possible tree depth to 8. Read more about the actual
62
- layout of the HAMT tree in `hamt.c`.
63
-
64
- This constant is used to define a datastucture for storing iteration state.
65
- */
66
- #define _Py_HAMT_MAX_TREE_DEPTH 8
67
-
68
-
69
- /* Abstract tree node. */
70
- typedef struct {
71
- PyObject_HEAD
72
- } HamtNode;
73
-
74
-
75
- /* An HAMT immutable mapping collection. */
76
- typedef struct {
77
- PyObject_HEAD
78
- HamtNode *h_root;
79
- PyObject *h_weakreflist;
80
- Py_ssize_t h_count;
81
- } HamtObject;
82
-
83
-
84
- typedef struct {
85
- PyObject_VAR_HEAD
86
- uint32_t b_bitmap;
87
- PyObject *b_array[1];
88
- } HamtNode_Bitmap;
89
-
90
-
91
- /* A struct to hold the state of depth-first traverse of the tree.
92
-
93
- HAMT is an immutable collection. Iterators will hold a strong reference
94
- to it, and every node in the HAMT has strong references to its children.
95
-
96
- So for iterators, we can implement zero allocations and zero reference
97
- inc/dec depth-first iteration.
98
-
99
- - i_nodes: an array of seven pointers to tree nodes
100
- - i_level: the current node in i_nodes
101
- - i_pos: an array of positions within nodes in i_nodes.
102
- */
103
- typedef struct {
104
- HamtNode *i_nodes[_Py_HAMT_MAX_TREE_DEPTH];
105
- Py_ssize_t i_pos[_Py_HAMT_MAX_TREE_DEPTH];
106
- int8_t i_level;
107
- } HamtIteratorState;
108
-
109
-
110
- /* Base iterator object.
111
-
112
- Contains the iteration state, a pointer to the HAMT tree,
113
- and a pointer to the 'yield function'. The latter is a simple
114
- function that returns a key/value tuple for the 'Items' iterator,
115
- just a key for the 'Keys' iterator, and a value for the 'Values'
116
- iterator.
117
- */
118
- typedef struct {
119
- PyObject_HEAD
120
- HamtObject *hi_obj;
121
- HamtIteratorState hi_iter;
122
- binaryfunc hi_yield;
123
- } HamtIterator;
124
-
125
-
126
- ////
127
-
128
- #define _MODULE_NAME "_hamt"
129
- #define _PACKAGE_NAME "omextra.collections.hamt"
130
- #define _MODULE_FULL_NAME _PACKAGE_NAME "." _MODULE_NAME
131
-
132
- //
133
-
134
- typedef struct hamt_module_state {
135
- /* Type objects */
136
- PyTypeObject *Hamt_Type;
137
- PyTypeObject *HamtItems_Type;
138
- PyTypeObject *HamtKeys_Type;
139
- PyTypeObject *HamtValues_Type;
140
- PyTypeObject *Hamt_ArrayNode_Type;
141
- PyTypeObject *Hamt_BitmapNode_Type;
142
- PyTypeObject *Hamt_CollisionNode_Type;
143
-
144
- /* Singleton objects */
145
- HamtObject *empty_hamt;
146
- HamtNode_Bitmap *empty_bitmap_node;
147
- } hamt_module_state;
148
-
149
- static inline hamt_module_state * get_hamt_module_state(PyObject *module)
150
- {
151
- void *state = PyModule_GetState(module);
152
- assert(state != NULL);
153
- return (hamt_module_state *)state;
154
- }
155
-
156
- static inline hamt_module_state * get_hamt_state_from_type(PyTypeObject *type)
157
- {
158
- PyObject *module = PyType_GetModule(type);
159
- assert(module != NULL);
160
- return get_hamt_module_state(module);
161
- }
162
-
163
- static inline hamt_module_state * get_hamt_state_from_obj(PyObject *obj)
164
- {
165
- PyTypeObject *type = Py_TYPE(obj);
166
- return get_hamt_state_from_type(type);
167
- }
168
-
169
- ////
170
-
171
- // Population count: count the number of 1's in 'x'
172
- // (number of bits set to 1), also known as the hamming weight.
173
- //
174
- // Implementation note. CPUID is not used, to test if x86 POPCNT instruction
175
- // can be used, to keep the implementation simple. For example, Visual Studio
176
- // __popcnt() is not used this reason. The clang and GCC builtin function can
177
- // use the x86 POPCNT instruction if the target architecture has SSE4a or
178
- // newer.
179
- static inline int
180
- _popcount32(uint32_t x)
181
- {
182
- #if (defined(__clang__) || defined(__GNUC__))
183
-
184
- #if SIZEOF_INT >= 4
185
- Py_BUILD_ASSERT(sizeof(x) <= sizeof(unsigned int));
186
- return __builtin_popcount(x);
187
- #else
188
- // The C standard guarantees that unsigned long will always be big enough
189
- // to hold a uint32_t value without losing information.
190
- Py_BUILD_ASSERT(sizeof(x) <= sizeof(unsigned long));
191
- return __builtin_popcountl(x);
192
- #endif
193
-
194
- #else
195
- // 32-bit SWAR (SIMD Within A Register) popcount
196
-
197
- // Binary: 0 1 0 1 ...
198
- const uint32_t M1 = 0x55555555;
199
- // Binary: 00 11 00 11. ..
200
- const uint32_t M2 = 0x33333333;
201
- // Binary: 0000 1111 0000 1111 ...
202
- const uint32_t M4 = 0x0F0F0F0F;
203
-
204
- // Put count of each 2 bits into those 2 bits
205
- x = x - ((x >> 1) & M1);
206
- // Put count of each 4 bits into those 4 bits
207
- x = (x & M2) + ((x >> 2) & M2);
208
- // Put count of each 8 bits into those 8 bits
209
- x = (x + (x >> 4)) & M4;
210
- // Sum of the 4 byte counts.
211
- // Take care when considering changes to the next line. Portability and
212
- // correctness are delicate here, thanks to C's "integer promotions" (C99
213
- // §6.3.1.1p2). On machines where the `int` type has width greater than 32
214
- // bits, `x` will be promoted to an `int`, and following C's "usual
215
- // arithmetic conversions" (C99 §6.3.1.8), the multiplication will be
216
- // performed as a multiplication of two `unsigned int` operands. In this
217
- // case it's critical that we cast back to `uint32_t` in order to keep only
218
- // the least significant 32 bits. On machines where the `int` type has
219
- // width no greater than 32, the multiplication is of two 32-bit unsigned
220
- // integer types, and the (uint32_t) cast is a no-op. In both cases, we
221
- // avoid the risk of undefined behaviour due to overflow of a
222
- // multiplication of signed integer types.
223
- return (uint32_t)(x * 0x01010101U) >> 24;
224
- #endif
225
- }
226
-
227
- ////
228
-
229
- /* Create a new HAMT immutable mapping. */
230
- HamtObject * _Hamt_New(hamt_module_state *state);
231
-
232
- /* Return a new collection based on "o", but with an additional
233
- key/val pair. */
234
- HamtObject * _Hamt_Assoc(HamtObject *o, PyObject *key, PyObject *val);
235
-
236
- /* Return a new collection based on "o", but without "key". */
237
- HamtObject * _Hamt_Without(HamtObject *o, PyObject *key);
238
-
239
- /* Find "key" in the "o" collection.
240
-
241
- Return:
242
- - -1: An error occurred.
243
- - 0: "key" wasn't found in "o".
244
- - 1: "key" is in "o"; "*val" is set to its value (a borrowed ref).
245
- */
246
- int _Hamt_Find(HamtObject *o, PyObject *key, PyObject **val);
247
-
248
- /* Check if "v" is equal to "w".
249
-
250
- Return:
251
- - 0: v != w
252
- - 1: v == w
253
- - -1: An error occurred.
254
- */
255
- int _Hamt_Eq(HamtObject *v, HamtObject *w);
256
-
257
- /* Return the size of "o"; equivalent of "len(o)". */
258
- Py_ssize_t _Hamt_Len(HamtObject *o);
259
-
260
- /* Return a Keys iterator over "o". */
261
- PyObject * _Hamt_NewIterKeys(HamtObject *o);
262
-
263
- /* Return a Values iterator over "o". */
264
- PyObject * _Hamt_NewIterValues(HamtObject *o);
265
-
266
- /* Return a Items iterator over "o". */
267
- PyObject * _Hamt_NewIterItems(HamtObject *o);
268
-
269
- ////
270
-
271
- /* Type check helper - checks if object is a HAMT by comparing against module state type */
272
- static inline int
273
- Hamt_Check(PyObject *o)
274
- {
275
- PyTypeObject *type = Py_TYPE(o);
276
- PyObject *mod = PyType_GetModule(type);
277
- if (mod == NULL) {
278
- // Not a heap type or not from a module, definitely not our HAMT
279
- PyErr_Clear();
280
- return 0;
281
- }
282
- hamt_module_state *state = get_hamt_module_state(mod);
283
- return Py_IS_TYPE(o, state->Hamt_Type);
284
- }
285
-
286
-
287
- /*
288
- This file provides an implementation of an immutable mapping using the
289
- Hash Array Mapped Trie (or HAMT) datastructure.
290
-
291
- This design allows to have:
292
-
293
- 1. Efficient copy: immutable mappings can be copied by reference,
294
- making it an O(1) operation.
295
-
296
- 2. Efficient mutations: due to structural sharing, only a portion of
297
- the trie needs to be copied when the collection is mutated. The
298
- cost of set/delete operations is O(log N).
299
-
300
- 3. Efficient lookups: O(log N).
301
-
302
- (where N is number of key/value items in the immutable mapping.)
303
-
304
-
305
- HAMT
306
- ====
307
-
308
- The core idea of HAMT is that the shape of the trie is encoded into the
309
- hashes of keys.
310
-
311
- Say we want to store a K/V pair in our mapping. First, we calculate the
312
- hash of K, let's say it's 19830128, or in binary:
313
-
314
- 0b1001011101001010101110000 = 19830128
315
-
316
- Now let's partition this bit representation of the hash into blocks of
317
- 5 bits each:
318
-
319
- 0b00_00000_10010_11101_00101_01011_10000 = 19830128
320
- (6) (5) (4) (3) (2) (1)
321
-
322
- Each block of 5 bits represents a number between 0 and 31. So if we have
323
- a tree that consists of nodes, each of which is an array of 32 pointers,
324
- those 5-bit blocks will encode a position on a single tree level.
325
-
326
- For example, storing the key K with hash 19830128, results in the following
327
- tree structure:
328
-
329
- (array of 32 pointers)
330
- +---+ -- +----+----+----+ -- +----+
331
- root node | 0 | .. | 15 | 16 | 17 | .. | 31 | 0b10000 = 16 (1)
332
- (level 1) +---+ -- +----+----+----+ -- +----+
333
- |
334
- +---+ -- +----+----+----+ -- +----+
335
- a 2nd level node | 0 | .. | 10 | 11 | 12 | .. | 31 | 0b01011 = 11 (2)
336
- +---+ -- +----+----+----+ -- +----+
337
- |
338
- +---+ -- +----+----+----+ -- +----+
339
- a 3rd level node | 0 | .. | 04 | 05 | 06 | .. | 31 | 0b00101 = 5 (3)
340
- +---+ -- +----+----+----+ -- +----+
341
- |
342
- +---+ -- +----+----+----+----+
343
- a 4th level node | 0 | .. | 04 | 29 | 30 | 31 | 0b11101 = 29 (4)
344
- +---+ -- +----+----+----+----+
345
- |
346
- +---+ -- +----+----+----+ -- +----+
347
- a 5th level node | 0 | .. | 17 | 18 | 19 | .. | 31 | 0b10010 = 18 (5)
348
- +---+ -- +----+----+----+ -- +----+
349
- |
350
- +--------------+
351
- |
352
- +---+ -- +----+----+----+ -- +----+
353
- a 6th level node | 0 | .. | 15 | 16 | 17 | .. | 31 | 0b00000 = 0 (6)
354
- +---+ -- +----+----+----+ -- +----+
355
- |
356
- V -- our value (or collision)
357
-
358
- To rehash: for a K/V pair, the hash of K encodes where in the tree V will
359
- be stored.
360
-
361
- To optimize memory footprint and handle hash collisions, our implementation
362
- uses three different types of nodes:
363
-
364
- * A Bitmap node;
365
- * An Array node;
366
- * A Collision node.
367
-
368
- Because we implement an immutable dictionary, our nodes are also
369
- immutable. Therefore, when we need to modify a node, we copy it, and
370
- do that modification to the copy.
371
-
372
-
373
- Array Nodes
374
- -----------
375
-
376
- These nodes are very simple. Essentially they are arrays of 32 pointers
377
- we used to illustrate the high-level idea in the previous section.
378
-
379
- We use Array nodes only when we need to store more than 16 pointers
380
- in a single node.
381
-
382
- Array nodes do not store key objects or value objects. They are used
383
- only as an indirection level - their pointers point to other nodes in
384
- the tree.
385
-
386
-
387
- Bitmap Node
388
- -----------
389
-
390
- Allocating a new 32-pointers array for every node of our tree would be
391
- very expensive. Unless we store millions of keys, most of tree nodes would
392
- be very sparse.
393
-
394
- When we have less than 16 elements in a node, we don't want to use the
395
- Array node, that would mean that we waste a lot of memory. Instead,
396
- we can use bitmap compression and can have just as many pointers
397
- as we need!
398
-
399
- Bitmap nodes consist of two fields:
400
-
401
- 1. An array of pointers. If a Bitmap node holds N elements, the
402
- array will be of N pointers.
403
-
404
- 2. A 32bit integer -- a bitmap field. If an N-th bit is set in the
405
- bitmap, it means that the node has an N-th element.
406
-
407
- For example, say we need to store a 3 elements sparse array:
408
-
409
- +---+ -- +---+ -- +----+ -- +----+
410
- | 0 | .. | 4 | .. | 11 | .. | 17 |
411
- +---+ -- +---+ -- +----+ -- +----+
412
- | | |
413
- o1 o2 o3
414
-
415
- We allocate a three-pointer Bitmap node. Its bitmap field will be
416
- then set to:
417
-
418
- 0b_00100_00010_00000_10000 == (1 << 17) | (1 << 11) | (1 << 4)
419
-
420
- To check if our Bitmap node has an I-th element we can do:
421
-
422
- bitmap & (1 << I)
423
-
424
-
425
- And here's a formula to calculate a position in our pointer array
426
- which would correspond to an I-th element:
427
-
428
- popcount(bitmap & ((1 << I) - 1))
429
-
430
-
431
- Let's break it down:
432
-
433
- * `popcount` is a function that returns a number of bits set to 1;
434
-
435
- * `((1 << I) - 1)` is a mask to filter the bitmask to contain bits
436
- set to the *right* of our bit.
437
-
438
-
439
- So for our 17, 11, and 4 indexes:
440
-
441
- * bitmap & ((1 << 17) - 1) == 0b100000010000 => 2 bits are set => index is 2.
442
-
443
- * bitmap & ((1 << 11) - 1) == 0b10000 => 1 bit is set => index is 1.
444
-
445
- * bitmap & ((1 << 4) - 1) == 0b0 => 0 bits are set => index is 0.
446
-
447
-
448
- To conclude: Bitmap nodes are just like Array nodes -- they can store
449
- a number of pointers, but use bitmap compression to eliminate unused
450
- pointers.
451
-
452
-
453
- Bitmap nodes have two pointers for each item:
454
-
455
- +----+----+----+----+ -- +----+----+
456
- | k1 | v1 | k2 | v2 | .. | kN | vN |
457
- +----+----+----+----+ -- +----+----+
458
-
459
- When kI == NULL, vI points to another tree level.
460
-
461
- When kI != NULL, the actual key object is stored in kI, and its
462
- value is stored in vI.
463
-
464
-
465
- Collision Nodes
466
- ---------------
467
-
468
- Collision nodes are simple arrays of pointers -- two pointers per
469
- key/value. When there's a hash collision, say for k1/v1 and k2/v2
470
- we have `hash(k1)==hash(k2)`. Then our collision node will be:
471
-
472
- +----+----+----+----+
473
- | k1 | v1 | k2 | v2 |
474
- +----+----+----+----+
475
-
476
-
477
- Tree Structure
478
- --------------
479
-
480
- All nodes are PyObjects.
481
-
482
- The `HamtObject` object has a pointer to the root node (h_root),
483
- and has a length field (h_count).
484
-
485
- High-level functions accept a HamtObject object and dispatch to
486
- lower-level functions depending on what kind of node h_root points to.
487
-
488
-
489
- Operations
490
- ==========
491
-
492
- There are three fundamental operations on an immutable dictionary:
493
-
494
- 1. "o.assoc(k, v)" will return a new immutable dictionary, that will be
495
- a copy of "o", but with the "k/v" item set.
496
-
497
- Functions in this file:
498
-
499
- hamt_node_assoc, hamt_node_bitmap_assoc,
500
- hamt_node_array_assoc, hamt_node_collision_assoc
501
-
502
- `hamt_node_assoc` function accepts a node object, and calls
503
- other functions depending on its actual type.
504
-
505
- 2. "o.find(k)" will lookup key "k" in "o".
506
-
507
- Functions:
508
-
509
- hamt_node_find, hamt_node_bitmap_find,
510
- hamt_node_array_find, hamt_node_collision_find
511
-
512
- 3. "o.without(k)" will return a new immutable dictionary, that will be
513
- a copy of "o", buth without the "k" key.
514
-
515
- Functions:
516
-
517
- hamt_node_without, hamt_node_bitmap_without,
518
- hamt_node_array_without, hamt_node_collision_without
519
-
520
-
521
- Further Reading
522
- ===============
523
-
524
- 1. http://blog.higher-order.net/2009/09/08/understanding-clojures-persistenthashmap-deftwice.html
525
-
526
- 2. http://blog.higher-order.net/2010/08/16/assoc-and-clojures-persistenthashmap-part-ii.html
527
-
528
- 3. Clojure's PersistentHashMap implementation:
529
- https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/PersistentHashMap.java
530
-
531
-
532
- Debug
533
- =====
534
-
535
- The HAMT datatype is accessible for testing purposes under the
536
- `_testinternalcapi` module:
537
-
538
- >>> from _testinternalcapi import hamt
539
- >>> h = hamt()
540
- >>> h2 = h.set('a', 2)
541
- >>> h3 = h2.set('b', 3)
542
- >>> list(h3)
543
- ['a', 'b']
544
-
545
- When CPython is built in debug mode, a '__dump__()' method is available
546
- to introspect the tree:
547
-
548
- >>> print(h3.__dump__())
549
- HAMT(len=2):
550
- BitmapNode(size=4 count=2 bitmap=0b110 id=0x10eb9d9e8):
551
- 'a': 2
552
- 'b': 3
553
- */
554
-
555
-
556
- static inline int
557
- IS_ARRAY_NODE(HamtNode *node)
558
- {
559
- hamt_module_state *state = get_hamt_state_from_obj((PyObject*)node);
560
- return Py_IS_TYPE(node, state->Hamt_ArrayNode_Type);
561
- }
562
-
563
- static inline int
564
- IS_BITMAP_NODE(HamtNode *node)
565
- {
566
- hamt_module_state *state = get_hamt_state_from_obj((PyObject*)node);
567
- return Py_IS_TYPE(node, state->Hamt_BitmapNode_Type);
568
- }
569
-
570
- static inline int
571
- IS_COLLISION_NODE(HamtNode *node)
572
- {
573
- hamt_module_state *state = get_hamt_state_from_obj((PyObject*)node);
574
- return Py_IS_TYPE(node, state->Hamt_CollisionNode_Type);
575
- }
576
-
577
-
578
- /* Return type for 'find' (lookup a key) functions.
579
-
580
- * F_ERROR - an error occurred;
581
- * F_NOT_FOUND - the key was not found;
582
- * F_FOUND - the key was found.
583
- */
584
- typedef enum {F_ERROR, F_NOT_FOUND, F_FOUND} hamt_find_t;
585
-
586
-
587
- /* Return type for 'without' (delete a key) functions.
588
-
589
- * W_ERROR - an error occurred;
590
- * W_NOT_FOUND - the key was not found: there's nothing to delete;
591
- * W_EMPTY - the key was found: the node/tree would be empty
592
- if the key is deleted;
593
- * W_NEWNODE - the key was found: a new node/tree is returned
594
- without that key.
595
- */
596
- typedef enum {W_ERROR, W_NOT_FOUND, W_EMPTY, W_NEWNODE} hamt_without_t;
597
-
598
-
599
- /* Low-level iterator protocol type.
600
-
601
- * I_ITEM - a new item has been yielded;
602
- * I_END - the whole tree was visited (similar to StopIteration).
603
- */
604
- typedef enum {I_ITEM, I_END} hamt_iter_t;
605
-
606
-
607
- #define HAMT_ARRAY_NODE_SIZE 32
608
-
609
-
610
- typedef struct {
611
- PyObject_HEAD
612
- HamtNode *a_array[HAMT_ARRAY_NODE_SIZE];
613
- Py_ssize_t a_count;
614
- } HamtNode_Array;
615
-
616
- #define _HamtNode_Array_CAST(op) ((HamtNode_Array *)(op))
617
-
618
-
619
- typedef struct {
620
- PyObject_VAR_HEAD
621
- int32_t c_hash;
622
- PyObject *c_array[1];
623
- } HamtNode_Collision;
624
-
625
- #define _HamtNode_Collision_CAST(op) ((HamtNode_Collision *)(op))
626
-
627
-
628
- static HamtObject *
629
- hamt_alloc(hamt_module_state *state);
630
-
631
- static HamtNode *
632
- hamt_node_assoc(HamtNode *node,
633
- uint32_t shift, int32_t hash,
634
- PyObject *key, PyObject *val, int* added_leaf);
635
-
636
- static hamt_without_t
637
- hamt_node_without(HamtNode *node,
638
- uint32_t shift, int32_t hash,
639
- PyObject *key,
640
- HamtNode **new_node);
641
-
642
- static hamt_find_t
643
- hamt_node_find(HamtNode *node,
644
- uint32_t shift, int32_t hash,
645
- PyObject *key, PyObject **val);
646
-
647
- #ifdef Py_DEBUG
648
- static int
649
- hamt_node_dump(HamtNode *node,
650
- _PyUnicodeWriter *writer, int level);
651
- #endif
652
-
653
- static HamtNode *
654
- hamt_node_array_new(hamt_module_state *state, Py_ssize_t);
655
-
656
- static HamtNode *
657
- hamt_node_collision_new(hamt_module_state *state, int32_t hash, Py_ssize_t size);
658
-
659
- static inline Py_ssize_t
660
- hamt_node_collision_count(HamtNode_Collision *node);
661
-
662
-
663
- #ifdef Py_DEBUG
664
- static void
665
- _hamt_node_array_validate(void *obj_raw)
666
- {
667
- PyObject *obj = _PyObject_CAST(obj_raw);
668
- assert(IS_ARRAY_NODE(obj));
669
- HamtNode_Array *node = (HamtNode_Array*)obj;
670
- Py_ssize_t i = 0, count = 0;
671
- for (; i < HAMT_ARRAY_NODE_SIZE; i++) {
672
- if (node->a_array[i] != NULL) {
673
- count++;
674
- }
675
- }
676
- assert(count == node->a_count);
677
- }
678
-
679
- #define VALIDATE_ARRAY_NODE(NODE) \
680
- do { _hamt_node_array_validate(NODE); } while (0);
681
- #else
682
- #define VALIDATE_ARRAY_NODE(NODE)
683
- #endif
684
-
685
-
686
- /* Returns -1 on error */
687
- static inline int32_t
688
- hamt_hash(PyObject *o)
689
- {
690
- Py_hash_t hash = PyObject_Hash(o);
691
-
692
- #if SIZEOF_PY_HASH_T <= 4
693
- return hash;
694
- #else
695
- if (hash == -1) {
696
- /* exception */
697
- return -1;
698
- }
699
-
700
- /* While it's somewhat suboptimal to reduce Python's 64 bit hash to
701
- 32 bits via XOR, it seems that the resulting hash function
702
- is good enough (this is also how Long type is hashed in Java.)
703
- Storing 10, 100, 1000 Python strings results in a relatively
704
- shallow and uniform tree structure.
705
-
706
- Also it's worth noting that it would be possible to adapt the tree
707
- structure to 64 bit hashes, but that would increase memory pressure
708
- and provide little to no performance benefits for collections with
709
- fewer than billions of key/value pairs.
710
-
711
- Important: do not change this hash reducing function. There are many
712
- tests that need an exact tree shape to cover all code paths and
713
- we do that by specifying concrete values for test data's `__hash__`.
714
- If this function is changed most of the regression tests would
715
- become useless.
716
- */
717
- int32_t xored = (int32_t)(hash & 0xffffffffl) ^ (int32_t)(hash >> 32);
718
- return xored == -1 ? -2 : xored;
719
- #endif
720
- }
721
-
722
- static inline uint32_t
723
- hamt_mask(int32_t hash, uint32_t shift)
724
- {
725
- return (((uint32_t)hash >> shift) & 0x01f);
726
- }
727
-
728
- static inline uint32_t
729
- hamt_bitpos(int32_t hash, uint32_t shift)
730
- {
731
- return (uint32_t)1 << hamt_mask(hash, shift);
732
- }
733
-
734
- static inline uint32_t
735
- hamt_bitindex(uint32_t bitmap, uint32_t bit)
736
- {
737
- return (uint32_t)_popcount32(bitmap & (bit - 1));
738
- }
739
-
740
-
741
- /////////////////////////////////// Dump Helpers
742
- #ifdef Py_DEBUG
743
-
744
- static int
745
- _hamt_dump_ident(_PyUnicodeWriter *writer, int level)
746
- {
747
- /* Write `' ' * level` to the `writer` */
748
- PyObject *str = NULL;
749
- PyObject *num = NULL;
750
- PyObject *res = NULL;
751
- int ret = -1;
752
-
753
- str = PyUnicode_FromString(" ");
754
- if (str == NULL) {
755
- goto error;
756
- }
757
-
758
- num = PyLong_FromLong((long)level);
759
- if (num == NULL) {
760
- goto error;
761
- }
762
-
763
- res = PyNumber_Multiply(str, num);
764
- if (res == NULL) {
765
- goto error;
766
- }
767
-
768
- ret = _PyUnicodeWriter_WriteStr(writer, res);
769
-
770
- error:
771
- Py_XDECREF(res);
772
- Py_XDECREF(str);
773
- Py_XDECREF(num);
774
- return ret;
775
- }
776
-
777
- static int
778
- _hamt_dump_format(_PyUnicodeWriter *writer, const char *format, ...)
779
- {
780
- /* A convenient helper combining _PyUnicodeWriter_WriteStr and
781
- PyUnicode_FromFormatV.
782
- */
783
- PyObject* msg;
784
- int ret;
785
-
786
- va_list vargs;
787
- va_start(vargs, format);
788
- msg = PyUnicode_FromFormatV(format, vargs);
789
- va_end(vargs);
790
-
791
- if (msg == NULL) {
792
- return -1;
793
- }
794
-
795
- ret = _PyUnicodeWriter_WriteStr(writer, msg);
796
- Py_DECREF(msg);
797
- return ret;
798
- }
799
-
800
- #endif /* Py_DEBUG */
801
- /////////////////////////////////// Bitmap Node
802
-
803
- #define _HamtNode_Bitmap_CAST(op) ((HamtNode_Bitmap *)(op))
804
-
805
-
806
- static HamtNode *
807
- hamt_node_bitmap_new(hamt_module_state *state, Py_ssize_t size)
808
- {
809
- /* Create a new bitmap node of size 'size' */
810
-
811
- HamtNode_Bitmap *node;
812
- Py_ssize_t i;
813
-
814
- if (size == 0) {
815
- /* Since bitmap nodes are immutable, we can cache the instance
816
- for size=0 and reuse it whenever we need an empty bitmap node.
817
- */
818
- return (HamtNode *)Py_NewRef(state->empty_bitmap_node);
819
- }
820
-
821
- assert(size >= 0);
822
- assert(size % 2 == 0);
823
-
824
- /* No freelist; allocate a new bitmap node */
825
- node = PyObject_GC_NewVar(
826
- HamtNode_Bitmap, state->Hamt_BitmapNode_Type, size);
827
- if (node == NULL) {
828
- return NULL;
829
- }
830
-
831
- Py_SET_SIZE(node, size);
832
-
833
- for (i = 0; i < size; i++) {
834
- node->b_array[i] = NULL;
835
- }
836
-
837
- node->b_bitmap = 0;
838
-
839
- PyObject_GC_Track(node);
840
-
841
- return (HamtNode *)node;
842
- }
843
-
844
- static inline Py_ssize_t
845
- hamt_node_bitmap_count(HamtNode_Bitmap *node)
846
- {
847
- return Py_SIZE(node) / 2;
848
- }
849
-
850
- static HamtNode_Bitmap *
851
- hamt_node_bitmap_clone(HamtNode_Bitmap *node)
852
- {
853
- /* Clone a bitmap node; return a new one with the same child notes. */
854
-
855
- HamtNode_Bitmap *clone;
856
- Py_ssize_t i;
857
-
858
- hamt_module_state *state = get_hamt_state_from_obj((PyObject*)node);
859
- clone = (HamtNode_Bitmap *)hamt_node_bitmap_new(state, Py_SIZE(node));
860
- if (clone == NULL) {
861
- return NULL;
862
- }
863
-
864
- for (i = 0; i < Py_SIZE(node); i++) {
865
- clone->b_array[i] = Py_XNewRef(node->b_array[i]);
866
- }
867
-
868
- clone->b_bitmap = node->b_bitmap;
869
- return clone;
870
- }
871
-
872
- static HamtNode_Bitmap *
873
- hamt_node_bitmap_clone_without(HamtNode_Bitmap *o, uint32_t bit)
874
- {
875
- assert(bit & o->b_bitmap);
876
- assert(hamt_node_bitmap_count(o) > 1);
877
-
878
- hamt_module_state *state = get_hamt_state_from_obj((PyObject*)o);
879
- HamtNode_Bitmap *new = (HamtNode_Bitmap *)hamt_node_bitmap_new(
880
- state, Py_SIZE(o) - 2);
881
- if (new == NULL) {
882
- return NULL;
883
- }
884
-
885
- uint32_t idx = hamt_bitindex(o->b_bitmap, bit);
886
- uint32_t key_idx = 2 * idx;
887
- uint32_t val_idx = key_idx + 1;
888
- uint32_t i;
889
-
890
- for (i = 0; i < key_idx; i++) {
891
- new->b_array[i] = Py_XNewRef(o->b_array[i]);
892
- }
893
-
894
- assert(Py_SIZE(o) >= 0 && Py_SIZE(o) <= 32);
895
- for (i = val_idx + 1; i < (uint32_t)Py_SIZE(o); i++) {
896
- new->b_array[i - 2] = Py_XNewRef(o->b_array[i]);
897
- }
898
-
899
- new->b_bitmap = o->b_bitmap & ~bit;
900
- return new;
901
- }
902
-
903
- static HamtNode *
904
- hamt_node_new_bitmap_or_collision(
905
- hamt_module_state *state,
906
- uint32_t shift,
907
- PyObject *key1, PyObject *val1,
908
- int32_t key2_hash,
909
- PyObject *key2, PyObject *val2)
910
- {
911
- /* Helper method. Creates a new node for key1/val and key2/val2
912
- pairs.
913
-
914
- If key1 hash is equal to the hash of key2, a Collision node
915
- will be created. If they are not equal, a Bitmap node is
916
- created.
917
- */
918
-
919
- int32_t key1_hash = hamt_hash(key1);
920
- if (key1_hash == -1) {
921
- return NULL;
922
- }
923
-
924
- if (key1_hash == key2_hash) {
925
- HamtNode_Collision *n;
926
- n = (HamtNode_Collision *)hamt_node_collision_new(state, key1_hash, 4);
927
- if (n == NULL) {
928
- return NULL;
929
- }
930
-
931
- n->c_array[0] = Py_NewRef(key1);
932
- n->c_array[1] = Py_NewRef(val1);
933
-
934
- n->c_array[2] = Py_NewRef(key2);
935
- n->c_array[3] = Py_NewRef(val2);
936
-
937
- return (HamtNode *)n;
938
- }
939
- else {
940
- int added_leaf = 0;
941
- HamtNode *n = hamt_node_bitmap_new(state, 0);
942
- if (n == NULL) {
943
- return NULL;
944
- }
945
-
946
- HamtNode *n2 = hamt_node_assoc(
947
- n, shift, key1_hash, key1, val1, &added_leaf);
948
- Py_DECREF(n);
949
- if (n2 == NULL) {
950
- return NULL;
951
- }
952
-
953
- n = hamt_node_assoc(n2, shift, key2_hash, key2, val2, &added_leaf);
954
- Py_DECREF(n2);
955
- if (n == NULL) {
956
- return NULL;
957
- }
958
-
959
- return n;
960
- }
961
- }
962
-
963
- static HamtNode *
964
- hamt_node_bitmap_assoc(HamtNode_Bitmap *self,
965
- uint32_t shift, int32_t hash,
966
- PyObject *key, PyObject *val, int* added_leaf)
967
- {
968
- /* assoc operation for bitmap nodes.
969
-
970
- Return: a new node, or self if key/val already is in the
971
- collection.
972
-
973
- 'added_leaf' is later used in '_Hamt_Assoc' to determine if
974
- `hamt.set(key, val)` increased the size of the collection.
975
- */
976
-
977
- uint32_t bit = hamt_bitpos(hash, shift);
978
- uint32_t idx = hamt_bitindex(self->b_bitmap, bit);
979
-
980
- /* Bitmap node layout:
981
-
982
- +------+------+------+------+ --- +------+------+
983
- | key1 | val1 | key2 | val2 | ... | keyN | valN |
984
- +------+------+------+------+ --- +------+------+
985
- where `N < Py_SIZE(node)`.
986
-
987
- The `node->b_bitmap` field is a bitmap. For a given
988
- `(shift, hash)` pair we can determine:
989
-
990
- - If this node has the corresponding key/val slots.
991
- - The index of key/val slots.
992
- */
993
-
994
- if (self->b_bitmap & bit) {
995
- /* The key is set in this node */
996
-
997
- uint32_t key_idx = 2 * idx;
998
- uint32_t val_idx = key_idx + 1;
999
-
1000
- assert(val_idx < (size_t)Py_SIZE(self));
1001
-
1002
- PyObject *key_or_null = self->b_array[key_idx];
1003
- PyObject *val_or_node = self->b_array[val_idx];
1004
-
1005
- if (key_or_null == NULL) {
1006
- /* key is NULL. This means that we have a few keys
1007
- that have the same (hash, shift) pair. */
1008
-
1009
- assert(val_or_node != NULL);
1010
-
1011
- HamtNode *sub_node = hamt_node_assoc(
1012
- (HamtNode *)val_or_node,
1013
- shift + 5, hash, key, val, added_leaf);
1014
- if (sub_node == NULL) {
1015
- return NULL;
1016
- }
1017
-
1018
- if (val_or_node == (PyObject *)sub_node) {
1019
- Py_DECREF(sub_node);
1020
- return (HamtNode *)Py_NewRef(self);
1021
- }
1022
-
1023
- HamtNode_Bitmap *ret = hamt_node_bitmap_clone(self);
1024
- if (ret == NULL) {
1025
- return NULL;
1026
- }
1027
- Py_SETREF(ret->b_array[val_idx], (PyObject*)sub_node);
1028
- return (HamtNode *)ret;
1029
- }
1030
-
1031
- assert(key != NULL);
1032
- /* key is not NULL. This means that we have only one other
1033
- key in this collection that matches our hash for this shift. */
1034
-
1035
- int comp_err = PyObject_RichCompareBool(key, key_or_null, Py_EQ);
1036
- if (comp_err < 0) { /* exception in __eq__ */
1037
- return NULL;
1038
- }
1039
- if (comp_err == 1) { /* key == key_or_null */
1040
- if (val == val_or_node) {
1041
- /* we already have the same key/val pair; return self. */
1042
- return (HamtNode *)Py_NewRef(self);
1043
- }
1044
-
1045
- /* We're setting a new value for the key we had before.
1046
- Make a new bitmap node with a replaced value, and return it. */
1047
- HamtNode_Bitmap *ret = hamt_node_bitmap_clone(self);
1048
- if (ret == NULL) {
1049
- return NULL;
1050
- }
1051
- Py_SETREF(ret->b_array[val_idx], Py_NewRef(val));
1052
- return (HamtNode *)ret;
1053
- }
1054
-
1055
- /* It's a new key, and it has the same index as *one* another key.
1056
- We have a collision. We need to create a new node which will
1057
- combine the existing key and the key we're adding.
1058
-
1059
- `hamt_node_new_bitmap_or_collision` will either create a new
1060
- Collision node if the keys have identical hashes, or
1061
- a new Bitmap node.
1062
- */
1063
- HamtNode *sub_node = hamt_node_new_bitmap_or_collision(
1064
- get_hamt_state_from_obj((PyObject*)self),
1065
- shift + 5,
1066
- key_or_null, val_or_node, /* existing key/val */
1067
- hash,
1068
- key, val /* new key/val */
1069
- );
1070
- if (sub_node == NULL) {
1071
- return NULL;
1072
- }
1073
-
1074
- HamtNode_Bitmap *ret = hamt_node_bitmap_clone(self);
1075
- if (ret == NULL) {
1076
- Py_DECREF(sub_node);
1077
- return NULL;
1078
- }
1079
- Py_SETREF(ret->b_array[key_idx], NULL);
1080
- Py_SETREF(ret->b_array[val_idx], (PyObject *)sub_node);
1081
-
1082
- *added_leaf = 1;
1083
- return (HamtNode *)ret;
1084
- }
1085
- else {
1086
- /* There was no key before with the same (shift,hash). */
1087
-
1088
- uint32_t n = (uint32_t)_popcount32(self->b_bitmap);
1089
-
1090
- if (n >= 16) {
1091
- /* When we have a situation where we want to store more
1092
- than 16 nodes at one level of the tree, we no longer
1093
- want to use the Bitmap node with bitmap encoding.
1094
-
1095
- Instead we start using an Array node, which has
1096
- simpler (faster) implementation at the expense of
1097
- having preallocated 32 pointers for its keys/values
1098
- pairs.
1099
-
1100
- Small hamt objects (<30 keys) usually don't have any
1101
- Array nodes at all. Between ~30 and ~400 keys hamt
1102
- objects usually have one Array node, and usually it's
1103
- a root node.
1104
- */
1105
-
1106
- uint32_t jdx = hamt_mask(hash, shift);
1107
- /* 'jdx' is the index of where the new key should be added
1108
- in the new Array node we're about to create. */
1109
-
1110
- HamtNode *empty = NULL;
1111
- HamtNode_Array *new_node = NULL;
1112
- HamtNode *res = NULL;
1113
-
1114
- hamt_module_state *state = get_hamt_state_from_obj((PyObject*)self);
1115
-
1116
- /* Create a new Array node. */
1117
- new_node = (HamtNode_Array *)hamt_node_array_new(state, n + 1);
1118
- if (new_node == NULL) {
1119
- goto fin;
1120
- }
1121
-
1122
- /* Create an empty bitmap node for the next
1123
- hamt_node_assoc call. */
1124
- empty = hamt_node_bitmap_new(state, 0);
1125
- if (empty == NULL) {
1126
- goto fin;
1127
- }
1128
-
1129
- /* Make a new bitmap node for the key/val we're adding.
1130
- Set that bitmap node to new-array-node[jdx]. */
1131
- new_node->a_array[jdx] = hamt_node_assoc(
1132
- empty, shift + 5, hash, key, val, added_leaf);
1133
- if (new_node->a_array[jdx] == NULL) {
1134
- goto fin;
1135
- }
1136
-
1137
- /* Copy existing key/value pairs from the current Bitmap
1138
- node to the new Array node we've just created. */
1139
- Py_ssize_t i, j;
1140
- for (i = 0, j = 0; i < HAMT_ARRAY_NODE_SIZE; i++) {
1141
- if (((self->b_bitmap >> i) & 1) != 0) {
1142
- /* Ensure we don't accidentally override `jdx` element
1143
- we set few lines above.
1144
- */
1145
- assert(new_node->a_array[i] == NULL);
1146
-
1147
- if (self->b_array[j] == NULL) {
1148
- new_node->a_array[i] =
1149
- (HamtNode *)Py_NewRef(self->b_array[j + 1]);
1150
- }
1151
- else {
1152
- int32_t rehash = hamt_hash(self->b_array[j]);
1153
- if (rehash == -1) {
1154
- goto fin;
1155
- }
1156
-
1157
- new_node->a_array[i] = hamt_node_assoc(
1158
- empty, shift + 5,
1159
- rehash,
1160
- self->b_array[j],
1161
- self->b_array[j + 1],
1162
- added_leaf);
1163
-
1164
- if (new_node->a_array[i] == NULL) {
1165
- goto fin;
1166
- }
1167
- }
1168
- j += 2;
1169
- }
1170
- }
1171
-
1172
- VALIDATE_ARRAY_NODE(new_node)
1173
-
1174
- /* That's it! */
1175
- res = (HamtNode *)new_node;
1176
-
1177
- fin:
1178
- Py_XDECREF(empty);
1179
- if (res == NULL) {
1180
- Py_XDECREF(new_node);
1181
- }
1182
- return res;
1183
- }
1184
- else {
1185
- /* We have less than 16 keys at this level; let's just
1186
- create a new bitmap node out of this node with the
1187
- new key/val pair added. */
1188
-
1189
- uint32_t key_idx = 2 * idx;
1190
- uint32_t val_idx = key_idx + 1;
1191
- uint32_t i;
1192
-
1193
- *added_leaf = 1;
1194
-
1195
- /* Allocate new Bitmap node which can have one more key/val
1196
- pair in addition to what we have already. */
1197
- hamt_module_state *state = get_hamt_state_from_obj((PyObject*)self);
1198
- HamtNode_Bitmap *new_node =
1199
- (HamtNode_Bitmap *)hamt_node_bitmap_new(state, 2 * (n + 1));
1200
- if (new_node == NULL) {
1201
- return NULL;
1202
- }
1203
-
1204
- /* Copy all keys/values that will be before the new key/value
1205
- we are adding. */
1206
- for (i = 0; i < key_idx; i++) {
1207
- new_node->b_array[i] = Py_XNewRef(self->b_array[i]);
1208
- }
1209
-
1210
- /* Set the new key/value to the new Bitmap node. */
1211
- new_node->b_array[key_idx] = Py_NewRef(key);
1212
- new_node->b_array[val_idx] = Py_NewRef(val);
1213
-
1214
- /* Copy all keys/values that will be after the new key/value
1215
- we are adding. */
1216
- assert(Py_SIZE(self) >= 0 && Py_SIZE(self) <= 32);
1217
- for (i = key_idx; i < (uint32_t)Py_SIZE(self); i++) {
1218
- new_node->b_array[i + 2] = Py_XNewRef(self->b_array[i]);
1219
- }
1220
-
1221
- new_node->b_bitmap = self->b_bitmap | bit;
1222
- return (HamtNode *)new_node;
1223
- }
1224
- }
1225
- }
1226
-
1227
- static hamt_without_t
1228
- hamt_node_bitmap_without(HamtNode_Bitmap *self,
1229
- uint32_t shift, int32_t hash,
1230
- PyObject *key,
1231
- HamtNode **new_node)
1232
- {
1233
- uint32_t bit = hamt_bitpos(hash, shift);
1234
- if ((self->b_bitmap & bit) == 0) {
1235
- return W_NOT_FOUND;
1236
- }
1237
-
1238
- uint32_t idx = hamt_bitindex(self->b_bitmap, bit);
1239
-
1240
- uint32_t key_idx = 2 * idx;
1241
- uint32_t val_idx = key_idx + 1;
1242
-
1243
- PyObject *key_or_null = self->b_array[key_idx];
1244
- PyObject *val_or_node = self->b_array[val_idx];
1245
-
1246
- if (key_or_null == NULL) {
1247
- /* key == NULL means that 'value' is another tree node. */
1248
-
1249
- HamtNode *sub_node = NULL;
1250
-
1251
- hamt_without_t res = hamt_node_without(
1252
- (HamtNode *)val_or_node,
1253
- shift + 5, hash, key, &sub_node);
1254
-
1255
- switch (res) {
1256
- case W_EMPTY:
1257
- /* It's impossible for us to receive a W_EMPTY here:
1258
-
1259
- - Array nodes are converted to Bitmap nodes when
1260
- we delete 16th item from them;
1261
-
1262
- - Collision nodes are converted to Bitmap when
1263
- there is one item in them;
1264
-
1265
- - Bitmap node's without() inlines single-item
1266
- sub-nodes.
1267
-
1268
- So in no situation we can have a single-item
1269
- Bitmap child of another Bitmap node.
1270
- */
1271
- Py_UNREACHABLE();
1272
-
1273
- case W_NEWNODE: {
1274
- assert(sub_node != NULL);
1275
-
1276
- if (IS_BITMAP_NODE(sub_node)) {
1277
- HamtNode_Bitmap *sub_tree = (HamtNode_Bitmap *)sub_node;
1278
- if (hamt_node_bitmap_count(sub_tree) == 1 &&
1279
- sub_tree->b_array[0] != NULL)
1280
- {
1281
- /* A bitmap node with one key/value pair. Just
1282
- merge it into this node.
1283
-
1284
- Note that we don't inline Bitmap nodes that
1285
- have a NULL key -- those nodes point to another
1286
- tree level, and we cannot simply move tree levels
1287
- up or down.
1288
- */
1289
-
1290
- HamtNode_Bitmap *clone = hamt_node_bitmap_clone(self);
1291
- if (clone == NULL) {
1292
- Py_DECREF(sub_node);
1293
- return W_ERROR;
1294
- }
1295
-
1296
- PyObject *key = sub_tree->b_array[0];
1297
- PyObject *val = sub_tree->b_array[1];
1298
-
1299
- Py_XSETREF(clone->b_array[key_idx], Py_NewRef(key));
1300
- Py_SETREF(clone->b_array[val_idx], Py_NewRef(val));
1301
-
1302
- Py_DECREF(sub_tree);
1303
-
1304
- *new_node = (HamtNode *)clone;
1305
- return W_NEWNODE;
1306
- }
1307
- }
1308
-
1309
- #ifdef Py_DEBUG
1310
- /* Ensure that Collision.without implementation
1311
- converts to Bitmap nodes itself.
1312
- */
1313
- if (IS_COLLISION_NODE(sub_node)) {
1314
- assert(hamt_node_collision_count(
1315
- (HamtNode_Collision*)sub_node) > 1);
1316
- }
1317
- #endif
1318
-
1319
- HamtNode_Bitmap *clone = hamt_node_bitmap_clone(self);
1320
- if (clone == NULL) {
1321
- return W_ERROR;
1322
- }
1323
-
1324
- Py_SETREF(clone->b_array[val_idx],
1325
- (PyObject *)sub_node); /* borrow */
1326
-
1327
- *new_node = (HamtNode *)clone;
1328
- return W_NEWNODE;
1329
- }
1330
-
1331
- case W_ERROR:
1332
- case W_NOT_FOUND:
1333
- assert(sub_node == NULL);
1334
- return res;
1335
-
1336
- default:
1337
- Py_UNREACHABLE();
1338
- }
1339
- }
1340
- else {
1341
- /* We have a regular key/value pair */
1342
-
1343
- int cmp = PyObject_RichCompareBool(key_or_null, key, Py_EQ);
1344
- if (cmp < 0) {
1345
- return W_ERROR;
1346
- }
1347
- if (cmp == 0) {
1348
- return W_NOT_FOUND;
1349
- }
1350
-
1351
- if (hamt_node_bitmap_count(self) == 1) {
1352
- return W_EMPTY;
1353
- }
1354
-
1355
- *new_node = (HamtNode *)
1356
- hamt_node_bitmap_clone_without(self, bit);
1357
- if (*new_node == NULL) {
1358
- return W_ERROR;
1359
- }
1360
-
1361
- return W_NEWNODE;
1362
- }
1363
- }
1364
-
1365
- static hamt_find_t
1366
- hamt_node_bitmap_find(HamtNode_Bitmap *self,
1367
- uint32_t shift, int32_t hash,
1368
- PyObject *key, PyObject **val)
1369
- {
1370
- /* Lookup a key in a Bitmap node. */
1371
-
1372
- uint32_t bit = hamt_bitpos(hash, shift);
1373
- uint32_t idx;
1374
- uint32_t key_idx;
1375
- uint32_t val_idx;
1376
- PyObject *key_or_null;
1377
- PyObject *val_or_node;
1378
- int comp_err;
1379
-
1380
- if ((self->b_bitmap & bit) == 0) {
1381
- return F_NOT_FOUND;
1382
- }
1383
-
1384
- idx = hamt_bitindex(self->b_bitmap, bit);
1385
- key_idx = idx * 2;
1386
- val_idx = key_idx + 1;
1387
-
1388
- assert(val_idx < (size_t)Py_SIZE(self));
1389
-
1390
- key_or_null = self->b_array[key_idx];
1391
- val_or_node = self->b_array[val_idx];
1392
-
1393
- if (key_or_null == NULL) {
1394
- /* There are a few keys that have the same hash at the current shift
1395
- that match our key. Dispatch the lookup further down the tree. */
1396
- assert(val_or_node != NULL);
1397
- return hamt_node_find((HamtNode *)val_or_node,
1398
- shift + 5, hash, key, val);
1399
- }
1400
-
1401
- /* We have only one key -- a potential match. Let's compare if the
1402
- key we are looking at is equal to the key we are looking for. */
1403
- assert(key != NULL);
1404
- comp_err = PyObject_RichCompareBool(key, key_or_null, Py_EQ);
1405
- if (comp_err < 0) { /* exception in __eq__ */
1406
- return F_ERROR;
1407
- }
1408
- if (comp_err == 1) { /* key == key_or_null */
1409
- *val = val_or_node;
1410
- return F_FOUND;
1411
- }
1412
-
1413
- return F_NOT_FOUND;
1414
- }
1415
-
1416
- static int
1417
- hamt_node_bitmap_traverse(PyObject *op, visitproc visit, void *arg)
1418
- {
1419
- /* Bitmap's tp_traverse */
1420
-
1421
- HamtNode_Bitmap *self = _HamtNode_Bitmap_CAST(op);
1422
- for (Py_ssize_t i = Py_SIZE(self); --i >= 0;) {
1423
- Py_VISIT(self->b_array[i]);
1424
- }
1425
-
1426
- return 0;
1427
- }
1428
-
1429
- static void
1430
- hamt_node_bitmap_dealloc(PyObject *self)
1431
- {
1432
- /* Bitmap's tp_dealloc */
1433
-
1434
- HamtNode_Bitmap *node = _HamtNode_Bitmap_CAST(self);
1435
- Py_ssize_t i, len = Py_SIZE(self);
1436
-
1437
- if (len == 0) {
1438
- /* The empty node is managed by the module state. */
1439
- assert(node == get_hamt_state_from_obj(self)->empty_bitmap_node);
1440
- #ifdef Py_DEBUG
1441
- _Py_FatalRefcountError("deallocating the empty hamt node bitmap singleton");
1442
- #else
1443
- return;
1444
- #endif
1445
- }
1446
-
1447
- PyObject_GC_UnTrack(self);
1448
- Py_TRASHCAN_BEGIN(self, hamt_node_bitmap_dealloc)
1449
-
1450
- if (len > 0) {
1451
- i = len;
1452
- while (--i >= 0) {
1453
- Py_XDECREF(node->b_array[i]);
1454
- }
1455
- }
1456
-
1457
- Py_TYPE(self)->tp_free(self);
1458
- Py_TRASHCAN_END
1459
- }
1460
-
1461
- #ifdef Py_DEBUG
1462
- static int
1463
- hamt_node_bitmap_dump(HamtNode_Bitmap *node,
1464
- _PyUnicodeWriter *writer, int level)
1465
- {
1466
- /* Debug build: __dump__() method implementation for Bitmap nodes. */
1467
-
1468
- Py_ssize_t i;
1469
- PyObject *tmp1;
1470
- PyObject *tmp2;
1471
-
1472
- if (_hamt_dump_ident(writer, level + 1)) {
1473
- goto error;
1474
- }
1475
-
1476
- if (_hamt_dump_format(writer, "BitmapNode(size=%zd count=%zd ",
1477
- Py_SIZE(node), Py_SIZE(node) / 2))
1478
- {
1479
- goto error;
1480
- }
1481
-
1482
- tmp1 = PyLong_FromUnsignedLong(node->b_bitmap);
1483
- if (tmp1 == NULL) {
1484
- goto error;
1485
- }
1486
- // Format as binary using format spec 'b' (like f"{num:b}" in Python)
1487
- PyObject *format_spec = PyUnicode_FromString("b");
1488
- if (format_spec == NULL) {
1489
- Py_DECREF(tmp1);
1490
- goto error;
1491
- }
1492
- tmp2 = PyObject_Format(tmp1, format_spec);
1493
- Py_DECREF(format_spec);
1494
- Py_DECREF(tmp1);
1495
- if (tmp2 == NULL) {
1496
- goto error;
1497
- }
1498
- if (_hamt_dump_format(writer, "bitmap=%S id=%p):\n", tmp2, node)) {
1499
- Py_DECREF(tmp2);
1500
- goto error;
1501
- }
1502
- Py_DECREF(tmp2);
1503
-
1504
- for (i = 0; i < Py_SIZE(node); i += 2) {
1505
- PyObject *key_or_null = node->b_array[i];
1506
- PyObject *val_or_node = node->b_array[i + 1];
1507
-
1508
- if (_hamt_dump_ident(writer, level + 2)) {
1509
- goto error;
1510
- }
1511
-
1512
- if (key_or_null == NULL) {
1513
- if (_hamt_dump_format(writer, "NULL:\n")) {
1514
- goto error;
1515
- }
1516
-
1517
- if (hamt_node_dump((HamtNode *)val_or_node,
1518
- writer, level + 2))
1519
- {
1520
- goto error;
1521
- }
1522
- }
1523
- else {
1524
- if (_hamt_dump_format(writer, "%R: %R", key_or_null,
1525
- val_or_node))
1526
- {
1527
- goto error;
1528
- }
1529
- }
1530
-
1531
- if (_hamt_dump_format(writer, "\n")) {
1532
- goto error;
1533
- }
1534
- }
1535
-
1536
- return 0;
1537
- error:
1538
- return -1;
1539
- }
1540
- #endif /* Py_DEBUG */
1541
-
1542
-
1543
- /////////////////////////////////// Collision Node
1544
-
1545
-
1546
- static HamtNode *
1547
- hamt_node_collision_new(hamt_module_state *state, int32_t hash, Py_ssize_t size)
1548
- {
1549
- /* Create a new Collision node. */
1550
-
1551
- HamtNode_Collision *node;
1552
- Py_ssize_t i;
1553
-
1554
- assert(size >= 4);
1555
- assert(size % 2 == 0);
1556
-
1557
- node = PyObject_GC_NewVar(
1558
- HamtNode_Collision, state->Hamt_CollisionNode_Type, size);
1559
- if (node == NULL) {
1560
- return NULL;
1561
- }
1562
-
1563
- for (i = 0; i < size; i++) {
1564
- node->c_array[i] = NULL;
1565
- }
1566
-
1567
- Py_SET_SIZE(node, size);
1568
- node->c_hash = hash;
1569
-
1570
- PyObject_GC_Track(node);
1571
-
1572
- return (HamtNode *)node;
1573
- }
1574
-
1575
- static hamt_find_t
1576
- hamt_node_collision_find_index(HamtNode_Collision *self, PyObject *key,
1577
- Py_ssize_t *idx)
1578
- {
1579
- /* Lookup `key` in the Collision node `self`. Set the index of the
1580
- found key to 'idx'. */
1581
-
1582
- Py_ssize_t i;
1583
- PyObject *el;
1584
-
1585
- for (i = 0; i < Py_SIZE(self); i += 2) {
1586
- el = self->c_array[i];
1587
-
1588
- assert(el != NULL);
1589
- int cmp = PyObject_RichCompareBool(key, el, Py_EQ);
1590
- if (cmp < 0) {
1591
- return F_ERROR;
1592
- }
1593
- if (cmp == 1) {
1594
- *idx = i;
1595
- return F_FOUND;
1596
- }
1597
- }
1598
-
1599
- return F_NOT_FOUND;
1600
- }
1601
-
1602
- static HamtNode *
1603
- hamt_node_collision_assoc(HamtNode_Collision *self,
1604
- uint32_t shift, int32_t hash,
1605
- PyObject *key, PyObject *val, int* added_leaf)
1606
- {
1607
- /* Set a new key to this level (currently a Collision node)
1608
- of the tree. */
1609
-
1610
- if (hash == self->c_hash) {
1611
- /* The hash of the 'key' we are adding matches the hash of
1612
- other keys in this Collision node. */
1613
-
1614
- Py_ssize_t key_idx = -1;
1615
- hamt_find_t found;
1616
- HamtNode_Collision *new_node;
1617
- Py_ssize_t i;
1618
- hamt_module_state *state;
1619
-
1620
- /* Let's try to lookup the new 'key', maybe we already have it. */
1621
- found = hamt_node_collision_find_index(self, key, &key_idx);
1622
- switch (found) {
1623
- case F_ERROR:
1624
- /* Exception. */
1625
- return NULL;
1626
-
1627
- case F_NOT_FOUND:
1628
- /* This is a totally new key. Clone the current node,
1629
- add a new key/value to the cloned node. */
1630
-
1631
- state = get_hamt_state_from_obj((PyObject*)self);
1632
- new_node = (HamtNode_Collision *)hamt_node_collision_new(
1633
- state, self->c_hash, Py_SIZE(self) + 2);
1634
- if (new_node == NULL) {
1635
- return NULL;
1636
- }
1637
-
1638
- for (i = 0; i < Py_SIZE(self); i++) {
1639
- new_node->c_array[i] = Py_NewRef(self->c_array[i]);
1640
- }
1641
-
1642
- new_node->c_array[i] = Py_NewRef(key);
1643
- new_node->c_array[i + 1] = Py_NewRef(val);
1644
-
1645
- *added_leaf = 1;
1646
- return (HamtNode *)new_node;
1647
-
1648
- case F_FOUND:
1649
- /* There's a key which is equal to the key we are adding. */
1650
-
1651
- assert(key_idx >= 0);
1652
- assert(key_idx < Py_SIZE(self));
1653
- Py_ssize_t val_idx = key_idx + 1;
1654
-
1655
- if (self->c_array[val_idx] == val) {
1656
- /* We're setting a key/value pair that's already set. */
1657
- return (HamtNode *)Py_NewRef(self);
1658
- }
1659
-
1660
- /* We need to replace old value for the key
1661
- with a new value. Create a new Collision node.*/
1662
- hamt_module_state *state2 = get_hamt_state_from_obj((PyObject*)self);
1663
- new_node = (HamtNode_Collision *)hamt_node_collision_new(
1664
- state2, self->c_hash, Py_SIZE(self));
1665
- if (new_node == NULL) {
1666
- return NULL;
1667
- }
1668
-
1669
- /* Copy all elements of the old node to the new one. */
1670
- for (i = 0; i < Py_SIZE(self); i++) {
1671
- new_node->c_array[i] = Py_NewRef(self->c_array[i]);
1672
- }
1673
-
1674
- /* Replace the old value with the new value for the our key. */
1675
- Py_SETREF(new_node->c_array[val_idx], Py_NewRef(val));
1676
-
1677
- return (HamtNode *)new_node;
1678
-
1679
- default:
1680
- Py_UNREACHABLE();
1681
- }
1682
- }
1683
- else {
1684
- /* The hash of the new key is different from the hash that
1685
- all keys of this Collision node have.
1686
-
1687
- Create a Bitmap node inplace with two children:
1688
- key/value pair that we're adding, and the Collision node
1689
- we're replacing on this tree level.
1690
- */
1691
-
1692
- HamtNode_Bitmap *new_node;
1693
- HamtNode *assoc_res;
1694
-
1695
- hamt_module_state *state = get_hamt_state_from_obj((PyObject*)self);
1696
- new_node = (HamtNode_Bitmap *)hamt_node_bitmap_new(state, 2);
1697
- if (new_node == NULL) {
1698
- return NULL;
1699
- }
1700
- new_node->b_bitmap = hamt_bitpos(self->c_hash, shift);
1701
- new_node->b_array[1] = Py_NewRef(self);
1702
-
1703
- assoc_res = hamt_node_bitmap_assoc(
1704
- new_node, shift, hash, key, val, added_leaf);
1705
- Py_DECREF(new_node);
1706
- return assoc_res;
1707
- }
1708
- }
1709
-
1710
- static inline Py_ssize_t
1711
- hamt_node_collision_count(HamtNode_Collision *node)
1712
- {
1713
- return Py_SIZE(node) / 2;
1714
- }
1715
-
1716
- static hamt_without_t
1717
- hamt_node_collision_without(HamtNode_Collision *self,
1718
- uint32_t shift, int32_t hash,
1719
- PyObject *key,
1720
- HamtNode **new_node)
1721
- {
1722
- if (hash != self->c_hash) {
1723
- return W_NOT_FOUND;
1724
- }
1725
-
1726
- Py_ssize_t key_idx = -1;
1727
- hamt_find_t found = hamt_node_collision_find_index(self, key, &key_idx);
1728
-
1729
- switch (found) {
1730
- case F_ERROR:
1731
- return W_ERROR;
1732
-
1733
- case F_NOT_FOUND:
1734
- return W_NOT_FOUND;
1735
-
1736
- case F_FOUND:
1737
- assert(key_idx >= 0);
1738
- assert(key_idx < Py_SIZE(self));
1739
-
1740
- Py_ssize_t new_count = hamt_node_collision_count(self) - 1;
1741
-
1742
- if (new_count == 0) {
1743
- /* The node has only one key/value pair and it's for the
1744
- key we're trying to delete. So a new node will be empty
1745
- after the removal.
1746
- */
1747
- return W_EMPTY;
1748
- }
1749
-
1750
- if (new_count == 1) {
1751
- /* The node has two keys, and after deletion the
1752
- new Collision node would have one. Collision nodes
1753
- with one key shouldn't exist, so convert it to a
1754
- Bitmap node.
1755
- */
1756
- hamt_module_state *state = get_hamt_state_from_obj((PyObject*)self);
1757
- HamtNode_Bitmap *node = (HamtNode_Bitmap *)
1758
- hamt_node_bitmap_new(state, 2);
1759
- if (node == NULL) {
1760
- return W_ERROR;
1761
- }
1762
-
1763
- if (key_idx == 0) {
1764
- node->b_array[0] = Py_NewRef(self->c_array[2]);
1765
- node->b_array[1] = Py_NewRef(self->c_array[3]);
1766
- }
1767
- else {
1768
- assert(key_idx == 2);
1769
- node->b_array[0] = Py_NewRef(self->c_array[0]);
1770
- node->b_array[1] = Py_NewRef(self->c_array[1]);
1771
- }
1772
-
1773
- node->b_bitmap = hamt_bitpos(hash, shift);
1774
-
1775
- *new_node = (HamtNode *)node;
1776
- return W_NEWNODE;
1777
- }
1778
-
1779
- /* Allocate a new Collision node with capacity for one
1780
- less key/value pair */
1781
- hamt_module_state *state3 = get_hamt_state_from_obj((PyObject*)self);
1782
- HamtNode_Collision *new = (HamtNode_Collision *)
1783
- hamt_node_collision_new(
1784
- state3, self->c_hash, Py_SIZE(self) - 2);
1785
- if (new == NULL) {
1786
- return W_ERROR;
1787
- }
1788
-
1789
- /* Copy all other keys from `self` to `new` */
1790
- Py_ssize_t i;
1791
- for (i = 0; i < key_idx; i++) {
1792
- new->c_array[i] = Py_NewRef(self->c_array[i]);
1793
- }
1794
- for (i = key_idx + 2; i < Py_SIZE(self); i++) {
1795
- new->c_array[i - 2] = Py_NewRef(self->c_array[i]);
1796
- }
1797
-
1798
- *new_node = (HamtNode*)new;
1799
- return W_NEWNODE;
1800
-
1801
- default:
1802
- Py_UNREACHABLE();
1803
- }
1804
- }
1805
-
1806
- static hamt_find_t
1807
- hamt_node_collision_find(HamtNode_Collision *self,
1808
- uint32_t shift, int32_t hash,
1809
- PyObject *key, PyObject **val)
1810
- {
1811
- /* Lookup `key` in the Collision node `self`. Set the value
1812
- for the found key to 'val'. */
1813
-
1814
- Py_ssize_t idx = -1;
1815
- hamt_find_t res;
1816
-
1817
- res = hamt_node_collision_find_index(self, key, &idx);
1818
- if (res == F_ERROR || res == F_NOT_FOUND) {
1819
- return res;
1820
- }
1821
-
1822
- assert(idx >= 0);
1823
- assert(idx + 1 < Py_SIZE(self));
1824
-
1825
- *val = self->c_array[idx + 1];
1826
- assert(*val != NULL);
1827
-
1828
- return F_FOUND;
1829
- }
1830
-
1831
-
1832
- static int
1833
- hamt_node_collision_traverse(PyObject *op, visitproc visit, void *arg)
1834
- {
1835
- /* Collision's tp_traverse */
1836
-
1837
- HamtNode_Collision *self = _HamtNode_Collision_CAST(op);
1838
- for (Py_ssize_t i = Py_SIZE(self); --i >= 0; ) {
1839
- Py_VISIT(self->c_array[i]);
1840
- }
1841
-
1842
- return 0;
1843
- }
1844
-
1845
- static void
1846
- hamt_node_collision_dealloc(PyObject *self)
1847
- {
1848
- /* Collision's tp_dealloc */
1849
-
1850
- Py_ssize_t len = Py_SIZE(self);
1851
-
1852
- PyObject_GC_UnTrack(self);
1853
- Py_TRASHCAN_BEGIN(self, hamt_node_collision_dealloc)
1854
-
1855
- if (len > 0) {
1856
- HamtNode_Collision *node = _HamtNode_Collision_CAST(self);
1857
- while (--len >= 0) {
1858
- Py_XDECREF(node->c_array[len]);
1859
- }
1860
- }
1861
-
1862
- Py_TYPE(self)->tp_free(self);
1863
- Py_TRASHCAN_END
1864
- }
1865
-
1866
- #ifdef Py_DEBUG
1867
- static int
1868
- hamt_node_collision_dump(HamtNode_Collision *node,
1869
- _PyUnicodeWriter *writer, int level)
1870
- {
1871
- /* Debug build: __dump__() method implementation for Collision nodes. */
1872
-
1873
- Py_ssize_t i;
1874
-
1875
- if (_hamt_dump_ident(writer, level + 1)) {
1876
- goto error;
1877
- }
1878
-
1879
- if (_hamt_dump_format(writer, "CollisionNode(size=%zd id=%p):\n",
1880
- Py_SIZE(node), node))
1881
- {
1882
- goto error;
1883
- }
1884
-
1885
- for (i = 0; i < Py_SIZE(node); i += 2) {
1886
- PyObject *key = node->c_array[i];
1887
- PyObject *val = node->c_array[i + 1];
1888
-
1889
- if (_hamt_dump_ident(writer, level + 2)) {
1890
- goto error;
1891
- }
1892
-
1893
- if (_hamt_dump_format(writer, "%R: %R\n", key, val)) {
1894
- goto error;
1895
- }
1896
- }
1897
-
1898
- return 0;
1899
- error:
1900
- return -1;
1901
- }
1902
- #endif /* Py_DEBUG */
1903
-
1904
-
1905
- /////////////////////////////////// Array Node
1906
-
1907
-
1908
- static HamtNode *
1909
- hamt_node_array_new(hamt_module_state *state, Py_ssize_t count)
1910
- {
1911
- Py_ssize_t i;
1912
-
1913
- HamtNode_Array *node = PyObject_GC_New(
1914
- HamtNode_Array, state->Hamt_ArrayNode_Type);
1915
- if (node == NULL) {
1916
- return NULL;
1917
- }
1918
-
1919
- for (i = 0; i < HAMT_ARRAY_NODE_SIZE; i++) {
1920
- node->a_array[i] = NULL;
1921
- }
1922
-
1923
- node->a_count = count;
1924
-
1925
- PyObject_GC_Track(node);
1926
- return (HamtNode *)node;
1927
- }
1928
-
1929
- static HamtNode_Array *
1930
- hamt_node_array_clone(HamtNode_Array *node)
1931
- {
1932
- HamtNode_Array *clone;
1933
- Py_ssize_t i;
1934
-
1935
- VALIDATE_ARRAY_NODE(node)
1936
-
1937
- hamt_module_state *state = get_hamt_state_from_obj((PyObject*)node);
1938
-
1939
- /* Create a new Array node. */
1940
- clone = (HamtNode_Array *)hamt_node_array_new(state, node->a_count);
1941
- if (clone == NULL) {
1942
- return NULL;
1943
- }
1944
-
1945
- /* Copy all elements from the current Array node to the new one. */
1946
- for (i = 0; i < HAMT_ARRAY_NODE_SIZE; i++) {
1947
- clone->a_array[i] = (HamtNode*)Py_XNewRef(node->a_array[i]);
1948
- }
1949
-
1950
- VALIDATE_ARRAY_NODE(clone)
1951
- return clone;
1952
- }
1953
-
1954
- static HamtNode *
1955
- hamt_node_array_assoc(HamtNode_Array *self,
1956
- uint32_t shift, int32_t hash,
1957
- PyObject *key, PyObject *val, int* added_leaf)
1958
- {
1959
- /* Set a new key to this level (currently a Collision node)
1960
- of the tree.
1961
-
1962
- Array nodes don't store values, they can only point to
1963
- other nodes. They are simple arrays of 32 BaseNode pointers/
1964
- */
1965
-
1966
- uint32_t idx = hamt_mask(hash, shift);
1967
- HamtNode *node = self->a_array[idx];
1968
- HamtNode *child_node;
1969
- HamtNode_Array *new_node;
1970
- Py_ssize_t i;
1971
-
1972
- if (node == NULL) {
1973
- /* There's no child node for the given hash. Create a new
1974
- Bitmap node for this key. */
1975
-
1976
- HamtNode_Bitmap *empty = NULL;
1977
-
1978
- /* Get an empty Bitmap node to work with. */
1979
- hamt_module_state *state = get_hamt_state_from_obj((PyObject*)self);
1980
- empty = (HamtNode_Bitmap *)hamt_node_bitmap_new(state, 0);
1981
- if (empty == NULL) {
1982
- return NULL;
1983
- }
1984
-
1985
- /* Set key/val to the newly created empty Bitmap, thus
1986
- creating a new Bitmap node with our key/value pair. */
1987
- child_node = hamt_node_bitmap_assoc(
1988
- empty,
1989
- shift + 5, hash, key, val, added_leaf);
1990
- Py_DECREF(empty);
1991
- if (child_node == NULL) {
1992
- return NULL;
1993
- }
1994
-
1995
- /* Create a new Array node. */
1996
- new_node = (HamtNode_Array *)hamt_node_array_new(state, self->a_count + 1);
1997
- if (new_node == NULL) {
1998
- Py_DECREF(child_node);
1999
- return NULL;
2000
- }
2001
-
2002
- /* Copy all elements from the current Array node to the
2003
- new one. */
2004
- for (i = 0; i < HAMT_ARRAY_NODE_SIZE; i++) {
2005
- new_node->a_array[i] = (HamtNode*)Py_XNewRef(self->a_array[i]);
2006
- }
2007
-
2008
- assert(new_node->a_array[idx] == NULL);
2009
- new_node->a_array[idx] = child_node; /* borrow */
2010
- VALIDATE_ARRAY_NODE(new_node)
2011
- }
2012
- else {
2013
- /* There's a child node for the given hash.
2014
- Set the key to it./ */
2015
- child_node = hamt_node_assoc(
2016
- node, shift + 5, hash, key, val, added_leaf);
2017
- if (child_node == NULL) {
2018
- return NULL;
2019
- }
2020
- else if (child_node == (HamtNode *)self) {
2021
- Py_DECREF(child_node);
2022
- return (HamtNode *)self;
2023
- }
2024
-
2025
- new_node = hamt_node_array_clone(self);
2026
- if (new_node == NULL) {
2027
- Py_DECREF(child_node);
2028
- return NULL;
2029
- }
2030
-
2031
- Py_SETREF(new_node->a_array[idx], child_node); /* borrow */
2032
- VALIDATE_ARRAY_NODE(new_node)
2033
- }
2034
-
2035
- return (HamtNode *)new_node;
2036
- }
2037
-
2038
- static hamt_without_t
2039
- hamt_node_array_without(HamtNode_Array *self,
2040
- uint32_t shift, int32_t hash,
2041
- PyObject *key,
2042
- HamtNode **new_node)
2043
- {
2044
- uint32_t idx = hamt_mask(hash, shift);
2045
- HamtNode *node = self->a_array[idx];
2046
-
2047
- if (node == NULL) {
2048
- return W_NOT_FOUND;
2049
- }
2050
-
2051
- HamtNode *sub_node = NULL;
2052
- hamt_without_t res = hamt_node_without(
2053
- (HamtNode *)node,
2054
- shift + 5, hash, key, &sub_node);
2055
-
2056
- switch (res) {
2057
- case W_NOT_FOUND:
2058
- case W_ERROR:
2059
- assert(sub_node == NULL);
2060
- return res;
2061
-
2062
- case W_NEWNODE: {
2063
- /* We need to replace a node at the `idx` index.
2064
- Clone this node and replace.
2065
- */
2066
- assert(sub_node != NULL);
2067
-
2068
- HamtNode_Array *clone = hamt_node_array_clone(self);
2069
- if (clone == NULL) {
2070
- Py_DECREF(sub_node);
2071
- return W_ERROR;
2072
- }
2073
-
2074
- Py_SETREF(clone->a_array[idx], sub_node); /* borrow */
2075
- *new_node = (HamtNode*)clone; /* borrow */
2076
- return W_NEWNODE;
2077
- }
2078
-
2079
- case W_EMPTY: {
2080
- assert(sub_node == NULL);
2081
- /* We need to remove a node at the `idx` index.
2082
- Calculate the size of the replacement Array node.
2083
- */
2084
- Py_ssize_t new_count = self->a_count - 1;
2085
-
2086
- if (new_count == 0) {
2087
- return W_EMPTY;
2088
- }
2089
-
2090
- if (new_count >= 16) {
2091
- /* We convert Bitmap nodes to Array nodes, when a
2092
- Bitmap node needs to store more than 15 key/value
2093
- pairs. So we will create a new Array node if we
2094
- the number of key/values after deletion is still
2095
- greater than 15.
2096
- */
2097
-
2098
- HamtNode_Array *new = hamt_node_array_clone(self);
2099
- if (new == NULL) {
2100
- return W_ERROR;
2101
- }
2102
- new->a_count = new_count;
2103
- Py_CLEAR(new->a_array[idx]);
2104
-
2105
- *new_node = (HamtNode*)new; /* borrow */
2106
- return W_NEWNODE;
2107
- }
2108
-
2109
- /* New Array node would have less than 16 key/value
2110
- pairs. We need to create a replacement Bitmap node. */
2111
-
2112
- Py_ssize_t bitmap_size = new_count * 2;
2113
- uint32_t bitmap = 0;
2114
-
2115
- hamt_module_state *state = get_hamt_state_from_obj((PyObject*)self);
2116
- HamtNode_Bitmap *new = (HamtNode_Bitmap *)
2117
- hamt_node_bitmap_new(state, bitmap_size);
2118
- if (new == NULL) {
2119
- return W_ERROR;
2120
- }
2121
-
2122
- Py_ssize_t new_i = 0;
2123
- for (uint32_t i = 0; i < HAMT_ARRAY_NODE_SIZE; i++) {
2124
- if (i == idx) {
2125
- /* Skip the node we are deleting. */
2126
- continue;
2127
- }
2128
-
2129
- HamtNode *node = self->a_array[i];
2130
- if (node == NULL) {
2131
- /* Skip any missing nodes. */
2132
- continue;
2133
- }
2134
-
2135
- bitmap |= 1U << i;
2136
-
2137
- if (IS_BITMAP_NODE(node)) {
2138
- HamtNode_Bitmap *child = (HamtNode_Bitmap *)node;
2139
-
2140
- if (hamt_node_bitmap_count(child) == 1 &&
2141
- child->b_array[0] != NULL)
2142
- {
2143
- /* node is a Bitmap with one key/value pair, just
2144
- merge it into the new Bitmap node we're building.
2145
-
2146
- Note that we don't inline Bitmap nodes that
2147
- have a NULL key -- those nodes point to another
2148
- tree level, and we cannot simply move tree levels
2149
- up or down.
2150
- */
2151
- PyObject *key = child->b_array[0];
2152
- PyObject *val = child->b_array[1];
2153
-
2154
- new->b_array[new_i] = Py_NewRef(key);
2155
- new->b_array[new_i + 1] = Py_NewRef(val);
2156
- }
2157
- else {
2158
- new->b_array[new_i] = NULL;
2159
- new->b_array[new_i + 1] = Py_NewRef(node);
2160
- }
2161
- }
2162
- else {
2163
-
2164
- #ifdef Py_DEBUG
2165
- if (IS_COLLISION_NODE(node)) {
2166
- Py_ssize_t child_count = hamt_node_collision_count(
2167
- (HamtNode_Collision*)node);
2168
- assert(child_count > 1);
2169
- }
2170
- else if (IS_ARRAY_NODE(node)) {
2171
- assert(((HamtNode_Array*)node)->a_count >= 16);
2172
- }
2173
- #endif
2174
-
2175
- /* Just copy the node into our new Bitmap */
2176
- new->b_array[new_i] = NULL;
2177
- new->b_array[new_i + 1] = Py_NewRef(node);
2178
- }
2179
-
2180
- new_i += 2;
2181
- }
2182
-
2183
- new->b_bitmap = bitmap;
2184
- *new_node = (HamtNode*)new; /* borrow */
2185
- return W_NEWNODE;
2186
- }
2187
-
2188
- default:
2189
- Py_UNREACHABLE();
2190
- }
2191
- }
2192
-
2193
- static hamt_find_t
2194
- hamt_node_array_find(HamtNode_Array *self,
2195
- uint32_t shift, int32_t hash,
2196
- PyObject *key, PyObject **val)
2197
- {
2198
- /* Lookup `key` in the Array node `self`. Set the value
2199
- for the found key to 'val'. */
2200
-
2201
- uint32_t idx = hamt_mask(hash, shift);
2202
- HamtNode *node;
2203
-
2204
- node = self->a_array[idx];
2205
- if (node == NULL) {
2206
- return F_NOT_FOUND;
2207
- }
2208
-
2209
- /* Dispatch to the generic hamt_node_find */
2210
- return hamt_node_find(node, shift + 5, hash, key, val);
2211
- }
2212
-
2213
- static int
2214
- hamt_node_array_traverse(PyObject *op, visitproc visit, void *arg)
2215
- {
2216
- /* Array's tp_traverse */
2217
-
2218
- HamtNode_Array *self = _HamtNode_Array_CAST(op);
2219
- for (Py_ssize_t i = 0; i < HAMT_ARRAY_NODE_SIZE; i++) {
2220
- Py_VISIT(self->a_array[i]);
2221
- }
2222
-
2223
- return 0;
2224
- }
2225
-
2226
- static void
2227
- hamt_node_array_dealloc(PyObject *self)
2228
- {
2229
- /* Array's tp_dealloc */
2230
-
2231
- PyObject_GC_UnTrack(self);
2232
- Py_TRASHCAN_BEGIN(self, hamt_node_array_dealloc)
2233
-
2234
- HamtNode_Array *obj = _HamtNode_Array_CAST(self);
2235
- for (Py_ssize_t i = 0; i < HAMT_ARRAY_NODE_SIZE; i++) {
2236
- Py_XDECREF(obj->a_array[i]);
2237
- }
2238
-
2239
- Py_TYPE(self)->tp_free(self);
2240
- Py_TRASHCAN_END
2241
- }
2242
-
2243
- #ifdef Py_DEBUG
2244
- static int
2245
- hamt_node_array_dump(HamtNode_Array *node,
2246
- _PyUnicodeWriter *writer, int level)
2247
- {
2248
- /* Debug build: __dump__() method implementation for Array nodes. */
2249
-
2250
- Py_ssize_t i;
2251
-
2252
- if (_hamt_dump_ident(writer, level + 1)) {
2253
- goto error;
2254
- }
2255
-
2256
- if (_hamt_dump_format(writer, "ArrayNode(id=%p):\n", node)) {
2257
- goto error;
2258
- }
2259
-
2260
- for (i = 0; i < HAMT_ARRAY_NODE_SIZE; i++) {
2261
- if (node->a_array[i] == NULL) {
2262
- continue;
2263
- }
2264
-
2265
- if (_hamt_dump_ident(writer, level + 2)) {
2266
- goto error;
2267
- }
2268
-
2269
- if (_hamt_dump_format(writer, "%zd::\n", i)) {
2270
- goto error;
2271
- }
2272
-
2273
- if (hamt_node_dump(node->a_array[i], writer, level + 1)) {
2274
- goto error;
2275
- }
2276
-
2277
- if (_hamt_dump_format(writer, "\n")) {
2278
- goto error;
2279
- }
2280
- }
2281
-
2282
- return 0;
2283
- error:
2284
- return -1;
2285
- }
2286
- #endif /* Py_DEBUG */
2287
-
2288
-
2289
- /////////////////////////////////// Node Dispatch
2290
-
2291
-
2292
- static HamtNode *
2293
- hamt_node_assoc(HamtNode *node,
2294
- uint32_t shift, int32_t hash,
2295
- PyObject *key, PyObject *val, int* added_leaf)
2296
- {
2297
- /* Set key/value to the 'node' starting with the given shift/hash.
2298
- Return a new node, or the same node if key/value already
2299
- set.
2300
-
2301
- added_leaf will be set to 1 if key/value wasn't in the
2302
- tree before.
2303
-
2304
- This method automatically dispatches to the suitable
2305
- hamt_node_{nodetype}_assoc method.
2306
- */
2307
-
2308
- if (IS_BITMAP_NODE(node)) {
2309
- return hamt_node_bitmap_assoc(
2310
- (HamtNode_Bitmap *)node,
2311
- shift, hash, key, val, added_leaf);
2312
- }
2313
- else if (IS_ARRAY_NODE(node)) {
2314
- return hamt_node_array_assoc(
2315
- (HamtNode_Array *)node,
2316
- shift, hash, key, val, added_leaf);
2317
- }
2318
- else {
2319
- assert(IS_COLLISION_NODE(node));
2320
- return hamt_node_collision_assoc(
2321
- (HamtNode_Collision *)node,
2322
- shift, hash, key, val, added_leaf);
2323
- }
2324
- }
2325
-
2326
- static hamt_without_t
2327
- hamt_node_without(HamtNode *node,
2328
- uint32_t shift, int32_t hash,
2329
- PyObject *key,
2330
- HamtNode **new_node)
2331
- {
2332
- if (IS_BITMAP_NODE(node)) {
2333
- return hamt_node_bitmap_without(
2334
- (HamtNode_Bitmap *)node,
2335
- shift, hash, key,
2336
- new_node);
2337
- }
2338
- else if (IS_ARRAY_NODE(node)) {
2339
- return hamt_node_array_without(
2340
- (HamtNode_Array *)node,
2341
- shift, hash, key,
2342
- new_node);
2343
- }
2344
- else {
2345
- assert(IS_COLLISION_NODE(node));
2346
- return hamt_node_collision_without(
2347
- (HamtNode_Collision *)node,
2348
- shift, hash, key,
2349
- new_node);
2350
- }
2351
- }
2352
-
2353
- static hamt_find_t
2354
- hamt_node_find(HamtNode *node,
2355
- uint32_t shift, int32_t hash,
2356
- PyObject *key, PyObject **val)
2357
- {
2358
- /* Find the key in the node starting with the given shift/hash.
2359
-
2360
- If a value is found, the result will be set to F_FOUND, and
2361
- *val will point to the found value object.
2362
-
2363
- If a value wasn't found, the result will be set to F_NOT_FOUND.
2364
-
2365
- If an exception occurs during the call, the result will be F_ERROR.
2366
-
2367
- This method automatically dispatches to the suitable
2368
- hamt_node_{nodetype}_find method.
2369
- */
2370
-
2371
- if (IS_BITMAP_NODE(node)) {
2372
- return hamt_node_bitmap_find(
2373
- (HamtNode_Bitmap *)node,
2374
- shift, hash, key, val);
2375
-
2376
- }
2377
- else if (IS_ARRAY_NODE(node)) {
2378
- return hamt_node_array_find(
2379
- (HamtNode_Array *)node,
2380
- shift, hash, key, val);
2381
- }
2382
- else {
2383
- assert(IS_COLLISION_NODE(node));
2384
- return hamt_node_collision_find(
2385
- (HamtNode_Collision *)node,
2386
- shift, hash, key, val);
2387
- }
2388
- }
2389
-
2390
- #ifdef Py_DEBUG
2391
- static int
2392
- hamt_node_dump(HamtNode *node,
2393
- _PyUnicodeWriter *writer, int level)
2394
- {
2395
- /* Debug build: __dump__() method implementation for a node.
2396
-
2397
- This method automatically dispatches to the suitable
2398
- hamt_node_{nodetype})_dump method.
2399
- */
2400
-
2401
- if (IS_BITMAP_NODE(node)) {
2402
- return hamt_node_bitmap_dump(
2403
- (HamtNode_Bitmap *)node, writer, level);
2404
- }
2405
- else if (IS_ARRAY_NODE(node)) {
2406
- return hamt_node_array_dump(
2407
- (HamtNode_Array *)node, writer, level);
2408
- }
2409
- else {
2410
- assert(IS_COLLISION_NODE(node));
2411
- return hamt_node_collision_dump(
2412
- (HamtNode_Collision *)node, writer, level);
2413
- }
2414
- }
2415
- #endif /* Py_DEBUG */
2416
-
2417
-
2418
- /////////////////////////////////// Iterators: Machinery
2419
-
2420
-
2421
- static hamt_iter_t
2422
- hamt_iterator_next(HamtIteratorState *iter, PyObject **key, PyObject **val);
2423
-
2424
-
2425
- static void
2426
- hamt_iterator_init(HamtIteratorState *iter, HamtNode *root)
2427
- {
2428
- for (uint32_t i = 0; i < _Py_HAMT_MAX_TREE_DEPTH; i++) {
2429
- iter->i_nodes[i] = NULL;
2430
- iter->i_pos[i] = 0;
2431
- }
2432
-
2433
- iter->i_level = 0;
2434
-
2435
- /* Note: we don't incref/decref nodes in i_nodes. */
2436
- iter->i_nodes[0] = root;
2437
- }
2438
-
2439
- static hamt_iter_t
2440
- hamt_iterator_bitmap_next(HamtIteratorState *iter,
2441
- PyObject **key, PyObject **val)
2442
- {
2443
- int8_t level = iter->i_level;
2444
-
2445
- HamtNode_Bitmap *node = (HamtNode_Bitmap *)(iter->i_nodes[level]);
2446
- Py_ssize_t pos = iter->i_pos[level];
2447
-
2448
- if (pos + 1 >= Py_SIZE(node)) {
2449
- #ifdef Py_DEBUG
2450
- assert(iter->i_level >= 0);
2451
- iter->i_nodes[iter->i_level] = NULL;
2452
- #endif
2453
- iter->i_level--;
2454
- return hamt_iterator_next(iter, key, val);
2455
- }
2456
-
2457
- if (node->b_array[pos] == NULL) {
2458
- iter->i_pos[level] = pos + 2;
2459
-
2460
- int8_t next_level = level + 1;
2461
- assert(next_level < _Py_HAMT_MAX_TREE_DEPTH);
2462
- iter->i_level = next_level;
2463
- iter->i_pos[next_level] = 0;
2464
- iter->i_nodes[next_level] = (HamtNode *)
2465
- node->b_array[pos + 1];
2466
-
2467
- return hamt_iterator_next(iter, key, val);
2468
- }
2469
-
2470
- *key = node->b_array[pos];
2471
- *val = node->b_array[pos + 1];
2472
- iter->i_pos[level] = pos + 2;
2473
- return I_ITEM;
2474
- }
2475
-
2476
- static hamt_iter_t
2477
- hamt_iterator_collision_next(HamtIteratorState *iter,
2478
- PyObject **key, PyObject **val)
2479
- {
2480
- int8_t level = iter->i_level;
2481
-
2482
- HamtNode_Collision *node = (HamtNode_Collision *)(iter->i_nodes[level]);
2483
- Py_ssize_t pos = iter->i_pos[level];
2484
-
2485
- if (pos + 1 >= Py_SIZE(node)) {
2486
- #ifdef Py_DEBUG
2487
- assert(iter->i_level >= 0);
2488
- iter->i_nodes[iter->i_level] = NULL;
2489
- #endif
2490
- iter->i_level--;
2491
- return hamt_iterator_next(iter, key, val);
2492
- }
2493
-
2494
- *key = node->c_array[pos];
2495
- *val = node->c_array[pos + 1];
2496
- iter->i_pos[level] = pos + 2;
2497
- return I_ITEM;
2498
- }
2499
-
2500
- static hamt_iter_t
2501
- hamt_iterator_array_next(HamtIteratorState *iter,
2502
- PyObject **key, PyObject **val)
2503
- {
2504
- int8_t level = iter->i_level;
2505
-
2506
- HamtNode_Array *node = (HamtNode_Array *)(iter->i_nodes[level]);
2507
- Py_ssize_t pos = iter->i_pos[level];
2508
-
2509
- if (pos >= HAMT_ARRAY_NODE_SIZE) {
2510
- #ifdef Py_DEBUG
2511
- assert(iter->i_level >= 0);
2512
- iter->i_nodes[iter->i_level] = NULL;
2513
- #endif
2514
- iter->i_level--;
2515
- return hamt_iterator_next(iter, key, val);
2516
- }
2517
-
2518
- for (Py_ssize_t i = pos; i < HAMT_ARRAY_NODE_SIZE; i++) {
2519
- if (node->a_array[i] != NULL) {
2520
- iter->i_pos[level] = i + 1;
2521
-
2522
- int8_t next_level = level + 1;
2523
- assert(next_level < _Py_HAMT_MAX_TREE_DEPTH);
2524
- iter->i_pos[next_level] = 0;
2525
- iter->i_nodes[next_level] = node->a_array[i];
2526
- iter->i_level = next_level;
2527
-
2528
- return hamt_iterator_next(iter, key, val);
2529
- }
2530
- }
2531
-
2532
- #ifdef Py_DEBUG
2533
- assert(iter->i_level >= 0);
2534
- iter->i_nodes[iter->i_level] = NULL;
2535
- #endif
2536
-
2537
- iter->i_level--;
2538
- return hamt_iterator_next(iter, key, val);
2539
- }
2540
-
2541
- static hamt_iter_t
2542
- hamt_iterator_next(HamtIteratorState *iter, PyObject **key, PyObject **val)
2543
- {
2544
- if (iter->i_level < 0) {
2545
- return I_END;
2546
- }
2547
-
2548
- assert(iter->i_level < _Py_HAMT_MAX_TREE_DEPTH);
2549
-
2550
- HamtNode *current = iter->i_nodes[iter->i_level];
2551
-
2552
- if (IS_BITMAP_NODE(current)) {
2553
- return hamt_iterator_bitmap_next(iter, key, val);
2554
- }
2555
- else if (IS_ARRAY_NODE(current)) {
2556
- return hamt_iterator_array_next(iter, key, val);
2557
- }
2558
- else {
2559
- assert(IS_COLLISION_NODE(current));
2560
- return hamt_iterator_collision_next(iter, key, val);
2561
- }
2562
- }
2563
-
2564
-
2565
- /////////////////////////////////// HAMT high-level functions
2566
-
2567
-
2568
- HamtObject *
2569
- _Hamt_Assoc(HamtObject *o, PyObject *key, PyObject *val)
2570
- {
2571
- int32_t key_hash;
2572
- int added_leaf = 0;
2573
- HamtNode *new_root;
2574
- HamtObject *new_o;
2575
-
2576
- key_hash = hamt_hash(key);
2577
- if (key_hash == -1) {
2578
- return NULL;
2579
- }
2580
-
2581
- new_root = hamt_node_assoc(
2582
- (HamtNode *)(o->h_root),
2583
- 0, key_hash, key, val, &added_leaf);
2584
- if (new_root == NULL) {
2585
- return NULL;
2586
- }
2587
-
2588
- if (new_root == o->h_root) {
2589
- Py_DECREF(new_root);
2590
- return (HamtObject*)Py_NewRef(o);
2591
- }
2592
-
2593
- hamt_module_state *state = get_hamt_state_from_obj((PyObject*)o);
2594
- new_o = hamt_alloc(state);
2595
- if (new_o == NULL) {
2596
- Py_DECREF(new_root);
2597
- return NULL;
2598
- }
2599
-
2600
- new_o->h_root = new_root; /* borrow */
2601
- new_o->h_count = added_leaf ? o->h_count + 1 : o->h_count;
2602
-
2603
- return new_o;
2604
- }
2605
-
2606
- HamtObject *
2607
- _Hamt_Without(HamtObject *o, PyObject *key)
2608
- {
2609
- int32_t key_hash = hamt_hash(key);
2610
- if (key_hash == -1) {
2611
- return NULL;
2612
- }
2613
-
2614
- HamtNode *new_root = NULL;
2615
-
2616
- hamt_without_t res = hamt_node_without(
2617
- (HamtNode *)(o->h_root),
2618
- 0, key_hash, key,
2619
- &new_root);
2620
-
2621
- hamt_module_state *state = get_hamt_state_from_obj((PyObject*)o);
2622
-
2623
- switch (res) {
2624
- case W_ERROR:
2625
- return NULL;
2626
- case W_EMPTY: {
2627
- return _Hamt_New(state);
2628
- }
2629
- case W_NOT_FOUND:
2630
- return (HamtObject*)Py_NewRef(o);
2631
- case W_NEWNODE: {
2632
- assert(new_root != NULL);
2633
-
2634
- HamtObject *new_o = hamt_alloc(state);
2635
- if (new_o == NULL) {
2636
- Py_DECREF(new_root);
2637
- return NULL;
2638
- }
2639
-
2640
- new_o->h_root = new_root; /* borrow */
2641
- new_o->h_count = o->h_count - 1;
2642
- assert(new_o->h_count >= 0);
2643
- return new_o;
2644
- }
2645
- default:
2646
- Py_UNREACHABLE();
2647
- }
2648
- }
2649
-
2650
- static hamt_find_t
2651
- hamt_find(HamtObject *o, PyObject *key, PyObject **val)
2652
- {
2653
- if (o->h_count == 0) {
2654
- return F_NOT_FOUND;
2655
- }
2656
-
2657
- int32_t key_hash = hamt_hash(key);
2658
- if (key_hash == -1) {
2659
- return F_ERROR;
2660
- }
2661
-
2662
- return hamt_node_find(o->h_root, 0, key_hash, key, val);
2663
- }
2664
-
2665
- int
2666
- _Hamt_Find(HamtObject *o, PyObject *key, PyObject **val)
2667
- {
2668
- hamt_find_t res = hamt_find(o, key, val);
2669
- switch (res) {
2670
- case F_ERROR:
2671
- return -1;
2672
- case F_NOT_FOUND:
2673
- return 0;
2674
- case F_FOUND:
2675
- return 1;
2676
- default:
2677
- Py_UNREACHABLE();
2678
- }
2679
- }
2680
-
2681
- int
2682
- _Hamt_Eq(HamtObject *v, HamtObject *w)
2683
- {
2684
- if (v == w) {
2685
- return 1;
2686
- }
2687
-
2688
- if (v->h_count != w->h_count) {
2689
- return 0;
2690
- }
2691
-
2692
- Py_INCREF(v);
2693
- Py_INCREF(w);
2694
-
2695
- int res = 1;
2696
- HamtIteratorState iter;
2697
- hamt_iter_t iter_res;
2698
- hamt_find_t find_res;
2699
- PyObject *v_key;
2700
- PyObject *v_val;
2701
- PyObject *w_val;
2702
-
2703
- hamt_iterator_init(&iter, v->h_root);
2704
-
2705
- do {
2706
- iter_res = hamt_iterator_next(&iter, &v_key, &v_val);
2707
- if (iter_res == I_ITEM) {
2708
- find_res = hamt_find(w, v_key, &w_val);
2709
- switch (find_res) {
2710
- case F_ERROR:
2711
- res = -1;
2712
- goto done;
2713
-
2714
- case F_NOT_FOUND:
2715
- res = 0;
2716
- goto done;
2717
-
2718
- case F_FOUND: {
2719
- Py_INCREF(v_key);
2720
- Py_INCREF(v_val);
2721
- Py_INCREF(w_val);
2722
- int cmp = PyObject_RichCompareBool(v_val, w_val, Py_EQ);
2723
- Py_DECREF(v_key);
2724
- Py_DECREF(v_val);
2725
- Py_DECREF(w_val);
2726
- if (cmp < 0) {
2727
- res = -1;
2728
- goto done;
2729
- }
2730
- if (cmp == 0) {
2731
- res = 0;
2732
- goto done;
2733
- }
2734
- }
2735
- }
2736
- }
2737
- } while (iter_res != I_END);
2738
-
2739
- done:
2740
- Py_DECREF(v);
2741
- Py_DECREF(w);
2742
- return res;
2743
- }
2744
-
2745
- Py_ssize_t
2746
- _Hamt_Len(HamtObject *o)
2747
- {
2748
- return o->h_count;
2749
- }
2750
-
2751
- static HamtObject *
2752
- hamt_alloc(hamt_module_state *state)
2753
- {
2754
- HamtObject *o;
2755
- o = PyObject_GC_New(HamtObject, state->Hamt_Type);
2756
- if (o == NULL) {
2757
- return NULL;
2758
- }
2759
- o->h_count = 0;
2760
- o->h_root = NULL;
2761
- o->h_weakreflist = NULL;
2762
- PyObject_GC_Track(o);
2763
- return o;
2764
- }
2765
-
2766
- HamtObject *
2767
- _Hamt_New(hamt_module_state *state)
2768
- {
2769
- /* HAMT is an immutable object so we can easily cache an
2770
- empty instance. */
2771
- return (HamtObject*)Py_NewRef(state->empty_hamt);
2772
- }
2773
-
2774
- #ifdef Py_DEBUG
2775
- static PyObject *
2776
- hamt_dump(HamtObject *self)
2777
- {
2778
- _PyUnicodeWriter writer;
2779
-
2780
- _PyUnicodeWriter_Init(&writer);
2781
-
2782
- if (_hamt_dump_format(&writer, "HAMT(len=%zd):\n", self->h_count)) {
2783
- goto error;
2784
- }
2785
-
2786
- if (hamt_node_dump(self->h_root, &writer, 0)) {
2787
- goto error;
2788
- }
2789
-
2790
- return _PyUnicodeWriter_Finish(&writer);
2791
-
2792
- error:
2793
- _PyUnicodeWriter_Dealloc(&writer);
2794
- return NULL;
2795
- }
2796
- #endif /* Py_DEBUG */
2797
-
2798
-
2799
- /////////////////////////////////// Iterators: Shared Iterator Implementation
2800
-
2801
-
2802
- static int
2803
- hamt_baseiter_tp_clear(PyObject *op)
2804
- {
2805
- HamtIterator *it = (HamtIterator*)op;
2806
- Py_CLEAR(it->hi_obj);
2807
- return 0;
2808
- }
2809
-
2810
- static void
2811
- hamt_baseiter_tp_dealloc(PyObject *it)
2812
- {
2813
- PyObject_GC_UnTrack(it);
2814
- (void)hamt_baseiter_tp_clear(it);
2815
- PyObject_GC_Del(it);
2816
- }
2817
-
2818
- static int
2819
- hamt_baseiter_tp_traverse(PyObject *op, visitproc visit, void *arg)
2820
- {
2821
- HamtIterator *it = (HamtIterator*)op;
2822
- Py_VISIT(it->hi_obj);
2823
- return 0;
2824
- }
2825
-
2826
- static PyObject *
2827
- hamt_baseiter_tp_iternext(PyObject *op)
2828
- {
2829
- HamtIterator *it = (HamtIterator*)op;
2830
- PyObject *key;
2831
- PyObject *val;
2832
- hamt_iter_t res = hamt_iterator_next(&it->hi_iter, &key, &val);
2833
-
2834
- switch (res) {
2835
- case I_END:
2836
- PyErr_SetNone(PyExc_StopIteration);
2837
- return NULL;
2838
-
2839
- case I_ITEM: {
2840
- return (*(it->hi_yield))(key, val);
2841
- }
2842
-
2843
- default: {
2844
- Py_UNREACHABLE();
2845
- }
2846
- }
2847
- }
2848
-
2849
- static Py_ssize_t
2850
- hamt_baseiter_tp_len(HamtIterator *it)
2851
- {
2852
- return it->hi_obj->h_count;
2853
- }
2854
-
2855
- static PyObject *
2856
- hamt_baseiter_new(PyTypeObject *type, binaryfunc yield, HamtObject *o)
2857
- {
2858
- HamtIterator *it = PyObject_GC_New(HamtIterator, type);
2859
- if (it == NULL) {
2860
- return NULL;
2861
- }
2862
-
2863
- it->hi_obj = (HamtObject*)Py_NewRef(o);
2864
- it->hi_yield = yield;
2865
-
2866
- hamt_iterator_init(&it->hi_iter, o->h_root);
2867
-
2868
- return (PyObject*)it;
2869
- }
2870
-
2871
- #define ITERATOR_TYPE_SHARED_SLOTS \
2872
- .tp_basicsize = sizeof(HamtIterator), \
2873
- .tp_itemsize = 0, \
2874
- .tp_as_mapping = &HamtIterator_as_mapping, \
2875
- .tp_dealloc = hamt_baseiter_tp_dealloc, \
2876
- .tp_getattro = PyObject_GenericGetAttr, \
2877
- .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, \
2878
- .tp_traverse = hamt_baseiter_tp_traverse, \
2879
- .tp_clear = hamt_baseiter_tp_clear, \
2880
- .tp_iter = PyObject_SelfIter, \
2881
- .tp_iternext = hamt_baseiter_tp_iternext,
2882
-
2883
-
2884
- /////////////////////////////////// _HamtItems_Type
2885
-
2886
-
2887
- static PyType_Slot HamtItems_Type_slots[] = {
2888
- {Py_tp_dealloc, hamt_baseiter_tp_dealloc},
2889
- {Py_tp_getattro, PyObject_GenericGetAttr},
2890
- {Py_tp_traverse, hamt_baseiter_tp_traverse},
2891
- {Py_tp_clear, hamt_baseiter_tp_clear},
2892
- {Py_tp_iter, PyObject_SelfIter},
2893
- {Py_tp_iternext, hamt_baseiter_tp_iternext},
2894
- {Py_mp_length, hamt_baseiter_tp_len},
2895
- {0, NULL},
2896
- };
2897
-
2898
- static PyType_Spec HamtItems_Type_spec = {
2899
- .name = "hamt.items",
2900
- .basicsize = sizeof(HamtIterator),
2901
- .itemsize = 0,
2902
- .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
2903
- .slots = HamtItems_Type_slots,
2904
- };
2905
-
2906
- static PyObject *
2907
- hamt_iter_yield_items(PyObject *key, PyObject *val)
2908
- {
2909
- return PyTuple_Pack(2, key, val);
2910
- }
2911
-
2912
- PyObject *
2913
- _Hamt_NewIterItems(HamtObject *o)
2914
- {
2915
- hamt_module_state *state = get_hamt_state_from_obj((PyObject*)o);
2916
- return hamt_baseiter_new(
2917
- state->HamtItems_Type, hamt_iter_yield_items, o);
2918
- }
2919
-
2920
-
2921
- /////////////////////////////////// _HamtKeys_Type
2922
-
2923
-
2924
- static PyType_Slot HamtKeys_Type_slots[] = {
2925
- {Py_tp_dealloc, hamt_baseiter_tp_dealloc},
2926
- {Py_tp_getattro, PyObject_GenericGetAttr},
2927
- {Py_tp_traverse, hamt_baseiter_tp_traverse},
2928
- {Py_tp_clear, hamt_baseiter_tp_clear},
2929
- {Py_tp_iter, PyObject_SelfIter},
2930
- {Py_tp_iternext, hamt_baseiter_tp_iternext},
2931
- {Py_mp_length, hamt_baseiter_tp_len},
2932
- {0, NULL},
2933
- };
2934
-
2935
- static PyType_Spec HamtKeys_Type_spec = {
2936
- .name = "hamt.keys",
2937
- .basicsize = sizeof(HamtIterator),
2938
- .itemsize = 0,
2939
- .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
2940
- .slots = HamtKeys_Type_slots,
2941
- };
2942
-
2943
- static PyObject *
2944
- hamt_iter_yield_keys(PyObject *key, PyObject *val)
2945
- {
2946
- return Py_NewRef(key);
2947
- }
2948
-
2949
- PyObject *
2950
- _Hamt_NewIterKeys(HamtObject *o)
2951
- {
2952
- hamt_module_state *state = get_hamt_state_from_obj((PyObject*)o);
2953
- return hamt_baseiter_new(
2954
- state->HamtKeys_Type, hamt_iter_yield_keys, o);
2955
- }
2956
-
2957
-
2958
- /////////////////////////////////// _HamtValues_Type
2959
-
2960
-
2961
- static PyType_Slot HamtValues_Type_slots[] = {
2962
- {Py_tp_dealloc, hamt_baseiter_tp_dealloc},
2963
- {Py_tp_getattro, PyObject_GenericGetAttr},
2964
- {Py_tp_traverse, hamt_baseiter_tp_traverse},
2965
- {Py_tp_clear, hamt_baseiter_tp_clear},
2966
- {Py_tp_iter, PyObject_SelfIter},
2967
- {Py_tp_iternext, hamt_baseiter_tp_iternext},
2968
- {Py_mp_length, hamt_baseiter_tp_len},
2969
- {0, NULL},
2970
- };
2971
-
2972
- static PyType_Spec HamtValues_Type_spec = {
2973
- .name = "hamt.values",
2974
- .basicsize = sizeof(HamtIterator),
2975
- .itemsize = 0,
2976
- .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
2977
- .slots = HamtValues_Type_slots,
2978
- };
2979
-
2980
- static PyObject *
2981
- hamt_iter_yield_values(PyObject *key, PyObject *val)
2982
- {
2983
- return Py_NewRef(val);
2984
- }
2985
-
2986
- PyObject *
2987
- _Hamt_NewIterValues(HamtObject *o)
2988
- {
2989
- hamt_module_state *state = get_hamt_state_from_obj((PyObject*)o);
2990
- return hamt_baseiter_new(
2991
- state->HamtValues_Type, hamt_iter_yield_values, o);
2992
- }
2993
-
2994
-
2995
- /////////////////////////////////// _Hamt_Type
2996
-
2997
-
2998
- #ifdef Py_DEBUG
2999
- static PyObject *
3000
- hamt_dump(HamtObject *self);
3001
- #endif
3002
-
3003
- #define _HamtObject_CAST(op) ((HamtObject *)(op))
3004
-
3005
-
3006
- static PyObject *
3007
- hamt_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
3008
- {
3009
- hamt_module_state *state = get_hamt_state_from_type(type);
3010
- return (PyObject*)_Hamt_New(state);
3011
- }
3012
-
3013
- static int
3014
- hamt_tp_clear(PyObject *op)
3015
- {
3016
- HamtObject *self = _HamtObject_CAST(op);
3017
- Py_CLEAR(self->h_root);
3018
- return 0;
3019
- }
3020
-
3021
-
3022
- static int
3023
- hamt_tp_traverse(PyObject *op, visitproc visit, void *arg)
3024
- {
3025
- HamtObject *self = _HamtObject_CAST(op);
3026
- Py_VISIT(self->h_root);
3027
- return 0;
3028
- }
3029
-
3030
- static void
3031
- hamt_tp_dealloc(PyObject *self)
3032
- {
3033
- hamt_module_state *state = get_hamt_state_from_obj(self);
3034
- HamtObject *obj = _HamtObject_CAST(self);
3035
- if (obj == state->empty_hamt) {
3036
- /* The empty one is managed by the module state. */
3037
- #ifdef Py_DEBUG
3038
- _Py_FatalRefcountError("deallocating the empty hamt singleton");
3039
- #else
3040
- return;
3041
- #endif
3042
- }
3043
-
3044
- PyObject_GC_UnTrack(self);
3045
- if (obj->h_weakreflist != NULL) {
3046
- PyObject_ClearWeakRefs(self);
3047
- }
3048
- (void)hamt_tp_clear(self);
3049
- Py_TYPE(self)->tp_free(self);
3050
- }
3051
-
3052
-
3053
- static PyObject *
3054
- hamt_tp_richcompare(PyObject *v, PyObject *w, int op)
3055
- {
3056
- if (!Hamt_Check(v) || !Hamt_Check(w) || (op != Py_EQ && op != Py_NE)) {
3057
- Py_RETURN_NOTIMPLEMENTED;
3058
- }
3059
-
3060
- int res = _Hamt_Eq((HamtObject *)v, (HamtObject *)w);
3061
- if (res < 0) {
3062
- return NULL;
3063
- }
3064
-
3065
- if (op == Py_NE) {
3066
- res = !res;
3067
- }
3068
-
3069
- if (res) {
3070
- Py_RETURN_TRUE;
3071
- }
3072
- else {
3073
- Py_RETURN_FALSE;
3074
- }
3075
- }
3076
-
3077
- static int
3078
- hamt_tp_contains(PyObject *op, PyObject *key)
3079
- {
3080
- PyObject *val;
3081
- HamtObject *self = _HamtObject_CAST(op);
3082
- return _Hamt_Find(self, key, &val);
3083
- }
3084
-
3085
- static PyObject *
3086
- hamt_tp_subscript(PyObject *op, PyObject *key)
3087
- {
3088
- PyObject *val;
3089
- HamtObject *self = _HamtObject_CAST(op);
3090
- hamt_find_t res = hamt_find(self, key, &val);
3091
- switch (res) {
3092
- case F_ERROR:
3093
- return NULL;
3094
- case F_FOUND:
3095
- return Py_NewRef(val);
3096
- case F_NOT_FOUND:
3097
- PyErr_SetObject(PyExc_KeyError, key);
3098
- return NULL;
3099
- default:
3100
- Py_UNREACHABLE();
3101
- }
3102
- }
3103
-
3104
- static Py_ssize_t
3105
- hamt_tp_len(PyObject *op)
3106
- {
3107
- HamtObject *self = _HamtObject_CAST(op);
3108
- return _Hamt_Len(self);
3109
- }
3110
-
3111
- static PyObject *
3112
- hamt_tp_iter(PyObject *op)
3113
- {
3114
- HamtObject *self = _HamtObject_CAST(op);
3115
- return _Hamt_NewIterKeys(self);
3116
- }
3117
-
3118
- static PyObject *
3119
- hamt_py_set(PyObject *op, PyObject *args)
3120
- {
3121
- PyObject *key;
3122
- PyObject *val;
3123
-
3124
- if (!PyArg_UnpackTuple(args, "set", 2, 2, &key, &val)) {
3125
- return NULL;
3126
- }
3127
-
3128
- HamtObject *self = _HamtObject_CAST(op);
3129
- return (PyObject *)_Hamt_Assoc(self, key, val);
3130
- }
3131
-
3132
- static PyObject *
3133
- hamt_py_get(PyObject *op, PyObject *args)
3134
- {
3135
- PyObject *key;
3136
- PyObject *def = NULL;
3137
-
3138
- if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &def)) {
3139
- return NULL;
3140
- }
3141
-
3142
- PyObject *val = NULL;
3143
- HamtObject *self = _HamtObject_CAST(op);
3144
- hamt_find_t res = hamt_find(self, key, &val);
3145
- switch (res) {
3146
- case F_ERROR:
3147
- return NULL;
3148
- case F_FOUND:
3149
- return Py_NewRef(val);
3150
- case F_NOT_FOUND:
3151
- if (def == NULL) {
3152
- Py_RETURN_NONE;
3153
- }
3154
- return Py_NewRef(def);
3155
- default:
3156
- Py_UNREACHABLE();
3157
- }
3158
- }
3159
-
3160
- static PyObject *
3161
- hamt_py_delete(PyObject *op, PyObject *key)
3162
- {
3163
- HamtObject *self = _HamtObject_CAST(op);
3164
- return (PyObject *)_Hamt_Without(self, key);
3165
- }
3166
-
3167
- static PyObject *
3168
- hamt_py_items(PyObject *op, PyObject *args)
3169
- {
3170
- HamtObject *self = _HamtObject_CAST(op);
3171
- return _Hamt_NewIterItems(self);
3172
- }
3173
-
3174
- static PyObject *
3175
- hamt_py_values(PyObject *op, PyObject *args)
3176
- {
3177
- HamtObject *self = _HamtObject_CAST(op);
3178
- return _Hamt_NewIterValues(self);
3179
- }
3180
-
3181
- static PyObject *
3182
- hamt_py_keys(PyObject *op, PyObject *Py_UNUSED(args))
3183
- {
3184
- HamtObject *self = _HamtObject_CAST(op);
3185
- return _Hamt_NewIterKeys(self);
3186
- }
3187
-
3188
- #ifdef Py_DEBUG
3189
- static PyObject *
3190
- hamt_py_dump(PyObject *op, PyObject *Py_UNUSED(args))
3191
- {
3192
- HamtObject *self = _HamtObject_CAST(op);
3193
- return hamt_dump(self);
3194
- }
3195
- #endif
3196
-
3197
-
3198
- static PyMethodDef Hamt_methods[] = {
3199
- {"set", hamt_py_set, METH_VARARGS, NULL},
3200
- {"get", hamt_py_get, METH_VARARGS, NULL},
3201
- {"delete", hamt_py_delete, METH_O, NULL},
3202
- {"items", hamt_py_items, METH_NOARGS, NULL},
3203
- {"keys", hamt_py_keys, METH_NOARGS, NULL},
3204
- {"values", hamt_py_values, METH_NOARGS, NULL},
3205
- #ifdef Py_DEBUG
3206
- {"__dump__", hamt_py_dump, METH_NOARGS, NULL},
3207
- #endif
3208
- {NULL, NULL}
3209
- };
3210
-
3211
- static PyType_Slot Hamt_Type_slots[] = {
3212
- {Py_tp_dealloc, hamt_tp_dealloc},
3213
- {Py_tp_getattro, PyObject_GenericGetAttr},
3214
- {Py_tp_traverse, hamt_tp_traverse},
3215
- {Py_tp_clear, hamt_tp_clear},
3216
- {Py_tp_new, hamt_tp_new},
3217
- {Py_tp_iter, hamt_tp_iter},
3218
- {Py_tp_richcompare, hamt_tp_richcompare},
3219
- {Py_tp_hash, PyObject_HashNotImplemented},
3220
- {Py_tp_methods, Hamt_methods},
3221
- {Py_mp_length, hamt_tp_len},
3222
- {Py_mp_subscript, hamt_tp_subscript},
3223
- {Py_sq_contains, hamt_tp_contains},
3224
- {0, NULL},
3225
- };
3226
-
3227
- static PyType_Spec Hamt_Type_spec = {
3228
- .name = "hamt.hamt",
3229
- .basicsize = sizeof(HamtObject),
3230
- .itemsize = 0,
3231
- .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
3232
- .slots = Hamt_Type_slots,
3233
- };
3234
-
3235
-
3236
- /////////////////////////////////// Tree Node Types
3237
-
3238
-
3239
- static PyType_Slot Hamt_ArrayNode_Type_slots[] = {
3240
- {Py_tp_dealloc, hamt_node_array_dealloc},
3241
- {Py_tp_getattro, PyObject_GenericGetAttr},
3242
- {Py_tp_traverse, hamt_node_array_traverse},
3243
- {Py_tp_free, PyObject_GC_Del},
3244
- {Py_tp_hash, PyObject_HashNotImplemented},
3245
- {0, NULL},
3246
- };
3247
-
3248
- static PyType_Spec Hamt_ArrayNode_Type_spec = {
3249
- .name = "hamt.hamt_array_node",
3250
- .basicsize = sizeof(HamtNode_Array),
3251
- .itemsize = 0,
3252
- .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
3253
- .slots = Hamt_ArrayNode_Type_slots,
3254
- };
3255
-
3256
- static PyType_Slot Hamt_BitmapNode_Type_slots[] = {
3257
- {Py_tp_dealloc, hamt_node_bitmap_dealloc},
3258
- {Py_tp_getattro, PyObject_GenericGetAttr},
3259
- {Py_tp_traverse, hamt_node_bitmap_traverse},
3260
- {Py_tp_free, PyObject_GC_Del},
3261
- {Py_tp_hash, PyObject_HashNotImplemented},
3262
- {0, NULL},
3263
- };
3264
-
3265
- static PyType_Spec Hamt_BitmapNode_Type_spec = {
3266
- .name = "hamt.hamt_bitmap_node",
3267
- .basicsize = sizeof(HamtNode_Bitmap) - sizeof(PyObject *),
3268
- .itemsize = sizeof(PyObject *),
3269
- .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
3270
- .slots = Hamt_BitmapNode_Type_slots,
3271
- };
3272
-
3273
- static PyType_Slot Hamt_CollisionNode_Type_slots[] = {
3274
- {Py_tp_dealloc, hamt_node_collision_dealloc},
3275
- {Py_tp_getattro, PyObject_GenericGetAttr},
3276
- {Py_tp_traverse, hamt_node_collision_traverse},
3277
- {Py_tp_free, PyObject_GC_Del},
3278
- {Py_tp_hash, PyObject_HashNotImplemented},
3279
- {0, NULL},
3280
- };
3281
-
3282
- static PyType_Spec Hamt_CollisionNode_Type_spec = {
3283
- .name = "hamt.hamt_collision_node",
3284
- .basicsize = sizeof(HamtNode_Collision) - sizeof(PyObject *),
3285
- .itemsize = sizeof(PyObject *),
3286
- .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
3287
- .slots = Hamt_CollisionNode_Type_slots,
3288
- };
3289
-
3290
- ////
3291
-
3292
- static PyObject *
3293
- py_hamt_new(PyObject *self, PyObject *args)
3294
- {
3295
- if (!PyArg_ParseTuple(args, "")) {
3296
- return NULL;
3297
- }
3298
-
3299
- hamt_module_state *state = get_hamt_module_state(self);
3300
- HamtObject *hamt = _Hamt_New(state);
3301
- if (!hamt) {
3302
- return NULL;
3303
- }
3304
-
3305
- return (PyObject *)hamt;
3306
- }
3307
-
3308
- static PyObject *
3309
- py_hamt_assoc(PyObject *self, PyObject *args)
3310
- {
3311
- PyObject *hamt_obj;
3312
- PyObject *key;
3313
- PyObject *val;
3314
-
3315
- if (!PyArg_ParseTuple(args, "OOO", &hamt_obj, &key, &val)) {
3316
- return NULL;
3317
- }
3318
-
3319
- if (!Hamt_Check(hamt_obj)) {
3320
- PyErr_SetString(PyExc_TypeError, "first argument must be a HAMT object");
3321
- return NULL;
3322
- }
3323
-
3324
- HamtObject *result = _Hamt_Assoc((HamtObject *)hamt_obj, key, val);
3325
- if (!result) {
3326
- return NULL;
3327
- }
3328
-
3329
- return (PyObject *)result;
3330
- }
3331
-
3332
- static PyObject *
3333
- py_hamt_without(PyObject *self, PyObject *args)
3334
- {
3335
- PyObject *hamt_obj;
3336
- PyObject *key;
3337
-
3338
- if (!PyArg_ParseTuple(args, "OO", &hamt_obj, &key)) {
3339
- return NULL;
3340
- }
3341
-
3342
- if (!Hamt_Check(hamt_obj)) {
3343
- PyErr_SetString(PyExc_TypeError, "first argument must be a HAMT object");
3344
- return NULL;
3345
- }
3346
-
3347
- HamtObject *result = _Hamt_Without((HamtObject *)hamt_obj, key);
3348
- if (!result) {
3349
- return NULL;
3350
- }
3351
-
3352
- return (PyObject *)result;
3353
- }
3354
-
3355
- static PyObject *
3356
- py_hamt_find(PyObject *self, PyObject *args)
3357
- {
3358
- PyObject *hamt_obj;
3359
- PyObject *key;
3360
-
3361
- if (!PyArg_ParseTuple(args, "OO", &hamt_obj, &key)) {
3362
- return NULL;
3363
- }
3364
-
3365
- if (!Hamt_Check(hamt_obj)) {
3366
- PyErr_SetString(PyExc_TypeError, "first argument must be a HAMT object");
3367
- return NULL;
3368
- }
3369
-
3370
- PyObject *val = NULL;
3371
- int result = _Hamt_Find((HamtObject *)hamt_obj, key, &val);
3372
-
3373
- if (result == -1) {
3374
- return NULL;
3375
- }
3376
-
3377
- if (result == 0) {
3378
- Py_RETURN_NONE;
3379
- }
3380
-
3381
- // result == 1, key found, val is a borrowed reference
3382
- Py_INCREF(val);
3383
- return val;
3384
- }
3385
-
3386
- static PyObject *
3387
- py_hamt_eq(PyObject *self, PyObject *args)
3388
- {
3389
- PyObject *v_obj;
3390
- PyObject *w_obj;
3391
-
3392
- if (!PyArg_ParseTuple(args, "OO", &v_obj, &w_obj)) {
3393
- return NULL;
3394
- }
3395
-
3396
- if (!Hamt_Check(v_obj)) {
3397
- PyErr_SetString(PyExc_TypeError, "first argument must be a HAMT object");
3398
- return NULL;
3399
- }
3400
-
3401
- if (!Hamt_Check(w_obj)) {
3402
- PyErr_SetString(PyExc_TypeError, "second argument must be a HAMT object");
3403
- return NULL;
3404
- }
3405
-
3406
- int result = _Hamt_Eq((HamtObject *)v_obj, (HamtObject *)w_obj);
3407
-
3408
- if (result == -1) {
3409
- return NULL;
3410
- }
3411
-
3412
- if (result == 0) {
3413
- Py_RETURN_FALSE;
3414
- }
3415
-
3416
- Py_RETURN_TRUE;
3417
- }
3418
-
3419
- static PyObject *
3420
- py_hamt_len(PyObject *self, PyObject *args)
3421
- {
3422
- PyObject *hamt_obj;
3423
-
3424
- if (!PyArg_ParseTuple(args, "O", &hamt_obj)) {
3425
- return NULL;
3426
- }
3427
-
3428
- if (!Hamt_Check(hamt_obj)) {
3429
- PyErr_SetString(PyExc_TypeError, "argument must be a HAMT object");
3430
- return NULL;
3431
- }
3432
-
3433
- Py_ssize_t len = _Hamt_Len((HamtObject *)hamt_obj);
3434
- return PyLong_FromSsize_t(len);
3435
- }
3436
-
3437
- static PyObject *
3438
- py_hamt_iter_keys(PyObject *self, PyObject *args)
3439
- {
3440
- PyObject *hamt_obj;
3441
-
3442
- if (!PyArg_ParseTuple(args, "O", &hamt_obj)) {
3443
- return NULL;
3444
- }
3445
-
3446
- if (!Hamt_Check(hamt_obj)) {
3447
- PyErr_SetString(PyExc_TypeError, "argument must be a HAMT object");
3448
- return NULL;
3449
- }
3450
-
3451
- PyObject *iter = _Hamt_NewIterKeys((HamtObject *)hamt_obj);
3452
- if (!iter) {
3453
- return NULL;
3454
- }
3455
-
3456
- return iter;
3457
- }
3458
-
3459
- static PyObject *
3460
- py_hamt_iter_values(PyObject *self, PyObject *args)
3461
- {
3462
- PyObject *hamt_obj;
3463
-
3464
- if (!PyArg_ParseTuple(args, "O", &hamt_obj)) {
3465
- return NULL;
3466
- }
3467
-
3468
- if (!Hamt_Check(hamt_obj)) {
3469
- PyErr_SetString(PyExc_TypeError, "argument must be a HAMT object");
3470
- return NULL;
3471
- }
3472
-
3473
- PyObject *iter = _Hamt_NewIterValues((HamtObject *)hamt_obj);
3474
- if (!iter) {
3475
- return NULL;
3476
- }
3477
-
3478
- return iter;
3479
- }
3480
-
3481
- static PyObject *
3482
- py_hamt_iter_items(PyObject *self, PyObject *args)
3483
- {
3484
- PyObject *hamt_obj;
3485
-
3486
- if (!PyArg_ParseTuple(args, "O", &hamt_obj)) {
3487
- return NULL;
3488
- }
3489
-
3490
- if (!Hamt_Check(hamt_obj)) {
3491
- PyErr_SetString(PyExc_TypeError, "argument must be a HAMT object");
3492
- return NULL;
3493
- }
3494
-
3495
- PyObject *iter = _Hamt_NewIterItems((HamtObject *)hamt_obj);
3496
- if (!iter) {
3497
- return NULL;
3498
- }
3499
-
3500
- return iter;
3501
- }
3502
-
3503
- //
3504
-
3505
- static int _hamt_module_exec(PyObject *module)
3506
- {
3507
- hamt_module_state *state = get_hamt_module_state(module);
3508
-
3509
- /* Initialize type objects */
3510
- state->Hamt_Type = (PyTypeObject *)PyType_FromModuleAndSpec(module, &Hamt_Type_spec, NULL);
3511
- if (state->Hamt_Type == NULL) {
3512
- return -1;
3513
- }
3514
- if (PyModule_AddType(module, state->Hamt_Type) < 0) {
3515
- return -1;
3516
- }
3517
-
3518
- state->HamtItems_Type = (PyTypeObject *)PyType_FromModuleAndSpec(module, &HamtItems_Type_spec, NULL);
3519
- if (state->HamtItems_Type == NULL) {
3520
- return -1;
3521
- }
3522
-
3523
- state->HamtKeys_Type = (PyTypeObject *)PyType_FromModuleAndSpec(module, &HamtKeys_Type_spec, NULL);
3524
- if (state->HamtKeys_Type == NULL) {
3525
- return -1;
3526
- }
3527
-
3528
- state->HamtValues_Type = (PyTypeObject *)PyType_FromModuleAndSpec(module, &HamtValues_Type_spec, NULL);
3529
- if (state->HamtValues_Type == NULL) {
3530
- return -1;
3531
- }
3532
-
3533
- state->Hamt_ArrayNode_Type = (PyTypeObject *)PyType_FromModuleAndSpec(module, &Hamt_ArrayNode_Type_spec, NULL);
3534
- if (state->Hamt_ArrayNode_Type == NULL) {
3535
- return -1;
3536
- }
3537
-
3538
- state->Hamt_BitmapNode_Type = (PyTypeObject *)PyType_FromModuleAndSpec(module, &Hamt_BitmapNode_Type_spec, NULL);
3539
- if (state->Hamt_BitmapNode_Type == NULL) {
3540
- return -1;
3541
- }
3542
-
3543
- state->Hamt_CollisionNode_Type = (PyTypeObject *)PyType_FromModuleAndSpec(module, &Hamt_CollisionNode_Type_spec, NULL);
3544
- if (state->Hamt_CollisionNode_Type == NULL) {
3545
- return -1;
3546
- }
3547
-
3548
- /* Initialize singleton objects */
3549
-
3550
- /* Create empty bitmap node */
3551
- state->empty_bitmap_node = PyObject_GC_New(HamtNode_Bitmap, state->Hamt_BitmapNode_Type);
3552
- if (state->empty_bitmap_node == NULL) {
3553
- return -1;
3554
- }
3555
- Py_SET_SIZE(state->empty_bitmap_node, 0);
3556
- state->empty_bitmap_node->b_bitmap = 0;
3557
- PyObject_GC_Track(state->empty_bitmap_node);
3558
-
3559
- /* Create empty HAMT object */
3560
- state->empty_hamt = PyObject_GC_New(HamtObject, state->Hamt_Type);
3561
- if (state->empty_hamt == NULL) {
3562
- return -1;
3563
- }
3564
- state->empty_hamt->h_root = (HamtNode *)Py_NewRef(state->empty_bitmap_node);
3565
- state->empty_hamt->h_weakreflist = NULL;
3566
- state->empty_hamt->h_count = 0;
3567
- PyObject_GC_Track(state->empty_hamt);
3568
-
3569
- return 0;
3570
- }
3571
-
3572
- static int _hamt_module_traverse(PyObject *module, visitproc visit, void *arg)
3573
- {
3574
- hamt_module_state *state = get_hamt_module_state(module);
3575
-
3576
- /* Visit type objects */
3577
- Py_VISIT(state->Hamt_Type);
3578
- Py_VISIT(state->HamtItems_Type);
3579
- Py_VISIT(state->HamtKeys_Type);
3580
- Py_VISIT(state->HamtValues_Type);
3581
- Py_VISIT(state->Hamt_ArrayNode_Type);
3582
- Py_VISIT(state->Hamt_BitmapNode_Type);
3583
- Py_VISIT(state->Hamt_CollisionNode_Type);
3584
-
3585
- /* Visit singleton objects */
3586
- Py_VISIT(state->empty_hamt);
3587
- Py_VISIT(state->empty_bitmap_node);
3588
-
3589
- return 0;
3590
- }
3591
-
3592
- static int _hamt_module_clear(PyObject *module)
3593
- {
3594
- hamt_module_state *state = get_hamt_module_state(module);
3595
-
3596
- /* Clear type objects */
3597
- Py_CLEAR(state->Hamt_Type);
3598
- Py_CLEAR(state->HamtItems_Type);
3599
- Py_CLEAR(state->HamtKeys_Type);
3600
- Py_CLEAR(state->HamtValues_Type);
3601
- Py_CLEAR(state->Hamt_ArrayNode_Type);
3602
- Py_CLEAR(state->Hamt_BitmapNode_Type);
3603
- Py_CLEAR(state->Hamt_CollisionNode_Type);
3604
-
3605
- /* Clear singleton objects */
3606
- Py_CLEAR(state->empty_hamt);
3607
- Py_CLEAR(state->empty_bitmap_node);
3608
-
3609
- return 0;
3610
- }
3611
-
3612
- static void _hamt_module_free(void *module)
3613
- {
3614
- _hamt_module_clear((PyObject *)module);
3615
- }
3616
-
3617
- //
3618
-
3619
- PyDoc_STRVAR(hamt_doc, _MODULE_NAME);
3620
-
3621
- static PyMethodDef hamt_methods[] = {
3622
- {"new", py_hamt_new, METH_VARARGS, "Create a new HAMT immutable mapping"},
3623
- {"assoc", py_hamt_assoc, METH_VARARGS, "Return a new HAMT with an additional key/value pair"},
3624
- {"without", py_hamt_without, METH_VARARGS, "Return a new HAMT without the specified key"},
3625
- {"find", py_hamt_find, METH_VARARGS, "Find a key in the HAMT, return value or None"},
3626
- {"eq", py_hamt_eq, METH_VARARGS, "Check if two HAMTs are equal"},
3627
- {"len", py_hamt_len, METH_VARARGS, "Return the number of items in the HAMT"},
3628
- {"iter_keys", py_hamt_iter_keys, METH_VARARGS, "Return a keys iterator over the HAMT"},
3629
- {"iter_values", py_hamt_iter_values, METH_VARARGS, "Return a values iterator over the HAMT"},
3630
- {"iter_items", py_hamt_iter_items, METH_VARARGS, "Return an items iterator over the HAMT"},
3631
- {NULL, NULL, 0, NULL}
3632
- };
3633
-
3634
- static struct PyModuleDef_Slot hamt_slots[] = {
3635
- {Py_mod_exec, (void *) _hamt_module_exec},
3636
- {Py_mod_gil, Py_MOD_GIL_NOT_USED},
3637
- {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
3638
- {0, NULL}
3639
- };
3640
-
3641
- static struct PyModuleDef hamt_module = {
3642
- .m_base = PyModuleDef_HEAD_INIT,
3643
- .m_name = _MODULE_NAME,
3644
- .m_doc = hamt_doc,
3645
- .m_size = sizeof(hamt_module_state),
3646
- .m_methods = hamt_methods,
3647
- .m_slots = hamt_slots,
3648
- .m_traverse = _hamt_module_traverse,
3649
- .m_clear = _hamt_module_clear,
3650
- .m_free = _hamt_module_free,
3651
- };
3652
-
3653
- PyMODINIT_FUNC PyInit__hamt(void)
3654
- {
3655
- return PyModuleDef_Init(&hamt_module);
3656
- }