8000 Pull request #79: [GR-40354] Implement missing pieces · hpyproject/numpy-hpy@fdc2b16 · GitHub
[go: up one dir, main page]

Skip to content

Commit fdc2b16

Browse files
committed
Pull request numpy#79: [GR-40354] Implement missing pieces
Merge in ~STEPAN.SINDELAR_ORACLE.COM/numpy-hpy from mq/GR-40354 to labs-hpy-port * commit 'f4cf11d2341e1734b8da1035c63e876daaacb600': address comments implement more missing pieces Implement missing pieces
2 parents 28e07fd + f4cf11d commit fdc2b16

File tree

16 files changed

+777
-229
lines changed

16 files changed

+777
-229
lines changed

numpy/core/code_generators/numpy_api.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,7 @@
465465
# 'HPyArray_Resize': (80,),
466466
# 'HPyArray_MoveInto': (81,),
467467
'HPyArray_CopyInto': (82,),
468-
# 'HPyArray_CopyAnyInto': (83,),
468+
'HPyArray_CopyAnyInto': (83,),
469469
'HPyArray_CopyObject': (84,),
470470
'HPyArray_NewCopy': (85,),
471471
# 'HPyArray_ToList': (86,),
@@ -488,7 +488,7 @@
488488
# 'HPyArray_FillObjectArray': (103,),
489489
# 'HPyArray_FillWithScalar': (104,),
490490
# 'HPyArray_CheckStrides': (105,),
491-
# 'HPyArray_DescrNewByteorder': (106,),
491+
'HPyArray_DescrNewByteorder': (106,),
492492
# 'HPyArray_IterAllButAxis': (107,),
493493
'HPyArray_CheckFromAny': (108,),
494494
'HPyArray_FromArray': (109,),
@@ -538,7 +538,7 @@
538538
# 'HPyArray_All': (153,),
539539
# 'HPyArray_Any': (154,),
540540
'HPyArray_Compress': (155,),
541-
# 'HPyArray_Flatten': (156,),
541+
'HPyArray_Flatten': (156,),
542542
'HPyArray_Ravel': (157,),
543543
# 'HPyArray_MultiplyList': (158,),
544544
# 'HPyArray_MultiplyIntList': (159,),

numpy/core/include/numpy/ndarrayobject.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,8 +343,34 @@ NPY_TITLE_KEY_check(PyObject *key, PyObject *value)
343343
return 0;
344344
}
345345

346+
static NPY_INLINE int
347+
HNPY_TITLE_KEY_check(HPyContext *ctx, HPy key, HPy value)
348+
{
349+
HPy title;
350+
if (HPy_Length(ctx, value) != 3) {
351+
return 0;
352+
}
353+
title = HPy_GetItem_i(ctx, value, 2);
354+
if (HPy_Is(ctx, key, title)) {
355+
return 1;
356+
}
357+
#ifdef PYPY_VERSION
358+
/*
359+
* On PyPy, dictionary keys do not always preserve object identity.
360+
* Fall back to comparison by value.
361+
*/
362+
hpy_abort_not_implemented("PyPy unimplemeted path 'PyUnicode_Compare' missing");
363+
// if (PyUnicode_Check(title) && PyUnicode_Check(key)) {
364+
// return PyUnicode_Compare(title, key) == 0 ? 1 : 0;
365+
// }
366+
#endif
367+
return 0;
368+
}
369+
370+
346371
/* Macro, for backward compat with "if NPY_TITLE_KEY(key, value) { ..." */
347372
#define NPY_TITLE_KEY(key, value) (NPY_TITLE_KEY_check((key), (value)))
373+
#define HNPY_TITLE_KEY(ctx, key, value) (HNPY_TITLE_KEY_check(ctx, (key), (value)))
348374

349375
#define DEPRECATE(msg) PyErr_WarnEx(PyExc_DeprecationWarning,msg,1)
350376
#define HPY_DEPRECATE(ctx, msg) HPyErr_WarnEx(ctx,ctx->h_DeprecationWarning,msg,1)

numpy/core/src/common/array_assign.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,11 @@ raw_array_is_aligned(int ndim, npy_intp const *shape,
120120
*/
121121
NPY_NO_EXPORT int
122122
IsAligned(PyArrayObject *ap);
123+
NPY_NO_EXPORT int
124+
HPyIsAligned(HPyContext *ctx, HPy h_ap, PyArrayObject *ap);
125+
NPY_NO_EXPORT int
126+
HPyIsAlignedWithDescr(HPyContext *ctx, HPy h_ap, PyArrayObject *ap,
127+
PyArray_Descr *ap_descr_data);
123128

124129
/*
125130
* Checks if an array is aligned to its "uint alignment"

numpy/core/src/multiarray/array_coercion.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,7 @@ HPyArray_Pack(HPyContext *ctx, HPy /* (PyArray_Descr *) */ descr, char *item, HP
580580
_hpy_set_descr(ctx, dummy_arr, dummy_arr_data, HPy_NULL);
581581
if (PyDataType_REFCHK(tmp_descr_data)) {
582582
/* We could probably use move-references above */
583-
PyArray_Item_INCREF(data, HPy_AsPyObject(ctx, tmp_descr));
583+
PyArray_Item_INCREF(data, (PyArray_Descr *)HPy_AsPyObject(ctx, tmp_descr));
584584
}
585585

586586
int res = 0;
@@ -604,7 +604,7 @@ HPyArray_Pack(HPyContext *ctx, HPy /* (PyArray_Descr *) */ descr, char *item, HP
604604
finish:
605605
if (PyDataType_REFCHK(tmp_descr_data)) {
606606
/* We could probably use move-references above */
607-
PyArray_Item_XDECREF(data, HPy_AsPyObject(ctx, tmp_descr));
607+
PyArray_Item_XDECREF(data, (PyArray_Descr *)HPy_AsPyObject(ctx, tmp_descr));
608608
}
609609
// TODO HPY LABS PORT: PyObject_Free
610610
// PyObject_Free(data);
@@ -1062,7 +1062,7 @@ h_find_descriptor_from_array(HPyContext *ctx, HPy h_arr, HPy h_DType, HPy *h_out
10621062
PyArray_DTypeMeta *DType = (PyArray_DTypeMeta *)HPy_AsPyObject(ctx, h_DType);
10631063
PyArray_Descr *out_descr = NULL;
10641064
int ret = find_descriptor_from_array(arr, DType, &out_descr);
1065-
*h_out_descr = HPy_FromPyObject(ctx, out_descr);
1065+
*h_out_descr = HPy_FromPyObject(ctx, (PyObject *)out_descr);
10661066
return ret;
10671067
}
10681068

@@ -1140,7 +1140,7 @@ HPyArray_AdaptDescriptorToArray(HPyContext *ctx, HPy arr, HPy dtype)
11401140
if (HPy_IsNull(new_dtype)) {
11411141
/* This is an object array but contained no elements, use default */
11421142
PyArray_DTypeMeta *new_DType_data = PyArray_DTypeMeta_AsStruct(ctx, new_DType);
1143-
HPy new_dtype = HNPY_DT_CALL_default_descr(ctx, new_DType, new_DType_data);
1143+
new_DType = HNPY_DT_CALL_default_descr(ctx, new_DType, new_DType_data);
11441144
}
11451145
}
11461146
HPy_Close(ctx, new_DType);

numpy/core/src/multiarray/ctors.c

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3674,6 +3674,191 @@ PyArray_CopyAsFlat(PyArrayObject *dst, PyArrayObject *src, NPY_ORDER order)
36743674
return res;
36753675
}
36763676

3677+
/*
3678+
* Private implementation of PyArray_CopyAnyInto with an additional order
3679+
* parameter.
3680+
*/
3681+
NPY_NO_EXPORT int
3682+
HPyArray_CopyAsFlat(HPyContext *ctx,
3683+
HPy /* PyArrayObject * */ dst,
3684+
HPy /* PyArrayObject * */ src, NPY_ORDER order)
3685+
{
3686+
NpyIter *dst_iter, *src_iter;
3687+
3688+
NpyIter_IterNextFunc *dst_iternext, *src_iternext;
3689+
char **dst_dataptr, **src_dataptr;
3690+
npy_intp dst_stride, src_stride;
3691+
npy_intp *dst_countptr, *src_countptr;
3692+
npy_uint32 baseflags;
3693+
3694+
npy_intp dst_count, src_count, count;
3695+
npy_intp dst_size, src_size;
3696+
int needs_api;
3697+
3698+
HPY_NPY_BEGIN_THREADS_DEF;
3699+
3700+
PyArrayObject *dst_data = PyArrayObject_AsStruct(ctx, dst);
3701+
if (HPyArray_FailUnlessWriteableWithStruct(ctx, dst, dst_data, "destination array") < 0) {
3702+
return -1;
3703+
}
3704+
3705+
/*
3706+
* If the shapes match and a particular order is forced
3707+
* for both, use the more efficient CopyInto
3708+
*/
3709+
PyArrayObject *src_data = PyArrayObject_AsStruct(ctx, src);
3710+
if (order != NPY_ANYORDER && order != NPY_KEEPORDER &&
3711+
PyArray_NDIM(dst_data) == PyArray_NDIM(src_data) &&
3712+
PyArray_CompareLists(PyArray_DIMS(dst_data), PyArray_DIMS(src_data),
3713+
PyArray_NDIM(dst_data))) {
3714+
return HPyArray_CopyInto(ctx, dst, src);
3715+
}
3716+
3717+
dst_size = HPyArray_SIZE(dst_data);
3718+
src_size = HPyArray_SIZE(src_data);
3719+
if (dst_size != src_size) {
3720+
// PyErr_Format(PyExc_ValueError,
3721+
// "cannot copy from array of size %" NPY_INTP_FMT " into an array "
3722+
// "of size %" NPY_INTP_FMT, src_size, dst_size);
3723+
HPyErr_SetString(ctx, ctx->h_ValueError,
3724+
"cannot copy from array of size %" NPY_INTP_FMT " into an array "
3725+
"of size %" NPY_INTP_FMT);
3726+
return -1;
3727+
}
3728+
3729+
/* Zero-sized arrays require nothing be done */
3730+
if (dst_size == 0) {
3731+
return 0;
3732+
}
3733+
3734+
baseflags = NPY_ITER_EXTERNAL_LOOP |
3735+
NPY_ITER_DONT_NEGATE_STRIDES |
3736+
NPY_ITER_REFS_OK;
3737+
3738+
/*
3739+
* This copy is based on matching C-order traversals of src and dst.
3740+
* By using two iterators, we can find maximal sub-chunks that
3741+
* can be processed at once.
3742+
*/
3743+
dst_iter = HNpyIter_New(ctx, dst, NPY_ITER_WRITEONLY | baseflags,
3744+
order,
3745+
NPY_NO_CASTING,
3746+
HPy_NULL);
3747+
if (dst_iter == NULL) {
3748+
return -1;
3749+
}
3750+
src_iter = HNpyIter_New(ctx, src, NPY_ITER_READONLY | baseflags,
3751+
order,
3752+
NPY_NO_CASTING,
3753+
HPy_NULL);
3754+
if (src_iter == NULL) {
3755+
HNpyIter_Deallocate(ctx, dst_iter);
3756+
return -1;
3757+
}
3758+
3759+
/* Get all the values needed for the inner loop */
3760+
dst_iternext = HNpyIter_GetIterNext(ctx, dst_iter, NULL);
3761+
dst_dataptr = NpyIter_GetDataPtrArray(dst_iter);
3762+
/* Since buffering is disabled, we can cache the stride */
3763+
dst_stride = NpyIter_GetInnerStrideArray(dst_iter)[0];
3764+
dst_countptr = NpyIter_GetInnerLoopSizePtr(dst_iter);
3765+
3766+
src_iternext = HNpyIter_GetIterNext(ctx, src_iter, NULL);
3767+
src_dataptr = NpyIter_GetDataPtrArray(src_iter);
3768+
/* Since buffering is disabled, we can cache the stride */
3769+
src_stride = NpyIter_GetInnerStrideArray(src_iter)[0];
3770+
src_countptr = NpyIter_GetInnerLoopSizePtr(src_iter);
3771+
3772+
if (dst_iternext == NULL || src_iternext == NULL) {
3773+
HNpyIter_Deallocate(ctx, dst_iter);
3774+
HNpyIter_Deallocate(ctx, src_iter);
3775+
return -1;
3776+
}
3777+
3778+
needs_api = NpyIter_IterationNeedsAPI(dst_iter) ||
3779+
NpyIter_IterationNeedsAPI(src_iter);
3780+
3781+
/*
3782+
* Because buffering is disabled in the iterator, the inner loop
3783+
* strides will be the same throughout the iteration loop. Thus,
3784+
* we can pass them to this function to take advantage of
3785+
* contiguous strides, etc.
3786+
*/
3787+
NPY_cast_info cast_info;
3788+
HPy src_descr = HPyArray_DESCR(ctx, src, src_data);
3789+
PyArray_Descr *src_descr_data = PyArray_Descr_AsStruct(ctx, src_descr);
3790+
HPy dst_descr = HPyArray_DESCR(ctx, src, dst_data);
3791+
PyArray_Descr *dst_descr_data = PyArray_Descr_AsStruct(ctx, dst_descr);
3792+
if (HPyArray_GetDTypeTransferFunction(ctx,
3793+
HIsUintAlignedWithDescr(ctx, src, src_data, src_descr_data) &&
3794+
HPyIsAlignedWithDescr(ctx, src, src_data, src_descr_data) &&
3795+
HIsUintAlignedWithDescr(ctx, dst, dst_data, dst_descr_data) &&
3796+
HPyIsAlignedWithDescr(ctx, dst, dst_data, dst_descr_data),
3797+
src_stride, dst_stride,
3798+
src_descr, src_descr,
3799+
0,
3800+
&cast_info, &needs_api) != NPY_SUCCEED) {
3801+
HNpyIter_Deallocate(ctx, dst_iter);
3802+
HNpyIter_Deallocate(ctx, src_iter);
3803+
return -1;
3804+
}
3805+
3806+
if (!needs_api) {
3807+
HPY_NPY_BEGIN_THREADS(ctx);
3808+
}
3809+
3810+
dst_count = *dst_countptr;
3811+
src_count = *src_countptr;
3812+
char *args[2] = {src_dataptr[0], dst_dataptr[0]};
3813+
npy_intp strides[2] = {src_stride, dst_stride};
3814+
3815+
int res = 0;
3816+
for(;;) {
3817+
/* Transfer the biggest amount that fits both */
3818+
count = (src_count < dst_count) ? src_count : dst_count;
3819+
if (cast_info.func(ctx, &cast_info.context,
3820+
args, &count, strides, cast_info.auxdata) < 0) {
3821+
res = -1;
3822+
break;
3823+
}
3824+
3825+
/* If we exhausted the dst block, refresh it */
3826+
if (dst_count == count) {
3827+
res = dst_iternext(ctx, dst_iter);
3828+
if (res == 0) {
3829+
break;
3830+
}
3831+
dst_count = *dst_countptr;
3832+
args[1] = dst_dataptr[0];
3833+
}
3834+
else {
3835+
dst_count -= count;
3836+
args[1] += count*dst_stride;
3837+
}
3838+
3839+
/* If we exhausted the src block, refresh it */
3840+
if (src_count == count) {
3841+
res = src_iternext(ctx, src_iter);
3842+
if (res == 0) {
3843+
break;
3844+
}
3845+
src_count = *src_countptr;
3846+
args[0] = src_dataptr[0];
3847+
}
3848+
else {
3849+
src_count -= count;
3850+
args[0] += count*src_stride;
3851+
}
3852+
}
3853+
3854+
HPY_NPY_END_THREADS(ctx);
3855+
3856+
HNPY_cast_info_xfree(ctx, &cast_info);
3857+
HNpyIter_Deallocate(ctx, dst_iter);
3858+
HNpyIter_Deallocate(ctx, src_iter);
3859+
return res;
3860+
}
3861+
36773862
/*NUMPY_API
36783863
* Copy an Array into another array -- memory must not overlap
36793864
* Does not require src and dest to have "broadcastable" shapes
@@ -3691,6 +3876,25 @@ PyArray_CopyAnyInto(PyArrayObject *dst, PyArrayObject *src)
36913876
return PyArray_CopyAsFlat(dst, src, NPY_CORDER);
36923877
}
36933878

3879+
/*HPY_NUMPY_API
3880+
* Copy an Array into another array -- memory must not overlap
3881+
* Does not require src and dest to have "broadcastable" shapes
3882+
* (only the same number of elements).
3883+
*
3884+
* TODO: For NumPy 2.0, this could accept an order parameter which
3885+
* only allows NPY_CORDER and NPY_FORDER. Could also rename
3886+
* this to CopyAsFlat to make the name more intuitive.
3887+
*
3888+
* Returns 0 on success, -1 on error.
3889+
*/
3890+
NPY_NO_EXPORT int
3891+
HPyArray_CopyAnyInto(HPyContext *ctx,
3892+
HPy /* PyArrayObject * */ dst,
3893+
HPy /* PyArrayObject * */ src)
3894+
{
3895+
return HPyArray_CopyAsFlat(ctx, dst, src, NPY_CORDER);
3896+
}
3897+
36943898
/*NUMPY_API
36953899
* Copy an Array into another array.
36963900
* Broadcast to the destination shape if necessary.

numpy/core/src/multiarray/ctors.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@ HPyArray_CheckAxis(HPyContext *ctx, HPy h_arr, int *axis, int flags);
103103
NPY_NO_EXPORT int
104104
PyArray_CopyAsFlat(PyArrayObject *dst, PyArrayObject *src,
105105
NPY_ORDER order);
106+
NPY_NO_EXPORT int
107+
HPyArray_CopyAsFlat(HPyContext *ctx,
108+
HPy /* PyArrayObject * */ dst,
109+
HPy /* PyArrayObject * */ src, NPY_ORDER order);
106110

107111
/* FIXME: remove those from here */
108112
NPY_NO_EXPORT void

0 commit comments

Comments
 (0)
0