-
Notifications
You must be signed in to change notification settings - Fork 35
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
Adding support for streaming through the input arrays of a pipeline #182
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,7 +34,6 @@ | |
|
||
#include "PyArray.hpp" | ||
#include <pdal/io/MemoryViewReader.hpp> | ||
#include <numpy/arrayobject.h> | ||
|
||
namespace pdal | ||
{ | ||
|
@@ -95,7 +94,8 @@ std::string pyObjectToString(PyObject *pname) | |
#define PyDataType_NAMES(descr) ((descr)->names) | ||
#endif | ||
|
||
Array::Array(PyArrayObject* array) : m_array(array), m_rowMajor(true) | ||
Array::Array(PyArrayObject* array, std::shared_ptr<ArrayStreamHandler> stream_handler) | ||
: m_array(array), m_rowMajor(true), m_stream_handler(std::move(stream_handler)) | ||
{ | ||
Py_XINCREF(array); | ||
|
||
|
@@ -164,51 +164,85 @@ Array::~Array() | |
Py_XDECREF(m_array); | ||
} | ||
|
||
|
||
ArrayIter& Array::iterator() | ||
std::shared_ptr<ArrayIter> Array::iterator() | ||
{ | ||
ArrayIter *it = new ArrayIter(m_array); | ||
m_iterators.emplace_back((it)); | ||
return *it; | ||
return std::make_shared<ArrayIter>(m_array, m_stream_handler); | ||
} | ||
|
||
ArrayIter::ArrayIter(PyArrayObject* np_array, std::shared_ptr<ArrayStreamHandler> stream_handler) | ||
: m_stream_handler(std::move(stream_handler)) | ||
{ | ||
resetIterator(np_array); | ||
} | ||
|
||
ArrayIter::ArrayIter(PyArrayObject* np_array) | ||
void ArrayIter::resetIterator(std::optional<PyArrayObject*> np_array = {}) | ||
{ | ||
m_iter = NpyIter_New(np_array, | ||
NPY_ITER_EXTERNAL_LOOP | NPY_ITER_READONLY | NPY_ITER_REFS_OK, | ||
NPY_KEEPORDER, NPY_NO_CASTING, NULL); | ||
if (!m_iter) | ||
throw pdal_error("Unable to create numpy iterator."); | ||
std::optional<int> stream_chunk_size = std::nullopt; | ||
if (m_stream_handler) { | ||
stream_chunk_size = (*m_stream_handler)(); | ||
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. The handler returns uint64_t, but assigns to int. Is there any reason for optional? Seems like initializing to 0 would work fine. 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. I've changed type to Will be this: Instead of this: |
||
if (*stream_chunk_size == 0) { | ||
m_done = true; | ||
return; | ||
} | ||
} | ||
|
||
if (np_array) { | ||
// Init iterator | ||
m_iter = NpyIter_New(np_array.value(), | ||
NPY_ITER_EXTERNAL_LOOP | NPY_ITER_READONLY | NPY_ITER_REFS_OK, | ||
NPY_KEEPORDER, NPY_NO_CASTING, NULL); | ||
if (!m_iter) | ||
throw pdal_error("Unable to create numpy iterator."); | ||
} else { | ||
// Otherwise, reset the iterator to the initial state | ||
if (NpyIter_Reset(m_iter, NULL) != NPY_SUCCEED) { | ||
NpyIter_Deallocate(m_iter); | ||
throw pdal_error("Unable to reset numpy iterator."); | ||
} | ||
} | ||
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. set 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. Good catch. I've fixed it for the error case of |
||
|
||
char *itererr; | ||
m_iterNext = NpyIter_GetIterNext(m_iter, &itererr); | ||
if (!m_iterNext) | ||
{ | ||
NpyIter_Deallocate(m_iter); | ||
throw pdal_error(std::string("Unable to create numpy iterator: ") + | ||
itererr); | ||
throw pdal_error(std::string("Unable to create numpy iterator: ") + itererr); | ||
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. This seems like a misleading error message. |
||
} | ||
m_data = NpyIter_GetDataPtrArray(m_iter); | ||
m_stride = NpyIter_GetInnerStrideArray(m_iter); | ||
m_size = NpyIter_GetInnerLoopSizePtr(m_iter); | ||
m_stride = *NpyIter_GetInnerStrideArray(m_iter); | ||
m_size = *NpyIter_GetInnerLoopSizePtr(m_iter); | ||
if (stream_chunk_size) { | ||
if (0 <= *stream_chunk_size && *stream_chunk_size <= m_size) { | ||
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. Seems you could use 0 as a sentinel since a chunk size of 0 seems pointless. |
||
m_size = *stream_chunk_size; | ||
} else { | ||
throw pdal_error(std::string("Stream chunk size not in the range of array length: ") + | ||
std::to_string(*stream_chunk_size)); | ||
} | ||
} | ||
m_done = false; | ||
} | ||
|
||
ArrayIter::~ArrayIter() | ||
{ | ||
NpyIter_Deallocate(m_iter); | ||
if (m_iter != nullptr) { | ||
NpyIter_Deallocate(m_iter); | ||
} | ||
} | ||
|
||
ArrayIter& ArrayIter::operator++() | ||
{ | ||
if (m_done) | ||
return *this; | ||
|
||
if (--(*m_size)) | ||
*m_data += *m_stride; | ||
else if (!m_iterNext(m_iter)) | ||
m_done = true; | ||
if (--m_size) { | ||
*m_data += m_stride; | ||
} else if (!m_iterNext(m_iter)) { | ||
if (m_stream_handler) { | ||
resetIterator(); | ||
} else { | ||
m_done = true; | ||
} | ||
} | ||
return *this; | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like there are really two separate cases here. An
initialize
case and areset
case, variously triggered by the optional argument. Perhaps more clear to have two functions?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm. This didn't come out as nicely as I was thinking, so I may regret my comment ;)