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.
- {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/PKG-INFO +2 -9
- {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/README.md +0 -7
- omlish_cext-0.0.0.dev554/omlish/collections/fixed/_fixedmap.cc +1023 -0
- {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/omlish_cext.egg-info/PKG-INFO +2 -9
- {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/omlish_cext.egg-info/SOURCES.txt +1 -0
- omlish_cext-0.0.0.dev554/omlish_cext.egg-info/requires.txt +1 -0
- {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/pyproject.toml +2 -2
- {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/setup.py +5 -0
- omlish_cext-0.0.0.dev552/omlish_cext.egg-info/requires.txt +0 -1
- {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/LICENSE +0 -0
- {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/omlish/_check.cc +0 -0
- {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/omlish/collections/hamt/_hamt.c +0 -0
- {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/omlish/collections/treap/_treap.cc +0 -0
- {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/omlish/dispatch/_dispatch.cc +0 -0
- {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/omlish/dispatch/_methods.cc +0 -0
- {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/omlish/lang/_asyncs.cc +0 -0
- {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/omlish/lang/_comparison.cc +0 -0
- {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/omlish/lang/imports/_capture.cc +0 -0
- {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/omlish/typedvalues/_collection.cc +0 -0
- {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/omlish_cext.egg-info/dependency_links.txt +0 -0
- {omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/omlish_cext.egg-info/top_level.txt +0 -0
- {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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
@@ -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.
|
|
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.
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{omlish_cext-0.0.0.dev552 → omlish_cext-0.0.0.dev554}/omlish_cext.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|