diff --git a/CMake/CMakeLists.txt b/CMake/CMakeLists.txt index dc7bdcaf..92525b05 100644 --- a/CMake/CMakeLists.txt +++ b/CMake/CMakeLists.txt @@ -9,28 +9,30 @@ find_package(Boost 1.55 REQUIRED COMPONENTS python iostreams serialization unit_test_framework) find_package(PythonLibs) find_package(Numpy) # optional -find_package(ROOT) # only used in one of the tests -include_directories(include ${Boost_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS}) +include_directories(include ${Boost_INCLUDE_DIRS}) add_definitions(-DBOOST_TEST_DYN_LINK) # for unit_test_framework set(LIBRARIES stdc++ ${Boost_LIBRARIES}) -if(Boost_PYTHON_FOUND) +if(Boost_PYTHON_FOUND AND PYTHONLIBS_FOUND) + set(USE_PYTHON True) + include_directories(${PYTHON_INCLUDE_DIRS}) LIST(APPEND LIBRARIES ${PYTHON_LIBRARIES}) + add_definitions(-DUSE_PYTHON) + + if(NUMPY_FOUND) + include_directories(${NUMPY_INCLUDE_DIR}) + add_definitions(-DUSE_NUMPY) + endif() endif() -if(NUMPY_FOUND) - include_directories(${NUMPY_INCLUDE_DIR}) - add_definitions(-DUSE_NUMPY) -endif() - +# core library add_library(histogram SHARED src/axis.cpp src/histogram_base.cpp - src/nhistogram.cpp + src/histogram.cpp src/nstore.cpp src/zero_suppression.cpp - # src/whistogram.cpp ) target_link_libraries(histogram ${LIBRARIES}) @@ -41,21 +43,24 @@ else() target_compile_options(histogram PUBLIC "-O3 -fomit-frame-pointer -mtune=generic") endif() -if(Boost_PYTHON_FOUND) +# python bindings +if(USE_PYTHON) add_library(pyhistogram MODULE src/python/module.cpp src/python/histogram_base.cpp - src/python/nhistogram.cpp + src/python/histogram.cpp ) target_link_libraries(pyhistogram histogram ${LIBRARIES}) set_target_properties(pyhistogram PROPERTIES OUTPUT_NAME "histogram" PREFIX "" SUFFIX ".so") endif() +# examples add_executable(sizeof examples/sizeof.cpp ) target_link_libraries(sizeof ${LIBRARIES}) +find_package(ROOT) # only used in speed comparison if(ROOT_FOUND) add_executable(nhistogram_speed examples/speed_vs_root.cpp) diff --git a/examples/speed_vs_root.cpp b/examples/speed_vs_root.cpp index 6c173313..7faf1a2d 100644 --- a/examples/speed_vs_root.cpp +++ b/examples/speed_vs_root.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -51,7 +51,7 @@ void compare_1d(unsigned n) t = clock() - t; best_root = std::min(best_root, double(t) / CLOCKS_PER_SEC); - nhistogram h(regular_axis(100, 0, 1)); + histogram h(regular_axis(100, 0, 1)); t = clock(); for (unsigned i = 0; i < n; ++i) h.fill(r[i]); @@ -80,7 +80,7 @@ void compare_3d(unsigned n) t = clock() - t; best_root = std::min(best_root, double(t) / CLOCKS_PER_SEC); - nhistogram h(regular_axis(100, 0, 1), + histogram h(regular_axis(100, 0, 1), regular_axis(100, 0, 1), regular_axis(100, 0, 1)); t = clock(); @@ -118,7 +118,7 @@ void compare_6d(unsigned n) t = clock() - t; best_root = std::min(best_root, double(t) / CLOCKS_PER_SEC); - nhistogram h(regular_axis(10, 0, 1), + histogram h(regular_axis(10, 0, 1), regular_axis(10, 0, 1), regular_axis(10, 0, 1), regular_axis(10, 0, 1), diff --git a/include/boost/histogram/detail/nstore.hpp b/include/boost/histogram/detail/nstore.hpp index c5964a87..5e52a719 100644 --- a/include/boost/histogram/detail/nstore.hpp +++ b/include/boost/histogram/detail/nstore.hpp @@ -1,10 +1,12 @@ -#ifndef _BOOST_HISTOGRAM_NSTORE_HPP_ -#define _BOOST_HISTOGRAM_NSTORE_HPP_ +#ifndef _BOOST_HISTOGRAM_DETAIL_NSTORE_HPP_ +#define _BOOST_HISTOGRAM_DETAIL_NSTORE_HPP_ +#include +#include #include #include -#include #include +#include #include #include #include @@ -20,7 +22,6 @@ class nstore { public: typedef uintptr_t size_type; -public: nstore(); nstore(const nstore&); nstore(size_type, unsigned d = sizeof(uint8_t)); @@ -30,11 +31,12 @@ public: nstore& operator+=(const nstore&); bool operator==(const nstore&) const; - uint64_t read(size_type) const; - void write(size_type, uint64_t); - inline void increase(size_type i) { switch (depth_) { + case sizeof(wtype): { + wtype& b = ((wtype*)buffer_)[i]; + b += 1.0; + } #define BOOST_HISTOGRAM_NSTORE_INC(T) \ case sizeof(T): { \ T& b = ((T*)buffer_)[i]; \ @@ -51,6 +53,14 @@ public: } } + inline void increase(size_type i, double w) { + assert(depth_ == sizeof(wtype)); + ((wtype*)buffer_)[i] += w; + } + + double value(size_type) const; + double variance(size_type) const; + const void* buffer() const { return buffer_; } unsigned depth() const { return depth_; } @@ -62,8 +72,24 @@ private: void create(); void destroy(); void grow(); + void wconvert(); - uint64_t max_count() const; + uint64_t max_count() const + { + switch (depth_) { + #define BOOST_HISTOGRAM_NSTORE_CASE(T) \ + case sizeof(T): return std::numeric_limits::max() + BOOST_HISTOGRAM_NSTORE_CASE(uint8_t); + BOOST_HISTOGRAM_NSTORE_CASE(uint16_t); + BOOST_HISTOGRAM_NSTORE_CASE(uint32_t); + BOOST_HISTOGRAM_NSTORE_CASE(uint64_t); + #undef BOOST_HISTOGRAM_NSTORE_CASE + default: assert(!"invalid depth"); + } + return 0; + } + + uint64_t ivalue(size_type) const; friend class serialization::access; template @@ -81,26 +107,50 @@ private: throw std::bad_alloc(); if (Archive::is_saving::value) { - std::vector buf; - if (zero_suppression_encode(buf, size_ * depth_, - (char*)buffer_, size_ * depth_)) { - bool is_zero_suppressed = true; - ar & is_zero_suppressed; - ar & buf; - } else { - bool is_zero_suppressed = false; - ar & is_zero_suppressed; - ar & serialization::make_array((char*)buffer_, size_ * depth_); + switch (depth_) { + #define BOOST_HISTOGRAM_NSTORE_SAVE(T) \ + case sizeof(T): { \ + std::vector buf; \ + if (zero_suppression_encode(buf, (T*)buffer_, size_)) { \ + bool is_zero_suppressed = true; \ + ar & is_zero_suppressed; \ + ar & buf; \ + } else { \ + bool is_zero_suppressed = false; \ + ar & is_zero_suppressed; \ + ar & serialization::make_array((T*)buffer_, size_); \ + } \ + } break + BOOST_HISTOGRAM_NSTORE_SAVE(uint8_t); + BOOST_HISTOGRAM_NSTORE_SAVE(uint16_t); + BOOST_HISTOGRAM_NSTORE_SAVE(uint32_t); + BOOST_HISTOGRAM_NSTORE_SAVE(uint64_t); + BOOST_HISTOGRAM_NSTORE_SAVE(wtype); + #undef BOOST_HISTOGRAM_NSTORE_SAVE + default: assert(!"invalid depth"); } - } else { + } + + if (Archive::is_loading::value) { bool is_zero_suppressed = false; ar & is_zero_suppressed; - if (is_zero_suppressed) { - std::vector buf; - ar & buf; - zero_suppression_decode((char*)buffer_, size_ * depth_, buf); - } else { - ar & serialization::make_array((char*)buffer_, size_ * depth_); + switch (depth_) { + #define BOOST_HISTOGRAM_NSTORE_LOAD(T) \ + case sizeof(T): \ + if (is_zero_suppressed) { \ + std::vector buf; \ + ar & buf; \ + zero_suppression_decode((T*)buffer_, size_, buf); \ + } else { \ + ar & serialization::make_array((T*)buffer_, size_); \ + } break + BOOST_HISTOGRAM_NSTORE_LOAD(uint8_t); + BOOST_HISTOGRAM_NSTORE_LOAD(uint16_t); + BOOST_HISTOGRAM_NSTORE_LOAD(uint32_t); + BOOST_HISTOGRAM_NSTORE_LOAD(uint64_t); + BOOST_HISTOGRAM_NSTORE_LOAD(wtype); + #undef BOOST_HISTOGRAM_NSTORE_LOAD + default: assert(!"invalid depth"); } } } diff --git a/include/boost/histogram/detail/wtype.hpp b/include/boost/histogram/detail/wtype.hpp new file mode 100644 index 00000000..25962f04 --- /dev/null +++ b/include/boost/histogram/detail/wtype.hpp @@ -0,0 +1,47 @@ +#ifndef _BOOST_HISTOGRAM_DETAIL_WTYPE_HPP_ +#define _BOOST_HISTOGRAM_DETAIL_WTYPE_HPP_ + +#include +#include + +namespace boost { +namespace histogram { +namespace detail { + +struct wtype { + double w, w2; + wtype() : w(0), w2(0) {} + wtype(const wtype& o) : w(o.w), w2(o.w2) {} + wtype(uint64_t i) : w(i), w2(i) {} + wtype& operator+=(const wtype& o) + { w += o.w; w2 += o.w2; return *this; } + wtype& operator+=(double v) + { w += v; w2 += v*v; return *this; } + wtype& operator=(uint64_t i) + { w = i; w2 = i; return *this; } + bool operator==(uint64_t i) const + { return w == i; } + bool operator!=(uint64_t i) const + { return w != i; } + bool operator==(const wtype& o) const + { return w == o.w && w2 == o.w2; } + bool operator!=(const wtype& o) const + { return w != o.w || w2 != o.w2; } + template + void serialize(Archive& ar, unsigned version) + { ar & w; ar & w2; } +}; + +static +inline +std::ostream& operator<<(std::ostream& os, const wtype& w) +{ + os << '(' << w.w << ',' << w.w2 << ')'; + return os; +} + +} +} +} + +#endif diff --git a/include/boost/histogram/detail/zero_suppression.hpp b/include/boost/histogram/detail/zero_suppression.hpp index 83be148b..b2fc3a03 100644 --- a/include/boost/histogram/detail/zero_suppression.hpp +++ b/include/boost/histogram/detail/zero_suppression.hpp @@ -1,20 +1,80 @@ #ifndef _BOOST_HISTOGRAM_DETAIL_ZERO_SUPPRESSION_HPP_ #define _BOOST_HISTOGRAM_DETAIL_ZERO_SUPPRESSION_HPP_ -#include +#include +#include +#include #include namespace boost { namespace histogram { namespace detail { +template bool -zero_suppression_encode(std::vector& output, std::size_t output_max, - const char* input, std::size_t input_len); +zero_suppression_encode(std::vector& output, const T* input, + uintptr_t size) +{ + #define BOOST_HISTOGRAM_ZERO_SUPPRESSION_FILL { \ + if ((size - output.size()) < 2) \ + return false; \ + output.push_back(0); \ + output.push_back(nzero); \ + nzero = 0; \ + } + const T* input_end = input + size; + T nzero = 0; + for (; input != input_end; ++input) { + if (*input != 0) { + if (nzero) + BOOST_HISTOGRAM_ZERO_SUPPRESSION_FILL + if (output.size() == size) + return false; + output.push_back(*input); + } + else { + ++nzero; + if (nzero == 0) // overflowed to zero + BOOST_HISTOGRAM_ZERO_SUPPRESSION_FILL + } + } + if (nzero) + BOOST_HISTOGRAM_ZERO_SUPPRESSION_FILL + return true; +} + +template void -zero_suppression_decode(char* output, std::size_t output_len, - const std::vector& input); +zero_suppression_decode(T* output, uintptr_t size, + const std::vector& input) +{ + const T* inp = &input[0]; + const T* output_end = output + size; + while (output != output_end) { + *output = *inp; + if (*inp == 0) { + const uintptr_t nzero = *(++inp); + for (T j = 1; j != nzero; ++j) { + *(++output) = 0; + if (output == output_end) + return; + } + } + ++inp; + ++output; + } +} + +template <> +void +zero_suppression_decode(wtype* output, uintptr_t size, + const std::vector& input); + +template <> +bool +zero_suppression_encode(std::vector& output, const wtype* input, + uintptr_t size); } } diff --git a/include/boost/histogram/nhistogram.hpp b/include/boost/histogram/histogram.hpp similarity index 55% rename from include/boost/histogram/nhistogram.hpp rename to include/boost/histogram/histogram.hpp index 788023fd..15ea3cae 100644 --- a/include/boost/histogram/nhistogram.hpp +++ b/include/boost/histogram/histogram.hpp @@ -1,5 +1,5 @@ -#ifndef _BOOST_HISTOGRAM_NHISTOGRAM_HPP_ -#define _BOOST_HISTOGRAM_NHISTOGRAM_HPP_ +#ifndef _BOOST_HISTOGRAM_HISTOGRAM_HPP_ +#define _BOOST_HISTOGRAM_HISTOGRAM_HPP_ #include #include @@ -9,28 +9,27 @@ #include #include #include -#include namespace boost { namespace histogram { -class nhistogram : public histogram_base { +class histogram : public histogram_base { public: - nhistogram() {} + histogram() {} - nhistogram(const nhistogram& o) : + histogram(const histogram& o) : histogram_base(o), data_(o.data_) {} explicit - nhistogram(const axes_type& axes) : + histogram(const axes_type& axes) : histogram_base(axes), data_(field_count()) {} #define BOOST_NHISTOGRAM_CTOR(z, n, unused) \ - nhistogram( BOOST_PP_ENUM_PARAMS_Z(z, n, const axis_type& a) ) : \ + histogram( BOOST_PP_ENUM_PARAMS_Z(z, n, const axis_type& a) ) : \ histogram_base( BOOST_PP_ENUM_PARAMS_Z(z, n, a) ), \ data_(field_count()) \ {} @@ -73,12 +72,43 @@ BOOST_PP_REPEAT_FROM_TO(1, BOOST_HISTOGRAM_AXIS_LIMIT, BOOST_NHISTOGRAM_CTOR, ni // generates fill functions taking 1 to AXIS_LIMT arguments BOOST_PP_REPEAT_FROM_TO(1, BOOST_HISTOGRAM_AXIS_LIMIT, BOOST_NHISTOGRAM_FILL, nil) + template + inline + void wfill(const Container& v, double w) + { + BOOST_ASSERT(v.size() == dim()); + const size_type k = pos(v); + if (k != uintmax_t(-1)) + data_.increase(k, w); + } + + // C-style call + inline + void wfill(unsigned n, const double* v, double w) + { + BOOST_ASSERT(n == dim()); + const size_type k = pos(v); + if (k != uintmax_t(-1)) + data_.increase(k, w); + } + +#define BOOST_NHISTOGRAM_WFILL(z, n, unused) \ + inline \ + void wfill( BOOST_PP_ENUM_PARAMS_Z(z, n, double x), double w ) \ + { \ + const double buffer[n] = { BOOST_PP_ENUM_PARAMS(n, x) }; \ + wfill(n, buffer, w); /* size is checked here */ \ + } + +// generates wfill functions taking 1 to AXIS_LIMT arguments +BOOST_PP_REPEAT_FROM_TO(1, BOOST_HISTOGRAM_AXIS_LIMIT, BOOST_NHISTOGRAM_WFILL, nil) + template double value(const Container& idx) const { BOOST_ASSERT(idx.size() == dim()); - return data_.read(linearize(idx)); + return data_.value(linearize(idx)); } // C-style call @@ -86,7 +116,7 @@ BOOST_PP_REPEAT_FROM_TO(1, BOOST_HISTOGRAM_AXIS_LIMIT, BOOST_NHISTOGRAM_FILL, ni const { BOOST_ASSERT(n == dim()); - return data_.read(linearize(idx)); + return data_.value(linearize(idx)); } #define BOOST_NHISTOGRAM_VALUE(z, n, unused) \ @@ -100,11 +130,38 @@ BOOST_PP_REPEAT_FROM_TO(1, BOOST_HISTOGRAM_AXIS_LIMIT, BOOST_NHISTOGRAM_FILL, ni // generates value functions taking 1 to AXIS_LIMT arguments BOOST_PP_REPEAT_FROM_TO(1, BOOST_HISTOGRAM_AXIS_LIMIT, BOOST_NHISTOGRAM_VALUE, nil) - bool operator==(const nhistogram& o) const + template + double variance(const Container& idx) + const + { + BOOST_ASSERT(idx.size() == dim()); + return data_.variance(linearize(idx)); + } + + // C-style call + double variance(unsigned n, const int* idx) + const + { + BOOST_ASSERT(n == dim()); + return data_.variance(linearize(idx)); + } + +#define BOOST_NHISTOGRAM_VARIANCE(z, n, unused) \ + double variance( BOOST_PP_ENUM_PARAMS_Z(z, n, int i) ) \ + const \ + { \ + const int idx[n] = { BOOST_PP_ENUM_PARAMS_Z(z, n, i) }; \ + return variance(n, idx); /* size is checked here */ \ + } + +// generates variance functions taking 1 to AXIS_LIMT arguments +BOOST_PP_REPEAT_FROM_TO(1, BOOST_HISTOGRAM_AXIS_LIMIT, BOOST_NHISTOGRAM_VARIANCE, nil) + + bool operator==(const histogram& o) const { return histogram_base::operator==(o) && data_ == o.data_; } - nhistogram& operator+=(const nhistogram& o) + histogram& operator+=(const histogram& o) { data_ += o.data_; return *this; } private: @@ -118,11 +175,11 @@ private: ar & data_; } - friend python::dict nhistogram_array_interface(nhistogram&); + friend class buffer_access; }; -nhistogram operator+(const nhistogram& a, const nhistogram& b) { - nhistogram result(a); +histogram operator+(const histogram& a, const histogram& b) { + histogram result(a); return result += b; } diff --git a/include/boost/histogram/wstore.hpp b/include/boost/histogram/wstore.hpp deleted file mode 100644 index 20cf767c..00000000 --- a/include/boost/histogram/wstore.hpp +++ /dev/null @@ -1,110 +0,0 @@ -#include -#include -#include -#include - -class wstore { -public: - typedef boost::uintmax_t size_type; - struct wcount { double w_, w2_; }; - -private: - size_type size_; - double* buffer_; - - friend class boost::serialization::access; - template - void serialize(Archive & ar, unsigned version) { - using boost::serialization::make_array; - size_type s = size_; - ar & make_nvp("size", size_); - if (s != size_) { - destroy(); - create(); - } - ar & make_nvp("data", \ - make_array(buffer_, size_ * 2)); - } - - void - create() { - buffer_ = (double*)std::calloc(size_, sizeof(wcount)); - } - - void - destroy() { - free(buffer_); - buffer_ = 0; - } - -public: - wstore() - : size_(0), buffer_(0) - {} - - wstore(size_type n) - : size_(n) - { - create(); - } - - wstore(const wstore& other) - : size_(other.size_) - { - create(); - *this = other; - } - - ~wstore() { destroy(); } - - wstore& - operator=(const wstore& other) - { - if (size_ != other.size_) { - destroy(); - size_ = other.size_; - create(); - } - std::memcpy(buffer_, other.buffer_, size_ * sizeof(wcount)); - return *this; - } - - inline - wcount& - operator[](size_type i) - { - return *((wcount*)buffer_ + i); - } - - inline - const wcount& - operator[](size_type i) const - { - return *((wcount*)buffer_ + i); - } - - wstore& - operator+=(const wstore& other) { - if (size_ != other.size_) - throw std::logic_error("sizes do not match"); - - for (size_type i = 0; i < (size_ * 2); ++i) - buffer_[i] += other.buffer_[i]; - return *this; - } - - bool - operator==(const wstore& other) const { - if (size_ != other.size_) - return false; - - for (size_type i = 0; i < (size_ * 2); ++i) - if (buffer_[i] != other.buffer_[i]) - return false; - - return true; - } - - inline size_type size() const { return size_; } - inline const double* buffer() const { return buffer_; } -}; diff --git a/src/nhistogram.cpp b/src/histogram.cpp similarity index 67% rename from src/nhistogram.cpp rename to src/histogram.cpp index 97a5c3f5..4e9f4a89 100644 --- a/src/nhistogram.cpp +++ b/src/histogram.cpp @@ -1,16 +1,16 @@ -#include +#include #include namespace boost { namespace histogram { double -nhistogram::sum() +histogram::sum() const { double result = 0.0; for (size_type i = 0, n = field_count(); i < n; ++i) - result += data_.read(i); + result += data_.value(i); return result; } diff --git a/src/nstore.cpp b/src/nstore.cpp index 67cc5239..fc09a738 100644 --- a/src/nstore.cpp +++ b/src/nstore.cpp @@ -50,8 +50,42 @@ nstore::operator+=(const nstore& o) { if (size_ != o.size_) throw std::logic_error("sizes do not match"); - for (size_type i = 0; i < size_; ++i) - write(i, read(i) + o.read(i)); + + if (depth_ != o.depth_) { + if (o.depth_ == sizeof(wtype)) + wconvert(); + else + while (depth_ < o.depth_) + grow(); + } + + if (depth_ == sizeof(wtype)) { + for (size_type i = 0; i < size_; ++i) + ((wtype*)buffer_)[i] += ((wtype*)o.buffer_)[i]; + } + else { + size_type i = 0; + while (i < size_) { + const uint64_t oi = o.ivalue(i); + switch (depth_) { + #define BOOST_HISTOGRAM_NSTORE_ADD(T) \ + case sizeof(T): { \ + T& b = ((T*)buffer_)[i]; \ + if ((std::numeric_limits::max() - b) >= oi) { \ + b += oi; \ + ++i; \ + break; \ + } else grow(); /* add fall through */ \ + } + BOOST_HISTOGRAM_NSTORE_ADD(uint8_t); + BOOST_HISTOGRAM_NSTORE_ADD(uint16_t); + BOOST_HISTOGRAM_NSTORE_ADD(uint32_t); + BOOST_HISTOGRAM_NSTORE_ADD(uint64_t); + #undef BOOST_HISTOGRAM_NSTORE_ADD + default: assert(!"invalid depth"); + } + } + } return *this; } @@ -64,42 +98,31 @@ nstore::operator==(const nstore& o) return std::memcmp(buffer_, o.buffer_, size_ * depth_) == 0; } -uint64_t -nstore::read(size_type i) +double +nstore::value(size_type i) + const +{ + if (depth_ == sizeof(wtype)) + return ((wtype*)buffer_)[i].w; + return ivalue(i); +} + +double +nstore::variance(size_type i) const { switch (depth_) { - #define BOOST_HISTOGRAM_NSTORE_READ(T) \ + case sizeof(wtype): return ((wtype*)buffer_)[i].w2; + #define BOOST_HISTOGRAM_NSTORE_VARIANCE(T) \ case sizeof(T): return ((T*)buffer_)[i] - BOOST_HISTOGRAM_NSTORE_READ(uint8_t); - BOOST_HISTOGRAM_NSTORE_READ(uint16_t); - BOOST_HISTOGRAM_NSTORE_READ(uint32_t); - BOOST_HISTOGRAM_NSTORE_READ(uint64_t); - #undef BOOST_HISTOGRAM_NSTORE_READ - default: assert(!"invalid depth"); - } - return 0; -} - -void -nstore::write(size_type i, uint64_t v) -{ - const uint64_t vmax = max_count(); - while (vmax < v) grow(); - - switch (depth_) { - #define BOOST_HISTOGRAM_NSTORE_WRITE(T) \ - case sizeof(T): { \ - ((T*)buffer_)[i] = v; \ - break; \ - } - BOOST_HISTOGRAM_NSTORE_WRITE(uint8_t); - BOOST_HISTOGRAM_NSTORE_WRITE(uint16_t); - BOOST_HISTOGRAM_NSTORE_WRITE(uint32_t); - BOOST_HISTOGRAM_NSTORE_WRITE(uint64_t); - #undef BOOST_HISTOGRAM_NSTORE_WRITE + BOOST_HISTOGRAM_NSTORE_VARIANCE(uint8_t); + BOOST_HISTOGRAM_NSTORE_VARIANCE(uint16_t); + BOOST_HISTOGRAM_NSTORE_VARIANCE(uint32_t); + BOOST_HISTOGRAM_NSTORE_VARIANCE(uint64_t); + #undef BOOST_HISTOGRAM_NSTORE_VARIANCE default: assert(!"invalid depth"); } + return 0.0; } void @@ -118,17 +141,17 @@ nstore::destroy() void nstore::grow() { - if (depth_ == sizeof(uint64_t)) - throw std::overflow_error("depth > 64 bit is not supported"); - if (depth_ == 0 || buffer_ == 0) - throw std::logic_error("cannot call grow on null buffer"); + assert(depth_ > 0); + assert(depth_ < sizeof(uint64_t)); + assert(buffer_ != 0); buffer_ = std::realloc(buffer_, size_ * 2 * depth_); if (!buffer_) throw std::bad_alloc(); + size_type i = size_; switch (depth_) { - #define BOOST_HISTOGRAM_NSTORE_GROW(T0, T1) \ - case sizeof(T0): \ - for (size_type i = size_ - 1; i != size_type(-1); --i) \ - ((T1*)buffer_)[i] = ((T0*)buffer_)[i]; \ + #define BOOST_HISTOGRAM_NSTORE_GROW(T0, T1) \ + case sizeof(T0): \ + while (i--) \ + ((T1*)buffer_)[i] = ((T0*)buffer_)[i]; \ break BOOST_HISTOGRAM_NSTORE_GROW(uint8_t, uint16_t); BOOST_HISTOGRAM_NSTORE_GROW(uint16_t, uint32_t); @@ -138,17 +161,41 @@ nstore::grow() depth_ *= 2; } +void +nstore::wconvert() +{ + assert(depth_ < sizeof(wtype)); + buffer_ = std::realloc(buffer_, size_ * sizeof(wtype)); + if (!buffer_) throw std::bad_alloc(); + size_type i = size_; + switch (depth_) { + #define BOOST_HISTOGRAM_NSTORE_CONVERT(T) \ + case sizeof(T): \ + while (i--) \ + ((wtype*)buffer_)[i] = ((T*)buffer_)[i]; \ + break + BOOST_HISTOGRAM_NSTORE_CONVERT(uint8_t); + BOOST_HISTOGRAM_NSTORE_CONVERT(uint16_t); + BOOST_HISTOGRAM_NSTORE_CONVERT(uint32_t); + BOOST_HISTOGRAM_NSTORE_CONVERT(uint64_t); + #undef BOOST_HISTOGRAM_NSTORE_CONVERT + default: break; // no nuthin' + } + depth_ = sizeof(wtype); +} + uint64_t -nstore::max_count() +nstore::ivalue(size_type i) const { switch (depth_) { - #define BOOST_HISTOGRAM_NSTORE_CASE(T) \ - case sizeof(T): return std::numeric_limits::max() - BOOST_HISTOGRAM_NSTORE_CASE(uint8_t); - BOOST_HISTOGRAM_NSTORE_CASE(uint16_t); - BOOST_HISTOGRAM_NSTORE_CASE(uint32_t); - BOOST_HISTOGRAM_NSTORE_CASE(uint64_t); + #define BOOST_HISTOGRAM_NSTORE_IVALUE(T) \ + case sizeof(T): return ((T*)buffer_)[i] + BOOST_HISTOGRAM_NSTORE_IVALUE(uint8_t); + BOOST_HISTOGRAM_NSTORE_IVALUE(uint16_t); + BOOST_HISTOGRAM_NSTORE_IVALUE(uint32_t); + BOOST_HISTOGRAM_NSTORE_IVALUE(uint64_t); + #undef BOOST_HISTOGRAM_NSTORE_IVALUE default: assert(!"invalid depth"); } return 0; diff --git a/src/python/nhistogram.cpp b/src/python/histogram.cpp similarity index 76% rename from src/python/nhistogram.cpp rename to src/python/histogram.cpp index cc9e9cc5..7edeaddd 100644 --- a/src/python/nhistogram.cpp +++ b/src/python/histogram.cpp @@ -1,10 +1,10 @@ +#include "serialization_suite.hpp" #include -#include +#include #include #include #include #include -#include "serialization_suite.hpp" #ifdef USE_NUMPY # define NO_IMPORT_ARRAY # define PY_ARRAY_UNIQUE_SYMBOL boost_histogram_ARRAY_API @@ -16,7 +16,7 @@ namespace boost { namespace histogram { python::object -nhistogram_init(python::tuple args, python::dict kwargs) { +histogram_init(python::tuple args, python::dict kwargs) { using namespace python; using python::tuple; @@ -48,24 +48,12 @@ nhistogram_init(python::tuple args, python::dict kwargs) { return pyinit(axes); } -python::dict -nhistogram_array_interface(nhistogram& self) { - python::list shape; - for (unsigned i = 0; i < self.dim(); ++i) - shape.append(self.shape(i)); - python::dict d; - d["shape"] = python::tuple(shape); - d["typestr"] = python::str("(args[0]); + histogram& self = extract(args[0]); #ifdef USE_NUMPY if (nargs == 2) { @@ -128,7 +116,7 @@ nhistogram_fill(python::tuple args, python::dict kwargs) { } uint64_t -nhistogram_getitem(const nhistogram& self, python::object oidx) { +histogram_getitem(const histogram& self, python::object oidx) { using namespace python; if (self.dim() == 1) @@ -147,26 +135,42 @@ nhistogram_getitem(const nhistogram& self, python::object oidx) { return self.value(self.dim(), idx); } -void register_nhistogram() +class buffer_access { +public: + static + python::dict + histogram_array_interface(histogram& self) { + python::list shape; + for (unsigned i = 0; i < self.dim(); ++i) + shape.append(self.shape(i)); + python::dict d; + d["shape"] = python::tuple(shape); + d["typestr"] = python::str(", - shared_ptr - >("nhistogram", no_init) - .def("__init__", raw_function(nhistogram_init)) + histogram, bases, + shared_ptr + >("histogram", no_init) + .def("__init__", raw_function(histogram_init)) // shadowed C++ ctors .def(init()) - .add_property("__array_interface__", nhistogram_array_interface) - .def("fill", raw_function(nhistogram_fill)) - .add_property("depth", &nhistogram::depth) - .add_property("sum", &nhistogram::sum) - .def("__getitem__", nhistogram_getitem) + .add_property("__array_interface__", &buffer_access::histogram_array_interface) + .def("fill", raw_function(histogram_fill)) + .add_property("depth", &histogram::depth) + .add_property("sum", &histogram::sum) + .def("__getitem__", histogram_getitem) .def(self == self) .def(self += self) .def(self + self) - .def_pickle(serialization_suite()) + .def_pickle(serialization_suite()) ; } diff --git a/src/python/module.cpp b/src/python/module.cpp index 8b579a7a..66801158 100644 --- a/src/python/module.cpp +++ b/src/python/module.cpp @@ -8,7 +8,7 @@ namespace boost { namespace histogram { void register_histogram_base(); - void register_nhistogram(); + void register_histogram(); } } @@ -18,5 +18,5 @@ BOOST_PYTHON_MODULE(histogram) import_array(); #endif boost::histogram::register_histogram_base(); - boost::histogram::register_nhistogram(); + boost::histogram::register_histogram(); } diff --git a/src/zero_suppression.cpp b/src/zero_suppression.cpp index 0ac233b1..aa471f7f 100644 --- a/src/zero_suppression.cpp +++ b/src/zero_suppression.cpp @@ -4,50 +4,52 @@ namespace boost { namespace histogram { namespace detail { +template <> bool -zero_suppression_encode(std::vector& output, std::size_t output_max, - const char* input, std::size_t input_len) +zero_suppression_encode(std::vector& output, const wtype* input, + uintptr_t size) { - #define FILL_OUTPUT { \ - if ((output_max - output.size()) < 2) \ + #define BOOST_HISTOGRAM_ZERO_SUPPRESSION_FILL { \ + if ((size - output.size()) < 2) \ return false; \ output.push_back(0); \ output.push_back(nzero); \ nzero = 0; \ } - const char* input_end = input + input_len; - unsigned nzero = 0; + const wtype* input_end = input + size; + uint32_t nzero = 0; for (; input != input_end; ++input) { if (*input != 0) { if (nzero) - FILL_OUTPUT - if (output.size() == output_max) + BOOST_HISTOGRAM_ZERO_SUPPRESSION_FILL + if (output.size() == size) return false; output.push_back(*input); } else { ++nzero; - if (nzero == 256) - FILL_OUTPUT + if (nzero == 0) // overflowed to zero + BOOST_HISTOGRAM_ZERO_SUPPRESSION_FILL } } if (nzero) - FILL_OUTPUT + BOOST_HISTOGRAM_ZERO_SUPPRESSION_FILL return true; } +template <> void -zero_suppression_decode(char* output, std::size_t output_len, - const std::vector& input) +zero_suppression_decode(wtype* output, uintptr_t size, + const std::vector& input) { - const char* inp = &input[0]; - const char* output_end = output + output_len; + const wtype* inp = &input[0]; + const wtype* output_end = output + size; while (output != output_end) { *output = *inp; if (*inp == 0) { - const char nzero = *(++inp); - for (char j = 1; j != nzero; ++j) { + const uintptr_t nzero = (++inp)->w; + for (uintptr_t j = 1; j != nzero; ++j) { *(++output) = 0; if (output == output_end) return; diff --git a/test/python_suite_test.py b/test/python_suite_test.py index b7e5ead6..ab8bfe7c 100755 --- a/test/python_suite_test.py +++ b/test/python_suite_test.py @@ -1,7 +1,7 @@ #!/usr/bin/env python import unittest from math import pi -from histogram import nhistogram, regular_axis, polar_axis, \ +from histogram import histogram, regular_axis, polar_axis, \ variable_axis, category_axis, integer_axis import cPickle import StringIO @@ -299,39 +299,39 @@ class test_integer_axis(unittest.TestCase): self.assertEqual(a.index(3), 4) self.assertEqual(a.index(4), 4) -class nhistogram_test(unittest.TestCase): +class histogram_test(unittest.TestCase): def test_init(self): - nhistogram(integer_axis(-1, 1)) + histogram(integer_axis(-1, 1)) with self.assertRaises(TypeError): - nhistogram(1) + histogram(1) with self.assertRaises(TypeError): - nhistogram("bla") + histogram("bla") with self.assertRaises(TypeError): - nhistogram([]) + histogram([]) with self.assertRaises(TypeError): - nhistogram(regular_axis) + histogram(regular_axis) with self.assertRaises(TypeError): - nhistogram(regular_axis()) + histogram(regular_axis()) with self.assertRaises(TypeError): - nhistogram([integer_axis(-1, 1)]) + histogram([integer_axis(-1, 1)]) with self.assertRaises(TypeError): - nhistogram(integer_axis(-1, 1), unknown_keyword="nh") + histogram(integer_axis(-1, 1), unknown_keyword="nh") - h = nhistogram(integer_axis(-1, 1)) + h = histogram(integer_axis(-1, 1)) self.assertEqual(h.dim, 1) self.assertEqual(h.axis(0), integer_axis(-1, 1)) self.assertEqual(h.shape(0), 5) self.assertEqual(h.depth, 1) - self.assertEqual(nhistogram(integer_axis(-1, 1, uoflow=False)).shape(0), 3) - self.assertNotEqual(h, nhistogram(regular_axis(1, -1, 1))) - self.assertNotEqual(h, nhistogram(integer_axis(-1, 2))) - self.assertNotEqual(h, nhistogram(integer_axis(-1, 1, label="ia"))) - self.assertNotEqual(h, nhistogram(integer_axis(-1, 1, uoflow=True))) + self.assertEqual(histogram(integer_axis(-1, 1, uoflow=False)).shape(0), 3) + self.assertNotEqual(h, histogram(regular_axis(1, -1, 1))) + self.assertNotEqual(h, histogram(integer_axis(-1, 2))) + self.assertNotEqual(h, histogram(integer_axis(-1, 1, label="ia"))) + self.assertNotEqual(h, histogram(integer_axis(-1, 1, uoflow=True))) def test_fill_1d(self): - h0 = nhistogram(integer_axis(-1, 1, uoflow=False)) - h1 = nhistogram(integer_axis(-1, 1, uoflow=True)) + h0 = histogram(integer_axis(-1, 1, uoflow=False)) + h1 = histogram(integer_axis(-1, 1, uoflow=True)) for h in (h0, h1): with self.assertRaises(StandardError): h.fill() @@ -363,7 +363,7 @@ class nhistogram_test(unittest.TestCase): self.assertEqual(h1[3], 1) def test_growth(self): - h = nhistogram(integer_axis(-1, 1)) + h = histogram(integer_axis(-1, 1)) h.fill(-1) h.fill(1) h.fill(1) @@ -382,7 +382,7 @@ class nhistogram_test(unittest.TestCase): def test_fill_2d(self): for uoflow in (False, True): - h = nhistogram(integer_axis(-1, 1, uoflow=uoflow), + h = histogram(integer_axis(-1, 1, uoflow=uoflow), regular_axis(4, -2, 2, uoflow=uoflow)) h.fill(-1, -2) h.fill(-1, -1) @@ -407,7 +407,7 @@ class nhistogram_test(unittest.TestCase): def test_add_2d(self): for uoflow in (False, True): - h = nhistogram(integer_axis(-1, 1, uoflow=uoflow), + h = histogram(integer_axis(-1, 1, uoflow=uoflow), regular_axis(4, -2, 2, uoflow=uoflow)) h.fill(-1, -2) h.fill(-1, -1) @@ -432,7 +432,7 @@ class nhistogram_test(unittest.TestCase): self.assertEqual(h[i, j], 2 * m[i][j]) def test_pickle(self): - a = nhistogram(category_axis('A', 'B', 'C'), + a = histogram(category_axis('A', 'B', 'C'), integer_axis(0, 3, label='ia'), regular_axis(4, 0.0, 4.0, uoflow=False), variable_axis(0.0, 1.0, 2.0)) @@ -460,7 +460,7 @@ class nhistogram_test(unittest.TestCase): @unittest.skipUnless("numpy" in globals(), "requires numpy") def test_numpy_conversion(self): - a = nhistogram(integer_axis(0, 2, uoflow=False)) + a = histogram(integer_axis(0, 2, uoflow=False)) for i in xrange(100): a.fill(1) b = numpy.array(a) # a copy @@ -481,19 +481,19 @@ class nhistogram_test(unittest.TestCase): @unittest.skipUnless("numpy" in globals(), "requires numpy") def test_fill_with_numpy_array(self): - a = nhistogram(integer_axis(0, 2, uoflow=False)) + a = histogram(integer_axis(0, 2, uoflow=False)) a.fill(numpy.array([-1, 0, 1, 2, 1, 4])) self.assertEqual(a[0], 1) self.assertEqual(a[1], 2) self.assertEqual(a[2], 1) - a = nhistogram(integer_axis(0, 1, uoflow=False), + a = histogram(integer_axis(0, 1, uoflow=False), regular_axis(2, 0, 2, uoflow=False)) a.fill(numpy.array([[-1., -1.], [0., 1.], [1., 0.1]])) self.assertEqual(a[0, 0], 0) self.assertEqual(a[0, 1], 1) self.assertEqual(a[1, 0], 1) self.assertEqual(a[1, 1], 0) - a = nhistogram(integer_axis(0, 2, uoflow=False)) + a = histogram(integer_axis(0, 2, uoflow=False)) a.fill([0, 0, 1, 2]) a.fill((1, 0, 2, 2)) self.assertEqual(a[0], 3) diff --git a/test/zero_suppression_test.cpp b/test/zero_suppression_test.cpp index acd4425d..7b415eb6 100644 --- a/test/zero_suppression_test.cpp +++ b/test/zero_suppression_test.cpp @@ -5,150 +5,278 @@ #include #include using namespace boost::assign; -using boost::histogram::detail::zero_suppression_encode; -using boost::histogram::detail::zero_suppression_decode; +using namespace boost::histogram::detail; namespace tt = boost::test_tools; +template void -print(const std::vector& v) { +print(const std::vector& v) { std::cerr << "["; for (unsigned i = 0; i < v.size(); ++i) { - std::cerr << unsigned(v[i]) << (i < v.size() - 1 ? ", " : "]"); + std::cerr << v[i] << (i < v.size() - 1 ? ", " : "]"); } std::cerr << "\n"; } -#define EQUAL_VECTORS(a, b) \ - BOOST_CHECK_EQUAL_COLLECTIONS(a.begin(), a.end(), b.begin(), b.end()) +#define EQUAL_VECTORS(a, b) BOOST_CHECK_EQUAL_COLLECTIONS(a.begin(), a.end(), b.begin(), b.end()) BOOST_AUTO_TEST_CASE( codec_no_zero ) { - std::vector a, b, c(3, 0); + std::vector a, b, c(3, 0); a += 1, 1, 1; - BOOST_CHECK(zero_suppression_encode(b, 3, &a[0], a.size())); + BOOST_CHECK(zero_suppression_encode(b, &a[0], a.size())); EQUAL_VECTORS(a, b); - zero_suppression_decode(&c[0], c.size(), b); + zero_suppression_decode(&c[0], c.size(), b); EQUAL_VECTORS(a, c); } -BOOST_AUTO_TEST_CASE( codec_fail ) -{ - std::vector a, b; - a += 1, 1, 1; - BOOST_CHECK(zero_suppression_encode(b, 2, &a[0], a.size()) == false); -} - BOOST_AUTO_TEST_CASE( codec_empty ) { - std::vector a, b, c; - BOOST_CHECK(zero_suppression_encode(b, 3, &a[0], a.size())); + std::vector a, b, c; + BOOST_CHECK(zero_suppression_encode(b, &a[0], a.size())); EQUAL_VECTORS(a, b); - zero_suppression_decode(&c[0], c.size(), b); + zero_suppression_decode(&c[0], c.size(), b); EQUAL_VECTORS(a, c); } -BOOST_AUTO_TEST_CASE( codec_zero_0 ) +BOOST_AUTO_TEST_CASE( codec_zero_0a ) { - std::vector a, b, c, d(2, 0); - a += 0, 1; - c += 0, 1, 1; - BOOST_CHECK(zero_suppression_encode(b, c.size(), &a[0], a.size())); + std::vector a, b; + a += 0; + BOOST_CHECK(zero_suppression_encode(b, &a[0], a.size()) == false); +} + +BOOST_AUTO_TEST_CASE( codec_zero_1a ) +{ + std::vector a, b, c, d(3, 0); + a += 1, 0, 0; + c += 1, 0, 2; + BOOST_CHECK(zero_suppression_encode(b, &a[0], a.size())); EQUAL_VECTORS(b, c); - zero_suppression_decode(&d[0], d.size(), b); + zero_suppression_decode(&d[0], d.size(), b); EQUAL_VECTORS(a, d); } -BOOST_AUTO_TEST_CASE( codec_zero_1 ) +BOOST_AUTO_TEST_CASE( codec_zero_2a ) { - std::vector a, b, c, d(3, 0); + std::vector a, b, c, d(3, 0); a += 0, 0, 1; c += 0, 2, 1; - BOOST_CHECK(zero_suppression_encode(b, c.size(), &a[0], a.size())); + BOOST_CHECK(zero_suppression_encode(b, &a[0], a.size())); EQUAL_VECTORS(b, c); - zero_suppression_decode(&d[0], d.size(), b); + zero_suppression_decode(&d[0], d.size(), b); EQUAL_VECTORS(a, d); } -BOOST_AUTO_TEST_CASE( codec_zero_2 ) +BOOST_AUTO_TEST_CASE( codec_zero_3a ) { - std::vector a, b, c, d(2, 0); + std::vector a, b, c, d(2, 0); a += 0, 0; c += 0, 2; - BOOST_CHECK(zero_suppression_encode(b, c.size(), &a[0], a.size())); + BOOST_CHECK(zero_suppression_encode(b, &a[0], a.size())); EQUAL_VECTORS(b, c); - zero_suppression_decode(&d[0], d.size(), b); + zero_suppression_decode(&d[0], d.size(), b); EQUAL_VECTORS(a, d); } -BOOST_AUTO_TEST_CASE( codec_zero_3 ) +BOOST_AUTO_TEST_CASE( codec_zero_0b ) { - std::vector a, b, c, d(1, 0); + std::vector a, b; a += 0; - c += 0, 1; - BOOST_CHECK(zero_suppression_encode(b, c.size(), &a[0], a.size())); + BOOST_CHECK(zero_suppression_encode(b, &a[0], a.size()) == false); +} + +BOOST_AUTO_TEST_CASE( codec_zero_1b ) +{ + std::vector a, b, c, d(3, 0); + a += 1, 0, 0; + c += 1, 0, 2; + BOOST_CHECK(zero_suppression_encode(b, &a[0], a.size())); EQUAL_VECTORS(b, c); - zero_suppression_decode(&d[0], d.size(), b); + zero_suppression_decode(&d[0], d.size(), b); + EQUAL_VECTORS(a, d); +} + +BOOST_AUTO_TEST_CASE( codec_zero_2b ) +{ + std::vector a, b, c, d(3, 0); + a += 0, 0, 1; + c += 0, 2, 1; + BOOST_CHECK(zero_suppression_encode(b, &a[0], a.size())); + EQUAL_VECTORS(b, c); + zero_suppression_decode(&d[0], d.size(), b); + EQUAL_VECTORS(a, d); +} + +BOOST_AUTO_TEST_CASE( codec_zero_3b ) +{ + std::vector a, b, c, d(2, 0); + a += 0, 0; + c += 0, 2; + BOOST_CHECK(zero_suppression_encode(b, &a[0], a.size())); + EQUAL_VECTORS(b, c); + zero_suppression_decode(&d[0], d.size(), b); + EQUAL_VECTORS(a, d); +} + +BOOST_AUTO_TEST_CASE( codec_zero_0c ) +{ + std::vector a, b; + a += 0; + BOOST_CHECK(zero_suppression_encode(b, &a[0], a.size()) == false); +} + +BOOST_AUTO_TEST_CASE( codec_zero_1c ) +{ + std::vector a, b, c, d(3, 0); + a += 1, 0, 0; + c += 1, 0, 2; + BOOST_CHECK(zero_suppression_encode(b, &a[0], a.size())); + EQUAL_VECTORS(b, c); + zero_suppression_decode(&d[0], d.size(), b); + EQUAL_VECTORS(a, d); +} + +BOOST_AUTO_TEST_CASE( codec_zero_2c ) +{ + std::vector a, b, c, d(3, 0); + a += 0, 0, 1; + c += 0, 2, 1; + BOOST_CHECK(zero_suppression_encode(b, &a[0], a.size())); + EQUAL_VECTORS(b, c); + zero_suppression_decode(&d[0], d.size(), b); + EQUAL_VECTORS(a, d); +} + +BOOST_AUTO_TEST_CASE( codec_zero_3c ) +{ + std::vector a, b, c, d(2, 0); + a += 0, 0; + c += 0, 2; + BOOST_CHECK(zero_suppression_encode(b, &a[0], a.size())); + EQUAL_VECTORS(b, c); + zero_suppression_decode(&d[0], d.size(), b); + EQUAL_VECTORS(a, d); +} + +BOOST_AUTO_TEST_CASE( codec_zero_0d ) +{ + std::vector a, b; + a += 0; + BOOST_CHECK(zero_suppression_encode(b, &a[0], a.size()) == false); +} + +BOOST_AUTO_TEST_CASE( codec_zero_1d ) +{ + std::vector a, b, c, d(3, 0); + a += 1, 0, 0; + c += 1, 0, 2; + BOOST_CHECK(zero_suppression_encode(b, &a[0], a.size())); + EQUAL_VECTORS(b, c); + zero_suppression_decode(&d[0], d.size(), b); + EQUAL_VECTORS(a, d); +} + +BOOST_AUTO_TEST_CASE( codec_zero_2d ) +{ + std::vector a, b, c, d(3, 0); + a += 0, 0, 1; + c += 0, 2, 1; + BOOST_CHECK(zero_suppression_encode(b, &a[0], a.size())); + EQUAL_VECTORS(b, c); + zero_suppression_decode(&d[0], d.size(), b); + EQUAL_VECTORS(a, d); +} + +BOOST_AUTO_TEST_CASE( codec_zero_3d ) +{ + std::vector a, b, c, d(2, 0); + a += 0, 0; + c += 0, 2; + BOOST_CHECK(zero_suppression_encode(b, &a[0], a.size())); + EQUAL_VECTORS(b, c); + zero_suppression_decode(&d[0], d.size(), b); EQUAL_VECTORS(a, d); } BOOST_AUTO_TEST_CASE( codec_zero_4 ) { - std::vector a, b, c, d(3, 0); - a += 0, 1, 0; - c += 0, 1, 1, 0, 1; - BOOST_CHECK(zero_suppression_encode(b, c.size(), &a[0], a.size())); + std::vector a, b, c, d(5, 0); + a += 0, 0, 0, 1, 0; + c += 0, 3, 1, 0, 1; + BOOST_CHECK(zero_suppression_encode(b, &a[0], a.size())); EQUAL_VECTORS(b, c); - zero_suppression_decode(&d[0], d.size(), b); + zero_suppression_decode(&d[0], d.size(), b); EQUAL_VECTORS(a, d); } BOOST_AUTO_TEST_CASE( codec_zero_5 ) { - std::vector a, b, c, d(4, 0); - a += 0, 1, 0, 0; - c += 0, 1, 1, 0, 2; - BOOST_CHECK(zero_suppression_encode(b, c.size(), &a[0], a.size())); + std::vector a, b, c, d(5, 0); + a += 0, 1, 0, 0, 0; + c += 0, 1, 1, 0, 3; + BOOST_CHECK(zero_suppression_encode(b, &a[0], a.size())); EQUAL_VECTORS(b, c); - zero_suppression_decode(&d[0], d.size(), b); + zero_suppression_decode(&d[0], d.size(), b); EQUAL_VECTORS(a, d); } BOOST_AUTO_TEST_CASE( codec_zero_6 ) { - std::vector a(255, 0), b, c, d(255, 0); + std::vector a(255, 0), b, c, d(255, 0); c += 0, 255; - BOOST_CHECK(zero_suppression_encode(b, c.size(), &a[0], a.size())); + BOOST_CHECK(zero_suppression_encode(b, &a[0], a.size())); EQUAL_VECTORS(b, c); - zero_suppression_decode(&d[0], d.size(), b); + zero_suppression_decode(&d[0], d.size(), b); EQUAL_VECTORS(a, d); } BOOST_AUTO_TEST_CASE( codec_zero_7 ) { - std::vector a(256, 0), b, c, d(256, 0); + std::vector a(256, 0), b, c, d(256, 0); c += 0, 0; - BOOST_CHECK(zero_suppression_encode(b, c.size(), &a[0], a.size())); + BOOST_CHECK(zero_suppression_encode(b, &a[0], a.size())); EQUAL_VECTORS(b, c); - zero_suppression_decode(&d[0], d.size(), b); + zero_suppression_decode(&d[0], d.size(), b); EQUAL_VECTORS(a, d); } BOOST_AUTO_TEST_CASE( codec_zero_8 ) { - std::vector a(257, 0), b, c, d(257, 0); + std::vector a(257, 0), b, c, d(257, 0); c += 0, 0, 0, 1; - BOOST_CHECK(zero_suppression_encode(b, c.size(), &a[0], a.size())); + BOOST_CHECK(zero_suppression_encode(b, &a[0], a.size())); EQUAL_VECTORS(b, c); - zero_suppression_decode(&d[0], d.size(), b); + zero_suppression_decode(&d[0], d.size(), b); EQUAL_VECTORS(a, d); } BOOST_AUTO_TEST_CASE( codec_zero_9 ) { - std::vector a(1000, 0), b, c, d(1000, 0); + std::vector a(1000, 0), b, c, d(1000, 0); c += 0, 0, 0, 0, 0, 0, 0, 232; - BOOST_CHECK(zero_suppression_encode(b, c.size(), &a[0], a.size())); + BOOST_CHECK(zero_suppression_encode(b, &a[0], a.size())); EQUAL_VECTORS(b, c); - zero_suppression_decode(&d[0], d.size(), b); + zero_suppression_decode(&d[0], d.size(), b); + EQUAL_VECTORS(a, d); +} + +BOOST_AUTO_TEST_CASE( codec_zero_10 ) +{ + std::vector a(1000, 0), b, c, d(1000, 0); + c += 0, 1000; + BOOST_CHECK(zero_suppression_encode(b, &a[0], a.size())); + EQUAL_VECTORS(b, c); + zero_suppression_decode(&d[0], d.size(), b); + EQUAL_VECTORS(a, d); +} + +BOOST_AUTO_TEST_CASE( codec_zero_11 ) +{ + std::vector a(65536, 0), b, c, d(65536, 0); + c += 0, 0; + BOOST_CHECK(zero_suppression_encode(b, &a[0], a.size())); + EQUAL_VECTORS(b, c); + zero_suppression_decode(&d[0], d.size(), b); EQUAL_VECTORS(a, d); }