omlish-cext 0.0.0.dev498__tar.gz → 0.0.0.dev499__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: omlish-cext
3
- Version: 0.0.0.dev498
3
+ Version: 0.0.0.dev499
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.dev498
17
+ Requires-Dist: omlish==0.0.0.dev499
18
18
  Dynamic: license-file
19
19
 
20
20
  # Overview
@@ -0,0 +1,209 @@
1
+ // @omlish-cext
2
+ #define PY_SSIZE_T_CLEAN
3
+ #include "Python.h"
4
+ #include "structmember.h"
5
+
6
+ #include <vector>
7
+
8
+ //
9
+
10
+ #define _MODULE_NAME "_check"
11
+ #define _PACKAGE_NAME "omlish"
12
+ #define _MODULE_FULL_NAME _PACKAGE_NAME "." _MODULE_NAME
13
+
14
+ typedef struct check_state {
15
+ PyObject *typing_any;
16
+ PyTypeObject *nonetype;
17
+ } check_state;
18
+
19
+ static inline check_state * get_check_state(PyObject *module)
20
+ {
21
+ void *state = PyModule_GetState(module);
22
+ assert(state != NULL);
23
+ return (check_state *)state;
24
+ }
25
+
26
+ //
27
+
28
+ PyDoc_STRVAR(unpack_isinstance_spec_doc, "unpack_isinstance_spec(spec)");
29
+
30
+ static PyObject * unpack_isinstance_spec(PyObject *module, PyObject *spec)
31
+ {
32
+ check_state *state = get_check_state(module);
33
+
34
+ // If spec is a type, return (spec,)
35
+ if (PyType_Check(spec)) {
36
+ return PyTuple_Pack(1, spec);
37
+ }
38
+
39
+ PyObject *tuple_spec = nullptr;
40
+
41
+ // If not a tuple, wrap it in a tuple
42
+ if (!PyTuple_Check(spec)) {
43
+ tuple_spec = PyTuple_Pack(1, spec);
44
+ if (tuple_spec == nullptr) {
45
+ return nullptr;
46
+ }
47
+ } else {
48
+ // It's already a tuple, so we'll work with it
49
+ tuple_spec = spec;
50
+ Py_INCREF(tuple_spec);
51
+ }
52
+
53
+ // Check if None is in spec
54
+ Py_ssize_t size = PyTuple_Size(tuple_spec);
55
+ if (size < 0) {
56
+ Py_DECREF(tuple_spec);
57
+ return nullptr;
58
+ }
59
+
60
+ bool has_none = false;
61
+ bool has_any = false;
62
+
63
+ for (Py_ssize_t i = 0; i < size; i++) {
64
+ PyObject *item = PyTuple_GetItem(tuple_spec, i); // borrowed reference
65
+ if (item == nullptr) {
66
+ Py_DECREF(tuple_spec);
67
+ return nullptr;
68
+ }
69
+
70
+ if (item == Py_None) {
71
+ has_none = true;
72
+ }
73
+
74
+ // Check if item is typing.Any
75
+ if (state->typing_any != nullptr) {
76
+ int cmp = PyObject_RichCompareBool(item, state->typing_any, Py_EQ);
77
+ if (cmp < 0) {
78
+ Py_DECREF(tuple_spec);
79
+ return nullptr;
80
+ }
81
+ if (cmp) {
82
+ has_any = true;
83
+ }
84
+ }
85
+ }
86
+
87
+ // If typing.Any is in spec, return (object,)
88
+ if (has_any) {
89
+ Py_DECREF(tuple_spec);
90
+ return PyTuple_Pack(1, &PyBaseObject_Type);
91
+ }
92
+
93
+ // If None is in spec, filter it out and add NoneType
94
+ if (has_none) {
95
+ std::vector<PyObject*> filtered;
96
+ filtered.reserve(size);
97
+
98
+ for (Py_ssize_t i = 0; i < size; i++) {
99
+ PyObject *item = PyTuple_GetItem(tuple_spec, i); // borrowed reference
100
+ if (item != Py_None) {
101
+ filtered.push_back(item);
102
+ }
103
+ }
104
+
105
+ // Add NoneType
106
+ filtered.push_back((PyObject *)state->nonetype);
107
+
108
+ // Create new tuple
109
+ PyObject *result = PyTuple_New(filtered.size());
110
+ if (result == nullptr) {
111
+ Py_DECREF(tuple_spec);
112
+ return nullptr;
113
+ }
114
+
115
+ for (size_t i = 0; i < filtered.size(); i++) {
116
+ Py_INCREF(filtered[i]);
117
+ PyTuple_SET_ITEM(result, i, filtered[i]);
118
+ }
119
+
120
+ Py_DECREF(tuple_spec);
121
+ return result;
122
+ }
123
+
124
+ // Return the tuple as-is
125
+ return tuple_spec;
126
+ }
127
+
128
+ //
129
+
130
+ PyDoc_STRVAR(check_doc, "Native C++ implementations for omlish.lite.check");
131
+
132
+ static int check_exec(PyObject *module)
133
+ {
134
+ check_state *state = get_check_state(module);
135
+
136
+ // Get typing.Any
137
+ PyObject *typing_module = PyImport_ImportModule("typing");
138
+ if (typing_module == nullptr) {
139
+ // If typing module is not available, just set to nullptr
140
+ PyErr_Clear();
141
+ state->typing_any = nullptr;
142
+ } else {
143
+ state->typing_any = PyObject_GetAttrString(typing_module, "Any");
144
+ Py_DECREF(typing_module);
145
+ if (state->typing_any == nullptr) {
146
+ PyErr_Clear();
147
+ }
148
+ }
149
+
150
+ // Get NoneType (type(None))
151
+ state->nonetype = Py_TYPE(Py_None);
152
+ Py_INCREF(state->nonetype);
153
+
154
+ return 0;
155
+ }
156
+
157
+ static int check_traverse(PyObject *module, visitproc visit, void *arg)
158
+ {
159
+ check_state *state = get_check_state(module);
160
+ Py_VISIT(state->typing_any);
161
+ Py_VISIT(state->nonetype);
162
+ return 0;
163
+ }
164
+
165
+ static int check_clear(PyObject *module)
166
+ {
167
+ check_state *state = get_check_state(module);
168
+ Py_CLEAR(state->typing_any);
169
+ Py_CLEAR(state->nonetype);
170
+ return 0;
171
+ }
172
+
173
+ static void check_free(void *module)
174
+ {
175
+ check_clear((PyObject *)module);
176
+ }
177
+
178
+ static PyMethodDef check_methods[] = {
179
+ {"unpack_isinstance_spec", (PyCFunction)unpack_isinstance_spec, METH_O, unpack_isinstance_spec_doc},
180
+ {NULL, NULL, 0, NULL}
181
+ };
182
+
183
+ static struct PyModuleDef_Slot check_slots[] = {
184
+ {Py_mod_exec, (void *) check_exec},
185
+ {Py_mod_gil, Py_MOD_GIL_NOT_USED},
186
+ {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED},
187
+ {0, NULL}
188
+ };
189
+
190
+ static struct PyModuleDef check_module = {
191
+ .m_base = PyModuleDef_HEAD_INIT,
192
+ .m_name = _MODULE_NAME,
193
+ .m_doc = check_doc,
194
+ .m_size = sizeof(check_state),
195
+ .m_methods = check_methods,
196
+ .m_slots = check_slots,
197
+ .m_traverse = check_traverse,
198
+ .m_clear = check_clear,
199
+ .m_free = check_free,
200
+ };
201
+
202
+ extern "C" {
203
+
204
+ PyMODINIT_FUNC PyInit__check(void)
205
+ {
206
+ return PyModuleDef_Init(&check_module);
207
+ }
208
+
209
+ }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: omlish-cext
3
- Version: 0.0.0.dev498
3
+ Version: 0.0.0.dev499
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.dev498
17
+ Requires-Dist: omlish==0.0.0.dev499
18
18
  Dynamic: license-file
19
19
 
20
20
  # Overview
@@ -2,6 +2,7 @@ LICENSE
2
2
  README.md
3
3
  pyproject.toml
4
4
  setup.py
5
+ omlish/_check.cc
5
6
  omlish/lang/_asyncs.cc
6
7
  omlish/lang/imports/_capture.cc
7
8
  omlish_cext.egg-info/PKG-INFO
@@ -0,0 +1 @@
1
+ omlish==0.0.0.dev499
@@ -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.dev498'
16
+ version = '0.0.0.dev499'
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.dev498',
27
+ 'omlish == 0.0.0.dev499',
28
28
  ]
29
29
 
30
30
  [tool.setuptools]
@@ -3,6 +3,11 @@ import setuptools as st
3
3
 
4
4
  st.setup(
5
5
  ext_modules=[
6
+ st.Extension(
7
+ name='omlish._check',
8
+ sources=['omlish/_check.cc'],
9
+ extra_compile_args=['-std=c++20'],
10
+ ),
6
11
  st.Extension(
7
12
  name='omlish.lang._asyncs',
8
13
  sources=['omlish/lang/_asyncs.cc'],
@@ -1 +0,0 @@
1
- omlish==0.0.0.dev498