arraykit 0.6.1__tar.gz → 0.6.2__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.
- {arraykit-0.6.1/arraykit.egg-info → arraykit-0.6.2}/PKG-INFO +1 -1
- {arraykit-0.6.1 → arraykit-0.6.2}/README.rst +8 -0
- {arraykit-0.6.1 → arraykit-0.6.2/arraykit.egg-info}/PKG-INFO +1 -1
- {arraykit-0.6.1 → arraykit-0.6.2}/setup.py +1 -1
- {arraykit-0.6.1 → arraykit-0.6.2}/src/_arraykit.c +276 -268
- {arraykit-0.6.1 → arraykit-0.6.2}/test/test_nonzero_1d.py +16 -1
- {arraykit-0.6.1 → arraykit-0.6.2}/test/test_tri_map.py +15 -1
- {arraykit-0.6.1 → arraykit-0.6.2}/LICENSE.txt +0 -0
- {arraykit-0.6.1 → arraykit-0.6.2}/MANIFEST.in +0 -0
- {arraykit-0.6.1 → arraykit-0.6.2}/arraykit.egg-info/SOURCES.txt +0 -0
- {arraykit-0.6.1 → arraykit-0.6.2}/arraykit.egg-info/dependency_links.txt +0 -0
- {arraykit-0.6.1 → arraykit-0.6.2}/arraykit.egg-info/requires.txt +0 -0
- {arraykit-0.6.1 → arraykit-0.6.2}/arraykit.egg-info/top_level.txt +0 -0
- {arraykit-0.6.1 → arraykit-0.6.2}/setup.cfg +0 -0
- {arraykit-0.6.1 → arraykit-0.6.2}/src/__init__.py +0 -0
- {arraykit-0.6.1 → arraykit-0.6.2}/src/__init__.pyi +0 -0
- {arraykit-0.6.1 → arraykit-0.6.2}/src/py.typed +0 -0
- {arraykit-0.6.1 → arraykit-0.6.2}/test/test_array_go.py +0 -0
- {arraykit-0.6.1 → arraykit-0.6.2}/test/test_block_index.py +0 -0
- {arraykit-0.6.1 → arraykit-0.6.2}/test/test_delimited_to_arrays.py +0 -0
- {arraykit-0.6.1 → arraykit-0.6.2}/test/test_delimited_to_arrays_integration.py +0 -0
- {arraykit-0.6.1 → arraykit-0.6.2}/test/test_delimited_to_arrays_property.py +0 -0
- {arraykit-0.6.1 → arraykit-0.6.2}/test/test_nonzero_1d_property.py +0 -0
- {arraykit-0.6.1 → arraykit-0.6.2}/test/test_pyi.py +0 -0
- {arraykit-0.6.1 → arraykit-0.6.2}/test/test_split_after_count.py +0 -0
- {arraykit-0.6.1 → arraykit-0.6.2}/test/test_type_discovery.py +0 -0
- {arraykit-0.6.1 → arraykit-0.6.2}/test/test_util.py +0 -0
|
@@ -37,6 +37,14 @@ ArrayKit requires the following:
|
|
|
37
37
|
What is New in ArrayKit
|
|
38
38
|
-------------------------
|
|
39
39
|
|
|
40
|
+
0.6.2
|
|
41
|
+
............
|
|
42
|
+
|
|
43
|
+
Extended ``nonzero_1d()`` to support non-contiguous arrays,
|
|
44
|
+
|
|
45
|
+
Optimizations to ``TriMap`` when mapping to object and flexible dtypes.
|
|
46
|
+
|
|
47
|
+
|
|
40
48
|
0.6.1
|
|
41
49
|
............
|
|
42
50
|
|
|
@@ -5,7 +5,7 @@ from setuptools import Extension # type: ignore
|
|
|
5
5
|
from setuptools import setup
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
|
|
8
|
-
AK_VERSION = '0.6.
|
|
8
|
+
AK_VERSION = '0.6.2'
|
|
9
9
|
|
|
10
10
|
def get_long_description() -> str:
|
|
11
11
|
return '''The ArrayKit library provides utilities for creating and transforming NumPy arrays, implementing performance-critical StaticFrame operations as Python C extensions.
|
|
@@ -3535,7 +3535,7 @@ resolve_dtype_iter(PyObject *Py_UNUSED(m), PyObject *arg) {
|
|
|
3535
3535
|
//------------------------------------------------------------------------------
|
|
3536
3536
|
// general utility
|
|
3537
3537
|
|
|
3538
|
-
#define
|
|
3538
|
+
#define NONZERO_APPEND_INDEX_RELATIVE { \
|
|
3539
3539
|
if (AK_UNLIKELY(count == capacity)) { \
|
|
3540
3540
|
capacity <<= 1; \
|
|
3541
3541
|
indices = (npy_int64*)realloc(indices, sizeof(npy_int64) * capacity);\
|
|
@@ -3546,7 +3546,18 @@ resolve_dtype_iter(PyObject *Py_UNUSED(m), PyObject *arg) {
|
|
|
3546
3546
|
indices[count++] = p - p_start; \
|
|
3547
3547
|
} \
|
|
3548
3548
|
|
|
3549
|
-
|
|
3549
|
+
#define NONZERO_APPEND_INDEX_ABSOLUTE { \
|
|
3550
|
+
if (AK_UNLIKELY(count == capacity)) { \
|
|
3551
|
+
capacity <<= 1; \
|
|
3552
|
+
indices = (npy_int64*)realloc(indices, sizeof(npy_int64) * capacity);\
|
|
3553
|
+
if (indices == NULL) { \
|
|
3554
|
+
return NULL; \
|
|
3555
|
+
} \
|
|
3556
|
+
} \
|
|
3557
|
+
indices[count++] = i; \
|
|
3558
|
+
} \
|
|
3559
|
+
|
|
3560
|
+
// Given a Boolean, contiguous 1D array, return the index positions in an int64 array. Through experimentation it has been verified that doing full-size allocation of memory does not permit outperforming NumPy at 10_000_000 scale; but doing less optimizations does help. Using bit masks does not improve perforamnce over pointer arithmetic. Prescanning for all empty is very effective. Note that NumPy befits from first counting the nonzeros, then allocating only enough data for the expexted number.
|
|
3550
3561
|
static inline PyObject*
|
|
3551
3562
|
AK_nonzero_1d(PyArrayObject* array) {
|
|
3552
3563
|
// the maxiumum number of indices we could return is the size of the array; if this is under a certain number, probably better to just allocate that rather than reallocate
|
|
@@ -3566,112 +3577,71 @@ AK_nonzero_1d(PyArrayObject* array) {
|
|
|
3566
3577
|
Py_ssize_t capacity = count_max < 1024 ? count_max : count_max / 8;
|
|
3567
3578
|
npy_int64* indices = (npy_int64*)malloc(sizeof(npy_int64) * capacity);
|
|
3568
3579
|
|
|
3569
|
-
// array is contiguous, 1d, boolean
|
|
3570
|
-
npy_bool* p_start = (npy_bool*)PyArray_DATA(array);
|
|
3571
|
-
npy_bool* p = p_start;
|
|
3572
|
-
npy_bool* p_end = p + count_max;
|
|
3573
|
-
npy_bool* p_end_roll = p_end - size_div.rem;
|
|
3574
|
-
|
|
3575
3580
|
NPY_BEGIN_THREADS_DEF;
|
|
3576
3581
|
NPY_BEGIN_THREADS;
|
|
3577
|
-
// Through experimentation it has been verified that doing full-size allocation of memory does not permit outperforming NumPy at 10_000_000 scale; but doing less optimizations does help.
|
|
3578
|
-
// Using bit masks does not improve perforamnce over pointer arithmetic.
|
|
3579
|
-
// Prescanning for all empty is very effective.
|
|
3580
3582
|
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3583
|
+
if (PyArray_IS_C_CONTIGUOUS(array)) {
|
|
3584
|
+
npy_bool* p_start = (npy_bool*)PyArray_DATA(array);
|
|
3585
|
+
npy_bool* p = p_start;
|
|
3586
|
+
npy_bool* p_end = p + count_max;
|
|
3587
|
+
npy_bool* p_end_roll = p_end - size_div.rem;
|
|
3588
|
+
|
|
3589
|
+
while (p < p_end_roll) {
|
|
3590
|
+
if (*(npy_uint64*)p == 0) {
|
|
3591
|
+
p += 8; // no true within this 8 byte roll region
|
|
3592
|
+
continue;
|
|
3593
|
+
}
|
|
3594
|
+
if (*p) {NONZERO_APPEND_INDEX_RELATIVE;}
|
|
3595
|
+
p++;
|
|
3596
|
+
if (*p) {NONZERO_APPEND_INDEX_RELATIVE;}
|
|
3597
|
+
p++;
|
|
3598
|
+
if (*p) {NONZERO_APPEND_INDEX_RELATIVE;}
|
|
3599
|
+
p++;
|
|
3600
|
+
if (*p) {NONZERO_APPEND_INDEX_RELATIVE;}
|
|
3601
|
+
p++;
|
|
3602
|
+
if (*p) {NONZERO_APPEND_INDEX_RELATIVE;}
|
|
3603
|
+
p++;
|
|
3604
|
+
if (*p) {NONZERO_APPEND_INDEX_RELATIVE;}
|
|
3605
|
+
p++;
|
|
3606
|
+
if (*p) {NONZERO_APPEND_INDEX_RELATIVE;}
|
|
3607
|
+
p++;
|
|
3608
|
+
if (*p) {NONZERO_APPEND_INDEX_RELATIVE;}
|
|
3609
|
+
p++;
|
|
3610
|
+
}
|
|
3611
|
+
while (p < p_end) {
|
|
3612
|
+
if (*p) {NONZERO_APPEND_INDEX_RELATIVE;}
|
|
3613
|
+
p++;
|
|
3585
3614
|
}
|
|
3586
|
-
if (*p) {NONZERO_APPEND_INDEX;}
|
|
3587
|
-
p++;
|
|
3588
|
-
if (*p) {NONZERO_APPEND_INDEX;}
|
|
3589
|
-
p++;
|
|
3590
|
-
if (*p) {NONZERO_APPEND_INDEX;}
|
|
3591
|
-
p++;
|
|
3592
|
-
if (*p) {NONZERO_APPEND_INDEX;}
|
|
3593
|
-
p++;
|
|
3594
|
-
if (*p) {NONZERO_APPEND_INDEX;}
|
|
3595
|
-
p++;
|
|
3596
|
-
if (*p) {NONZERO_APPEND_INDEX;}
|
|
3597
|
-
p++;
|
|
3598
|
-
if (*p) {NONZERO_APPEND_INDEX;}
|
|
3599
|
-
p++;
|
|
3600
|
-
if (*p) {NONZERO_APPEND_INDEX;}
|
|
3601
|
-
p++;
|
|
3602
3615
|
}
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3616
|
+
else {
|
|
3617
|
+
npy_intp i = 0; // position within Boolean array
|
|
3618
|
+
npy_intp i_end = count_max;
|
|
3619
|
+
npy_intp i_end_roll = count_max - size_div.rem;
|
|
3620
|
+
while (i < i_end_roll) {
|
|
3621
|
+
if (*(npy_bool*)PyArray_GETPTR1(array, i)) {NONZERO_APPEND_INDEX_ABSOLUTE;}
|
|
3622
|
+
i++;
|
|
3623
|
+
if (*(npy_bool*)PyArray_GETPTR1(array, i)) {NONZERO_APPEND_INDEX_ABSOLUTE;}
|
|
3624
|
+
i++;
|
|
3625
|
+
if (*(npy_bool*)PyArray_GETPTR1(array, i)) {NONZERO_APPEND_INDEX_ABSOLUTE;}
|
|
3626
|
+
i++;
|
|
3627
|
+
if (*(npy_bool*)PyArray_GETPTR1(array, i)) {NONZERO_APPEND_INDEX_ABSOLUTE;}
|
|
3628
|
+
i++;
|
|
3629
|
+
if (*(npy_bool*)PyArray_GETPTR1(array, i)) {NONZERO_APPEND_INDEX_ABSOLUTE;}
|
|
3630
|
+
i++;
|
|
3631
|
+
if (*(npy_bool*)PyArray_GETPTR1(array, i)) {NONZERO_APPEND_INDEX_ABSOLUTE;}
|
|
3632
|
+
i++;
|
|
3633
|
+
if (*(npy_bool*)PyArray_GETPTR1(array, i)) {NONZERO_APPEND_INDEX_ABSOLUTE;}
|
|
3634
|
+
i++;
|
|
3635
|
+
if (*(npy_bool*)PyArray_GETPTR1(array, i)) {NONZERO_APPEND_INDEX_ABSOLUTE;}
|
|
3636
|
+
i++;
|
|
3637
|
+
}
|
|
3638
|
+
while (i < i_end) {
|
|
3639
|
+
if (*(npy_bool*)PyArray_GETPTR1(array, i)) {NONZERO_APPEND_INDEX_ABSOLUTE;}
|
|
3640
|
+
i++;
|
|
3641
|
+
}
|
|
3606
3642
|
}
|
|
3607
3643
|
NPY_END_THREADS;
|
|
3608
3644
|
|
|
3609
|
-
// npy_uint64 roll;
|
|
3610
|
-
// while (p < p_end_roll) {
|
|
3611
|
-
// roll = *(npy_uint64*)p;
|
|
3612
|
-
// if (roll == 0) {
|
|
3613
|
-
// p += 8; // no true within this 8 byte roll region
|
|
3614
|
-
// continue;
|
|
3615
|
-
// }
|
|
3616
|
-
// // this order depends on byte order
|
|
3617
|
-
// if (roll & 0xFF) {NONZERO_APPEND_OFFSET(0);}
|
|
3618
|
-
// if (roll & 0xFF00) {NONZERO_APPEND_OFFSET(1);}
|
|
3619
|
-
// if (roll & 0xFF0000) {NONZERO_APPEND_OFFSET(2);}
|
|
3620
|
-
// if (roll & 0xFF000000) {NONZERO_APPEND_OFFSET(3);}
|
|
3621
|
-
// if (roll & 0xFF00000000) {NONZERO_APPEND_OFFSET(4);}
|
|
3622
|
-
// if (roll & 0xFF0000000000) {NONZERO_APPEND_OFFSET(5);}
|
|
3623
|
-
// if (roll & 0xFF000000000000) {NONZERO_APPEND_OFFSET(6);}
|
|
3624
|
-
// if (roll & 0xFF00000000000000) {NONZERO_APPEND_OFFSET(7);}
|
|
3625
|
-
// p += 8;
|
|
3626
|
-
// }
|
|
3627
|
-
// while (p < p_end) {
|
|
3628
|
-
// if (*p) {NONZERO_APPEND_OFFSET(0);}
|
|
3629
|
-
// p++;
|
|
3630
|
-
// }
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
// while (p < p_end_roll) {
|
|
3634
|
-
// if (*(npy_uint64*)p == 0) {
|
|
3635
|
-
// p += 8; // no true within this roll region
|
|
3636
|
-
// continue;
|
|
3637
|
-
// }
|
|
3638
|
-
// if (AK_UNLIKELY(count + 8 >= capacity)) {
|
|
3639
|
-
// capacity <<= 1;
|
|
3640
|
-
// indices = (npy_int64*)realloc(indices, sizeof(npy_int64) * capacity);
|
|
3641
|
-
// if (indices == NULL) {
|
|
3642
|
-
// return NULL;
|
|
3643
|
-
// }
|
|
3644
|
-
// }
|
|
3645
|
-
// if (*p) {indices[count++] = p - p_start;}
|
|
3646
|
-
// p++;
|
|
3647
|
-
// if (*p) {indices[count++] = p - p_start;}
|
|
3648
|
-
// p++;
|
|
3649
|
-
// if (*p) {indices[count++] = p - p_start;}
|
|
3650
|
-
// p++;
|
|
3651
|
-
// if (*p) {indices[count++] = p - p_start;}
|
|
3652
|
-
// p++;
|
|
3653
|
-
// if (*p) {indices[count++] = p - p_start;}
|
|
3654
|
-
// p++;
|
|
3655
|
-
// if (*p) {indices[count++] = p - p_start;}
|
|
3656
|
-
// p++;
|
|
3657
|
-
// if (*p) {indices[count++] = p - p_start;}
|
|
3658
|
-
// p++;
|
|
3659
|
-
// if (*p) {indices[count++] = p - p_start;}
|
|
3660
|
-
// p++;
|
|
3661
|
-
// }
|
|
3662
|
-
// // at most three more indices remain
|
|
3663
|
-
// if (AK_UNLIKELY(count + 7 >= capacity)) {
|
|
3664
|
-
// capacity <<= 1;
|
|
3665
|
-
// indices = (npy_int64*)realloc(indices, sizeof(npy_int64) * capacity);
|
|
3666
|
-
// if (indices == NULL) {
|
|
3667
|
-
// return NULL;
|
|
3668
|
-
// }
|
|
3669
|
-
// }
|
|
3670
|
-
// while (p < p_end) {
|
|
3671
|
-
// if (*p) {indices[count++] = p - p_start;}
|
|
3672
|
-
// p++;
|
|
3673
|
-
// }
|
|
3674
|
-
|
|
3675
3645
|
npy_intp dims = {count};
|
|
3676
3646
|
final = PyArray_SimpleNewFromData(1, &dims, NPY_INT64, (void*)indices);
|
|
3677
3647
|
if (!final) {
|
|
@@ -3683,7 +3653,8 @@ AK_nonzero_1d(PyArrayObject* array) {
|
|
|
3683
3653
|
PyArray_CLEARFLAGS((PyArrayObject*)final, NPY_ARRAY_WRITEABLE);
|
|
3684
3654
|
return final;
|
|
3685
3655
|
}
|
|
3686
|
-
#undef
|
|
3656
|
+
#undef NONZERO_APPEND_INDEX_RELATIVE
|
|
3657
|
+
#undef NONZERO_APPEND_INDEX_ABSOLUTE
|
|
3687
3658
|
|
|
3688
3659
|
static PyObject*
|
|
3689
3660
|
nonzero_1d(PyObject *Py_UNUSED(m), PyObject *a) {
|
|
@@ -3697,10 +3668,6 @@ nonzero_1d(PyObject *Py_UNUSED(m), PyObject *a) {
|
|
|
3697
3668
|
PyErr_SetString(PyExc_ValueError, "Array must be of type bool");
|
|
3698
3669
|
return NULL;
|
|
3699
3670
|
}
|
|
3700
|
-
if (!PyArray_IS_C_CONTIGUOUS(array)) {
|
|
3701
|
-
PyErr_SetString(PyExc_ValueError, "Array must be contiguous");
|
|
3702
|
-
return NULL;
|
|
3703
|
-
}
|
|
3704
3671
|
return AK_nonzero_1d(array);
|
|
3705
3672
|
}
|
|
3706
3673
|
|
|
@@ -5869,8 +5836,6 @@ typedef struct TriMapObject {
|
|
|
5869
5836
|
Py_ssize_t src_len;
|
|
5870
5837
|
Py_ssize_t dst_len;
|
|
5871
5838
|
Py_ssize_t len;
|
|
5872
|
-
// Py_ssize_t src_connected;
|
|
5873
|
-
// Py_ssize_t dst_connected;
|
|
5874
5839
|
bool is_many;
|
|
5875
5840
|
bool finalized;
|
|
5876
5841
|
|
|
@@ -5932,8 +5897,6 @@ TriMap_init(PyObject *self, PyObject *args, PyObject *kwargs) {
|
|
|
5932
5897
|
tm->is_many = false;
|
|
5933
5898
|
tm->finalized = false;
|
|
5934
5899
|
tm->len = 0;
|
|
5935
|
-
// tm->src_connected = 0;
|
|
5936
|
-
// tm->dst_connected = 0;
|
|
5937
5900
|
|
|
5938
5901
|
// we create arrays, and also pre-extract pointers to array data for fast insertion; we keep the array for optimal summing routines
|
|
5939
5902
|
npy_intp dims_src_len[] = {src_len};
|
|
@@ -6039,7 +6002,7 @@ TriMap_repr(TriMapObject *self) {
|
|
|
6039
6002
|
is_finalized);
|
|
6040
6003
|
}
|
|
6041
6004
|
|
|
6042
|
-
// Provide the integer positions connecting the `src` to the `dst`. If there is no match to `src` or `dst`, the unmatched position can be provided with -1. From each side, a connection is documented to the current `len`. Each time this is called `len` is incremented, indicating the inrease in position
|
|
6005
|
+
// Provide the integer positions connecting the `src` to the `dst`. If there is no match to `src` or `dst`, the unmatched position can be provided with -1. From each side, a connection is documented to the current `len`. Each time this is called `len` is incremented, indicating the inrease in position in the `final`. Return NULL on error.
|
|
6043
6006
|
|
|
6044
6007
|
// Inner function for calling from C; returns 0 on success, -1 on error. Exceptions will be set on error.
|
|
6045
6008
|
static inline int
|
|
@@ -6062,7 +6025,6 @@ AK_TM_register_one(TriMapObject* tm, Py_ssize_t src_from, Py_ssize_t dst_from) {
|
|
|
6062
6025
|
}
|
|
6063
6026
|
tm->src_one[tm->src_one_count] = (TriMapOne){src_from, tm->len};
|
|
6064
6027
|
tm->src_one_count += 1;
|
|
6065
|
-
// tm->src_connected += 1;
|
|
6066
6028
|
}
|
|
6067
6029
|
if (dst_matched) {
|
|
6068
6030
|
if (AK_UNLIKELY(tm->dst_one_count == tm->dst_one_capacity)) {
|
|
@@ -6076,7 +6038,6 @@ AK_TM_register_one(TriMapObject* tm, Py_ssize_t src_from, Py_ssize_t dst_from) {
|
|
|
6076
6038
|
}
|
|
6077
6039
|
tm->dst_one[tm->dst_one_count] = (TriMapOne){dst_from, tm->len};
|
|
6078
6040
|
tm->dst_one_count += 1;
|
|
6079
|
-
// tm->dst_connected += 1;
|
|
6080
6041
|
}
|
|
6081
6042
|
if (src_matched && dst_matched) {
|
|
6082
6043
|
if (!tm->is_many) {
|
|
@@ -6215,8 +6176,6 @@ TriMap_register_many(TriMapObject *self, PyObject *args) {
|
|
|
6215
6176
|
npy_int64 pos = *(npy_int64*)PyArray_GETPTR1(dst_from, i); // always int64
|
|
6216
6177
|
self->dst_match_data[pos] = NPY_TRUE;
|
|
6217
6178
|
}
|
|
6218
|
-
// self->src_connected += increment;
|
|
6219
|
-
// self->dst_connected += increment;
|
|
6220
6179
|
self->len += increment;
|
|
6221
6180
|
self->is_many = true;
|
|
6222
6181
|
Py_RETURN_NONE;
|
|
@@ -6359,7 +6318,7 @@ TriMap_dst_no_fill(TriMapObject *self, PyObject *Py_UNUSED(unused)) {
|
|
|
6359
6318
|
Py_RETURN_FALSE;
|
|
6360
6319
|
}
|
|
6361
6320
|
|
|
6362
|
-
# define
|
|
6321
|
+
# define AK_TM_TRANSFER_SCALAR(npy_type_to, npy_type_from) do { \
|
|
6363
6322
|
npy_type_to* array_to_data = (npy_type_to*)PyArray_DATA(array_to); \
|
|
6364
6323
|
TriMapOne* o = one_pairs; \
|
|
6365
6324
|
TriMapOne* o_end = o + one_count; \
|
|
@@ -6396,57 +6355,11 @@ TriMap_dst_no_fill(TriMapObject *self, PyObject *Py_UNUSED(unused)) {
|
|
|
6396
6355
|
} \
|
|
6397
6356
|
} \
|
|
6398
6357
|
} \
|
|
6399
|
-
}
|
|
6400
|
-
|
|
6401
|
-
// The elsize of the `to` array will be equal to or greater than the from array
|
|
6402
|
-
#define TRANSFER_FLEXIBLE(c_type) { \
|
|
6403
|
-
npy_intp t_element_size = PyArray_DESCR(array_to)->elsize; \
|
|
6404
|
-
npy_intp t_element_cp = t_element_size / sizeof(c_type); \
|
|
6405
|
-
npy_intp f_element_size = PyArray_DESCR(array_from)->elsize; \
|
|
6406
|
-
npy_intp f_element_cp = f_element_size / sizeof(c_type); \
|
|
6407
|
-
npy_intp gap = t_element_size - f_element_size; \
|
|
6408
|
-
c_type* array_to_data = (c_type*)PyArray_DATA(array_to); \
|
|
6409
|
-
c_type* f; \
|
|
6410
|
-
c_type* t; \
|
|
6411
|
-
c_type* t_end; \
|
|
6412
|
-
npy_intp dst_pos; \
|
|
6413
|
-
npy_int64 f_pos; \
|
|
6414
|
-
PyArrayObject* dst; \
|
|
6415
|
-
TriMapOne* o = one_pairs; \
|
|
6416
|
-
TriMapOne* o_end = o + one_count; \
|
|
6417
|
-
for (; o < o_end; o++) { \
|
|
6418
|
-
f = (c_type*)PyArray_GETPTR1(array_from, o->from); \
|
|
6419
|
-
t = array_to_data + t_element_cp * o->to; \
|
|
6420
|
-
memcpy(t, f, f_element_size); \
|
|
6421
|
-
memset(t + f_element_cp, '\0', gap); \
|
|
6422
|
-
} \
|
|
6423
|
-
for (Py_ssize_t i = 0; i < tm->many_count; i++) { \
|
|
6424
|
-
t = array_to_data + t_element_cp * tm->many_to[i].start; \
|
|
6425
|
-
t_end = array_to_data + t_element_cp * tm->many_to[i].stop; \
|
|
6426
|
-
if (from_src) { \
|
|
6427
|
-
f = (c_type*)PyArray_GETPTR1(array_from, tm->many_from[i].src);\
|
|
6428
|
-
for (; t < t_end; t += t_element_cp) { \
|
|
6429
|
-
memcpy(t, f, f_element_size); \
|
|
6430
|
-
memset(t + f_element_cp, '\0', gap); \
|
|
6431
|
-
} \
|
|
6432
|
-
} \
|
|
6433
|
-
else { \
|
|
6434
|
-
dst_pos = 0; \
|
|
6435
|
-
dst = tm->many_from[i].dst; \
|
|
6436
|
-
for (; t < t_end; t += t_element_cp) { \
|
|
6437
|
-
f_pos = *(npy_int64*)PyArray_GETPTR1(dst, dst_pos); \
|
|
6438
|
-
f = (c_type*)PyArray_GETPTR1(array_from, f_pos); \
|
|
6439
|
-
memcpy(t, f, f_element_size); \
|
|
6440
|
-
memset(t + f_element_cp, '\0', gap); \
|
|
6441
|
-
dst_pos++; \
|
|
6442
|
-
} \
|
|
6443
|
-
} \
|
|
6444
|
-
} \
|
|
6445
|
-
} \
|
|
6358
|
+
} while (0) \
|
|
6446
6359
|
|
|
6447
6360
|
// Based on `tm` state, transfer from src or from dst (depending on `from_src`) to a `array_to`, a newly created contiguous array that is compatible with the values in `array_from`. Returns -1 on error. This only needs to match to / from type combinations that are possible from `resolve_dtype`, i.e., bool never goes to integer.
|
|
6448
6361
|
static inline int
|
|
6449
|
-
|
|
6362
|
+
AK_TM_transfer_scalar(TriMapObject* tm,
|
|
6450
6363
|
bool from_src,
|
|
6451
6364
|
PyArrayObject* array_from,
|
|
6452
6365
|
PyArrayObject* array_to) {
|
|
@@ -6455,206 +6368,194 @@ AK_TM_transfer(TriMapObject* tm,
|
|
|
6455
6368
|
|
|
6456
6369
|
switch(PyArray_TYPE(array_to)){
|
|
6457
6370
|
case NPY_BOOL:
|
|
6458
|
-
|
|
6371
|
+
AK_TM_TRANSFER_SCALAR(npy_bool, npy_bool);
|
|
6459
6372
|
return 0;
|
|
6460
6373
|
case NPY_INT64:
|
|
6461
6374
|
switch (PyArray_TYPE(array_from)) {
|
|
6462
6375
|
case NPY_INT64:
|
|
6463
|
-
|
|
6376
|
+
AK_TM_TRANSFER_SCALAR(npy_int64, npy_int64);
|
|
6464
6377
|
return 0;
|
|
6465
6378
|
case NPY_INT32:
|
|
6466
|
-
|
|
6379
|
+
AK_TM_TRANSFER_SCALAR(npy_int64, npy_int32);
|
|
6467
6380
|
return 0;
|
|
6468
6381
|
case NPY_INT16:
|
|
6469
|
-
|
|
6382
|
+
AK_TM_TRANSFER_SCALAR(npy_int64, npy_int16);
|
|
6470
6383
|
return 0;
|
|
6471
6384
|
case NPY_INT8:
|
|
6472
|
-
|
|
6385
|
+
AK_TM_TRANSFER_SCALAR(npy_int64, npy_int8);
|
|
6473
6386
|
return 0;
|
|
6474
6387
|
case NPY_UINT32:
|
|
6475
|
-
|
|
6388
|
+
AK_TM_TRANSFER_SCALAR(npy_int64, npy_uint32);
|
|
6476
6389
|
return 0;
|
|
6477
6390
|
case NPY_UINT16:
|
|
6478
|
-
|
|
6391
|
+
AK_TM_TRANSFER_SCALAR(npy_int64, npy_uint16);
|
|
6479
6392
|
return 0;
|
|
6480
6393
|
case NPY_UINT8:
|
|
6481
|
-
|
|
6394
|
+
AK_TM_TRANSFER_SCALAR(npy_int64, npy_uint8);
|
|
6482
6395
|
return 0;
|
|
6483
6396
|
}
|
|
6484
6397
|
break;
|
|
6485
6398
|
case NPY_INT32:
|
|
6486
6399
|
switch (PyArray_TYPE(array_from)) {
|
|
6487
6400
|
case NPY_INT32:
|
|
6488
|
-
|
|
6401
|
+
AK_TM_TRANSFER_SCALAR(npy_int32, npy_int32);
|
|
6489
6402
|
return 0;
|
|
6490
6403
|
case NPY_INT16:
|
|
6491
|
-
|
|
6404
|
+
AK_TM_TRANSFER_SCALAR(npy_int32, npy_int16);
|
|
6492
6405
|
return 0;
|
|
6493
6406
|
case NPY_INT8:
|
|
6494
|
-
|
|
6407
|
+
AK_TM_TRANSFER_SCALAR(npy_int32, npy_int8);
|
|
6495
6408
|
return 0;
|
|
6496
6409
|
case NPY_UINT16:
|
|
6497
|
-
|
|
6410
|
+
AK_TM_TRANSFER_SCALAR(npy_int32, npy_uint16);
|
|
6498
6411
|
return 0;
|
|
6499
6412
|
case NPY_UINT8:
|
|
6500
|
-
|
|
6413
|
+
AK_TM_TRANSFER_SCALAR(npy_int32, npy_uint8);
|
|
6501
6414
|
return 0;
|
|
6502
6415
|
}
|
|
6503
6416
|
break;
|
|
6504
6417
|
case NPY_INT16:
|
|
6505
6418
|
switch (PyArray_TYPE(array_from)) {
|
|
6506
6419
|
case NPY_INT16:
|
|
6507
|
-
|
|
6420
|
+
AK_TM_TRANSFER_SCALAR(npy_int16, npy_int16);
|
|
6508
6421
|
return 0;
|
|
6509
6422
|
case NPY_INT8:
|
|
6510
|
-
|
|
6423
|
+
AK_TM_TRANSFER_SCALAR(npy_int16, npy_int8);
|
|
6511
6424
|
return 0;
|
|
6512
6425
|
case NPY_UINT8:
|
|
6513
|
-
|
|
6426
|
+
AK_TM_TRANSFER_SCALAR(npy_int16, npy_uint8);
|
|
6514
6427
|
return 0;
|
|
6515
6428
|
}
|
|
6516
6429
|
break;
|
|
6517
6430
|
case NPY_INT8:
|
|
6518
|
-
|
|
6431
|
+
AK_TM_TRANSFER_SCALAR(npy_int8, npy_int8);
|
|
6519
6432
|
return 0;
|
|
6520
6433
|
case NPY_UINT64:
|
|
6521
6434
|
switch (PyArray_TYPE(array_from)) {
|
|
6522
6435
|
case NPY_UINT64:
|
|
6523
|
-
|
|
6436
|
+
AK_TM_TRANSFER_SCALAR(npy_uint64, npy_uint64);
|
|
6524
6437
|
return 0;
|
|
6525
6438
|
case NPY_UINT32:
|
|
6526
|
-
|
|
6439
|
+
AK_TM_TRANSFER_SCALAR(npy_uint64, npy_uint32);
|
|
6527
6440
|
return 0;
|
|
6528
6441
|
case NPY_UINT16:
|
|
6529
|
-
|
|
6442
|
+
AK_TM_TRANSFER_SCALAR(npy_uint64, npy_uint16);
|
|
6530
6443
|
return 0;
|
|
6531
6444
|
case NPY_UINT8:
|
|
6532
|
-
|
|
6445
|
+
AK_TM_TRANSFER_SCALAR(npy_uint64, npy_uint8);
|
|
6533
6446
|
return 0;
|
|
6534
6447
|
}
|
|
6535
6448
|
break;
|
|
6536
6449
|
case NPY_UINT32:
|
|
6537
6450
|
switch (PyArray_TYPE(array_from)) {
|
|
6538
6451
|
case NPY_UINT32:
|
|
6539
|
-
|
|
6452
|
+
AK_TM_TRANSFER_SCALAR(npy_uint32, npy_uint32);
|
|
6540
6453
|
return 0;
|
|
6541
6454
|
case NPY_UINT16:
|
|
6542
|
-
|
|
6455
|
+
AK_TM_TRANSFER_SCALAR(npy_uint32, npy_uint16);
|
|
6543
6456
|
return 0;
|
|
6544
6457
|
case NPY_UINT8:
|
|
6545
|
-
|
|
6458
|
+
AK_TM_TRANSFER_SCALAR(npy_uint32, npy_uint8);
|
|
6546
6459
|
return 0;
|
|
6547
6460
|
}
|
|
6548
6461
|
break;
|
|
6549
6462
|
case NPY_UINT16:
|
|
6550
6463
|
switch (PyArray_TYPE(array_from)) {
|
|
6551
6464
|
case NPY_UINT16:
|
|
6552
|
-
|
|
6465
|
+
AK_TM_TRANSFER_SCALAR(npy_uint16, npy_uint16);
|
|
6553
6466
|
return 0;
|
|
6554
6467
|
case NPY_UINT8:
|
|
6555
|
-
|
|
6468
|
+
AK_TM_TRANSFER_SCALAR(npy_uint16, npy_uint8);
|
|
6556
6469
|
return 0;
|
|
6557
6470
|
}
|
|
6558
6471
|
break;
|
|
6559
6472
|
case NPY_UINT8:
|
|
6560
|
-
|
|
6473
|
+
AK_TM_TRANSFER_SCALAR(npy_uint8, npy_uint8);
|
|
6561
6474
|
return 0;
|
|
6562
6475
|
case NPY_FLOAT64:
|
|
6563
6476
|
switch (PyArray_TYPE(array_from)) {
|
|
6564
6477
|
case NPY_FLOAT64:
|
|
6565
|
-
|
|
6478
|
+
AK_TM_TRANSFER_SCALAR(npy_float64, npy_float64);
|
|
6566
6479
|
return 0;
|
|
6567
6480
|
case NPY_FLOAT32:
|
|
6568
|
-
|
|
6481
|
+
AK_TM_TRANSFER_SCALAR(npy_float64, npy_float32);
|
|
6569
6482
|
return 0;
|
|
6570
6483
|
case NPY_FLOAT16:
|
|
6571
|
-
|
|
6484
|
+
AK_TM_TRANSFER_SCALAR(npy_float64, npy_float16);
|
|
6572
6485
|
return 0;
|
|
6573
6486
|
case NPY_INT64:
|
|
6574
|
-
|
|
6487
|
+
AK_TM_TRANSFER_SCALAR(npy_float64, npy_int64);
|
|
6575
6488
|
return 0;
|
|
6576
6489
|
case NPY_INT32:
|
|
6577
|
-
|
|
6490
|
+
AK_TM_TRANSFER_SCALAR(npy_float64, npy_int32);
|
|
6578
6491
|
return 0;
|
|
6579
6492
|
case NPY_INT16:
|
|
6580
|
-
|
|
6493
|
+
AK_TM_TRANSFER_SCALAR(npy_float64, npy_int16);
|
|
6581
6494
|
return 0;
|
|
6582
6495
|
case NPY_INT8:
|
|
6583
|
-
|
|
6496
|
+
AK_TM_TRANSFER_SCALAR(npy_float64, npy_int8);
|
|
6584
6497
|
return 0;
|
|
6585
6498
|
case NPY_UINT64:
|
|
6586
|
-
|
|
6499
|
+
AK_TM_TRANSFER_SCALAR(npy_float64, npy_uint64);
|
|
6587
6500
|
return 0;
|
|
6588
6501
|
case NPY_UINT32:
|
|
6589
|
-
|
|
6502
|
+
AK_TM_TRANSFER_SCALAR(npy_float64, npy_uint32);
|
|
6590
6503
|
return 0;
|
|
6591
6504
|
case NPY_UINT16:
|
|
6592
|
-
|
|
6505
|
+
AK_TM_TRANSFER_SCALAR(npy_float64, npy_uint16);
|
|
6593
6506
|
return 0;
|
|
6594
6507
|
case NPY_UINT8:
|
|
6595
|
-
|
|
6508
|
+
AK_TM_TRANSFER_SCALAR(npy_float64, npy_uint8);
|
|
6596
6509
|
return 0;
|
|
6597
6510
|
}
|
|
6598
6511
|
break;
|
|
6599
6512
|
case NPY_FLOAT32:
|
|
6600
6513
|
switch (PyArray_TYPE(array_from)) {
|
|
6601
6514
|
case NPY_FLOAT32:
|
|
6602
|
-
|
|
6515
|
+
AK_TM_TRANSFER_SCALAR(npy_float32, npy_float32);
|
|
6603
6516
|
return 0;
|
|
6604
6517
|
case NPY_FLOAT16:
|
|
6605
|
-
|
|
6518
|
+
AK_TM_TRANSFER_SCALAR(npy_float32, npy_float16);
|
|
6606
6519
|
return 0;
|
|
6607
6520
|
case NPY_INT16:
|
|
6608
|
-
|
|
6521
|
+
AK_TM_TRANSFER_SCALAR(npy_float32, npy_int16);
|
|
6609
6522
|
return 0;
|
|
6610
6523
|
case NPY_INT8:
|
|
6611
|
-
|
|
6524
|
+
AK_TM_TRANSFER_SCALAR(npy_float32, npy_int8);
|
|
6612
6525
|
return 0;
|
|
6613
6526
|
case NPY_UINT16:
|
|
6614
|
-
|
|
6527
|
+
AK_TM_TRANSFER_SCALAR(npy_float32, npy_uint16);
|
|
6615
6528
|
return 0;
|
|
6616
6529
|
case NPY_UINT8:
|
|
6617
|
-
|
|
6530
|
+
AK_TM_TRANSFER_SCALAR(npy_float32, npy_uint8);
|
|
6618
6531
|
return 0;
|
|
6619
6532
|
}
|
|
6620
6533
|
break;
|
|
6621
6534
|
case NPY_FLOAT16:
|
|
6622
6535
|
switch (PyArray_TYPE(array_from)) {
|
|
6623
6536
|
case NPY_FLOAT16:
|
|
6624
|
-
|
|
6537
|
+
AK_TM_TRANSFER_SCALAR(npy_float16, npy_float16);
|
|
6625
6538
|
return 0;
|
|
6626
6539
|
case NPY_INT8:
|
|
6627
|
-
|
|
6540
|
+
AK_TM_TRANSFER_SCALAR(npy_float16, npy_int8);
|
|
6628
6541
|
return 0;
|
|
6629
6542
|
case NPY_UINT16:
|
|
6630
|
-
|
|
6543
|
+
AK_TM_TRANSFER_SCALAR(npy_float16, npy_uint16);
|
|
6631
6544
|
return 0;
|
|
6632
6545
|
case NPY_UINT8:
|
|
6633
|
-
|
|
6546
|
+
AK_TM_TRANSFER_SCALAR(npy_float16, npy_uint8);
|
|
6634
6547
|
return 0;
|
|
6635
6548
|
}
|
|
6636
6549
|
break;
|
|
6637
|
-
case NPY_UNICODE: {
|
|
6638
|
-
TRANSFER_FLEXIBLE(Py_UCS4);
|
|
6639
|
-
return 0;
|
|
6640
|
-
}
|
|
6641
|
-
case NPY_STRING: {
|
|
6642
|
-
TRANSFER_FLEXIBLE(char);
|
|
6643
|
-
return 0;
|
|
6644
|
-
}
|
|
6645
6550
|
case NPY_DATETIME: {
|
|
6646
|
-
|
|
6551
|
+
AK_TM_TRANSFER_SCALAR(npy_int64, npy_int64);
|
|
6647
6552
|
return 0;
|
|
6648
6553
|
}
|
|
6649
6554
|
}
|
|
6650
|
-
// AK_DEBUG_MSG_OBJ("array_to", (PyObject*)array_to);
|
|
6651
|
-
// AK_DEBUG_MSG_OBJ("array_from", (PyObject*)array_from);
|
|
6652
6555
|
PyErr_SetString(PyExc_TypeError, "No handling for types");
|
|
6653
6556
|
return -1;
|
|
6654
6557
|
}
|
|
6655
|
-
|
|
6656
|
-
#undef TRANSFER_SCALARS
|
|
6657
|
-
#undef TRANSFER_FLEXIBLE
|
|
6558
|
+
#undef AK_TM_TRANSFER_SCALAR
|
|
6658
6559
|
|
|
6659
6560
|
// Returns -1 on error. Specialized transfer from any type of an array to an object array.
|
|
6660
6561
|
static inline int
|
|
@@ -6740,12 +6641,10 @@ AK_TM_fill_object(TriMapObject* tm,
|
|
|
6740
6641
|
|
|
6741
6642
|
PyArrayObject* final_fill = (PyArrayObject*)(from_src
|
|
6742
6643
|
? tm->final_src_fill : tm->final_dst_fill);
|
|
6743
|
-
|
|
6744
6644
|
PyObject** array_to_data = (PyObject**)PyArray_DATA(array_to);
|
|
6745
6645
|
npy_int64* p = (npy_int64*)PyArray_DATA(final_fill);
|
|
6746
6646
|
npy_int64* p_end = p + PyArray_SIZE(final_fill);
|
|
6747
6647
|
PyObject** target;
|
|
6748
|
-
// npy_int64 pos;
|
|
6749
6648
|
while (p < p_end) {
|
|
6750
6649
|
target = array_to_data + *p++;
|
|
6751
6650
|
Py_INCREF(fill_value);
|
|
@@ -6754,29 +6653,117 @@ AK_TM_fill_object(TriMapObject* tm,
|
|
|
6754
6653
|
return 0;
|
|
6755
6654
|
}
|
|
6756
6655
|
|
|
6757
|
-
|
|
6758
|
-
|
|
6759
|
-
|
|
6760
|
-
|
|
6761
|
-
|
|
6762
|
-
|
|
6763
|
-
|
|
6764
|
-
|
|
6765
|
-
|
|
6766
|
-
|
|
6767
|
-
|
|
6768
|
-
|
|
6769
|
-
|
|
6770
|
-
|
|
6771
|
-
|
|
6772
|
-
|
|
6773
|
-
|
|
6774
|
-
|
|
6775
|
-
|
|
6776
|
-
|
|
6777
|
-
|
|
6778
|
-
|
|
6656
|
+
#define AK_TM_TRANSFER_FLEXIBLE(c_type) do { \
|
|
6657
|
+
Py_ssize_t one_count = from_src ? tm->src_one_count : tm->dst_one_count;\
|
|
6658
|
+
TriMapOne* one_pairs = from_src ? tm->src_one : tm->dst_one; \
|
|
6659
|
+
npy_intp t_element_size = PyArray_DESCR(array_to)->elsize; \
|
|
6660
|
+
npy_intp t_element_cp = t_element_size / sizeof(c_type); \
|
|
6661
|
+
npy_intp f_element_size = PyArray_DESCR(array_from)->elsize; \
|
|
6662
|
+
c_type* array_to_data = (c_type*)PyArray_DATA(array_to); \
|
|
6663
|
+
c_type* f; \
|
|
6664
|
+
c_type* t; \
|
|
6665
|
+
c_type* t_end; \
|
|
6666
|
+
npy_intp dst_pos; \
|
|
6667
|
+
npy_int64 f_pos; \
|
|
6668
|
+
PyArrayObject* dst; \
|
|
6669
|
+
TriMapOne* o = one_pairs; \
|
|
6670
|
+
TriMapOne* o_end = o + one_count; \
|
|
6671
|
+
for (; o < o_end; o++) { \
|
|
6672
|
+
f = (c_type*)PyArray_GETPTR1(array_from, o->from); \
|
|
6673
|
+
t = array_to_data + t_element_cp * o->to; \
|
|
6674
|
+
memcpy(t, f, f_element_size); \
|
|
6675
|
+
} \
|
|
6676
|
+
for (Py_ssize_t i = 0; i < tm->many_count; i++) { \
|
|
6677
|
+
t = array_to_data + t_element_cp * tm->many_to[i].start; \
|
|
6678
|
+
t_end = array_to_data + t_element_cp * tm->many_to[i].stop; \
|
|
6679
|
+
if (from_src) { \
|
|
6680
|
+
f = (c_type*)PyArray_GETPTR1(array_from, tm->many_from[i].src);\
|
|
6681
|
+
for (; t < t_end; t += t_element_cp) { \
|
|
6682
|
+
memcpy(t, f, f_element_size); \
|
|
6683
|
+
} \
|
|
6684
|
+
} \
|
|
6685
|
+
else { \
|
|
6686
|
+
dst_pos = 0; \
|
|
6687
|
+
dst = tm->many_from[i].dst; \
|
|
6688
|
+
for (; t < t_end; t += t_element_cp) { \
|
|
6689
|
+
f_pos = *(npy_int64*)PyArray_GETPTR1(dst, dst_pos); \
|
|
6690
|
+
f = (c_type*)PyArray_GETPTR1(array_from, f_pos); \
|
|
6691
|
+
memcpy(t, f, f_element_size); \
|
|
6692
|
+
dst_pos++; \
|
|
6693
|
+
} \
|
|
6694
|
+
} \
|
|
6695
|
+
} \
|
|
6696
|
+
} while (0) \
|
|
6697
|
+
|
|
6698
|
+
// Returns -1 on error.
|
|
6699
|
+
static inline int
|
|
6700
|
+
AK_TM_fill_unicode(TriMapObject* tm,
|
|
6701
|
+
bool from_src,
|
|
6702
|
+
PyArrayObject* array_to,
|
|
6703
|
+
PyObject* fill_value) {
|
|
6704
|
+
PyArrayObject* final_fill = (PyArrayObject*)(from_src
|
|
6705
|
+
? tm->final_src_fill : tm->final_dst_fill);
|
|
6706
|
+
|
|
6707
|
+
Py_UCS4* array_to_data = (Py_UCS4*)PyArray_DATA(array_to);
|
|
6708
|
+
// code points per element
|
|
6709
|
+
npy_intp cp = PyArray_DESCR(array_to)->elsize / UCS4_SIZE;
|
|
6710
|
+
|
|
6711
|
+
bool decref_fill_value = false;
|
|
6712
|
+
if (PyBytes_Check(fill_value)) {
|
|
6713
|
+
fill_value = PyUnicode_FromEncodedObject(fill_value, "utf-8", NULL);
|
|
6714
|
+
if (fill_value == NULL) {
|
|
6715
|
+
return -1;
|
|
6716
|
+
}
|
|
6717
|
+
decref_fill_value = true;
|
|
6718
|
+
}
|
|
6719
|
+
else if (!PyUnicode_Check(fill_value)) {
|
|
6720
|
+
return -1;
|
|
6721
|
+
}
|
|
6722
|
+
Py_ssize_t fill_cp = PyUnicode_GET_LENGTH(fill_value) * UCS4_SIZE; // code points
|
|
6723
|
+
// p is the index position to fill
|
|
6724
|
+
npy_int64* p = (npy_int64*)PyArray_DATA(final_fill);
|
|
6725
|
+
npy_int64* p_end = p + PyArray_SIZE(final_fill);
|
|
6726
|
+
Py_UCS4* target;
|
|
6727
|
+
while (p < p_end) {
|
|
6728
|
+
target = array_to_data + (*p * cp);
|
|
6729
|
+
// disabling copying a null
|
|
6730
|
+
if (PyUnicode_AsUCS4(fill_value, target, fill_cp, 0) == NULL) {
|
|
6731
|
+
return -1;
|
|
6732
|
+
}
|
|
6733
|
+
p++;
|
|
6734
|
+
}
|
|
6735
|
+
if (decref_fill_value) {
|
|
6736
|
+
Py_DECREF(fill_value);
|
|
6737
|
+
}
|
|
6738
|
+
return 0;
|
|
6739
|
+
}
|
|
6779
6740
|
|
|
6741
|
+
// Returns -1 on error.
|
|
6742
|
+
static inline int
|
|
6743
|
+
AK_TM_fill_string(TriMapObject* tm,
|
|
6744
|
+
bool from_src,
|
|
6745
|
+
PyArrayObject* array_to,
|
|
6746
|
+
PyObject* fill_value) {
|
|
6747
|
+
PyArrayObject* final_fill = (PyArrayObject*)(from_src
|
|
6748
|
+
? tm->final_src_fill : tm->final_dst_fill);
|
|
6749
|
+
|
|
6750
|
+
char* array_to_data = (char*)PyArray_DATA(array_to);
|
|
6751
|
+
npy_intp cp = PyArray_DESCR(array_to)->elsize;
|
|
6752
|
+
if (!PyBytes_Check(fill_value)) {
|
|
6753
|
+
return -1;
|
|
6754
|
+
}
|
|
6755
|
+
Py_ssize_t fill_cp = PyBytes_GET_SIZE(fill_value);
|
|
6756
|
+
const char* fill_data = PyBytes_AS_STRING(fill_value);
|
|
6757
|
+
// p is the index position to fill
|
|
6758
|
+
npy_int64* p = (npy_int64*)PyArray_DATA(final_fill);
|
|
6759
|
+
npy_int64* p_end = p + PyArray_SIZE(final_fill);
|
|
6760
|
+
char* target;
|
|
6761
|
+
while (p < p_end) {
|
|
6762
|
+
target = array_to_data + (*p++ * cp);
|
|
6763
|
+
memcpy(target, fill_data, fill_cp);
|
|
6764
|
+
}
|
|
6765
|
+
return 0;
|
|
6766
|
+
}
|
|
6780
6767
|
|
|
6781
6768
|
// Returns NULL on error.
|
|
6782
6769
|
static inline PyObject*
|
|
@@ -6790,6 +6777,9 @@ AK_TM_map_no_fill(TriMapObject* tm,
|
|
|
6790
6777
|
npy_intp dims[] = {tm->len};
|
|
6791
6778
|
PyArrayObject* array_to;
|
|
6792
6779
|
bool dtype_is_obj = PyArray_TYPE(array_from) == NPY_OBJECT;
|
|
6780
|
+
bool dtype_is_unicode = PyArray_TYPE(array_from) == NPY_UNICODE;
|
|
6781
|
+
bool dtype_is_string = PyArray_TYPE(array_from) == NPY_STRING;
|
|
6782
|
+
|
|
6793
6783
|
// create to array
|
|
6794
6784
|
if (dtype_is_obj) { // initializes values to NULL
|
|
6795
6785
|
array_to = (PyArrayObject*)PyArray_SimpleNew(1, dims, NPY_OBJECT);
|
|
@@ -6810,8 +6800,14 @@ AK_TM_map_no_fill(TriMapObject* tm,
|
|
|
6810
6800
|
return NULL;
|
|
6811
6801
|
}
|
|
6812
6802
|
}
|
|
6803
|
+
else if (dtype_is_unicode) {
|
|
6804
|
+
AK_TM_TRANSFER_FLEXIBLE(Py_UCS4);
|
|
6805
|
+
}
|
|
6806
|
+
else if (dtype_is_string) {
|
|
6807
|
+
AK_TM_TRANSFER_FLEXIBLE(char);
|
|
6808
|
+
}
|
|
6813
6809
|
else {
|
|
6814
|
-
if (
|
|
6810
|
+
if (AK_TM_transfer_scalar(tm, from_src, array_from, array_to)) {
|
|
6815
6811
|
Py_DECREF((PyObject*)array_to);
|
|
6816
6812
|
return NULL;
|
|
6817
6813
|
}
|
|
@@ -6864,15 +6860,22 @@ AK_TM_map_fill(TriMapObject* tm,
|
|
|
6864
6860
|
// passing a borrowed ref; returns a new ref
|
|
6865
6861
|
PyArray_Descr* dtype = AK_resolve_dtype(PyArray_DESCR(array_from), fill_value_dtype);
|
|
6866
6862
|
bool dtype_is_obj = dtype->type_num == NPY_OBJECT;
|
|
6863
|
+
bool dtype_is_unicode = dtype->type_num == NPY_UNICODE;
|
|
6864
|
+
bool dtype_is_string = dtype->type_num == NPY_STRING;
|
|
6867
6865
|
|
|
6868
6866
|
npy_intp dims[] = {tm->len};
|
|
6869
6867
|
PyArrayObject* array_to;
|
|
6868
|
+
|
|
6870
6869
|
if (dtype_is_obj) {
|
|
6871
6870
|
Py_DECREF(dtype); // not needed
|
|
6872
6871
|
// will initialize to NULL, not None
|
|
6873
6872
|
array_to = (PyArrayObject*)PyArray_SimpleNew(1, dims, NPY_OBJECT);
|
|
6874
6873
|
Py_INCREF(array_from); // normalize refs when casting
|
|
6875
6874
|
}
|
|
6875
|
+
else if (dtype_is_unicode || dtype_is_string) {
|
|
6876
|
+
array_to = (PyArrayObject*)PyArray_Zeros(1, dims, dtype, 0); // steals dtype ref
|
|
6877
|
+
Py_INCREF(array_from); // normalize refs when casting
|
|
6878
|
+
}
|
|
6876
6879
|
else {
|
|
6877
6880
|
array_to = (PyArrayObject*)PyArray_Empty(1, dims, dtype, 0); // steals dtype ref
|
|
6878
6881
|
if (PyArray_TYPE(array_from) == NPY_DATETIME &&
|
|
@@ -6893,44 +6896,51 @@ AK_TM_map_fill(TriMapObject* tm,
|
|
|
6893
6896
|
Py_DECREF((PyObject*)array_from);
|
|
6894
6897
|
return NULL;
|
|
6895
6898
|
}
|
|
6899
|
+
// array_from, array_to inc refed and dec refed on error
|
|
6896
6900
|
if (dtype_is_obj) {
|
|
6897
6901
|
if (AK_TM_transfer_object(tm, from_src, array_from, array_to)) {
|
|
6898
|
-
|
|
6899
|
-
Py_DECREF((PyObject*)array_from);
|
|
6900
|
-
return NULL;
|
|
6902
|
+
goto error;
|
|
6901
6903
|
}
|
|
6902
6904
|
if (AK_TM_fill_object(tm, from_src, array_to, fill_value)) {
|
|
6903
|
-
|
|
6904
|
-
|
|
6905
|
-
|
|
6905
|
+
goto error;
|
|
6906
|
+
}
|
|
6907
|
+
}
|
|
6908
|
+
else if (dtype_is_unicode) {
|
|
6909
|
+
AK_TM_TRANSFER_FLEXIBLE(Py_UCS4);
|
|
6910
|
+
if (AK_TM_fill_unicode(tm, from_src, array_to, fill_value)) {
|
|
6911
|
+
goto error;
|
|
6912
|
+
}
|
|
6913
|
+
}
|
|
6914
|
+
else if (dtype_is_string) {
|
|
6915
|
+
AK_TM_TRANSFER_FLEXIBLE(char);
|
|
6916
|
+
if (AK_TM_fill_string(tm, from_src, array_to, fill_value)) {
|
|
6917
|
+
goto error;
|
|
6906
6918
|
}
|
|
6907
6919
|
}
|
|
6908
|
-
// TODO: add special hanldig for unicode/bytes
|
|
6909
6920
|
else {
|
|
6910
6921
|
// Most simple is to fill with scalar, then overwrite values as needed; for object and flexible dtypes this is not efficient; for object dtypes, this obbligates us to decref the filled value when assigning
|
|
6911
6922
|
if (PyArray_FillWithScalar(array_to, fill_value)) { // -1 on error
|
|
6912
|
-
|
|
6913
|
-
Py_DECREF((PyObject*)array_from);
|
|
6914
|
-
return NULL;
|
|
6923
|
+
goto error;
|
|
6915
6924
|
}
|
|
6916
|
-
if (
|
|
6917
|
-
|
|
6918
|
-
Py_DECREF((PyObject*)array_from);
|
|
6919
|
-
return NULL;
|
|
6925
|
+
if (AK_TM_transfer_scalar(tm, from_src, array_from, array_to)) {
|
|
6926
|
+
goto error;
|
|
6920
6927
|
}
|
|
6921
6928
|
}
|
|
6922
|
-
|
|
6923
6929
|
Py_DECREF((PyObject*)array_from); // ref inc for this function
|
|
6924
6930
|
PyArray_CLEARFLAGS(array_to, NPY_ARRAY_WRITEABLE);
|
|
6925
6931
|
return (PyObject*)array_to;
|
|
6932
|
+
error:
|
|
6933
|
+
Py_DECREF((PyObject*)array_to);
|
|
6934
|
+
Py_DECREF((PyObject*)array_from);
|
|
6935
|
+
return NULL;
|
|
6926
6936
|
}
|
|
6937
|
+
#undef AK_TM_TRANSFER_FLEXIBLE
|
|
6927
6938
|
|
|
6928
6939
|
static PyObject*
|
|
6929
6940
|
TriMap_map_src_fill(TriMapObject *self, PyObject *args) {
|
|
6930
6941
|
PyArrayObject* array_from;
|
|
6931
6942
|
PyObject* fill_value;
|
|
6932
6943
|
PyArray_Descr* fill_value_dtype;
|
|
6933
|
-
|
|
6934
6944
|
if (!PyArg_ParseTuple(args,
|
|
6935
6945
|
"O!OO!:map_src_fill",
|
|
6936
6946
|
&PyArray_Type, &array_from,
|
|
@@ -6952,7 +6962,6 @@ TriMap_map_dst_fill(TriMapObject *self, PyObject *args) {
|
|
|
6952
6962
|
PyArrayObject* array_from;
|
|
6953
6963
|
PyObject* fill_value;
|
|
6954
6964
|
PyArray_Descr* fill_value_dtype;
|
|
6955
|
-
|
|
6956
6965
|
if (!PyArg_ParseTuple(args,
|
|
6957
6966
|
"O!OO!:map_dst_fill",
|
|
6958
6967
|
&PyArray_Type, &array_from,
|
|
@@ -6969,7 +6978,6 @@ TriMap_map_dst_fill(TriMapObject *self, PyObject *args) {
|
|
|
6969
6978
|
return AK_TM_map_fill(self, from_src, array_from, fill_value, fill_value_dtype);
|
|
6970
6979
|
}
|
|
6971
6980
|
|
|
6972
|
-
|
|
6973
6981
|
static PyMethodDef TriMap_methods[] = {
|
|
6974
6982
|
{"register_one", (PyCFunction)TriMap_register_one, METH_VARARGS, NULL},
|
|
6975
6983
|
{"register_unmatched_dst", (PyCFunction)TriMap_register_unmatched_dst, METH_NOARGS, NULL},
|
|
@@ -83,4 +83,19 @@ class TestUnit(unittest.TestCase):
|
|
|
83
83
|
a1[999] = True
|
|
84
84
|
self.assertEqual(nonzero_1d(a1).tolist(), [999, 9_999_999])
|
|
85
85
|
a1[0] = True
|
|
86
|
-
self.assertEqual(nonzero_1d(a1).tolist(), [0, 999, 9_999_999])
|
|
86
|
+
self.assertEqual(nonzero_1d(a1).tolist(), [0, 999, 9_999_999])
|
|
87
|
+
|
|
88
|
+
def test_nonzero_1d_f(self) -> None:
|
|
89
|
+
# non-contiguous
|
|
90
|
+
a1 = np.arange(40).reshape(10, 4) % 3 == 0
|
|
91
|
+
a2 = a1[:, 3]
|
|
92
|
+
self.assertEqual(nonzero_1d(a2).tolist(), [0, 3, 6, 9])
|
|
93
|
+
|
|
94
|
+
a3 = a1[:, 1]
|
|
95
|
+
self.assertEqual(nonzero_1d(a3).tolist(), [2, 5, 8])
|
|
96
|
+
|
|
97
|
+
def test_nonzero_1d_g(self) -> None:
|
|
98
|
+
a1 = np.arange(20).reshape(4, 5) % 3 == 0
|
|
99
|
+
a2 = a1[:, 4]
|
|
100
|
+
# array([False, True, False, False])
|
|
101
|
+
self.assertEqual(nonzero_1d(a2).tolist(), [1])
|
|
@@ -975,6 +975,21 @@ class TestUnit(unittest.TestCase):
|
|
|
975
975
|
post_dst = tm.map_dst_no_fill(dst)
|
|
976
976
|
self.assertEqual(post_dst.tolist(), [b'a', b'bbb', b'cc', b'cc', b'dddd', b'a'])
|
|
977
977
|
|
|
978
|
+
def test_tri_map_map_bytes_a(self) -> None:
|
|
979
|
+
src = np.array([b'a', b'bbb', b'cc'], dtype=np.bytes_)
|
|
980
|
+
dst = np.array([b'cc', b'dddd', b'eee'], dtype=np.bytes_)
|
|
981
|
+
|
|
982
|
+
tm = TriMap(len(src), len(dst))
|
|
983
|
+
tm.register_one(0, -1)
|
|
984
|
+
tm.register_one(1, -1)
|
|
985
|
+
tm.register_one(2, 0)
|
|
986
|
+
tm.register_unmatched_dst()
|
|
987
|
+
tm.finalize()
|
|
988
|
+
|
|
989
|
+
post_src = tm.map_src_fill(src, b'--', np.dtype(np.bytes_))
|
|
990
|
+
post_dst = tm.map_dst_fill(dst, b'--', np.dtype(np.bytes_))
|
|
991
|
+
self.assertEqual(post_src.tolist(), [b'a', b'bbb', b'cc', b'--', b'--'])
|
|
992
|
+
self.assertEqual(post_dst.tolist(), [b'--', b'--', b'cc', b'dddd', b'eee'])
|
|
978
993
|
#---------------------------------------------------------------------------
|
|
979
994
|
|
|
980
995
|
def test_tri_map_map_unicode_a(self) -> None:
|
|
@@ -994,7 +1009,6 @@ class TestUnit(unittest.TestCase):
|
|
|
994
1009
|
post_dst = tm.map_dst_fill(dst, '====', np.array('====').dtype)
|
|
995
1010
|
self.assertEqual(post_dst.tolist(), ['a', 'a', 'a', '====', 'cc', 'cc', '===='])
|
|
996
1011
|
|
|
997
|
-
|
|
998
1012
|
def test_tri_map_map_unicode_b(self) -> None:
|
|
999
1013
|
src = np.array(['a', 'bbb', 'cc', 'dddd'])
|
|
1000
1014
|
dst = np.array(['cc', 'a', 'a', 'a', 'cc'])
|
|
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
|
|
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
|