-
-
Notifications
You must be signed in to change notification settings - Fork 10.9k
ENH: Improved performance of PyArray_FromAny for sequences of array-like #13399
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -422,6 +422,10 @@ copy_and_swap(void *dst, void *src, int itemsize, npy_intp numitems, | |
} | ||
} | ||
|
||
NPY_NO_EXPORT PyObject * | ||
_array_from_array_like(PyObject *op, PyArray_Descr *requested_dtype, | ||
npy_bool writeable, PyObject *context); | ||
|
||
superbobry marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/* | ||
* adapted from Numarray, | ||
* a: destination array | ||
|
@@ -435,6 +439,7 @@ static int | |
setArrayFromSequence(PyArrayObject *a, PyObject *s, | ||
int dim, PyArrayObject * dst) | ||
{ | ||
PyObject *tmp; | ||
Py_ssize_t i, slen; | ||
int res = -1; | ||
|
||
|
@@ -478,6 +483,22 @@ setArrayFromSequence(PyArrayObject *a, PyObject *s, | |
goto fail; | ||
} | ||
|
||
tmp = _array_from_array_like(s, /*dtype*/NULL, /*writeable*/0, /*context*/NULL); | ||
superbobry marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (tmp == NULL) { | ||
goto fail; | ||
} | ||
else if (tmp != Py_NotImplemented) { | ||
if (PyArray_CopyInto(dst, (PyArrayObject *)tmp) < 0) { | ||
goto fail; | ||
} | ||
|
||
Py_DECREF(s); | ||
return 0; | ||
} | ||
else { | ||
Py_DECREF(Py_NotImplemented); | ||
} | ||
|
||
slen = PySequence_Length(s); | ||
if (slen < 0) { | ||
goto fail; | ||
|
@@ -1481,6 +1502,90 @@ _array_from_buffer_3118(PyObject *memoryview) | |
|
||
} | ||
|
||
|
||
/* | ||
* Attempts to extract an array from an array-like object. | ||
* | ||
* array-like is defined as either | ||
* | ||
* * an object implementing the PEP 3118 buffer interface; | ||
* * an object with __array_struct__ or __array_interface__ attributes; | ||
* * an object with an __array__ function. | ||
* | ||
* Returns Py_NotImplemented if a given object is not array-like; | ||
* PyArrayObject* in case of success and NULL in case of failure. | ||
superbobry marked this conversation as resolved.
Show resolved
Hide resolved
|
||
*/ | ||
NPY_NO_EXPORT PyObject * | ||
_array_from_array_like(PyObject *op, PyArray_Descr *requested_dtype, | ||
npy_bool writeable, PyObject *context) { | ||
PyObject* tmp; | ||
|
||
/* If op supports the PEP 3118 buffer interface */ | ||
if (!PyBytes_Check(op) && !PyUnicode_Check(op)) { | ||
PyObject *memoryview = PyMemoryView_FromObject(op); | ||
if (memoryview == NULL) { | ||
PyErr_Clear(); | ||
} | ||
else { | ||
tmp = _array_from_buffer_3118(memoryview); | ||
Py_DECREF(memoryview); | ||
if (tmp == NULL) { | ||
return NULL; | ||
} | ||
|
||
if (writeable | ||
&& PyArray_FailUnlessWriteable((PyArrayObject *) tmp, "PEP 3118 buffer") < 0) { | ||
Py_DECREF(tmp); | ||
return NULL; | ||
} | ||
|
||
return tmp; | ||
} | ||
} | ||
|
||
/* If op supports the __array_struct__ or __array_interface__ interface */ | ||
tmp = PyArray_FromStructInterface(op); | ||
if (tmp == NULL) { | ||
return NULL; | ||
} | ||
if (tmp == Py_NotImplemented) { | ||
tmp = PyArray_FromInterface(op); | ||
if (tmp == NULL) { | ||
return NULL; | ||
} | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For reviewers: the original code had a check clause at this point |
||
/* | ||
* If op supplies the __array__ function. | ||
* The documentation says this should produce a copy, so | ||
* we skip this method if writeable is true, because the intent | ||
* of writeable is to modify the operand. | ||
* XXX: If the implementation is wrong, and/or if actual | ||
* usage requires this behave differently, | ||
* this should be changed! | ||
*/ | ||
if (!writeable && tmp == Py_NotImplemented) { | ||
tmp = PyArray_FromArrayAttr(op, requested_dtype, context); | ||
if (tmp == NULL) { | ||
return NULL; | ||
} | ||
} | ||
|
||
if (tmp != Py_NotImplemented) { | ||
if (writeable | ||
&& PyArray_FailUnlessWriteable((PyArrayObject *) tmp, | ||
"array interface object") < 0) { | ||
Py_DECREF(tmp); | ||
return NULL; | ||
} | ||
return tmp; | ||
} | ||
|
||
Py_INCREF(Py_NotImplemented); | ||
return Py_NotImplemented; | ||
} | ||
|
||
|
||
/*NUMPY_API | ||
* Retrieves the array parameters for viewing/converting an arbitrary | ||
* PyObject* to a NumPy array. This allows the "innate type and shape" | ||
|
@@ -1588,69 +1693,20 @@ PyArray_GetArrayParamsFromObject(PyObject *op, | |
return 0; | ||
} | ||
|
||
/* If op supports the PEP 3118 buffer interface */ | ||
if (!PyBytes_Check(op) && !PyUnicode_Check(op)) { | ||
|
||
PyObject *memoryview = PyMemoryView_FromObject(op); | ||
if (memoryview == NULL) { | ||
PyErr_Clear(); | ||
} | ||
else { | ||
PyObject *arr = _array_from_buffer_3118(memoryview); | ||
Py_DECREF(memoryview); | ||
if (arr == NULL) { | ||
return -1; | ||
} | ||
if (writeable | ||
&& PyArray_FailUnlessWriteable((PyArrayObject *)arr, "PEP 3118 buffer") < 0) { | ||
Py_DECREF(arr); | ||
return -1; | ||
} | ||
*out_arr = (PyArrayObject *)arr; | ||
return 0; | ||
} | ||
} | ||
|
||
/* If op supports the __array_struct__ or __array_interface__ interface */ | ||
tmp = PyArray_FromStructInterface(op); | ||
/* If op is an array-like */ | ||
tmp = _array_from_array_like(op, requested_dtype, writeable, context); | ||
if (tmp == NULL) { | ||
return -1; | ||
} | ||
if (tmp == Py_NotImplemented) { | ||
tmp = PyArray_FromInterface(op); | ||
if (tmp == NULL) { | ||
return -1; | ||
} | ||
} | ||
if (tmp != Py_NotImplemented) { | ||
if (writeable | ||
&& PyArray_FailUnlessWriteable((PyArrayObject *)tmp, | ||
"array interface object") < 0) { | ||
Py_DECREF(tmp); | ||
return -1; | ||
} | ||
*out_arr = (PyArrayObject *)tmp; | ||
return (*out_arr) == NULL ? -1 : 0; | ||
else if (tmp != Py_NotImplemented) { | ||
*out_arr = (PyArrayObject*) tmp; | ||
return 0; | ||
} | ||
|
||
/* | ||
* If op supplies the __array__ function. | ||
* The documentation says this should produce a copy, so | ||
* we skip this method if writeable is true, because the intent | ||
* of writeable is to modify the operand. | ||
* XXX: If the implementation is wrong, and/or if actual | ||
* usage requires this behave differently, | ||
* this should be changed! | ||
*/ | ||
if (!writeable) { | ||
tmp = PyArray_FromArrayAttr(op, requested_dtype, context); | ||
if (tmp != Py_NotImplemented) { | ||
*out_arr = (PyArrayObject *)tmp; | ||
return (*out_arr) == NULL ? -1 : 0; | ||
} | ||
else { | ||
Py_DECREF(Py_NotImplemented); | ||
} | ||
|
||
/* Try to treat op as a list of lists */ | ||
/* Try to treat op as a list of lists or array-like objects. */ | ||
if (!writeable && PySequence_Check(op)) { | ||
int check_it, stop_at_string, stop_at_tuple, is_object; | ||
int type_num, type; | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.