omlish-cext 0.0.0.dev503__tar.gz → 0.0.0.dev505__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.dev503/omlish_cext.egg-info → omlish_cext-0.0.0.dev505}/PKG-INFO +2 -2
- omlish_cext-0.0.0.dev505/omlish/typedvalues/_collection.cc +545 -0
- {omlish_cext-0.0.0.dev503 → omlish_cext-0.0.0.dev505/omlish_cext.egg-info}/PKG-INFO +2 -2
- {omlish_cext-0.0.0.dev503 → omlish_cext-0.0.0.dev505}/omlish_cext.egg-info/SOURCES.txt +1 -0
- omlish_cext-0.0.0.dev505/omlish_cext.egg-info/requires.txt +1 -0
- {omlish_cext-0.0.0.dev503 → omlish_cext-0.0.0.dev505}/pyproject.toml +2 -2
- {omlish_cext-0.0.0.dev503 → omlish_cext-0.0.0.dev505}/setup.py +5 -0
- omlish_cext-0.0.0.dev503/omlish_cext.egg-info/requires.txt +0 -1
- {omlish_cext-0.0.0.dev503 → omlish_cext-0.0.0.dev505}/LICENSE +0 -0
- {omlish_cext-0.0.0.dev503 → omlish_cext-0.0.0.dev505}/README.md +0 -0
- {omlish_cext-0.0.0.dev503 → omlish_cext-0.0.0.dev505}/omlish/_check.cc +0 -0
- {omlish_cext-0.0.0.dev503 → omlish_cext-0.0.0.dev505}/omlish/lang/_asyncs.cc +0 -0
- {omlish_cext-0.0.0.dev503 → omlish_cext-0.0.0.dev505}/omlish/lang/imports/_capture.cc +0 -0
- {omlish_cext-0.0.0.dev503 → omlish_cext-0.0.0.dev505}/omlish_cext.egg-info/dependency_links.txt +0 -0
- {omlish_cext-0.0.0.dev503 → omlish_cext-0.0.0.dev505}/omlish_cext.egg-info/top_level.txt +0 -0
- {omlish_cext-0.0.0.dev503 → omlish_cext-0.0.0.dev505}/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.dev505
|
|
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.dev505
|
|
18
18
|
Dynamic: license-file
|
|
19
19
|
|
|
20
20
|
# Overview
|
|
@@ -0,0 +1,545 @@
|
|
|
1
|
+
// @omlish-cext
|
|
2
|
+
// @omlish-llm-author "claude-sonnet-4-5-20250929"
|
|
3
|
+
#define PY_SSIZE_T_CLEAN
|
|
4
|
+
#include "Python.h"
|
|
5
|
+
#include "structmember.h"
|
|
6
|
+
|
|
7
|
+
#include <vector>
|
|
8
|
+
#include <unordered_map>
|
|
9
|
+
|
|
10
|
+
//
|
|
11
|
+
|
|
12
|
+
#define _MODULE_NAME "_collection"
|
|
13
|
+
#define _PACKAGE_NAME "omlish.typedvalues"
|
|
14
|
+
#define _MODULE_FULL_NAME _PACKAGE_NAME "." _MODULE_NAME
|
|
15
|
+
|
|
16
|
+
typedef struct collection_state {
|
|
17
|
+
PyObject *typed_value_type;
|
|
18
|
+
PyObject *unique_typed_value_type;
|
|
19
|
+
PyObject *duplicate_error_type;
|
|
20
|
+
} collection_state;
|
|
21
|
+
|
|
22
|
+
static inline collection_state * get_collection_state(PyObject *module)
|
|
23
|
+
{
|
|
24
|
+
void *state = PyModule_GetState(module);
|
|
25
|
+
assert(state != NULL);
|
|
26
|
+
return (collection_state *)state;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
//
|
|
30
|
+
|
|
31
|
+
// Helper struct to track unique typed values during processing
|
|
32
|
+
struct UniqueInfo {
|
|
33
|
+
PyObject *unique_tv_cls; // The unique class
|
|
34
|
+
PyObject *tv; // The typed value
|
|
35
|
+
std::vector<PyObject*> *unique_lst; // Pointer to the list in unique_dct
|
|
36
|
+
size_t idx; // Index in unique_lst when added
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// Temporary list item - either a TypedValue or a UniqueInfo
|
|
40
|
+
struct TmpItem {
|
|
41
|
+
bool is_unique;
|
|
42
|
+
union {
|
|
43
|
+
PyObject *tv; // Non-unique typed value
|
|
44
|
+
UniqueInfo *unique_info; // Unique typed value info
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
TmpItem() : is_unique(false), tv(nullptr) {}
|
|
48
|
+
~TmpItem() {
|
|
49
|
+
if (is_unique && unique_info != nullptr) {
|
|
50
|
+
delete unique_info;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Disable copy, enable move
|
|
55
|
+
TmpItem(const TmpItem&) = delete;
|
|
56
|
+
TmpItem& operator=(const TmpItem&) = delete;
|
|
57
|
+
|
|
58
|
+
TmpItem(TmpItem&& other) noexcept : is_unique(other.is_unique) {
|
|
59
|
+
if (is_unique) {
|
|
60
|
+
unique_info = other.unique_info;
|
|
61
|
+
other.unique_info = nullptr;
|
|
62
|
+
} else {
|
|
63
|
+
tv = other.tv;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
TmpItem& operator=(TmpItem&& other) noexcept {
|
|
68
|
+
if (this != &other) {
|
|
69
|
+
if (is_unique && unique_info != nullptr) {
|
|
70
|
+
delete unique_info;
|
|
71
|
+
}
|
|
72
|
+
is_unique = other.is_unique;
|
|
73
|
+
if (is_unique) {
|
|
74
|
+
unique_info = other.unique_info;
|
|
75
|
+
other.unique_info = nullptr;
|
|
76
|
+
} else {
|
|
77
|
+
tv = other.tv;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return *this;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
PyDoc_STRVAR(init_typed_values_collection_doc,
|
|
85
|
+
"init_typed_values_collection(*tvs, override=False, check_type=None)\n"
|
|
86
|
+
"\n"
|
|
87
|
+
"Initialize a typed values collection.\n"
|
|
88
|
+
"\n"
|
|
89
|
+
"Returns a tuple of (tuple, dict, dict2) where:\n"
|
|
90
|
+
"- tuple: ordered sequence of typed values\n"
|
|
91
|
+
"- dict: mapping of type -> typed value or tuple of typed values\n"
|
|
92
|
+
"- dict2: extended dict including instance types for unique values");
|
|
93
|
+
|
|
94
|
+
static PyObject * init_typed_values_collection(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
|
|
95
|
+
{
|
|
96
|
+
collection_state *state = get_collection_state(module);
|
|
97
|
+
|
|
98
|
+
// Parse arguments
|
|
99
|
+
bool override = false;
|
|
100
|
+
PyObject *check_type = nullptr;
|
|
101
|
+
|
|
102
|
+
// Handle keyword arguments
|
|
103
|
+
Py_ssize_t nkwargs = kwnames ? PyTuple_GET_SIZE(kwnames) : 0;
|
|
104
|
+
|
|
105
|
+
for (Py_ssize_t i = 0; i < nkwargs; i++) {
|
|
106
|
+
PyObject *key = PyTuple_GET_ITEM(kwnames, i);
|
|
107
|
+
PyObject *value = args[nargs + i];
|
|
108
|
+
const char *key_str = PyUnicode_AsUTF8(key);
|
|
109
|
+
|
|
110
|
+
if (key_str == nullptr) {
|
|
111
|
+
return nullptr;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (strcmp(key_str, "override") == 0) {
|
|
115
|
+
int override_result = PyObject_IsTrue(value);
|
|
116
|
+
if (override_result == -1) {
|
|
117
|
+
return nullptr;
|
|
118
|
+
}
|
|
119
|
+
override = override_result;
|
|
120
|
+
} else if (strcmp(key_str, "check_type") == 0) {
|
|
121
|
+
check_type = value;
|
|
122
|
+
} else {
|
|
123
|
+
PyErr_Format(PyExc_TypeError, "unexpected keyword argument: %s", key_str);
|
|
124
|
+
return nullptr;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// If no positional arguments, return empty tuple and dicts
|
|
129
|
+
if (nargs == 0) {
|
|
130
|
+
PyObject *empty_tuple = PyTuple_New(0);
|
|
131
|
+
if (empty_tuple == nullptr) {
|
|
132
|
+
return nullptr;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
PyObject *empty_dict = PyDict_New();
|
|
136
|
+
if (empty_dict == nullptr) {
|
|
137
|
+
Py_DECREF(empty_tuple);
|
|
138
|
+
return nullptr;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
PyObject *empty_dict2 = PyDict_New();
|
|
142
|
+
if (empty_dict2 == nullptr) {
|
|
143
|
+
Py_DECREF(empty_tuple);
|
|
144
|
+
Py_DECREF(empty_dict);
|
|
145
|
+
return nullptr;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
PyObject *result = PyTuple_Pack(3, empty_tuple, empty_dict, empty_dict2);
|
|
149
|
+
Py_DECREF(empty_tuple);
|
|
150
|
+
Py_DECREF(empty_dict);
|
|
151
|
+
Py_DECREF(empty_dict2);
|
|
152
|
+
return result;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Temporary storage
|
|
156
|
+
std::vector<TmpItem> tmp_lst;
|
|
157
|
+
tmp_lst.reserve(nargs);
|
|
158
|
+
|
|
159
|
+
// Map from unique type to list of typed values
|
|
160
|
+
std::unordered_map<PyObject*, std::vector<PyObject*>> unique_dct;
|
|
161
|
+
|
|
162
|
+
struct UniqueKeysCleaner {
|
|
163
|
+
std::unordered_map<PyObject*, std::vector<PyObject*>> ↦
|
|
164
|
+
~UniqueKeysCleaner() { for (auto &pair : map) Py_DECREF(pair.first); }
|
|
165
|
+
} keys_cleaner{unique_dct};
|
|
166
|
+
|
|
167
|
+
// Process each typed value
|
|
168
|
+
for (Py_ssize_t i = 0; i < nargs; i++) {
|
|
169
|
+
PyObject *tv = args[i];
|
|
170
|
+
|
|
171
|
+
// Check type if requested
|
|
172
|
+
if (check_type != nullptr && check_type != Py_None) {
|
|
173
|
+
int result = PyObject_IsInstance(tv, check_type);
|
|
174
|
+
if (result == -1) {
|
|
175
|
+
return nullptr;
|
|
176
|
+
}
|
|
177
|
+
if (!result) {
|
|
178
|
+
PyErr_SetObject(PyExc_TypeError, tv);
|
|
179
|
+
return nullptr;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Check if it's a UniqueTypedValue
|
|
184
|
+
int is_unique = PyObject_IsInstance(tv, state->unique_typed_value_type);
|
|
185
|
+
if (is_unique == -1) {
|
|
186
|
+
return nullptr;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (is_unique) {
|
|
190
|
+
// Get the _unique_typed_value_cls attribute
|
|
191
|
+
PyObject *unique_tv_cls = PyObject_GetAttrString(tv, "_unique_typed_value_cls");
|
|
192
|
+
if (unique_tv_cls == nullptr) {
|
|
193
|
+
return nullptr;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Check for duplicates if not override
|
|
197
|
+
if (!override) {
|
|
198
|
+
auto it = unique_dct.find(unique_tv_cls);
|
|
199
|
+
if (it != unique_dct.end() && !it->second.empty()) {
|
|
200
|
+
// Duplicate found - raise error
|
|
201
|
+
PyObject *old_tv = it->second[0];
|
|
202
|
+
|
|
203
|
+
// Create DuplicateUniqueTypedValueError
|
|
204
|
+
PyObject *error = PyObject_CallFunction(
|
|
205
|
+
state->duplicate_error_type,
|
|
206
|
+
"OOO",
|
|
207
|
+
unique_tv_cls,
|
|
208
|
+
tv,
|
|
209
|
+
old_tv
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
Py_DECREF(unique_tv_cls);
|
|
213
|
+
|
|
214
|
+
if (error == nullptr) {
|
|
215
|
+
return nullptr;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
PyErr_SetObject(state->duplicate_error_type, error);
|
|
219
|
+
Py_DECREF(error);
|
|
220
|
+
return nullptr;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Add to unique_dct
|
|
225
|
+
// Use insert to avoid reference leak: if key already exists, we need to decref the new reference
|
|
226
|
+
auto insertion = unique_dct.insert({unique_tv_cls, std::vector<PyObject*>()});
|
|
227
|
+
if (!insertion.second) {
|
|
228
|
+
// Key already existed, decref the newly acquired reference
|
|
229
|
+
Py_DECREF(unique_tv_cls);
|
|
230
|
+
}
|
|
231
|
+
std::vector<PyObject*> &unique_lst = insertion.first->second;
|
|
232
|
+
unique_lst.push_back(tv);
|
|
233
|
+
|
|
234
|
+
// Create UniqueInfo
|
|
235
|
+
UniqueInfo *info = new UniqueInfo{
|
|
236
|
+
unique_tv_cls, // Borrowed reference (will be decreffed at end)
|
|
237
|
+
tv,
|
|
238
|
+
&unique_lst,
|
|
239
|
+
unique_lst.size()
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
// Add to tmp_lst
|
|
243
|
+
TmpItem item;
|
|
244
|
+
item.is_unique = true;
|
|
245
|
+
item.unique_info = info;
|
|
246
|
+
tmp_lst.push_back(std::move(item));
|
|
247
|
+
|
|
248
|
+
} else {
|
|
249
|
+
// Check if it's a TypedValue
|
|
250
|
+
int is_typed_value = PyObject_IsInstance(tv, state->typed_value_type);
|
|
251
|
+
if (is_typed_value == -1) {
|
|
252
|
+
return nullptr;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (!is_typed_value) {
|
|
256
|
+
PyErr_SetObject(PyExc_TypeError, tv);
|
|
257
|
+
return nullptr;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Non-unique typed value
|
|
261
|
+
TmpItem item;
|
|
262
|
+
item.is_unique = false;
|
|
263
|
+
item.tv = tv;
|
|
264
|
+
tmp_lst.push_back(std::move(item));
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Build output structures
|
|
269
|
+
PyObject *lst = PyList_New(0);
|
|
270
|
+
if (lst == nullptr) {
|
|
271
|
+
return nullptr;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
PyObject *tmp_dct = PyDict_New();
|
|
275
|
+
if (tmp_dct == nullptr) {
|
|
276
|
+
Py_DECREF(lst);
|
|
277
|
+
return nullptr;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Process tmp_lst to build output list and tmp_dct
|
|
281
|
+
for (auto &item : tmp_lst) {
|
|
282
|
+
if (item.is_unique) {
|
|
283
|
+
UniqueInfo *info = item.unique_info;
|
|
284
|
+
|
|
285
|
+
// Last-in-wins: only include if this is the last one
|
|
286
|
+
if (info->idx == info->unique_lst->size()) {
|
|
287
|
+
// Add to output list
|
|
288
|
+
if (PyList_Append(lst, info->tv) == -1) {
|
|
289
|
+
Py_DECREF(lst);
|
|
290
|
+
Py_DECREF(tmp_dct);
|
|
291
|
+
return nullptr;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Add to tmp_dct (scalar value for unique types)
|
|
295
|
+
if (PyDict_SetItem(tmp_dct, info->unique_tv_cls, info->tv) == -1) {
|
|
296
|
+
Py_DECREF(lst);
|
|
297
|
+
Py_DECREF(tmp_dct);
|
|
298
|
+
return nullptr;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
} else {
|
|
302
|
+
PyObject *tv = item.tv;
|
|
303
|
+
|
|
304
|
+
// Add to output list
|
|
305
|
+
if (PyList_Append(lst, tv) == -1) {
|
|
306
|
+
Py_DECREF(lst);
|
|
307
|
+
Py_DECREF(tmp_dct);
|
|
308
|
+
return nullptr;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Add to tmp_dct (accumulating list for non-unique types)
|
|
312
|
+
PyObject *tv_type = (PyObject *)Py_TYPE(tv);
|
|
313
|
+
PyObject *existing = PyDict_GetItem(tmp_dct, tv_type); // Borrowed reference
|
|
314
|
+
|
|
315
|
+
if (existing == nullptr) {
|
|
316
|
+
// Check if an error occurred during lookup
|
|
317
|
+
if (PyErr_Occurred()) {
|
|
318
|
+
Py_DECREF(lst);
|
|
319
|
+
Py_DECREF(tmp_dct);
|
|
320
|
+
return nullptr;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Create new list
|
|
324
|
+
PyObject *new_list = PyList_New(0);
|
|
325
|
+
if (new_list == nullptr) {
|
|
326
|
+
Py_DECREF(lst);
|
|
327
|
+
Py_DECREF(tmp_dct);
|
|
328
|
+
return nullptr;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
if (PyList_Append(new_list, tv) == -1) {
|
|
332
|
+
Py_DECREF(new_list);
|
|
333
|
+
Py_DECREF(lst);
|
|
334
|
+
Py_DECREF(tmp_dct);
|
|
335
|
+
return nullptr;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
if (PyDict_SetItem(tmp_dct, tv_type, new_list) == -1) {
|
|
339
|
+
Py_DECREF(new_list);
|
|
340
|
+
Py_DECREF(lst);
|
|
341
|
+
Py_DECREF(tmp_dct);
|
|
342
|
+
return nullptr;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
Py_DECREF(new_list);
|
|
346
|
+
} else {
|
|
347
|
+
// Append to existing list
|
|
348
|
+
if (PyList_Append(existing, tv) == -1) {
|
|
349
|
+
Py_DECREF(lst);
|
|
350
|
+
Py_DECREF(tmp_dct);
|
|
351
|
+
return nullptr;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// Convert list to tuple
|
|
358
|
+
PyObject *result_tuple = PyList_AsTuple(lst);
|
|
359
|
+
Py_DECREF(lst);
|
|
360
|
+
if (result_tuple == nullptr) {
|
|
361
|
+
Py_DECREF(tmp_dct);
|
|
362
|
+
return nullptr;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Build dct: convert lists to tuples
|
|
366
|
+
PyObject *dct = PyDict_New();
|
|
367
|
+
if (dct == nullptr) {
|
|
368
|
+
Py_DECREF(result_tuple);
|
|
369
|
+
Py_DECREF(tmp_dct);
|
|
370
|
+
return nullptr;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
PyObject *key, *value;
|
|
374
|
+
Py_ssize_t pos = 0;
|
|
375
|
+
|
|
376
|
+
while (PyDict_Next(tmp_dct, &pos, &key, &value)) {
|
|
377
|
+
if (PyList_Check(value)) {
|
|
378
|
+
PyObject *tuple_value = PyList_AsTuple(value);
|
|
379
|
+
if (tuple_value == nullptr) {
|
|
380
|
+
Py_DECREF(result_tuple);
|
|
381
|
+
Py_DECREF(tmp_dct);
|
|
382
|
+
Py_DECREF(dct);
|
|
383
|
+
return nullptr;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
if (PyDict_SetItem(dct, key, tuple_value) == -1) {
|
|
387
|
+
Py_DECREF(tuple_value);
|
|
388
|
+
Py_DECREF(result_tuple);
|
|
389
|
+
Py_DECREF(tmp_dct);
|
|
390
|
+
Py_DECREF(dct);
|
|
391
|
+
return nullptr;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
Py_DECREF(tuple_value);
|
|
395
|
+
} else {
|
|
396
|
+
// Scalar value (unique type)
|
|
397
|
+
if (PyDict_SetItem(dct, key, value) == -1) {
|
|
398
|
+
Py_DECREF(result_tuple);
|
|
399
|
+
Py_DECREF(tmp_dct);
|
|
400
|
+
Py_DECREF(dct);
|
|
401
|
+
return nullptr;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
Py_DECREF(tmp_dct);
|
|
407
|
+
|
|
408
|
+
// Build dct2: dct + unique values keyed by instance type
|
|
409
|
+
PyObject *dct2 = PyDict_Copy(dct);
|
|
410
|
+
if (dct2 == nullptr) {
|
|
411
|
+
Py_DECREF(result_tuple);
|
|
412
|
+
Py_DECREF(dct);
|
|
413
|
+
return nullptr;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// Add unique values by their instance type
|
|
417
|
+
pos = 0;
|
|
418
|
+
while (PyDict_Next(dct, &pos, &key, &value)) {
|
|
419
|
+
// Check if value is a UniqueTypedValue (not a tuple)
|
|
420
|
+
if (!PyTuple_Check(value)) {
|
|
421
|
+
int is_unique = PyObject_IsInstance(value, state->unique_typed_value_type);
|
|
422
|
+
if (is_unique == -1) {
|
|
423
|
+
Py_DECREF(result_tuple);
|
|
424
|
+
Py_DECREF(dct);
|
|
425
|
+
Py_DECREF(dct2);
|
|
426
|
+
return nullptr;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
if (is_unique) {
|
|
430
|
+
PyObject *value_type = (PyObject *)Py_TYPE(value);
|
|
431
|
+
if (PyDict_SetItem(dct2, value_type, value) == -1) {
|
|
432
|
+
Py_DECREF(result_tuple);
|
|
433
|
+
Py_DECREF(dct);
|
|
434
|
+
Py_DECREF(dct2);
|
|
435
|
+
return nullptr;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// Build final result
|
|
442
|
+
PyObject *result = PyTuple_Pack(3, result_tuple, dct, dct2);
|
|
443
|
+
Py_DECREF(result_tuple);
|
|
444
|
+
Py_DECREF(dct);
|
|
445
|
+
Py_DECREF(dct2);
|
|
446
|
+
|
|
447
|
+
return result;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
//
|
|
451
|
+
|
|
452
|
+
PyDoc_STRVAR(collection_doc, "Native C++ implementations for omlish.typedvalues.collection");
|
|
453
|
+
|
|
454
|
+
static int collection_exec(PyObject *module)
|
|
455
|
+
{
|
|
456
|
+
collection_state *state = get_collection_state(module);
|
|
457
|
+
|
|
458
|
+
// Import TypedValue
|
|
459
|
+
PyObject *values_module = PyImport_ImportModule("omlish.typedvalues.values");
|
|
460
|
+
if (values_module == nullptr) {
|
|
461
|
+
return -1;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
state->typed_value_type = PyObject_GetAttrString(values_module, "TypedValue");
|
|
465
|
+
if (state->typed_value_type == nullptr) {
|
|
466
|
+
Py_DECREF(values_module);
|
|
467
|
+
return -1;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
state->unique_typed_value_type = PyObject_GetAttrString(values_module, "UniqueTypedValue");
|
|
471
|
+
Py_DECREF(values_module);
|
|
472
|
+
if (state->unique_typed_value_type == nullptr) {
|
|
473
|
+
return -1;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// Import DuplicateUniqueTypedValueError
|
|
477
|
+
PyObject *collection_module = PyImport_ImportModule("omlish.typedvalues.collection");
|
|
478
|
+
if (collection_module == nullptr) {
|
|
479
|
+
return -1;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
state->duplicate_error_type = PyObject_GetAttrString(collection_module, "DuplicateUniqueTypedValueError");
|
|
483
|
+
Py_DECREF(collection_module);
|
|
484
|
+
if (state->duplicate_error_type == nullptr) {
|
|
485
|
+
return -1;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
return 0;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
static int collection_traverse(PyObject *module, visitproc visit, void *arg)
|
|
492
|
+
{
|
|
493
|
+
collection_state *state = get_collection_state(module);
|
|
494
|
+
Py_VISIT(state->typed_value_type);
|
|
495
|
+
Py_VISIT(state->unique_typed_value_type);
|
|
496
|
+
Py_VISIT(state->duplicate_error_type);
|
|
497
|
+
return 0;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
static int collection_clear(PyObject *module)
|
|
501
|
+
{
|
|
502
|
+
collection_state *state = get_collection_state(module);
|
|
503
|
+
Py_CLEAR(state->typed_value_type);
|
|
504
|
+
Py_CLEAR(state->unique_typed_value_type);
|
|
505
|
+
Py_CLEAR(state->duplicate_error_type);
|
|
506
|
+
return 0;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
static void collection_free(void *module)
|
|
510
|
+
{
|
|
511
|
+
collection_clear((PyObject *)module);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
static PyMethodDef collection_methods[] = {
|
|
515
|
+
{"init_typed_values_collection", (PyCFunction)(void(*)(void))init_typed_values_collection, METH_FASTCALL | METH_KEYWORDS, init_typed_values_collection_doc},
|
|
516
|
+
{NULL, NULL, 0, NULL}
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
static struct PyModuleDef_Slot collection_slots[] = {
|
|
520
|
+
{Py_mod_exec, (void *) collection_exec},
|
|
521
|
+
{Py_mod_gil, Py_MOD_GIL_NOT_USED},
|
|
522
|
+
{Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED},
|
|
523
|
+
{0, NULL}
|
|
524
|
+
};
|
|
525
|
+
|
|
526
|
+
static struct PyModuleDef collection_module = {
|
|
527
|
+
.m_base = PyModuleDef_HEAD_INIT,
|
|
528
|
+
.m_name = _MODULE_NAME,
|
|
529
|
+
.m_doc = collection_doc,
|
|
530
|
+
.m_size = sizeof(collection_state),
|
|
531
|
+
.m_methods = collection_methods,
|
|
532
|
+
.m_slots = collection_slots,
|
|
533
|
+
.m_traverse = collection_traverse,
|
|
534
|
+
.m_clear = collection_clear,
|
|
535
|
+
.m_free = collection_free,
|
|
536
|
+
};
|
|
537
|
+
|
|
538
|
+
extern "C" {
|
|
539
|
+
|
|
540
|
+
PyMODINIT_FUNC PyInit__collection(void)
|
|
541
|
+
{
|
|
542
|
+
return PyModuleDef_Init(&collection_module);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
}
|
|
@@ -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.dev505
|
|
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.dev505
|
|
18
18
|
Dynamic: license-file
|
|
19
19
|
|
|
20
20
|
# Overview
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
omlish==0.0.0.dev505
|
|
@@ -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.dev505'
|
|
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.dev505',
|
|
28
28
|
]
|
|
29
29
|
|
|
30
30
|
[tool.setuptools]
|
|
@@ -18,5 +18,10 @@ st.setup(
|
|
|
18
18
|
sources=['omlish/lang/imports/_capture.cc'],
|
|
19
19
|
extra_compile_args=['-std=c++20'],
|
|
20
20
|
),
|
|
21
|
+
st.Extension(
|
|
22
|
+
name='omlish.typedvalues._collection',
|
|
23
|
+
sources=['omlish/typedvalues/_collection.cc'],
|
|
24
|
+
extra_compile_args=['-std=c++20'],
|
|
25
|
+
),
|
|
21
26
|
],
|
|
22
27
|
)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
omlish==0.0.0.dev503
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{omlish_cext-0.0.0.dev503 → omlish_cext-0.0.0.dev505}/omlish_cext.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|