diff --git a/awkward-cpp/awkward/cpp/array/CPU_methods.h b/awkward-cpp/awkward/cpp/array/CPU_methods.h new file mode 100644 index 00000000..dad955d3 --- /dev/null +++ b/awkward-cpp/awkward/cpp/array/CPU_methods.h @@ -0,0 +1,120 @@ +#ifdef __cplusplus // specifies that this is C, not C++ +extern "C" { +#endif + +#ifndef CPU_METHODS_H // include guard +#define CPU_METHODS_H + +struct C_array_8 { // single-dimensional? + char *ptr = NULL; + ssize_t itemsize = 0; + ssize_t size = 0; + char byteorder = '='; // '=', '<', or '>' + ssize_t strides = 0; +}; + +struct C_array_16 { + short int *ptr = NULL; + ssize_t itemsize = 0; + ssize_t size = 0; + char byteorder = '='; + ssize_t strides = 0; +}; + +struct C_array_32 { + long int *ptr = NULL; + ssize_t itemsize = 0; + ssize_t size = 0; + char byteorder = '='; + ssize_t strides = 0; +}; + +struct C_array_64 { + long long *ptr = NULL; + ssize_t itemsize = 0; + ssize_t size = 0; + char byteorder = '='; + ssize_t strides = 0; +}; + +int byteswap_16bit(short int *val) { + return (*val = *val << 8 | *val >> 8) ? 1 : 0; +} + +int byteswap_32bit(long int *val) { + *val = ((*val << 8) & 0xFF00FF00) | ((*val >> 8) & 0xFF00FF); + return (*val = (*val << 16) | (*val >> 16)) ? 1 : 0; +} + +int byteswap_64bit(long long *val) { + *val = ((*val << 8) & 0xFF00FF00FF00FF00ULL) | ((*val >> 8) & 0x00FF00FF00FF00FFULL); + *val = ((*val << 16) & 0xFFFF0000FFFF0000ULL) | ((*val >> 16) & 0x0000FFFF0000FFFFULL); + return (*val = (*val << 32) | (*val >> 32)) ? 1 : 0; +} + +int isNative(char input) { // returns true if native, false if non-native + if (input == '=') + return 1; + union { + unsigned long int i; + char c[4]; + } bint = { 0x01020304 }; + return ((bint.c[0] == 1 && input != '<') + || (bint.c[0] != 1 && input != '>')); +} + +int makeNative_16bit(struct C_array_16 *input) { + if (input->itemsize != 2) + return 0; + int N = input->strides / input->itemsize; + if (!isNative(input->byteorder)) + for (ssize_t i = 0; i < input->size; i++) + if (!byteswap_16bit(&(input->ptr[i * N]))) + return 0; + return 1; +} + +int makeNative_32bit(struct C_array_32 *input) { + if (input->itemsize != 4) + return 0; + int N = input->strides / input->itemsize; + if (!isNative(input->byteorder)) + for (ssize_t i = 0; i < input->size; i++) + if (!byteswap_32bit(&(input->ptr[i * N]))) + return 0; + return 1; +} + +int makeNative_64bit(struct C_array_64 *input) { + if (input->itemsize != 8) + return 0; + int N = input->strides / input->itemsize; + if (!isNative(input->byteorder)) + for (ssize_t i = 0; i < input->size; i++) + if (!byteswap_64bit(&(input->ptr[i * N]))) + return 0; + return 1; +} + +int offsets2parents_int64(struct C_array_64 *offsets, struct C_array_64 *parents) { + makeNative_64bit(offsets); + if (offsets->itemsize != 8 || parents->itemsize != 8) + return 0; + int N_off = offsets->strides / offsets->itemsize; + int N_par = parents->strides / parents->itemsize; + ssize_t j = 0; + ssize_t k = -1; + for (ssize_t i = 0; i < offsets->size; i++) { + while (j < offsets->ptr[i * N_off]) + parents->ptr[N_par * j++] = (long long)k; + k++; + } + return 1; +} + + +#endif // end include guard + +#ifdef __cplusplus // end C compiler instruction +} +#endif diff --git a/awkward-cpp/awkward/cpp/array/array_impl.cpp b/awkward-cpp/awkward/cpp/array/array_impl.cpp index c69f0f87..ff3eb209 100644 --- a/awkward-cpp/awkward/cpp/array/array_impl.cpp +++ b/awkward-cpp/awkward/cpp/array/array_impl.cpp @@ -1,5 +1,7 @@ #include "jagged.h" +namespace py = pybind11; + PYBIND11_MODULE(array_impl, m) { py::class_(m, "JaggedArray") .def(py::init()) @@ -24,10 +26,12 @@ PYBIND11_MODULE(array_impl, m) { .def("__getitem__", (py::object (JaggedArray::*)(ssize_t)) &JaggedArray::python_getitem) .def("__getitem__", (py::object (JaggedArray::*)(py::slice)) &JaggedArray::python_getitem) .def("__getitem__", (py::object (JaggedArray::*)(py::array)) &JaggedArray::python_getitem) + .def("__getitem__", (py::object (JaggedArray::*)(py::tuple)) &JaggedArray::python_getitem) .def("__str__", &JaggedArray::str) .def("__len__", &JaggedArray::len) .def("__iter__", &JaggedArray::iter) .def("__repr__", &JaggedArray::repr); + py::class_(m, "JaggedArrayIterator") .def(py::init()) .def("__iter__", &JaggedArray::JaggedArrayIterator::iter) diff --git a/awkward-cpp/awkward/cpp/array/jagged.h b/awkward-cpp/awkward/cpp/array/jagged.h index e3bc34c8..582d3d7b 100644 --- a/awkward-cpp/awkward/cpp/array/jagged.h +++ b/awkward-cpp/awkward/cpp/array/jagged.h @@ -18,6 +18,7 @@ #include "util.h" #include "any.h" #include "numpytypes.h" +#include "CPU_methods.h" namespace py = pybind11; @@ -308,9 +309,20 @@ class JaggedArray : public AwkwardArray { return (JaggedArray*)deepcopy(); } + // THIS IS NOW AN EXPERIMENTAL ENVIRONMENT + static C_array_64 numpy_to_c64(py::array input) { + input = input.cast>(); + struct C_array_64 temp = { + (std::int64_t*)input.request().ptr, + 8, + input.request().size, + input.request().format.at(0), + input.request().strides[0] + }; + return temp; + } + static py::array_t offsets2parents(py::array offsets) { - makeIntNative(offsets); - offsets = offsets.cast>(); py::buffer_info offsets_info = offsets.request(); if (offsets_info.size <= 0) { throw std::invalid_argument("offsets must have at least one element"); @@ -318,20 +330,11 @@ class JaggedArray : public AwkwardArray { auto offsets_ptr = (std::int64_t*)offsets_info.ptr; int N = offsets_info.strides[0] / offsets_info.itemsize; - ssize_t parents_length = (ssize_t)offsets_ptr[offsets_info.size - 1]; + ssize_t parents_length = (ssize_t)offsets_ptr[(offsets_info.size - 1) * N]; auto parents = py::array_t(parents_length); - py::buffer_info parents_info = parents.request(); - - auto parents_ptr = (std::int64_t*)parents_info.ptr; - ssize_t j = 0; - ssize_t k = -1; - for (ssize_t i = 0; i < offsets_info.size; i++) { - while (j < (ssize_t)offsets_ptr[i * N]) { - parents_ptr[j] = (std::int64_t)k; - j += 1; - } - k += 1; + if (!offsets2parents_int64(&numpy_to_c64(offsets), &numpy_to_c64(parents))) { + throw std::exception("Error in: CPU_methods.h::offsets2parents_int64()"); } return parents; @@ -691,6 +694,43 @@ class JaggedArray : public AwkwardArray { return getitem(input)->unwrap(); } + /*AnyArray* getitem(py::tuple input) { + if (py::len(input) == 0) { + throw std::invalid_argument("getitem requires at least one argument"); + } + if (py::len(input) == 1) { + try { + ssize_t temp = input[0].cast(); + return getitem(temp); + } + catch (py::cast_error e) { } + try { + py::slice temp = input[0].cast(); + return getitem(temp); + } + catch (py::cast_error e) { } + try { + JaggedArray* temp = input[0].cast(); + throw std::invalid_argument("JaggedArray* argument support not yet implemented"); // TODO + } + catch (py::cast_error e) { } + try { + py::array temp = input[0].cast(); + return getitem(temp); + } + catch (py::cast_error e) { + throw std::invalid_argument("argument type not supported for __getitem__"); + } + } + if (py::len(input) == 2) { + + } + }*/ + + py::object python_getitem(py::tuple input) { + return getitem(input)->unwrap(); + } + py::object tolist() { py::list out; for (ssize_t i = 0; i < len(); i++) { diff --git a/awkward-cpp/awkward/cpp/array/util.h b/awkward-cpp/awkward/cpp/array/util.h index 0c9b4c94..55a3a096 100644 --- a/awkward-cpp/awkward/cpp/array/util.h +++ b/awkward-cpp/awkward/cpp/array/util.h @@ -7,6 +7,7 @@ #include #include #include +#include "CPU_methods.h" namespace py = pybind11; @@ -48,31 +49,22 @@ std::int64_t byteswap(std::int64_t val) { return (val << 32) | ((val >> 32) & 0xFFFFFFFFULL); } -bool isNative(py::array input) { - char ch = input.request().format.at(0); - union { - uint32_t i; - char c[4]; - } bint = { 0x01020304 }; - return ((bint.c[0] == 1 && ch != '<') || (bint.c[0] != 1 && ch != '>')); -} - bool isNativeInt(py::array input) { std::string intList = "qQlLhHbB"; if (intList.find(input.request().format.at(0)) == std::string::npos) { throw std::invalid_argument("argument must be of type int"); } - return isNative(input); + return isNative(input.request().format.at(0)); } template void makeNative(py::array_t input) { - if (isNative(input)) { + if (isNative(input.request().format.at(0))) { return; } py::buffer_info array_info = input.request(); auto array_ptr = (T*)array_info.ptr; - int N = array_info.shape[0] / array_info.itemsize; + int N = array_info.strides[0] / array_info.itemsize; for (ssize_t i = 0; i < array_info.size; i++) { array_ptr[i * N] = byteswap(array_ptr[i * N]);