From 8fd50d36da1a43b74eadf719f4748fc5cf5b303c Mon Sep 17 00:00:00 2001 From: Hans Dembinski Date: Tue, 28 Mar 2017 09:41:16 +0200 Subject: [PATCH] make views read-only and dont modified viewed --- build/CMakeLists.txt | 2 +- src/python/histogram.cpp | 50 +++++++++++++++++++++------------- test/adaptive_storage_test.cpp | 6 ++++ test/python_suite_test.py.in | 3 +- 4 files changed, 40 insertions(+), 21 deletions(-) diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index a81eb3d1..f1990e79 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -13,7 +13,7 @@ if(${CMAKE_BUILD_TYPE}) endif() if(MSVC) - add_definitions(/W3 /std:c++11) + add_definitions(/W3) else() # -fpermissive needed for cpp_int in gcc-6 add_definitions(-Wall -std=c++11 -fpermissive) diff --git a/src/python/histogram.cpp b/src/python/histogram.cpp index 411eb7e6..97eace76 100644 --- a/src/python/histogram.cpp +++ b/src/python/histogram.cpp @@ -299,7 +299,8 @@ struct storage_access { } std::pair operator()(const array& /*unused*/) const { std::pair p; - p.first = 0; // communicate that the type was array + p.first = sizeof(uint8_t); + p.second = python::str("|u") + python::str(p.first); return p; } std::pair operator()(const array& /*unused*/) const { @@ -310,9 +311,8 @@ struct storage_access { } std::pair operator()(const array& /*unused*/) const { std::pair p; - p.first = sizeof(double); - p.second = python::str("|f") + python::str(p.first); - p.first *= -1; // communicate that the type was array + p.first = 0; // communicate that the type was array + p.second = python::str("|f") + python::str(sizeof(double)); return p; } }; @@ -323,10 +323,24 @@ struct storage_access { data_visitor(const python::list& sh, const python::list& st) : shapes(sh), strides(st) {} template python::object operator()(const Array& b) const { - return python::make_tuple(reinterpret_cast(b.begin()), false); + return python::make_tuple(reinterpret_cast(b.begin()), true); } - python::object operator()(const array& /*unused*/) const { - return python::object(); // is never called + python::object operator()(const array& b) const { + // cannot pass non-existent memory to numpy; make new + // zero-initialized uint8 array, and pass it + int dim = python::len(shapes); + npy_intp shapes2[BOOST_HISTOGRAM_AXIS_LIMIT]; + for (int i = 0; i < dim; ++i) { + shapes2[i] = python::extract(shapes[i]); + } + PyObject *ptr = PyArray_SimpleNew(dim, shapes2, NPY_UINT8); + for (int i = 0; i < dim; ++i) { + PyArray_STRIDES((PyArrayObject *)ptr)[i] = python::extract(strides[i]); + } + auto *buf = static_cast(PyArray_DATA((PyArrayObject *)ptr)); + std::fill(buf, buf + b.size, uint8_t(0)); + PyArray_CLEARFLAGS((PyArrayObject*)ptr, NPY_ARRAY_WRITEABLE); + return python::object(python::handle<>(ptr)); } python::object operator()(const array& b) const { // cannot pass cpp_int to numpy; make new @@ -344,27 +358,21 @@ struct storage_access { for (std::size_t i = 0; i < b.size; ++i) { buf[i] = static_cast(b[i]); } + PyArray_CLEARFLAGS((PyArrayObject*)ptr, NPY_ARRAY_WRITEABLE); return python::object(python::handle<>(ptr)); } }; - static python::object array_interface(dynamic_histogram<> &self) { - auto &b = self.storage_.buffer_; + static python::object array_interface(const dynamic_histogram<> &self) { python::dict d; + python::list shapes; python::list strides; + auto &b = self.storage_.buffer_; auto dtype = apply_visitor(dtype_visitor(), b); auto stride = dtype.first; - if (stride == 0) { - // buffer not created yet, do that now - auto a = array(self.storage_.size()); - dtype = dtype_visitor()(a); - b = std::move(a); - stride = dtype.first; - } else - if (stride < 0) { - // buffer is weight, needs special treatment - stride *= -1; + if (stride == 0) { // buffer is weight, needs special treatment + stride = sizeof(double); strides.append(stride); stride *= 2; shapes.append(2); @@ -375,6 +383,10 @@ struct storage_access { strides.append(stride); stride *= s; } + if (self.dim() == 0) { + shapes.append(0); + strides.append(stride); + } d["shape"] = python::tuple(shapes); d["strides"] = python::tuple(strides); d["typestr"] = dtype.second; diff --git a/test/adaptive_storage_test.cpp b/test/adaptive_storage_test.cpp index dfbbcaaf..66760c2c 100644 --- a/test/adaptive_storage_test.cpp +++ b/test/adaptive_storage_test.cpp @@ -262,6 +262,12 @@ template <> void convert_container_storage_impl() { int main() { using namespace boost::histogram; + // empty state + { + adaptive_storage<> a; + BOOST_TEST_EQ(a.size(), 0); + } + // copy { copy_impl(); diff --git a/test/python_suite_test.py.in b/test/python_suite_test.py.in index a9eedafb..e194fe9a 100755 --- a/test/python_suite_test.py.in +++ b/test/python_suite_test.py.in @@ -687,7 +687,8 @@ class test_histogram(unittest.TestCase): b = histogram() b1 = numpy.asarray(b) - self.assertEqual(b1, 0) + self.assertEqual(b1.shape, (0,)) + self.assertEqual(numpy.sum(b1), 0) @unittest.skipUnless(have_numpy, "requires build with numpy-support") def test_numpy_conversion_5(self):