omlish-cext 0.0.0.dev552__tar.gz → 0.0.0.dev554__tar.gz

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.
Files changed (22) hide show
  1. {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/PKG-INFO +2 -9
  2. {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/README.md +0 -7
  3. omlish_cext-0.0.0.dev554/omlish/collections/fixed/_fixedmap.cc +1023 -0
  4. {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/omlish_cext.egg-info/PKG-INFO +2 -9
  5. {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/omlish_cext.egg-info/SOURCES.txt +1 -0
  6. omlish_cext-0.0.0.dev554/omlish_cext.egg-info/requires.txt +1 -0
  7. {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/pyproject.toml +2 -2
  8. {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/setup.py +5 -0
  9. omlish_cext-0.0.0.dev552/omlish_cext.egg-info/requires.txt +0 -1
  10. {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/LICENSE +0 -0
  11. {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/omlish/_check.cc +0 -0
  12. {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/omlish/collections/hamt/_hamt.c +0 -0
  13. {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/omlish/collections/treap/_treap.cc +0 -0
  14. {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/omlish/dispatch/_dispatch.cc +0 -0
  15. {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/omlish/dispatch/_methods.cc +0 -0
  16. {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/omlish/lang/_asyncs.cc +0 -0
  17. {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/omlish/lang/_comparison.cc +0 -0
  18. {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/omlish/lang/imports/_capture.cc +0 -0
  19. {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/omlish/typedvalues/_collection.cc +0 -0
  20. {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/omlish_cext.egg-info/dependency_links.txt +0 -0
  21. {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/omlish_cext.egg-info/top_level.txt +0 -0
  22. {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: omlish-cext
3
- Version: 0.0.0.dev552
3
+ Version: 0.0.0.dev554
4
4
  Summary: omlish
5
5
  Author: wrmsr
6
6
  License-Expression: BSD-3-Clause
@@ -14,7 +14,7 @@ Classifier: Programming Language :: Python :: 3.13
14
14
  Requires-Python: >=3.13
15
15
  Description-Content-Type: text/markdown
16
16
  License-File: LICENSE
17
- Requires-Dist: omlish==0.0.0.dev552
17
+ Requires-Dist: omlish==0.0.0.dev554
18
18
  Dynamic: license-file
19
19
 
20
20
  # Overview
@@ -103,11 +103,6 @@ dependencies of any kind**.
103
103
 
104
104
  - **[clients](https://github.com/wrmsr/omlish/blob/master/omlish/http/clients)** - An abstraction over HTTP clients,
105
105
  with urllib and httpx implementations.
106
- - **[coro](https://github.com/wrmsr/omlish/blob/master/omlish/http/coro)** - Coroutine /
107
- [sans-io](https://sans-io.readthedocs.io/) style reformulation of some stdlib http machinery - namely `http.server`
108
- (and soon `http.client`). This style of code can run the same in sync, async, or
109
- [any](https://docs.python.org/3/library/selectors.html)
110
- [other](https://github.com/wrmsr/omlish/blob/master/omlish/asyncs/bluelet) context.
111
106
 
112
107
  - **[inject](https://github.com/wrmsr/omlish/blob/master/omlish/inject)** - A
113
108
  [guice](https://github.com/google/guice)-style dependency injector.
@@ -117,8 +112,6 @@ dependencies of any kind**.
117
112
  - **[compress](https://github.com/wrmsr/omlish/blob/master/omlish/io/compress)** - Abstraction over various
118
113
  compression schemes, with particular attention to incremental operation. For example it includes
119
114
  [an incremental reformulation of stdlib's gzip](https://github.com/wrmsr/omlish/blob/master/omlish/io/compress/gzip.py).
120
- - **[coro](https://github.com/wrmsr/omlish/blob/master/omlish/io/coro)** - Utilities for coroutine / sans-io style
121
- code.
122
115
  - **[fdio](https://github.com/wrmsr/omlish/blob/master/omlish/io/fdio)** - An implementation of classic
123
116
  [selector](https://docs.python.org/3/library/selectors.html)-style IO dispatch, akin to the deprecated
124
117
  [asyncore](https://docs.python.org/3.11/library/asyncore.html). While more modern asyncio style code is generally
@@ -84,11 +84,6 @@ dependencies of any kind**.
84
84
 
85
85
  - **[clients](https://github.com/wrmsr/omlish/blob/master/omlish/http/clients)** - An abstraction over HTTP clients,
86
86
  with urllib and httpx implementations.
87
- - **[coro](https://github.com/wrmsr/omlish/blob/master/omlish/http/coro)** - Coroutine /
88
- [sans-io](https://sans-io.readthedocs.io/) style reformulation of some stdlib http machinery - namely `http.server`
89
- (and soon `http.client`). This style of code can run the same in sync, async, or
90
- [any](https://docs.python.org/3/library/selectors.html)
91
- [other](https://github.com/wrmsr/omlish/blob/master/omlish/asyncs/bluelet) context.
92
87
 
93
88
  - **[inject](https://github.com/wrmsr/omlish/blob/master/omlish/inject)** - A
94
89
  [guice](https://github.com/google/guice)-style dependency injector.
@@ -98,8 +93,6 @@ dependencies of any kind**.
98
93
  - **[compress](https://github.com/wrmsr/omlish/blob/master/omlish/io/compress)** - Abstraction over various
99
94
  compression schemes, with particular attention to incremental operation. For example it includes
100
95
  [an incremental reformulation of stdlib's gzip](https://github.com/wrmsr/omlish/blob/master/omlish/io/compress/gzip.py).
101
- - **[coro](https://github.com/wrmsr/omlish/blob/master/omlish/io/coro)** - Utilities for coroutine / sans-io style
102
- code.
103
96
  - **[fdio](https://github.com/wrmsr/omlish/blob/master/omlish/io/fdio)** - An implementation of classic
104
97
  [selector](https://docs.python.org/3/library/selectors.html)-style IO dispatch, akin to the deprecated
105
98
  [asyncore](https://docs.python.org/3.11/library/asyncore.html). While more modern asyncio style code is generally
@@ -0,0 +1,1023 @@
1
+ // @omlish-cext
2
+ #define PY_SSIZE_T_CLEAN
3
+ #include <Python.h>
4
+ #include <structmember.h>
5
+ #include <atomic>
6
+
7
+ #define _MODULE_NAME "_fixedmap"
8
+ #define _PACKAGE_NAME "omlish.collections.fixed"
9
+ #define _MODULE_FULL_NAME _PACKAGE_NAME "." _MODULE_NAME
10
+
11
+ //
12
+ // Types & Structs
13
+ //
14
+
15
+ struct FixedMapKeysObject {
16
+ PyObject_HEAD
17
+ PyObject* keys_tuple;
18
+ PyObject* key_indexes;
19
+ Py_hash_t* key_hashes;
20
+ Py_ssize_t* table;
21
+ Py_ssize_t table_size;
22
+ Py_hash_t hash;
23
+ };
24
+
25
+ struct FixedMapObject {
26
+ PyObject_HEAD
27
+ FixedMapKeysObject* keys;
28
+ PyObject* values_tuple;
29
+ Py_hash_t hash_cache;
30
+ };
31
+
32
+ // Views for FixedMap
33
+ struct FixedMapViewObject {
34
+ PyObject_HEAD
35
+ FixedMapObject* map;
36
+ };
37
+
38
+ // Iterator modes
39
+ enum IterMode {
40
+ ITER_KEYS_VALUES = 0,
41
+ ITER_KEYS_ITEMS = 1,
42
+ ITER_MAP_ITEMS = 2
43
+ };
44
+
45
+ struct FixedMapIterObject {
46
+ PyObject_HEAD
47
+ PyObject* source;
48
+ int mode;
49
+ Py_ssize_t index;
50
+ };
51
+
52
+ typedef struct fixedmap_state {
53
+ PyTypeObject* FixedMapKeys_Type;
54
+ PyTypeObject* FixedMap_Type;
55
+ PyTypeObject* FixedMapIter_Type;
56
+ PyTypeObject* FixedMapValuesView_Type;
57
+ PyTypeObject* FixedMapItemsView_Type;
58
+ } fixedmap_state;
59
+
60
+ static inline fixedmap_state* get_module_state(PyObject* module) {
61
+ void* state = PyModule_GetState(module);
62
+ assert(state != NULL);
63
+ return (fixedmap_state*)state;
64
+ }
65
+
66
+ static inline fixedmap_state* get_type_state(PyTypeObject* type) {
67
+ PyTypeObject* current = type;
68
+ while (current != NULL) {
69
+ void* state = PyType_GetModuleState(current);
70
+ if (state != NULL) {
71
+ return (fixedmap_state*)state;
72
+ }
73
+ current = current->tp_base;
74
+ }
75
+ Py_FatalError("_fixedmap state not found in type hierarchy");
76
+ return NULL;
77
+ }
78
+
79
+ //
80
+ // Utilities
81
+ //
82
+
83
+ static int dummy_init(PyObject* self, PyObject* args, PyObject* kwds) {
84
+ // Swallow the arguments since everything is handled in tp_new
85
+ return 0;
86
+ }
87
+
88
+ //
89
+ // FixedMapIter Implementation
90
+ //
91
+
92
+ static int FixedMapIter_traverse(FixedMapIterObject* self, visitproc visit, void* arg) {
93
+ Py_VISIT(self->source);
94
+ return 0;
95
+ }
96
+
97
+ static int FixedMapIter_clear(FixedMapIterObject* self) {
98
+ Py_CLEAR(self->source);
99
+ return 0;
100
+ }
101
+
102
+ static void FixedMapIter_dealloc(FixedMapIterObject* self) {
103
+ PyObject_GC_UnTrack(self);
104
+ FixedMapIter_clear(self);
105
+ Py_TYPE(self)->tp_free((PyObject*)self);
106
+ }
107
+
108
+ static PyObject* FixedMapIter_iternext(FixedMapIterObject* self) {
109
+ std::atomic_ref<Py_ssize_t> index_ref(self->index);
110
+ Py_ssize_t i = index_ref.fetch_add(1, std::memory_order_relaxed);
111
+
112
+ if (self->mode == ITER_KEYS_VALUES || self->mode == ITER_KEYS_ITEMS) {
113
+ FixedMapKeysObject* keys = (FixedMapKeysObject*)self->source;
114
+ if (i >= PyTuple_GET_SIZE(keys->keys_tuple)) {
115
+ return NULL;
116
+ }
117
+
118
+ if (self->mode == ITER_KEYS_VALUES) {
119
+ return PyLong_FromSsize_t(i);
120
+ } else { // ITER_KEYS_ITEMS
121
+ PyObject* key = PyTuple_GET_ITEM(keys->keys_tuple, i);
122
+ PyObject* val = PyLong_FromSsize_t(i);
123
+ if (!val) {
124
+ return NULL;
125
+ }
126
+ PyObject* tuple = PyTuple_Pack(2, key, val);
127
+ Py_DECREF(val);
128
+ return tuple;
129
+ }
130
+ } else {
131
+ FixedMapObject* map = (FixedMapObject*)self->source;
132
+ if (i >= PyTuple_GET_SIZE(map->values_tuple)) {
133
+ return NULL;
134
+ }
135
+
136
+ PyObject* key = PyTuple_GET_ITEM(map->keys->keys_tuple, i);
137
+ PyObject* val = PyTuple_GET_ITEM(map->values_tuple, i);
138
+ return PyTuple_Pack(2, key, val);
139
+ }
140
+ }
141
+
142
+ static PyType_Slot FixedMapIter_slots[] = {
143
+ {Py_tp_dealloc, (void*)FixedMapIter_dealloc},
144
+ {Py_tp_traverse, (void*)FixedMapIter_traverse},
145
+ {Py_tp_clear, (void*)FixedMapIter_clear},
146
+ {Py_tp_iter, (void*)PyObject_SelfIter},
147
+ {Py_tp_iternext, (void*)FixedMapIter_iternext},
148
+ {0, NULL}
149
+ };
150
+
151
+ static PyType_Spec FixedMapIter_spec = {
152
+ .name = _MODULE_FULL_NAME ".FixedMapIter",
153
+ .basicsize = sizeof(FixedMapIterObject),
154
+ .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
155
+ .slots = FixedMapIter_slots,
156
+ };
157
+
158
+ static PyObject* new_iterator(PyObject* source, int mode, fixedmap_state* state) {
159
+ FixedMapIterObject* iter = PyObject_GC_New(FixedMapIterObject, state->FixedMapIter_Type);
160
+ if (!iter) {
161
+ return NULL;
162
+ }
163
+ iter->source = Py_NewRef(source);
164
+ iter->mode = mode;
165
+ iter->index = 0;
166
+ PyObject_GC_Track(iter);
167
+ return (PyObject*)iter;
168
+ }
169
+
170
+ //
171
+ // View Implementations (ValuesView and ItemsView)
172
+ //
173
+
174
+ static int FixedMapView_traverse(FixedMapViewObject* self, visitproc visit, void* arg) {
175
+ Py_VISIT(self->map);
176
+ return 0;
177
+ }
178
+
179
+ static int FixedMapView_clear(FixedMapViewObject* self) {
180
+ Py_CLEAR(self->map);
181
+ return 0;
182
+ }
183
+
184
+ static void FixedMapView_dealloc(FixedMapViewObject* self) {
185
+ PyObject_GC_UnTrack(self);
186
+ FixedMapView_clear(self);
187
+ Py_TYPE(self)->tp_free((PyObject*)self);
188
+ }
189
+
190
+ static Py_ssize_t FixedMapView_len(FixedMapViewObject* self) {
191
+ return PyTuple_GET_SIZE(self->map->values_tuple);
192
+ }
193
+
194
+ static PyObject* FixedMapValuesView_iter(FixedMapViewObject* self) {
195
+ return PyObject_GetIter(self->map->values_tuple);
196
+ }
197
+
198
+ static PyObject* FixedMapItemsView_iter(FixedMapViewObject* self) {
199
+ fixedmap_state* state = get_type_state(Py_TYPE(self));
200
+ return new_iterator((PyObject*)self->map, ITER_MAP_ITEMS, state);
201
+ }
202
+
203
+ static PyType_Slot FixedMapValuesView_slots[] = {
204
+ {Py_tp_dealloc, (void*)FixedMapView_dealloc},
205
+ {Py_tp_traverse, (void*)FixedMapView_traverse},
206
+ {Py_tp_clear, (void*)FixedMapView_clear},
207
+ {Py_tp_iter, (void*)FixedMapValuesView_iter},
208
+ {Py_mp_length, (void*)FixedMapView_len},
209
+ {0, NULL}
210
+ };
211
+
212
+ static PyType_Spec FixedMapValuesView_spec = {
213
+ .name = _MODULE_FULL_NAME ".FixedMapValuesView",
214
+ .basicsize = sizeof(FixedMapViewObject),
215
+ .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
216
+ .slots = FixedMapValuesView_slots,
217
+ };
218
+
219
+ static PyType_Slot FixedMapItemsView_slots[] = {
220
+ {Py_tp_dealloc, (void*)FixedMapView_dealloc},
221
+ {Py_tp_traverse, (void*)FixedMapView_traverse},
222
+ {Py_tp_clear, (void*)FixedMapView_clear},
223
+ {Py_tp_iter, (void*)FixedMapItemsView_iter},
224
+ {Py_mp_length, (void*)FixedMapView_len},
225
+ {0, NULL}
226
+ };
227
+
228
+ static PyType_Spec FixedMapItemsView_spec = {
229
+ .name = _MODULE_FULL_NAME ".FixedMapItemsView",
230
+ .basicsize = sizeof(FixedMapViewObject),
231
+ .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
232
+ .slots = FixedMapItemsView_slots,
233
+ };
234
+
235
+ static PyObject* new_view(FixedMapObject* map, PyTypeObject* type) {
236
+ FixedMapViewObject* view = PyObject_GC_New(FixedMapViewObject, type);
237
+ if (!view) {
238
+ return NULL;
239
+ }
240
+ view->map = (FixedMapObject*)Py_NewRef(map);
241
+ PyObject_GC_Track(view);
242
+ return (PyObject*)view;
243
+ }
244
+
245
+ //
246
+ // FixedMapKeys Implementation
247
+ //
248
+
249
+ static int FixedMapKeys_traverse(FixedMapKeysObject* self, visitproc visit, void* arg) {
250
+ Py_VISIT(self->keys_tuple);
251
+ Py_VISIT(self->key_indexes);
252
+ return 0;
253
+ }
254
+
255
+ static int FixedMapKeys_clear(FixedMapKeysObject* self) {
256
+ Py_CLEAR(self->keys_tuple);
257
+ Py_CLEAR(self->key_indexes);
258
+ PyMem_Free(self->key_hashes);
259
+ self->key_hashes = NULL;
260
+ PyMem_Free(self->table);
261
+ self->table = NULL;
262
+ self->table_size = 0;
263
+ return 0;
264
+ }
265
+
266
+ static void FixedMapKeys_dealloc(FixedMapKeysObject* self) {
267
+ PyObject_GC_UnTrack(self);
268
+ FixedMapKeys_clear(self);
269
+ Py_TYPE(self)->tp_free((PyObject*)self);
270
+ }
271
+
272
+ static int FixedMapKeys_lookup_index(FixedMapKeysObject* self, PyObject* key, Py_ssize_t* out_idx) {
273
+ Py_ssize_t size = PyTuple_GET_SIZE(self->keys_tuple);
274
+ if (size == 0) {
275
+ return 0;
276
+ }
277
+
278
+ if (!self->table || !self->key_hashes || self->table_size <= 0) {
279
+ PyErr_SetString(PyExc_RuntimeError, "corrupt FixedMapKeys table");
280
+ return -1;
281
+ }
282
+
283
+ Py_hash_t h = PyObject_Hash(key);
284
+ if (h == -1) {
285
+ return -1;
286
+ }
287
+
288
+ Py_ssize_t mask = self->table_size - 1;
289
+ Py_ssize_t slot = (Py_ssize_t)((Py_uhash_t)h & (Py_uhash_t)mask);
290
+ for (;;) {
291
+ Py_ssize_t idx = self->table[slot];
292
+ if (idx == -1) {
293
+ return 0;
294
+ }
295
+
296
+ if (idx < 0 || idx >= size) {
297
+ PyErr_SetString(PyExc_RuntimeError, "corrupt FixedMapKeys table");
298
+ return -1;
299
+ }
300
+
301
+ PyObject* stored_key = PyTuple_GET_ITEM(self->keys_tuple, idx);
302
+ if (stored_key == key) {
303
+ *out_idx = idx;
304
+ return 1;
305
+ }
306
+
307
+ if (self->key_hashes[idx] == h) {
308
+ int eq = PyObject_RichCompareBool(stored_key, key, Py_EQ);
309
+ if (eq < 0) {
310
+ return -1;
311
+ }
312
+ if (eq > 0) {
313
+ *out_idx = idx;
314
+ return 1;
315
+ }
316
+ }
317
+
318
+ slot = (slot + 1) & mask;
319
+ }
320
+ }
321
+
322
+ static PyObject* FixedMapKeys_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
323
+ PyObject* keys_arg;
324
+ if (!PyArg_ParseTuple(args, "O", &keys_arg)) {
325
+ return NULL;
326
+ }
327
+
328
+ FixedMapKeysObject* self = (FixedMapKeysObject*)type->tp_alloc(type, 0);
329
+ if (!self) {
330
+ return NULL;
331
+ }
332
+
333
+ self->keys_tuple = PySequence_Tuple(keys_arg);
334
+ if (!self->keys_tuple) {
335
+ Py_DECREF(self);
336
+ return NULL;
337
+ }
338
+
339
+ Py_ssize_t size = PyTuple_GET_SIZE(self->keys_tuple);
340
+ self->table_size = 1;
341
+ while (self->table_size < size * 2) {
342
+ self->table_size <<= 1;
343
+ }
344
+
345
+ if (size > 0) {
346
+ self->key_hashes = PyMem_New(Py_hash_t, size);
347
+ if (!self->key_hashes) {
348
+ PyErr_NoMemory();
349
+ Py_DECREF(self);
350
+ return NULL;
351
+ }
352
+ }
353
+
354
+ self->table = PyMem_New(Py_ssize_t, self->table_size);
355
+ if (!self->table) {
356
+ PyErr_NoMemory();
357
+ Py_DECREF(self);
358
+ return NULL;
359
+ }
360
+ for (Py_ssize_t i = 0; i < self->table_size; i++) {
361
+ self->table[i] = -1;
362
+ }
363
+
364
+ PyObject* seen = PyDict_New();
365
+ if (!seen) {
366
+ Py_DECREF(self);
367
+ return NULL;
368
+ }
369
+
370
+ Py_ssize_t mask = self->table_size - 1;
371
+ for (Py_ssize_t i = 0; i < size; i++) {
372
+ PyObject* key = PyTuple_GET_ITEM(self->keys_tuple, i);
373
+
374
+ Py_hash_t h = PyObject_Hash(key);
375
+ if (h == -1) {
376
+ Py_DECREF(seen);
377
+ Py_DECREF(self);
378
+ return NULL;
379
+ }
380
+
381
+ int contains = PyDict_Contains(seen, key);
382
+ if (contains == -1 || contains == 1) {
383
+ if (contains == 1) {
384
+ PyErr_SetObject(PyExc_KeyError, key);
385
+ }
386
+ Py_DECREF(seen);
387
+ Py_DECREF(self);
388
+ return NULL;
389
+ }
390
+
391
+ PyObject* val = PyLong_FromSsize_t(i);
392
+ if (!val) {
393
+ Py_DECREF(seen);
394
+ Py_DECREF(self);
395
+ return NULL;
396
+ }
397
+ if (PyDict_SetItem(seen, key, val) < 0) {
398
+ Py_DECREF(val);
399
+ Py_DECREF(seen);
400
+ Py_DECREF(self);
401
+ return NULL;
402
+ }
403
+ Py_DECREF(val);
404
+
405
+ self->key_hashes[i] = h;
406
+
407
+ Py_ssize_t slot = (Py_ssize_t)((Py_uhash_t)h & (Py_uhash_t)mask);
408
+ while (self->table[slot] != -1) {
409
+ slot = (slot + 1) & mask;
410
+ }
411
+ self->table[slot] = i;
412
+ }
413
+
414
+ self->key_indexes = seen;
415
+
416
+ self->hash = PyObject_Hash(self->keys_tuple);
417
+ if (self->hash == -1) {
418
+ Py_DECREF(self);
419
+ return NULL;
420
+ }
421
+
422
+ if (!PyObject_GC_IsTracked((PyObject*)self)) {
423
+ PyObject_GC_Track(self);
424
+ }
425
+ return (PyObject*)self;
426
+ }
427
+
428
+ static Py_ssize_t FixedMapKeys_len(FixedMapKeysObject* self) {
429
+ return PyTuple_GET_SIZE(self->keys_tuple);
430
+ }
431
+
432
+ static PyObject* FixedMapKeys_getitem(FixedMapKeysObject* self, PyObject* key) {
433
+ Py_ssize_t idx;
434
+ int rc = FixedMapKeys_lookup_index(self, key, &idx);
435
+ if (rc < 0) {
436
+ return NULL;
437
+ }
438
+ if (!rc) {
439
+ PyErr_SetObject(PyExc_KeyError, key);
440
+ return NULL;
441
+ }
442
+ return PyLong_FromSsize_t(idx);
443
+ }
444
+
445
+ static PyObject* FixedMapKeys_get(FixedMapKeysObject* self, PyObject* args) {
446
+ PyObject *key = Py_None;
447
+ PyObject *def = Py_None;
448
+ if (!PyArg_ParseTuple(args, "O|O", &key, &def)) {
449
+ return NULL;
450
+ }
451
+
452
+ Py_ssize_t idx;
453
+ int rc = FixedMapKeys_lookup_index(self, key, &idx);
454
+ if (rc < 0) {
455
+ return NULL;
456
+ }
457
+ if (!rc) {
458
+ return Py_NewRef(def);
459
+ }
460
+ return PyLong_FromSsize_t(idx);
461
+ }
462
+
463
+ static Py_hash_t FixedMapKeys_hash(FixedMapKeysObject* self) {
464
+ return self->hash;
465
+ }
466
+
467
+ static PyObject* FixedMapKeys_richcompare(PyObject* a, PyObject* b, int op) {
468
+ if (op != Py_EQ && op != Py_NE) {
469
+ Py_RETURN_NOTIMPLEMENTED;
470
+ }
471
+ if (a == b) {
472
+ if (op == Py_EQ) {
473
+ Py_RETURN_TRUE;
474
+ } else {
475
+ Py_RETURN_FALSE;
476
+ }
477
+ }
478
+ fixedmap_state* state = get_type_state(Py_TYPE(a));
479
+ if (!PyObject_TypeCheck(a, state->FixedMapKeys_Type)) {
480
+ Py_RETURN_NOTIMPLEMENTED;
481
+ }
482
+ if (PyObject_TypeCheck(b, state->FixedMapKeys_Type)) {
483
+ return PyObject_RichCompare(((FixedMapKeysObject*)a)->keys_tuple, ((FixedMapKeysObject*)b)->keys_tuple, op);
484
+ }
485
+ Py_RETURN_NOTIMPLEMENTED;
486
+ }
487
+
488
+ static PyObject* FixedMapKeys_keys(FixedMapKeysObject* self, PyObject* Py_UNUSED(ignored)) {
489
+ return PyObject_CallMethod(self->key_indexes, "keys", NULL);
490
+ }
491
+
492
+ static PyObject* FixedMapKeys_values(FixedMapKeysObject* self, PyObject* Py_UNUSED(ignored)) {
493
+ return PyObject_CallMethod(self->key_indexes, "values", NULL);
494
+ }
495
+
496
+ static PyObject* FixedMapKeys_items(FixedMapKeysObject* self, PyObject* Py_UNUSED(ignored)) {
497
+ return PyObject_CallMethod(self->key_indexes, "items", NULL);
498
+ }
499
+
500
+ static PyMethodDef FixedMapKeys_methods[] = {
501
+ {"get", (PyCFunction)FixedMapKeys_get, METH_VARARGS, NULL},
502
+ {"keys", (PyCFunction)FixedMapKeys_keys, METH_NOARGS, NULL},
503
+ {"values", (PyCFunction)FixedMapKeys_values, METH_NOARGS, NULL},
504
+ {"items", (PyCFunction)FixedMapKeys_items, METH_NOARGS, NULL},
505
+ {NULL, NULL, 0, NULL}
506
+ };
507
+
508
+ static PyObject* FixedMapKeys_get_fixed_keys(FixedMapKeysObject* self, void* Py_UNUSED(closure)) {
509
+ return Py_NewRef(self->keys_tuple);
510
+ }
511
+
512
+ static PyObject* FixedMapKeys_get_debug(FixedMapKeysObject* self, void* Py_UNUSED(closure)) {
513
+ return PyDictProxy_New(self->key_indexes);
514
+ }
515
+
516
+ static PyObject* FixedMapKeys_repr(FixedMapKeysObject* self) {
517
+ PyObject* name = PyType_GetName(Py_TYPE(self));
518
+ if (!name) {
519
+ return NULL;
520
+ }
521
+ PyObject *repr = PyUnicode_FromFormat("%U(%R)", name, self->key_indexes);
522
+ Py_DECREF(name);
523
+ return repr;
524
+ }
525
+
526
+ static PyObject* FixedMapKeys_iter(FixedMapKeysObject* self) {
527
+ return PyObject_GetIter(self->keys_tuple);
528
+ }
529
+
530
+ static int FixedMapKeys_contains(FixedMapKeysObject* self, PyObject* key) {
531
+ Py_ssize_t idx;
532
+ int rc = FixedMapKeys_lookup_index(self, key, &idx);
533
+ if (rc < 0) {
534
+ return -1;
535
+ }
536
+ return rc > 0;
537
+ }
538
+
539
+ static PyGetSetDef FixedMapKeys_getsets[] = {
540
+ {"fixed_keys", (getter)FixedMapKeys_get_fixed_keys, NULL, NULL, NULL},
541
+ {"debug", (getter)FixedMapKeys_get_debug, NULL, NULL, NULL},
542
+ {NULL, NULL, NULL, NULL, NULL}
543
+ };
544
+
545
+ static PyType_Slot FixedMapKeys_slots[] = {
546
+ {Py_tp_dealloc, (void*)FixedMapKeys_dealloc},
547
+ {Py_tp_traverse, (void*)FixedMapKeys_traverse},
548
+ {Py_tp_clear, (void*)FixedMapKeys_clear},
549
+ {Py_tp_hash, (void*)FixedMapKeys_hash},
550
+ {Py_tp_richcompare, (void*)FixedMapKeys_richcompare},
551
+ {Py_tp_repr, (void*)FixedMapKeys_repr},
552
+ {Py_tp_iter, (void*)FixedMapKeys_iter},
553
+ {Py_tp_methods, (void*)FixedMapKeys_methods},
554
+ {Py_tp_getset, (void*)FixedMapKeys_getsets},
555
+ {Py_mp_length, (void*)FixedMapKeys_len},
556
+ {Py_mp_subscript, (void*)FixedMapKeys_getitem},
557
+ {Py_sq_contains, (void*)FixedMapKeys_contains},
558
+ {Py_tp_new, (void*)FixedMapKeys_new},
559
+ {Py_tp_init, (void*)dummy_init},
560
+ {0, NULL}
561
+ };
562
+
563
+ static PyType_Spec FixedMapKeys_spec = {
564
+ .name = _MODULE_FULL_NAME ".FixedMapKeys",
565
+ .basicsize = sizeof(FixedMapKeysObject),
566
+ .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE,
567
+ .slots = FixedMapKeys_slots,
568
+ };
569
+
570
+ //
571
+ // FixedMap Implementation
572
+ //
573
+
574
+ static int FixedMap_traverse(FixedMapObject* self, visitproc visit, void* arg) {
575
+ Py_VISIT(self->keys);
576
+ Py_VISIT(self->values_tuple);
577
+ return 0;
578
+ }
579
+
580
+ static int FixedMap_clear(FixedMapObject* self) {
581
+ Py_CLEAR(self->keys);
582
+ Py_CLEAR(self->values_tuple);
583
+ return 0;
584
+ }
585
+
586
+ static void FixedMap_dealloc(FixedMapObject* self) {
587
+ PyObject_GC_UnTrack(self);
588
+ FixedMap_clear(self);
589
+ Py_TYPE(self)->tp_free((PyObject*)self);
590
+ }
591
+
592
+ static PyObject* FixedMap_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
593
+ PyObject* keys_arg;
594
+ PyObject* values_arg;
595
+
596
+ fixedmap_state* state = get_type_state(type);
597
+
598
+ if (!PyArg_ParseTuple(args, "O!O", state->FixedMapKeys_Type, &keys_arg, &values_arg)) {
599
+ return NULL;
600
+ }
601
+
602
+ FixedMapObject* self = (FixedMapObject*)type->tp_alloc(type, 0);
603
+ if (!self) {
604
+ return NULL;
605
+ }
606
+
607
+ self->values_tuple = PyTuple_CheckExact(values_arg) ? Py_NewRef(values_arg) : PySequence_Tuple(values_arg);
608
+ if (!self->values_tuple) {
609
+ Py_DECREF(self);
610
+ return NULL;
611
+ }
612
+
613
+ FixedMapKeysObject* keys_obj = (FixedMapKeysObject*)keys_arg;
614
+ if (PyTuple_GET_SIZE(self->values_tuple) != PyTuple_GET_SIZE(keys_obj->keys_tuple)) {
615
+ PyErr_SetString(PyExc_ValueError, "length mismatch");
616
+ Py_DECREF(self);
617
+ return NULL;
618
+ }
619
+
620
+ self->keys = (FixedMapKeysObject*)Py_NewRef(keys_obj);
621
+ self->hash_cache = 0;
622
+ if (!PyObject_GC_IsTracked((PyObject*)self)) {
623
+ PyObject_GC_Track(self);
624
+ }
625
+ return (PyObject*)self;
626
+ }
627
+
628
+ static Py_hash_t FixedMap_hash(FixedMapObject* self) {
629
+ std::atomic_ref<Py_hash_t> cache(self->hash_cache);
630
+ Py_hash_t h = cache.load(std::memory_order_acquire);
631
+ if (h != 0) {
632
+ return h;
633
+ }
634
+ if (Py_EnterRecursiveCall(" in FixedMap hash")) {
635
+ return -1;
636
+ }
637
+
638
+ Py_hash_t kh = PyObject_Hash((PyObject*)self->keys);
639
+ if (kh == -1) {
640
+ Py_LeaveRecursiveCall();
641
+ return -1;
642
+ }
643
+
644
+ Py_ssize_t size = PyTuple_GET_SIZE(self->values_tuple);
645
+ Py_hash_t res = 0x9e3779b9;
646
+ for (Py_ssize_t i = 0; i < size; i++) {
647
+ Py_hash_t vh = PyObject_Hash(PyTuple_GET_ITEM(self->values_tuple, i));
648
+ if (vh == -1) {
649
+ Py_LeaveRecursiveCall();
650
+ return -1;
651
+ }
652
+ res = (res ^ vh) * 1000003 + (82520L + size + size + 2);
653
+ }
654
+ res ^= kh;
655
+ Py_LeaveRecursiveCall();
656
+ if (res == -1) {
657
+ res = -2;
658
+ } else if (res == 0) {
659
+ res = 1;
660
+ }
661
+ cache.store(res, std::memory_order_release);
662
+ return res;
663
+ }
664
+
665
+ static PyObject* FixedMap_richcompare(PyObject* a, PyObject* b, int op) {
666
+ if (op != Py_EQ && op != Py_NE) {
667
+ Py_RETURN_NOTIMPLEMENTED;
668
+ }
669
+ if (a == b) {
670
+ if (op == Py_EQ) {
671
+ Py_RETURN_TRUE;
672
+ } else {
673
+ Py_RETURN_FALSE;
674
+ }
675
+ }
676
+
677
+ if (Py_EnterRecursiveCall(" in FixedMap richcompare")) {
678
+ return NULL;
679
+ }
680
+
681
+ fixedmap_state* state = get_type_state(Py_TYPE(a));
682
+ if (PyObject_TypeCheck(b, state->FixedMap_Type)) {
683
+ FixedMapObject *ma = (FixedMapObject*)a, *mb = (FixedMapObject*)b;
684
+ if (PyTuple_GET_SIZE(ma->values_tuple) != PyTuple_GET_SIZE(mb->values_tuple)) {
685
+ Py_LeaveRecursiveCall();
686
+ if (op == Py_EQ) {
687
+ Py_RETURN_FALSE;
688
+ } else {
689
+ Py_RETURN_TRUE;
690
+ }
691
+ }
692
+ if (ma->keys == mb->keys) {
693
+ PyObject* ret = PyObject_RichCompare(ma->values_tuple, mb->values_tuple, op);
694
+ Py_LeaveRecursiveCall();
695
+ return ret;
696
+ }
697
+ }
698
+
699
+ Py_ssize_t al = PyObject_Length(a);
700
+ if (al < 0) {
701
+ PyErr_Clear();
702
+ }
703
+ Py_ssize_t bl = PyObject_Length(b);
704
+ if (bl < 0) {
705
+ PyErr_Clear();
706
+ }
707
+ if (al >= 0 && bl >= 0 && al != bl) {
708
+ Py_LeaveRecursiveCall();
709
+ if (op == Py_EQ) {
710
+ Py_RETURN_FALSE;
711
+ } else {
712
+ Py_RETURN_TRUE;
713
+ }
714
+ }
715
+
716
+ PyObject *it = PyObject_GetIter(a), *k;
717
+ if (!it) {
718
+ PyErr_Clear();
719
+ Py_LeaveRecursiveCall();
720
+ Py_RETURN_NOTIMPLEMENTED;
721
+ }
722
+ while ((k = PyIter_Next(it))) {
723
+ PyObject *va = PyObject_GetItem(a, k), *vb = PyObject_GetItem(b, k);
724
+ if (!va || !vb) {
725
+ Py_XDECREF(va);
726
+ Py_XDECREF(vb);
727
+ Py_DECREF(k);
728
+ Py_DECREF(it);
729
+ if (!vb && PyErr_ExceptionMatches(PyExc_KeyError)) {
730
+ PyErr_Clear();
731
+ Py_LeaveRecursiveCall();
732
+ if (op == Py_EQ) {
733
+ Py_RETURN_FALSE;
734
+ } else {
735
+ Py_RETURN_TRUE;
736
+ }
737
+ }
738
+ Py_LeaveRecursiveCall();
739
+ return NULL;
740
+ }
741
+ int eq = PyObject_RichCompareBool(va, vb, Py_EQ);
742
+ Py_DECREF(va);
743
+ Py_DECREF(vb);
744
+ Py_DECREF(k);
745
+ if (eq <= 0) {
746
+ Py_DECREF(it);
747
+ if (eq < 0) {
748
+ Py_LeaveRecursiveCall();
749
+ return NULL;
750
+ } else {
751
+ Py_LeaveRecursiveCall();
752
+ if (op == Py_EQ) {
753
+ Py_RETURN_FALSE;
754
+ } else {
755
+ Py_RETURN_TRUE;
756
+ }
757
+ }
758
+ }
759
+ }
760
+ Py_DECREF(it);
761
+ if (PyErr_Occurred()) {
762
+ Py_LeaveRecursiveCall();
763
+ return NULL;
764
+ }
765
+ Py_LeaveRecursiveCall();
766
+ if (op == Py_EQ) {
767
+ Py_RETURN_TRUE;
768
+ } else {
769
+ Py_RETURN_FALSE;
770
+ }
771
+ }
772
+
773
+ static PyObject* FixedMap_getitem(FixedMapObject* self, PyObject* key) {
774
+ Py_ssize_t idx;
775
+ int rc = FixedMapKeys_lookup_index(self->keys, key, &idx);
776
+ if (rc < 0) {
777
+ return NULL;
778
+ }
779
+ if (!rc) {
780
+ PyErr_SetObject(PyExc_KeyError, key);
781
+ return NULL;
782
+ }
783
+
784
+ if (idx < 0 || idx >= PyTuple_GET_SIZE(self->values_tuple)) {
785
+ PyErr_SetString(PyExc_RuntimeError, "corrupt FixedMap index");
786
+ return NULL;
787
+ }
788
+
789
+ return Py_NewRef(PyTuple_GET_ITEM(self->values_tuple, idx));
790
+ }
791
+
792
+ static PyObject* FixedMap_get(FixedMapObject* self, PyObject* args) {
793
+ PyObject *key, *def = Py_None;
794
+ if (!PyArg_ParseTuple(args, "O|O", &key, &def)) {
795
+ return NULL;
796
+ }
797
+
798
+ Py_ssize_t idx;
799
+ int rc = FixedMapKeys_lookup_index(self->keys, key, &idx);
800
+ if (rc < 0) {
801
+ return NULL;
802
+ }
803
+ if (!rc) {
804
+ return Py_NewRef(def);
805
+ }
806
+
807
+ if (idx < 0 || idx >= PyTuple_GET_SIZE(self->values_tuple)) {
808
+ PyErr_SetString(PyExc_RuntimeError, "corrupt FixedMap index");
809
+ return NULL;
810
+ }
811
+
812
+ return Py_NewRef(PyTuple_GET_ITEM(self->values_tuple, idx));
813
+ }
814
+
815
+ static PyObject* FixedMap_get_fixed_keys(FixedMapObject* self, void* closure) {
816
+ return Py_NewRef(self->keys);
817
+ }
818
+
819
+ static PyObject* FixedMap_get_fixed_values(FixedMapObject* self, void* closure) {
820
+ return Py_NewRef(self->values_tuple);
821
+ }
822
+
823
+ static PyObject* FixedMap_get_debug(FixedMapObject* self, void* closure) {
824
+ PyObject* d = PyDict_New();
825
+ if (!d) {
826
+ return NULL;
827
+ }
828
+
829
+ Py_ssize_t size = PyTuple_GET_SIZE(self->values_tuple);
830
+ for (Py_ssize_t i = 0; i < size; i++) {
831
+ PyObject* k = PyTuple_GET_ITEM(self->keys->keys_tuple, i);
832
+ PyObject* v = PyTuple_GET_ITEM(self->values_tuple, i);
833
+ if (PyDict_SetItem(d, k, v) < 0) {
834
+ Py_DECREF(d);
835
+ return NULL;
836
+ }
837
+ }
838
+ return d;
839
+ }
840
+
841
+ static PyObject* FixedMap_keys(FixedMapObject* self, PyObject* Py_UNUSED(ignored)) {
842
+ return Py_NewRef(self->keys);
843
+ }
844
+
845
+ static PyObject* FixedMap_values(FixedMapObject* self, PyObject* Py_UNUSED(ignored)) {
846
+ return new_view(self, get_type_state(Py_TYPE(self))->FixedMapValuesView_Type);
847
+ }
848
+
849
+ static PyObject* FixedMap_items(FixedMapObject* self, PyObject* Py_UNUSED(ignored)) {
850
+ return new_view(self, get_type_state(Py_TYPE(self))->FixedMapItemsView_Type);
851
+ }
852
+
853
+ static PyObject* FixedMap_itervalues(FixedMapObject* self, PyObject* Py_UNUSED(ignored)) {
854
+ return PyObject_GetIter(self->values_tuple);
855
+ }
856
+
857
+ static PyObject* FixedMap_iteritems(FixedMapObject* self, PyObject* Py_UNUSED(ignored)) {
858
+ return new_iterator((PyObject*)self, ITER_MAP_ITEMS, get_type_state(Py_TYPE(self)));
859
+ }
860
+
861
+ static PyObject* FixedMap_iter(FixedMapObject* self) {
862
+ return PyObject_GetIter(self->keys->keys_tuple);
863
+ }
864
+
865
+ static Py_ssize_t FixedMap_len(FixedMapObject* self) {
866
+ return PyTuple_GET_SIZE(self->values_tuple);
867
+ }
868
+
869
+ static int FixedMap_contains(FixedMapObject* self, PyObject* key) {
870
+ Py_ssize_t idx;
871
+ int rc = FixedMapKeys_lookup_index(self->keys, key, &idx);
872
+ if (rc < 0) {
873
+ return -1;
874
+ }
875
+ return rc > 0;
876
+ }
877
+
878
+
879
+ static PyMethodDef FixedMap_methods[] = {
880
+ {"get", (PyCFunction)FixedMap_get, METH_VARARGS, NULL},
881
+ {"keys", (PyCFunction)FixedMap_keys, METH_NOARGS, NULL},
882
+ {"values", (PyCFunction)FixedMap_values, METH_NOARGS, NULL},
883
+ {"items", (PyCFunction)FixedMap_items, METH_NOARGS, NULL},
884
+ {"itervalues", (PyCFunction)FixedMap_itervalues, METH_NOARGS, NULL},
885
+ {"iteritems", (PyCFunction)FixedMap_iteritems, METH_NOARGS, NULL},
886
+ {NULL, NULL, 0, NULL}
887
+ };
888
+
889
+ static PyGetSetDef FixedMap_getsets[] = {
890
+ {"fixed_keys", (getter)FixedMap_get_fixed_keys, NULL, NULL, NULL},
891
+ {"fixed_values", (getter)FixedMap_get_fixed_values, NULL, NULL, NULL},
892
+ {"debug", (getter)FixedMap_get_debug, NULL, NULL, NULL},
893
+ {NULL, NULL, NULL, NULL, NULL}
894
+ };
895
+
896
+ static PyType_Slot FixedMap_slots[] = {
897
+ {Py_tp_dealloc, (void*)FixedMap_dealloc},
898
+ {Py_tp_traverse, (void*)FixedMap_traverse},
899
+ {Py_tp_clear, (void*)FixedMap_clear},
900
+ {Py_tp_hash, (void*)FixedMap_hash},
901
+ {Py_tp_richcompare, (void*)FixedMap_richcompare},
902
+ {Py_tp_iter, (void*)FixedMap_iter},
903
+ {Py_tp_methods, (void*)FixedMap_methods},
904
+ {Py_tp_getset, (void*)FixedMap_getsets},
905
+ {Py_mp_length, (void*)FixedMap_len},
906
+ {Py_mp_subscript, (void*)FixedMap_getitem},
907
+ {Py_sq_contains, (void*)FixedMap_contains},
908
+ {Py_tp_new, (void*)FixedMap_new},
909
+ {Py_tp_init, (void*)dummy_init},
910
+ {0, NULL}
911
+ };
912
+
913
+ static PyType_Spec FixedMap_spec = {
914
+ .name = _MODULE_FULL_NAME ".FixedMap",
915
+ .basicsize = sizeof(FixedMapObject),
916
+ .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE,
917
+ .slots = FixedMap_slots,
918
+ };
919
+
920
+ //
921
+ // Module Initialization
922
+ //
923
+
924
+ PyDoc_STRVAR(fixedmap_doc, "C++ optimized implementation of FixedMap.");
925
+
926
+ static int fixedmap_exec(PyObject* module) {
927
+ fixedmap_state* state = get_module_state(module);
928
+
929
+ state->FixedMapKeys_Type = (PyTypeObject*)PyType_FromModuleAndSpec(module, &FixedMapKeys_spec, NULL);
930
+ if (!state->FixedMapKeys_Type) {
931
+ return -1;
932
+ }
933
+ if (PyModule_AddType(module, state->FixedMapKeys_Type) < 0) {
934
+ return -1;
935
+ }
936
+
937
+ state->FixedMap_Type = (PyTypeObject*)PyType_FromModuleAndSpec(module, &FixedMap_spec, NULL);
938
+ if (!state->FixedMap_Type) {
939
+ return -1;
940
+ }
941
+ if (PyModule_AddType(module, state->FixedMap_Type) < 0) {
942
+ return -1;
943
+ }
944
+
945
+ state->FixedMapIter_Type = (PyTypeObject*)PyType_FromModuleAndSpec(module, &FixedMapIter_spec, NULL);
946
+ if (!state->FixedMapIter_Type) {
947
+ return -1;
948
+ }
949
+ if (PyModule_AddType(module, state->FixedMapIter_Type) < 0) {
950
+ return -1;
951
+ }
952
+
953
+ state->FixedMapValuesView_Type = (PyTypeObject*)PyType_FromModuleAndSpec(module, &FixedMapValuesView_spec, NULL);
954
+ if (!state->FixedMapValuesView_Type) {
955
+ return -1;
956
+ }
957
+ if (PyModule_AddType(module, state->FixedMapValuesView_Type) < 0) {
958
+ return -1;
959
+ }
960
+
961
+ state->FixedMapItemsView_Type = (PyTypeObject*)PyType_FromModuleAndSpec(module, &FixedMapItemsView_spec, NULL);
962
+ if (!state->FixedMapItemsView_Type) {
963
+ return -1;
964
+ }
965
+ if (PyModule_AddType(module, state->FixedMapItemsView_Type) < 0) {
966
+ return -1;
967
+ }
968
+
969
+ return 0;
970
+ }
971
+
972
+ static int fixedmap_traverse(PyObject* module, visitproc visit, void* arg) {
973
+ fixedmap_state* state = get_module_state(module);
974
+ Py_VISIT(state->FixedMapKeys_Type);
975
+ Py_VISIT(state->FixedMap_Type);
976
+ Py_VISIT(state->FixedMapIter_Type);
977
+ Py_VISIT(state->FixedMapValuesView_Type);
978
+ Py_VISIT(state->FixedMapItemsView_Type);
979
+ return 0;
980
+ }
981
+
982
+ static int fixedmap_clear(PyObject* module) {
983
+ fixedmap_state* state = get_module_state(module);
984
+ Py_CLEAR(state->FixedMapKeys_Type);
985
+ Py_CLEAR(state->FixedMap_Type);
986
+ Py_CLEAR(state->FixedMapIter_Type);
987
+ Py_CLEAR(state->FixedMapValuesView_Type);
988
+ Py_CLEAR(state->FixedMapItemsView_Type);
989
+ return 0;
990
+ }
991
+
992
+ static void fixedmap_free(void* module) {
993
+ fixedmap_clear((PyObject*)module);
994
+ }
995
+
996
+ static PyMethodDef fixedmap_methods[] = {
997
+ {NULL, NULL, 0, NULL}
998
+ };
999
+
1000
+ static struct PyModuleDef_Slot fixedmap_slots[] = {
1001
+ {Py_mod_exec, (void*)fixedmap_exec},
1002
+ {Py_mod_gil, Py_MOD_GIL_NOT_USED},
1003
+ {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED},
1004
+ {0, NULL}
1005
+ };
1006
+
1007
+ static struct PyModuleDef fixedmap_module = {
1008
+ .m_base = PyModuleDef_HEAD_INIT,
1009
+ .m_name = _MODULE_NAME,
1010
+ .m_doc = fixedmap_doc,
1011
+ .m_size = sizeof(fixedmap_state),
1012
+ .m_methods = fixedmap_methods,
1013
+ .m_slots = fixedmap_slots,
1014
+ .m_traverse = fixedmap_traverse,
1015
+ .m_clear = fixedmap_clear,
1016
+ .m_free = fixedmap_free,
1017
+ };
1018
+
1019
+ extern "C" {
1020
+ PyMODINIT_FUNC PyInit__fixedmap(void) {
1021
+ return PyModuleDef_Init(&fixedmap_module);
1022
+ }
1023
+ }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: omlish-cext
3
- Version: 0.0.0.dev552
3
+ Version: 0.0.0.dev554
4
4
  Summary: omlish
5
5
  Author: wrmsr
6
6
  License-Expression: BSD-3-Clause
@@ -14,7 +14,7 @@ Classifier: Programming Language :: Python :: 3.13
14
14
  Requires-Python: >=3.13
15
15
  Description-Content-Type: text/markdown
16
16
  License-File: LICENSE
17
- Requires-Dist: omlish==0.0.0.dev552
17
+ Requires-Dist: omlish==0.0.0.dev554
18
18
  Dynamic: license-file
19
19
 
20
20
  # Overview
@@ -103,11 +103,6 @@ dependencies of any kind**.
103
103
 
104
104
  - **[clients](https://github.com/wrmsr/omlish/blob/master/omlish/http/clients)** - An abstraction over HTTP clients,
105
105
  with urllib and httpx implementations.
106
- - **[coro](https://github.com/wrmsr/omlish/blob/master/omlish/http/coro)** - Coroutine /
107
- [sans-io](https://sans-io.readthedocs.io/) style reformulation of some stdlib http machinery - namely `http.server`
108
- (and soon `http.client`). This style of code can run the same in sync, async, or
109
- [any](https://docs.python.org/3/library/selectors.html)
110
- [other](https://github.com/wrmsr/omlish/blob/master/omlish/asyncs/bluelet) context.
111
106
 
112
107
  - **[inject](https://github.com/wrmsr/omlish/blob/master/omlish/inject)** - A
113
108
  [guice](https://github.com/google/guice)-style dependency injector.
@@ -117,8 +112,6 @@ dependencies of any kind**.
117
112
  - **[compress](https://github.com/wrmsr/omlish/blob/master/omlish/io/compress)** - Abstraction over various
118
113
  compression schemes, with particular attention to incremental operation. For example it includes
119
114
  [an incremental reformulation of stdlib's gzip](https://github.com/wrmsr/omlish/blob/master/omlish/io/compress/gzip.py).
120
- - **[coro](https://github.com/wrmsr/omlish/blob/master/omlish/io/coro)** - Utilities for coroutine / sans-io style
121
- code.
122
115
  - **[fdio](https://github.com/wrmsr/omlish/blob/master/omlish/io/fdio)** - An implementation of classic
123
116
  [selector](https://docs.python.org/3/library/selectors.html)-style IO dispatch, akin to the deprecated
124
117
  [asyncore](https://docs.python.org/3.11/library/asyncore.html). While more modern asyncio style code is generally
@@ -3,6 +3,7 @@ README.md
3
3
  pyproject.toml
4
4
  setup.py
5
5
  omlish/_check.cc
6
+ omlish/collections/fixed/_fixedmap.cc
6
7
  omlish/collections/hamt/_hamt.c
7
8
  omlish/collections/treap/_treap.cc
8
9
  omlish/dispatch/_dispatch.cc
@@ -0,0 +1 @@
1
+ omlish==0.0.0.dev554
@@ -13,7 +13,7 @@ urls = {source = 'https://github.com/wrmsr/omlish'}
13
13
  license = 'BSD-3-Clause'
14
14
  readme = 'README.md'
15
15
  requires-python = '>=3.13'
16
- version = '0.0.0.dev552'
16
+ version = '0.0.0.dev554'
17
17
  classifiers = [
18
18
  'Development Status :: 2 - Pre-Alpha',
19
19
  'Intended Audience :: Developers',
@@ -24,7 +24,7 @@ classifiers = [
24
24
  ]
25
25
  description = 'omlish'
26
26
  dependencies = [
27
- 'omlish == 0.0.0.dev552',
27
+ 'omlish == 0.0.0.dev554',
28
28
  ]
29
29
 
30
30
  [tool.setuptools]
@@ -8,6 +8,11 @@ st.setup(
8
8
  sources=['omlish/_check.cc'],
9
9
  extra_compile_args=['-std=c++20'],
10
10
  ),
11
+ st.Extension(
12
+ name='omlish.collections.fixed._fixedmap',
13
+ sources=['omlish/collections/fixed/_fixedmap.cc'],
14
+ extra_compile_args=['-std=c++20'],
15
+ ),
11
16
  st.Extension(
12
17
  name='omlish.collections.hamt._hamt',
13
18
  sources=['omlish/collections/hamt/_hamt.c'],
@@ -1 +0,0 @@
1
- omlish==0.0.0.dev552