arraykit 1.2.0__cp314-cp314t-win32.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
arraykit/__init__.py ADDED
@@ -0,0 +1,40 @@
1
+ # pylint: disable=W0611
2
+ # pylint: disable=E0401
3
+ # pylint: disable=C0414
4
+
5
+ from ._arraykit import __version__
6
+ from ._arraykit import TriMap as TriMap
7
+ from ._arraykit import ArrayGO as ArrayGO
8
+ from ._arraykit import BlockIndex as BlockIndex
9
+ from ._arraykit import ErrorInitTypeBlocks as ErrorInitTypeBlocks
10
+
11
+ from ._arraykit import immutable_filter as immutable_filter
12
+ from ._arraykit import mloc as mloc
13
+ from ._arraykit import name_filter as name_filter
14
+ from ._arraykit import shape_filter as shape_filter
15
+ from ._arraykit import column_2d_filter as column_2d_filter
16
+ from ._arraykit import column_1d_filter as column_1d_filter
17
+ from ._arraykit import row_1d_filter as row_1d_filter
18
+ from ._arraykit import array_deepcopy as array_deepcopy
19
+ from ._arraykit import resolve_dtype as resolve_dtype
20
+ from ._arraykit import resolve_dtype_iter as resolve_dtype_iter
21
+ from ._arraykit import isna_element as isna_element
22
+ from ._arraykit import dtype_from_element as dtype_from_element
23
+ from ._arraykit import delimited_to_arrays as delimited_to_arrays
24
+ from ._arraykit import iterable_str_to_array_1d as iterable_str_to_array_1d
25
+ from ._arraykit import split_after_count as split_after_count
26
+ from ._arraykit import get_new_indexers_and_screen as get_new_indexers_and_screen
27
+ from ._arraykit import count_iteration as count_iteration
28
+ from ._arraykit import first_true_1d as first_true_1d
29
+ from ._arraykit import first_true_2d as first_true_2d
30
+ from ._arraykit import slice_to_ascending_slice as slice_to_ascending_slice
31
+ from ._arraykit import array_to_tuple_array as array_to_tuple_array
32
+ from ._arraykit import array_to_tuple_iter as array_to_tuple_iter
33
+ from ._arraykit import nonzero_1d as nonzero_1d
34
+ from ._arraykit import is_objectable_dt64 as is_objectable_dt64
35
+ from ._arraykit import is_objectable as is_objectable
36
+ from ._arraykit import astype_array as astype_array
37
+ from ._arraykit import AutoMap as AutoMap
38
+ from ._arraykit import FrozenAutoMap as FrozenAutoMap
39
+ from ._arraykit import NonUniqueError as NonUniqueError
40
+
arraykit/__init__.pyi ADDED
@@ -0,0 +1,211 @@
1
+ import typing as tp
2
+ import datetime
3
+
4
+ import numpy as np # type: ignore
5
+
6
+ _T = tp.TypeVar('_T')
7
+
8
+ __version__: str
9
+
10
+ _TLabel = tp.Union[
11
+ tp.Hashable,
12
+ int,
13
+ bool,
14
+ np.bool_,
15
+ np.integer,
16
+ float,
17
+ complex,
18
+ np.inexact,
19
+ str,
20
+ bytes,
21
+ None,
22
+ np.datetime64,
23
+ np.timedelta64,
24
+ datetime.date,
25
+ datetime.datetime,
26
+ tp.Tuple['_TLabel', ...],
27
+ ]
28
+
29
+ class ErrorInitTypeBlocks(RuntimeError):
30
+ def __init__(self, *args: tp.Any, **kwargs: tp.Any) -> None: ...
31
+ def with_traceback(self, tb: Exception) -> Exception: ...
32
+ def __setstate__(self) -> None: ...
33
+
34
+
35
+ class NonUniqueError(RuntimeError):
36
+ def __init__(self, *args: tp.Any, **kwargs: tp.Any) -> None: ...
37
+ def with_traceback(self, tb: Exception) -> Exception: ...
38
+ def __setstate__(self) -> None: ...
39
+
40
+ class ArrayGO:
41
+ values: np.ndarray
42
+ def __init__(
43
+ self, iterable: tp.Iterable[object], *, own_iterable: bool = ...
44
+ ) -> None: ...
45
+ def __iter__(self) -> tp.Iterator[tp.Any]: ...
46
+ def __getitem__(self, __key: object) -> tp.Any: ...
47
+ def __len__(self) -> int: ...
48
+ def __getnewargs__(self) -> tp.Tuple[np.ndarray]: ...
49
+ def append(self, __value: object) -> None: ...
50
+ def copy(self: _T) -> _T: ...
51
+ def extend(self, __values: tp.Iterable[object]) -> None: ...
52
+
53
+ class TriMap:
54
+ def __init__(self, /, src_len: int, dst_len: int) -> None: ...
55
+ def __repr__(self) -> str: ...
56
+ def register_one(self, /, src_from: int, dst_from: int) -> None: ...
57
+ def register_unmatched_dst(self) -> None: ...
58
+ def register_many(self, /, src_from: int, dst_from: np.ndarray) -> None: ...
59
+ def finalize(self) -> None: ...
60
+ def is_many(self) -> bool: ...
61
+ def src_no_fill(self) -> bool: ...
62
+ def dst_no_fill(self) -> bool: ...
63
+ def map_src_no_fill(self, /, array_from: np.ndarray) -> np.ndarray: ...
64
+ def map_dst_no_fill(self, /, array_from: np.ndarray) -> np.ndarray: ...
65
+ def map_src_fill(self, /,
66
+ array_from: np.ndarray,
67
+ fill_value: tp.Any,
68
+ fill_value_dtype: np.dtype
69
+ ) -> np.ndarray: ...
70
+ def map_dst_fill(self, /,
71
+ array_from: np.ndarray,
72
+ fill_value: tp.Any,
73
+ fill_value_dtype: np.dtype
74
+ ) -> np.ndarray: ...
75
+ def map_merge(self, /,
76
+ array_from_src: np.ndarray,
77
+ array_from_dst: np.ndarray,
78
+ ) -> np.ndarray: ...
79
+
80
+ class BlockIndex:
81
+ shape: tp.Tuple[int, int]
82
+ dtype: np.dtype
83
+ rows: int
84
+ columns: int
85
+
86
+ def __init__(
87
+ block_count: int = 0,
88
+ row_count: int = -1,
89
+ bir_count: int = 0,
90
+ bir_capacity: int = 8,
91
+ bir_bytes: bytes = b'',
92
+ dtype: np.dtype = None,
93
+ ) -> None: ...
94
+ def register(self, __value: np.ndarray) -> bool: ...
95
+ def to_list(self,) -> tp.List[tp.Tuple[int, int]]: ...
96
+ def to_bytes(self,) -> bytes: ...
97
+ def copy(self,) -> 'BlockIndex': ...
98
+ def __len__(self,) -> int: ...
99
+ def __iter__(self,) -> tp.Iterator[tp.Tuple[int, int]]: ...
100
+ def __reversed__(self,) -> tp.Iterator[tp.Tuple[int, int]]: ...
101
+ def __getitem__(self, __key: int) -> tp.Tuple[int, int]: ...
102
+ def __getstate__(self,) -> tp.Tuple[int, int, int, int, bytes]: ...
103
+ def __setstate__(self, state: tp.Tuple[int, int, int, int, bytes]) -> None: ...
104
+ def get_block(self, __key: int) -> int: ...
105
+ def get_column(self, __key: int) -> int: ...
106
+ def iter_select(self,
107
+ __key: tp.Union[slice, np.ndarray, tp.List[int]],
108
+ ) -> tp.Iterator[tp.Tuple[int, int]]: ...
109
+ def iter_contiguous(self,
110
+ __key: tp.Union[slice, np.ndarray, tp.List[int]],
111
+ *,
112
+ ascending: bool = False,
113
+ reduce: bool = False,
114
+ ) -> tp.Iterator[tp.Tuple[int, tp.Union[slice, int]]]: ...
115
+ def iter_block(self) -> tp.Iterator[tp.Tuple[int, slice]]: ...
116
+
117
+
118
+ class FrozenAutoMap:
119
+ def __init__(self, labels: tp.Iterable[_TLabel] | np.ndarray = (), /,) -> None: ...
120
+ def get(self, __key: _TLabel, /,) -> int: ...
121
+ def keys(self) -> tp.Iterator[_TLabel]: ...
122
+ def items(self) -> tp.Iterator[tuple[_TLabel, int]]: ...
123
+ def values(self) -> tp.Iterator[int]: ...
124
+ def get_all(self, __key: list[_TLabel] | np.ndarray) -> np.ndarray: ...
125
+ def get_any(self, __key: list[_TLabel] | np.ndarray) -> list[int]: ...
126
+
127
+ def __iter__(self) -> tp.Iterator[_TLabel]: ...
128
+ def __getitem__(self, __key: tp.Any) -> int: ...
129
+ def __contains__(self, __key: tp.Any) -> bool: ...
130
+ def __getnewargs__(self) -> tp.Any: ...
131
+ def __reversed__(self) -> tp.Any: ...
132
+ def __sizeof__(self) -> int: ...
133
+ def __getstate__(self) -> tp.Any: ...
134
+ def __setstate__(self, __state: tp.Any) -> None: ...
135
+ def __len__(self) -> int: ...
136
+
137
+ def __or__(self) -> tp.Any: ...
138
+ def __ror__(self) -> tp.Any: ...
139
+
140
+
141
+ class AutoMap(FrozenAutoMap):
142
+ def __init__(self, labels: tp.Iterable[_TLabel] | np.ndarray = (), /,) -> None: ...
143
+ def __ior__(self) -> tp.Any: ...
144
+ def add(self, __key: _TLabel) -> None: ...
145
+ def update(self, __keys: tp.Iterable[_TLabel] | np.ndarray) -> None: ...
146
+
147
+
148
+
149
+
150
+ def iterable_str_to_array_1d(
151
+ iterable: tp.Iterable[str],
152
+ *,
153
+ dtype: tp.Optional[tp.Any] = None,
154
+ thousandschar: str = ',',
155
+ decimalchar: str = '.',
156
+ ) -> np.ndarray: ...
157
+
158
+ def delimited_to_arrays(
159
+ file_like: tp.Iterable[str],
160
+ *,
161
+ axis: int = 0,
162
+ dtypes: tp.Optional[tp.Callable[[int], tp.Any]] = None,
163
+ line_select: tp.Optional[tp.Callable[[int], bool]] = None,
164
+ delimiter: str = ',',
165
+ doublequote: bool = True,
166
+ escapechar: tp.Optional[str] = '',
167
+ quotechar: tp.Optional[str] = '"',
168
+ quoting: int = 0,
169
+ skipinitialspace: bool = False,
170
+ strict: bool = False,
171
+ thousandschar: str = ',',
172
+ decimalchar: str = '.',
173
+ ) -> tp.List[np.array]: ...
174
+
175
+ def split_after_count(
176
+ string: str,
177
+ *,
178
+ delimiter: str = ',',
179
+ count: int = 0,
180
+ doublequote: bool = True,
181
+ escapechar: tp.Optional[str] = '',
182
+ quotechar: tp.Optional[str] = '"',
183
+ quoting: int = 0,
184
+ strict: bool = False,
185
+ ) -> tp.Tuple[str, str]: ...
186
+
187
+ def count_iteration(__iterable: tp.Iterable) -> int: ...
188
+
189
+ def immutable_filter(__array: np.ndarray) -> np.ndarray: ...
190
+ def mloc(__array: np.ndarray) -> int: ...
191
+ def name_filter(__name: _TLabel) -> _TLabel: ...
192
+ def shape_filter(__array: np.ndarray) -> np.ndarray: ...
193
+ def column_2d_filter(__array: np.ndarray) -> np.ndarray: ...
194
+ def column_1d_filter(__array: np.ndarray) -> np.ndarray: ...
195
+ def row_1d_filter(__array: np.ndarray) -> np.ndarray: ...
196
+ def array_deepcopy(__array: np.ndarray, memo: tp.Optional[tp.Dict[int, tp.Any]]) -> np.ndarray: ...
197
+ def resolve_dtype(__d1: np.dtype, __d2: np.dtype) -> np.dtype: ...
198
+ def resolve_dtype_iter(__dtypes: tp.Iterable[np.dtype]) -> np.dtype: ...
199
+ def isna_element(__value: tp.Any, include_none: bool = True) -> bool: ...
200
+ def dtype_from_element(__value: tp.Optional[_TLabel]) -> np.dtype: ...
201
+ def get_new_indexers_and_screen(indexers: np.ndarray, positions: np.ndarray) -> tp.Tuple[np.ndarray, np.ndarray]: ...
202
+
203
+ def first_true_1d(__array: np.ndarray, *, forward: bool) -> int: ...
204
+ def first_true_2d(__array: np.ndarray, *, forward: bool, axis: int) -> np.ndarray: ...
205
+ def nonzero_1d(__array: np.ndarray, /) -> np.ndarray: ...
206
+ def is_objectable_dt64(__array: np.ndarray, /) -> bool: ...
207
+ def is_objectable(__array: np.ndarray, /) -> bool: ...
208
+ def astype_array(__array: np.ndarray, __dtype: np.dtype | None, /) -> np.ndarray: ...
209
+ def slice_to_ascending_slice(__slice: slice, __size: int) -> slice: ...
210
+ def array_to_tuple_array(__array: np.ndarray) -> np.ndarray: ...
211
+ def array_to_tuple_iter(__array: np.ndarray) -> tp.Iterator[tp.Tuple[tp.Any, ...]]: ...
arraykit/_arraykit.c ADDED
@@ -0,0 +1,160 @@
1
+ # include "Python.h"
2
+
3
+ # define PY_ARRAY_UNIQUE_SYMBOL AK_ARRAY_API
4
+ # define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
5
+
6
+ # include "numpy/arrayobject.h"
7
+
8
+ # include "array_go.h"
9
+ # include "array_to_tuple.h"
10
+ # include "block_index.h"
11
+ # include "delimited_to_arrays.h"
12
+ # include "methods.h"
13
+ # include "tri_map.h"
14
+ # include "auto_map.h"
15
+
16
+ static PyMethodDef arraykit_methods[] = {
17
+ {"immutable_filter", immutable_filter, METH_O, NULL},
18
+ {"mloc", mloc, METH_O, NULL},
19
+ {"name_filter", name_filter, METH_O, NULL},
20
+ {"shape_filter", shape_filter, METH_O, NULL},
21
+ {"column_2d_filter", column_2d_filter, METH_O, NULL},
22
+ {"column_1d_filter", column_1d_filter, METH_O, NULL},
23
+ {"row_1d_filter", row_1d_filter, METH_O, NULL},
24
+ {"slice_to_ascending_slice", slice_to_ascending_slice, METH_VARARGS, NULL},
25
+ {"array_deepcopy",
26
+ (PyCFunction)array_deepcopy,
27
+ METH_VARARGS | METH_KEYWORDS,
28
+ NULL},
29
+ {"array_to_tuple_array", array_to_tuple_array, METH_O, NULL},
30
+ {"array_to_tuple_iter", array_to_tuple_iter, METH_O, NULL},
31
+ {"resolve_dtype", resolve_dtype, METH_VARARGS, NULL},
32
+ {"resolve_dtype_iter", resolve_dtype_iter, METH_O, NULL},
33
+ {"first_true_1d",
34
+ (PyCFunction)first_true_1d,
35
+ METH_VARARGS | METH_KEYWORDS,
36
+ NULL},
37
+ {"first_true_2d",
38
+ (PyCFunction)first_true_2d,
39
+ METH_VARARGS | METH_KEYWORDS,
40
+ NULL},
41
+ {"delimited_to_arrays",
42
+ (PyCFunction)delimited_to_arrays,
43
+ METH_VARARGS | METH_KEYWORDS,
44
+ NULL},
45
+ {"iterable_str_to_array_1d",
46
+ (PyCFunction)iterable_str_to_array_1d,
47
+ METH_VARARGS | METH_KEYWORDS,
48
+ NULL},
49
+ {"split_after_count",
50
+ (PyCFunction)split_after_count,
51
+ METH_VARARGS | METH_KEYWORDS,
52
+ NULL},
53
+ {"count_iteration", count_iteration, METH_O, NULL},
54
+ {"nonzero_1d", nonzero_1d, METH_O, NULL},
55
+ {"is_objectable_dt64", is_objectable_dt64, METH_O, NULL},
56
+ {"is_objectable", is_objectable, METH_O, NULL},
57
+ {"astype_array", astype_array, METH_VARARGS, NULL},
58
+ {"isna_element",
59
+ (PyCFunction)isna_element,
60
+ METH_VARARGS | METH_KEYWORDS,
61
+ NULL},
62
+ {"dtype_from_element", dtype_from_element, METH_O, NULL},
63
+ {"get_new_indexers_and_screen",
64
+ (PyCFunction)get_new_indexers_and_screen,
65
+ METH_VARARGS | METH_KEYWORDS,
66
+ NULL},
67
+ {NULL},
68
+ };
69
+
70
+ static struct PyModuleDef arraykit_module = {
71
+ PyModuleDef_HEAD_INIT,
72
+ .m_name = "_arraykit",
73
+ .m_doc = NULL,
74
+ .m_size = -1,
75
+ .m_methods = arraykit_methods,
76
+ };
77
+
78
+ PyObject*
79
+ PyInit__arraykit(void)
80
+ {
81
+ import_array();
82
+
83
+ ErrorInitTypeBlocks = PyErr_NewExceptionWithDoc(
84
+ "arraykit.ErrorInitTypeBlocks",
85
+ "RuntimeError error in block initialization.",
86
+ PyExc_RuntimeError,
87
+ NULL);
88
+ if (ErrorInitTypeBlocks == NULL) {
89
+ return NULL;
90
+ }
91
+
92
+ NonUniqueError = PyErr_NewExceptionWithDoc(
93
+ "arraykit.NonUniqueError",
94
+ "ValueError for non-unique values.",
95
+ PyExc_ValueError,
96
+ NULL);
97
+ if (NonUniqueError == NULL) {
98
+ return NULL;
99
+ }
100
+
101
+ // store a reference to the deepcopy function
102
+ PyObject *copy = PyImport_ImportModule("copy");
103
+ if (copy == NULL) {
104
+ return NULL;
105
+ }
106
+ PyObject *deepcopy = PyObject_GetAttrString(copy, "deepcopy");
107
+ Py_DECREF(copy);
108
+ if (deepcopy == NULL) {
109
+ return NULL;
110
+ }
111
+
112
+ // store a year dtype object
113
+ PyObject* dt_year_str = PyUnicode_FromString("datetime64[Y]");
114
+ if (!dt_year_str) return NULL;
115
+
116
+ PyArray_Descr* dt_year = NULL;
117
+ if (!PyArray_DescrConverter2(dt_year_str, &dt_year)) {
118
+ Py_DECREF(dt_year_str);
119
+ return NULL;
120
+ }
121
+ Py_DECREF(dt_year_str);
122
+
123
+
124
+ PyObject *m = PyModule_Create(&arraykit_module);
125
+ if (!m ||
126
+ PyModule_AddStringConstant(m, "__version__", Py_STRINGIFY(AK_VERSION)) ||
127
+ PyType_Ready(&BlockIndexType) ||
128
+ PyType_Ready(&BIIterType) ||
129
+ PyType_Ready(&BIIterSeqType) ||
130
+ PyType_Ready(&BIIterSliceType) ||
131
+ PyType_Ready(&BIIterBoolType) ||
132
+ PyType_Ready(&BIIterContiguousType) ||
133
+ PyType_Ready(&BIIterBlockType) ||
134
+ PyType_Ready(&TriMapType) ||
135
+ PyType_Ready(&ArrayGOType) ||
136
+ PyType_Ready(&AMType) ||
137
+ PyType_Ready(&FAMIType) ||
138
+ PyType_Ready(&FAMVType) ||
139
+ PyType_Ready(&FAMType) ||
140
+ PyModule_AddObject(m, "BlockIndex", (PyObject *) &BlockIndexType) ||
141
+ PyModule_AddObject(m, "TriMap", (PyObject *) &TriMapType) ||
142
+ PyModule_AddObject(m, "ArrayGO", (PyObject *) &ArrayGOType) ||
143
+ PyModule_AddObject(m, "deepcopy", deepcopy) ||
144
+ PyModule_AddObject(m, "ErrorInitTypeBlocks", ErrorInitTypeBlocks) ||
145
+ PyModule_AddObject(m, "AutoMap", (PyObject *)&AMType) ||
146
+ PyModule_AddObject(m, "FrozenAutoMap", (PyObject *)&FAMType) ||
147
+ PyModule_AddObject(m, "NonUniqueError", NonUniqueError) ||
148
+ PyModule_AddObject(m, "dt_year", (PyObject *)dt_year)
149
+ ){
150
+ Py_XDECREF(deepcopy);
151
+ Py_XDECREF(dt_year);
152
+ Py_XDECREF(m);
153
+ return NULL;
154
+ }
155
+ #ifdef Py_GIL_DISABLED
156
+ PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED);
157
+ #endif
158
+ return m;
159
+ }
160
+
Binary file
arraykit/array_go.c ADDED
@@ -0,0 +1,264 @@
1
+ # include "Python.h"
2
+
3
+ # define NO_IMPORT_ARRAY
4
+ # define PY_ARRAY_UNIQUE_SYMBOL AK_ARRAY_API
5
+ # define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
6
+
7
+ # include "numpy/arrayobject.h"
8
+
9
+ # include "array_go.h"
10
+ # include "utilities.h"
11
+
12
+ typedef struct ArrayGOObject {
13
+ PyObject_HEAD
14
+ PyObject *array;
15
+ PyObject *list;
16
+ } ArrayGOObject;
17
+
18
+ PyDoc_STRVAR(
19
+ ArrayGO_doc,
20
+ "\n"
21
+ "A grow only, one-dimensional, object type array, "
22
+ "specifically for usage in IndexHierarchy IndexLevel objects.\n"
23
+ "\n"
24
+ "Args:\n"
25
+ " own_iterable: flag iterable as ownable by this instance.\n"
26
+ );
27
+
28
+ PyDoc_STRVAR(
29
+ ArrayGO_copy_doc,
30
+ "Return a new ArrayGO with an immutable array from this ArrayGO\n"
31
+ );
32
+
33
+ PyDoc_STRVAR(ArrayGO_values_doc, "Return the immutable labels array\n");
34
+
35
+ //------------------------------------------------------------------------------
36
+ // ArrayGO utility functions
37
+
38
+ static inline int
39
+ update_array_cache(ArrayGOObject *self)
40
+ {
41
+ if (self->list) {
42
+ if (self->array) {
43
+ PyObject *container = PyTuple_Pack(2, self->array, self->list);
44
+ if (!container) {
45
+ return -1;
46
+ }
47
+ Py_SETREF(self->array, PyArray_Concatenate(container, 0));
48
+ Py_DECREF(container);
49
+ }
50
+ else {
51
+ self->array = PyArray_FROM_OT(self->list, NPY_OBJECT);
52
+ }
53
+ PyArray_CLEARFLAGS((PyArrayObject *)self->array, NPY_ARRAY_WRITEABLE);
54
+ Py_CLEAR(self->list);
55
+ }
56
+ return 0;
57
+ }
58
+
59
+ //------------------------------------------------------------------------------
60
+ // ArrayGO Methods:
61
+ static char * argnames[] = {"iterable", "own_iterable", NULL};
62
+
63
+ PyObject *
64
+ ArrayGO_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
65
+ {
66
+ PyObject *iterable;
67
+ int own_iterable = 0;
68
+ int parsed = PyArg_ParseTupleAndKeywords(
69
+ args, kwargs, "O|$p:ArrayGO", argnames, &iterable, &own_iterable
70
+ );
71
+ if (!parsed) {
72
+ return NULL;
73
+ }
74
+ ArrayGOObject *self = (ArrayGOObject *)cls->tp_alloc(cls, 0);
75
+ if (!self) {
76
+ return NULL;
77
+ }
78
+
79
+ if (PyArray_Check(iterable)) {
80
+ if (!PyDataType_ISOBJECT(PyArray_DESCR((PyArrayObject *)iterable))) {
81
+ PyErr_SetString(PyExc_NotImplementedError,
82
+ "only object arrays are supported");
83
+ Py_DECREF(self);
84
+ return NULL;
85
+ }
86
+ if (own_iterable) {
87
+ // ArrayGO(np.array(...), own_iterable=True)
88
+ PyArray_CLEARFLAGS((PyArrayObject *)iterable, NPY_ARRAY_WRITEABLE);
89
+ self->array = iterable;
90
+ Py_INCREF(iterable);
91
+ return (PyObject *)self;
92
+ }
93
+ // ArrayGO(np.array(...))
94
+ self->array = (PyObject *)AK_immutable_filter((PyArrayObject *)iterable);
95
+ if (!self->array) {
96
+ Py_CLEAR(self);
97
+ }
98
+ return (PyObject *)self;
99
+ }
100
+ if (PyList_CheckExact(iterable) && own_iterable) {
101
+ // ArrayGO([...], own_iterable=True)
102
+ self->list = iterable;
103
+ Py_INCREF(iterable);
104
+ return (PyObject *)self;
105
+ }
106
+ // ArrayGO([...])
107
+ self->list = PySequence_List(iterable);
108
+ if (!self->list) {
109
+ Py_CLEAR(self);
110
+ }
111
+ return (PyObject *)self;
112
+ }
113
+
114
+ PyObject *
115
+ ArrayGO_append(ArrayGOObject *self, PyObject *value)
116
+ {
117
+ if (!self->list) {
118
+ self->list = PyList_New(1);
119
+ if (!self->list) {
120
+ return NULL;
121
+ }
122
+ Py_INCREF(value);
123
+ PyList_SET_ITEM(self->list, 0, value);
124
+ }
125
+ else if (PyList_Append(self->list, value)) {
126
+ return NULL;
127
+ }
128
+ Py_RETURN_NONE;
129
+ }
130
+
131
+ PyObject *
132
+ ArrayGO_extend(ArrayGOObject *self, PyObject *values)
133
+ {
134
+ if (!self->list) {
135
+ self->list = PySequence_List(values);
136
+ if (!self->list) {
137
+ return NULL;
138
+ }
139
+ Py_RETURN_NONE;
140
+ }
141
+ Py_ssize_t len = PyList_Size(self->list);
142
+ if (len < 0 || PyList_SetSlice(self->list, len, len, values)) {
143
+ return NULL;
144
+ }
145
+ Py_RETURN_NONE;
146
+ }
147
+
148
+ PyObject *
149
+ ArrayGO_getnewargs(ArrayGOObject *self, PyObject *Py_UNUSED(unused))
150
+ {
151
+ if (self->list && update_array_cache(self)) {
152
+ return NULL;
153
+ }
154
+ return PyTuple_Pack(1, self->array);
155
+ }
156
+
157
+ PyObject *
158
+ ArrayGO_copy(ArrayGOObject *self, PyObject *Py_UNUSED(unused))
159
+ {
160
+ ArrayGOObject *copy = PyObject_GC_New(ArrayGOObject, &ArrayGOType);
161
+ copy->array = self->array;
162
+ copy->list = self->list ? PySequence_List(self->list) : NULL;
163
+ Py_XINCREF(copy->array);
164
+ return (PyObject *)copy;
165
+ }
166
+
167
+ PyObject *
168
+ ArrayGO_iter(ArrayGOObject *self)
169
+ {
170
+ if (self->list && update_array_cache(self)) {
171
+ return NULL;
172
+ }
173
+ return PyObject_GetIter(self->array);
174
+ }
175
+
176
+ PyObject *
177
+ ArrayGO_mp_subscript(ArrayGOObject *self, PyObject *key)
178
+ {
179
+ if (self->list && update_array_cache(self)) {
180
+ return NULL;
181
+ }
182
+ return PyObject_GetItem(self->array, key);
183
+ }
184
+
185
+ Py_ssize_t
186
+ ArrayGO_mp_length(ArrayGOObject *self)
187
+ {
188
+ return ((self->array ? PyArray_SIZE((PyArrayObject *)self->array) : 0)
189
+ + (self->list ? PyList_Size(self->list) : 0));
190
+ }
191
+
192
+ PyObject *
193
+ ArrayGO_values_getter(ArrayGOObject *self, void* Py_UNUSED(closure))
194
+ {
195
+ if (self->list && update_array_cache(self)) {
196
+ return NULL;
197
+ }
198
+ Py_INCREF(self->array);
199
+ return self->array;
200
+ }
201
+
202
+ int
203
+ ArrayGO_traverse(ArrayGOObject *self, visitproc visit, void *arg)
204
+ {
205
+ Py_VISIT(self->array);
206
+ Py_VISIT(self->list);
207
+ return 0;
208
+ }
209
+
210
+ int
211
+ ArrayGO_clear(ArrayGOObject *self)
212
+ {
213
+ Py_CLEAR(self->array);
214
+ Py_CLEAR(self->list);
215
+ return 0;
216
+ }
217
+
218
+ void
219
+ ArrayGO_dealloc(ArrayGOObject *self)
220
+ {
221
+ Py_XDECREF(self->array);
222
+ Py_XDECREF(self->list);
223
+ Py_TYPE(self)->tp_free((PyObject *)self);
224
+ }
225
+
226
+ // ArrayGo method bundles
227
+
228
+ static struct PyGetSetDef ArrayGO_getset[] = {
229
+ {"values", (getter)ArrayGO_values_getter, NULL, ArrayGO_values_doc, NULL},
230
+ {NULL},
231
+ };
232
+
233
+ static PyMethodDef ArrayGO_methods[] = {
234
+ {"append", (PyCFunction)ArrayGO_append, METH_O, NULL},
235
+ {"copy", (PyCFunction)ArrayGO_copy, METH_NOARGS, ArrayGO_copy_doc},
236
+ {"extend", (PyCFunction)ArrayGO_extend, METH_O, NULL},
237
+ {"__getnewargs__", (PyCFunction)ArrayGO_getnewargs, METH_NOARGS, NULL},
238
+ {NULL},
239
+ };
240
+
241
+ static PyMappingMethods ArrayGO_as_mapping = {
242
+ .mp_length = (lenfunc)ArrayGO_mp_length,
243
+ .mp_subscript = (binaryfunc) ArrayGO_mp_subscript,
244
+ };
245
+
246
+ //------------------------------------------------------------------------------
247
+ // ArrayGo PyTypeObject
248
+ // https://docs.python.org/3/c-api/typeobj.html
249
+
250
+ PyTypeObject ArrayGOType = {
251
+ PyVarObject_HEAD_INIT(NULL, 0)
252
+ .tp_as_mapping = &ArrayGO_as_mapping,
253
+ .tp_basicsize = sizeof(ArrayGOObject),
254
+ .tp_clear = (inquiry)ArrayGO_clear,
255
+ .tp_dealloc = (destructor)ArrayGO_dealloc,
256
+ .tp_doc = ArrayGO_doc,
257
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
258
+ .tp_getset = ArrayGO_getset,
259
+ .tp_iter = (getiterfunc)ArrayGO_iter,
260
+ .tp_methods = ArrayGO_methods,
261
+ .tp_name = "arraykit.ArrayGO",
262
+ .tp_new = ArrayGO_new,
263
+ .tp_traverse = (traverseproc)ArrayGO_traverse,
264
+ };
arraykit/array_go.h ADDED
@@ -0,0 +1,8 @@
1
+ # ifndef ARRAYKIT_SRC_ARRAY_GO_H_
2
+ # define ARRAYKIT_SRC_ARRAY_GO_H_
3
+
4
+ # include "Python.h"
5
+
6
+ extern PyTypeObject ArrayGOType;
7
+
8
+ # endif /* ARRAYKIT_SRC_ARRAY_GO_H_ */