getting rid of buffer.hpp again, better operator+= for dynamic_storage, no move from static_storage

This commit is contained in:
Hans Dembinski 2017-01-24 00:43:03 +01:00
parent 65a32b3630
commit 5f23c006a4
7 changed files with 428 additions and 475 deletions

View File

@ -1,250 +0,0 @@
// Copyright 2015-2016 Hans Dembinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef _BOOST_HISTOGRAM_DETAIL_BUFFER_HPP_
#define _BOOST_HISTOGRAM_DETAIL_BUFFER_HPP_
#include <cstdlib>
#include <algorithm>
#include <new> // for bad_alloc exception
#include <boost/mpl/map.hpp>
#include <boost/mpl/pair.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/at.hpp>
#include <boost/histogram/detail/weight.hpp>
namespace boost {
namespace histogram {
namespace detail {
using type_to_int = mpl::map<
mpl::pair<int8_t, mpl::int_<1>>,
mpl::pair<int16_t, mpl::int_<2>>,
mpl::pair<int32_t, mpl::int_<3>>,
mpl::pair<int64_t, mpl::int_<4>>,
mpl::pair<uint8_t, mpl::int_<1>>,
mpl::pair<uint16_t, mpl::int_<2>>,
mpl::pair<uint32_t, mpl::int_<3>>,
mpl::pair<uint64_t, mpl::int_<4>>,
mpl::pair<weight_t, mpl::int_<6>>
>;
using int_to_type = mpl::map<
mpl::pair<mpl::int_<1>, uint8_t>,
mpl::pair<mpl::int_<2>, uint16_t>,
mpl::pair<mpl::int_<3>, uint32_t>,
mpl::pair<mpl::int_<4>, uint64_t>,
mpl::pair<mpl::int_<6>, weight_t>
>;
template <typename T>
using next_storage_type =
typename mpl::at<int_to_type,
typename mpl::next<
typename mpl::at<type_to_int, T>::type
>::type
>::type;
class buffer {
public:
explicit
buffer(std::size_t s = 0) :
type_(),
size_(s),
ptr_(nullptr)
{}
buffer(const buffer& o) :
type_(o.type_), size_(o.size_), ptr_(nullptr)
{
realloc(depth());
std::copy(static_cast<const char*>(o.ptr_),
static_cast<const char*>(o.ptr_) + size() * depth(),
static_cast<char*>(ptr_));
}
buffer& operator=(const buffer& o)
{
if (this != &o) {
if (size_ != o.size_ || type_ != o.type_) {
size_ = o.size_;
type_ = o.type_;
realloc(depth());
}
std::copy(static_cast<const char*>(o.ptr_),
static_cast<const char*>(o.ptr_) + size() * depth(),
static_cast<char*>(ptr_));
}
return *this;
}
buffer(buffer&& o) :
type_(o.type_),
size_(o.size_),
ptr_(o.ptr_)
{
o.size_ = 0;
o.type_ = type();
o.ptr_ = nullptr;
}
buffer& operator=(buffer&& o)
{
if (this != &o) {
std::free(ptr_);
type_ = o.type_;
size_ = o.size_;
ptr_ = o.ptr_;
o.type_ = type();
o.size_ = 0;
o.ptr_ = nullptr;
}
return *this;
}
template <typename T, template<typename> class Storage>
buffer(const Storage<T>& o) :
size_(o.size()),
ptr_(nullptr)
{
using U = typename mpl::at<
int_to_type,
typename mpl::at<type_to_int, T>::type
>::type;
realloc(sizeof(U));
std::copy(o.data_, o.data_ + size_, &at<U>(0));
type_.set<U>();
}
template <typename T, template<typename> class Storage>
buffer& operator=(const Storage<T>& o) {
size_ = o.size();
using U = typename mpl::at<
int_to_type,
typename mpl::at<type_to_int, T>::type
>::type;
realloc(sizeof(U));
std::copy(o.data_, o.data_ + size_, &at<T>(0));
type_.set<U>();
return *this;
}
template <typename T, template<typename> class Storage>
buffer(Storage<T>&& o) :
size_(o.size_),
ptr_(const_cast<void*>(o.data_))
{
using U = typename mpl::at<
int_to_type,
typename mpl::at<type_to_int, T>::type
>::type;
type_.set<U>();
o.size_ = 0;
o.data_ = nullptr;
}
template <typename T, template<typename> class Storage>
buffer& operator=(Storage<T>&& o)
{
using U = typename mpl::at<
int_to_type,
typename mpl::at<type_to_int, T>::type
>::type;
std::free(ptr_);
size_ = o.size_;
ptr_ = static_cast<void*>(o.data_);
type_.set<U>();
o.size_ = 0;
o.data_ = nullptr;
return *this;
}
~buffer() { std::free(ptr_); }
std::size_t size() const { return size_; }
unsigned id() const { return type_.id_; }
unsigned depth() const { return type_.depth_; }
const void* data() const { return ptr_; }
bool operator==(const buffer& o) const {
return size_ == o.size_ &&
type_.id_ == o.type_.id_ &&
std::equal(static_cast<char*>(ptr_),
static_cast<char*>(ptr_) + size_ * depth(),
static_cast<char*>(o.ptr_));
}
template <typename T,
typename U = next_storage_type<T>>
void grow() {
static_assert(sizeof(U) >= sizeof(T), "U must be as large or larger than T");
realloc(sizeof(U));
std::copy_backward(&at<T>(0), &at<T>(size_), &at<U>(size_));
type_.set<U>();
}
void wconvert()
{
switch (type_.id_) {
case 0: initialize<weight_t>(); break;
case 1: grow<uint8_t, weight_t> (); break;
case 2: grow<uint16_t, weight_t>(); break;
case 3: grow<uint32_t, weight_t>(); break;
case 4: grow<uint64_t, weight_t>(); break;
case 6: /* do nothing */ break;
}
}
template <typename T>
void initialize() {
type_.set<T>();
ptr_ = nullptr;
realloc(sizeof(T));
std::fill(&at<T>(0), &at<T>(size_), T(0));
}
void realloc(unsigned d)
{
ptr_ = std::realloc(ptr_, size_ * d);
if (!ptr_ && (size_ * d > 0))
throw std::bad_alloc();
}
template <typename T>
T& at(std::size_t i) { return static_cast<T*>(ptr_)[i]; }
template <typename T>
const T& at(std::size_t i) const { return static_cast<const T*>(ptr_)[i]; }
private:
struct type {
char id_, depth_;
type() : id_(0), depth_(0) {}
type(const type&) = default;
type& operator=(const type&) = default;
template <typename T>
void set() {
id_ = mpl::at<type_to_int, T>::type::value;
depth_ = sizeof(T);
}
bool operator==(const type& o) const { return id_ == o.id_; }
bool operator!=(const type& o) const { return id_ != o.id_; }
};
type type_;
std::size_t size_;
void* ptr_;
template <class Archive>
friend void serialize(Archive&, buffer&, unsigned);
};
}
}
}
#endif

View File

@ -7,30 +7,35 @@
#ifndef _BOOST_HISTOGRAM_DETAIL_WEIGHT_HPP_
#define _BOOST_HISTOGRAM_DETAIL_WEIGHT_HPP_
#include <boost/operators.hpp>
namespace boost {
namespace histogram {
namespace detail {
/// Used by nstore to hold a sum of weighted counts and a variance estimate
struct weight_t {
struct weight_t
: boost::operators<weight_t>
{
double w, w2;
weight_t() = default;
weight_t(const weight_t&) = default;
weight_t(weight_t&&) = default;
weight_t& operator=(const weight_t&) = default;
weight_t& operator=(weight_t&&) = default;
weight_t& operator+=(const weight_t& o)
{ w += o.w; w2 += o.w2; return *this; }
weight_t& operator++()
{ ++w; ++w2; return *this; }
bool operator==(const weight_t& o) const
{ return w == o.w && w2 == o.w2; }
bool operator!=(const weight_t& o) const
{ return !operator==(o); }
weight_t& add_weight(double v)
{ w += v; w2 += v*v; return *this; }
explicit weight_t(int v) : w(v), w2(v) {}
template <typename T>
explicit weight_t(const T& t) : w(static_cast<double>(t)), w2(w) {}
template <typename T>
weight_t& operator=(T v)

View File

@ -8,11 +8,17 @@
#define _BOOST_HISTOGRAM_DYNAMIC_STORAGE_HPP_
#include <boost/histogram/detail/weight.hpp>
#include <boost/histogram/detail/buffer.hpp>
#include <boost/histogram/detail/mpl.hpp>
#include <boost/assert.hpp>
#include <boost/mpl/map.hpp>
#include <boost/mpl/pair.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/at.hpp>
#include <boost/cstdint.hpp>
#include <cstdint>
#include <cstddef>
#include <cstdlib> // malloc/free
#include <new> // for bad_alloc exception
#include <type_traits>
#include <algorithm>
#include <limits>
@ -20,56 +26,253 @@
namespace boost {
namespace histogram {
namespace {
namespace detail {
static_assert(std::is_pod<detail::weight_t>::value, "weight_t must be POD");
static_assert(std::is_pod<weight_t>::value, "weight_t must be POD");
using type_to_int = mpl::map<
mpl::pair<weight_t, mpl::int_<-1>>,
mpl::pair<int8_t, mpl::int_<1>>,
mpl::pair<int16_t, mpl::int_<2>>,
mpl::pair<int32_t, mpl::int_<3>>,
mpl::pair<int64_t, mpl::int_<4>>,
mpl::pair<uint8_t, mpl::int_<1>>,
mpl::pair<uint16_t, mpl::int_<2>>,
mpl::pair<uint32_t, mpl::int_<3>>,
mpl::pair<uint64_t, mpl::int_<4>>
>;
using int_to_type = mpl::map<
mpl::pair<mpl::int_<-1>, weight_t>,
mpl::pair<mpl::int_<1>, uint8_t>,
mpl::pair<mpl::int_<2>, uint16_t>,
mpl::pair<mpl::int_<3>, uint32_t>,
mpl::pair<mpl::int_<4>, uint64_t>
>;
template <typename T>
void increase_impl(detail::buffer& buf, std::size_t i) {
auto& b = buf.at<T>(i);
if (b < std::numeric_limits<T>::max())
++b;
using storage_type =
typename mpl::at<
detail::int_to_type,
typename mpl::at<
detail::type_to_int, T
>::type
>::type;
template <typename T>
using next_storage_type =
typename mpl::at<int_to_type,
typename mpl::next<
typename mpl::at<type_to_int, T>::type
>::type
>::type;
struct buffer
{
explicit buffer(std::size_t s = 0) :
size_(s),
ptr_(nullptr)
{}
buffer(const buffer& o) :
type_(o.type_), size_(o.size_), ptr_(nullptr)
{
realloc(type_.depth_);
std::copy(static_cast<const char*>(o.ptr_),
static_cast<const char*>(o.ptr_) + size_ * type_.depth_,
static_cast<char*>(ptr_));
}
buffer& operator=(const buffer& o)
{
if (this != &o) {
if (size_ != o.size_ || type_.id_ != o.type_.id_) {
size_ = o.size_;
type_ = o.type_;
realloc(type_.depth_);
}
std::copy(static_cast<const char*>(o.ptr_),
static_cast<const char*>(o.ptr_) + size_ * type_.depth_,
static_cast<char*>(ptr_));
}
return *this;
}
buffer(buffer&& o) :
type_(o.type_),
size_(o.size_),
ptr_(o.ptr_)
{
o.size_ = 0;
o.type_ = type();
o.ptr_ = nullptr;
}
buffer& operator=(buffer&& o)
{
if (this != &o) {
destroy_any();
type_ = o.type_;
size_ = o.size_;
ptr_ = o.ptr_;
o.type_ = type();
o.size_ = 0;
o.ptr_ = nullptr;
}
return *this;
}
~buffer() { destroy_any(); }
template <typename T>
void create() {
type_.set<T>();
ptr_ = std::malloc(size_ * sizeof(T));
new (ptr_) T[size_];
}
template <typename T>
void destroy() {
std::free(ptr_);
ptr_ = nullptr;
}
void destroy_any() {
switch (type_.id_) {
case -1: destroy<weight_t>(); break;
case 0: /* do nothing */ break;
case 1: destroy<uint8_t>(); break;
case 2: destroy<uint16_t>(); break;
case 3: destroy<uint32_t>(); break;
case 4: destroy<uint64_t>(); break;
}
}
template <typename T,
typename U = next_storage_type<T>>
void grow() {
static_assert(sizeof(U) >= sizeof(T), "U must be as large or larger than T");
realloc(sizeof(U));
std::copy_backward(&at<T>(0), &at<T>(size_), &at<U>(size_));
type_.set<U>();
}
void wconvert()
{
switch (type_.id_) {
case -1: /* do nothing */ break;
case 0: initialize<weight_t>(); break;
case 1: grow<uint8_t, weight_t> (); break;
case 2: grow<uint16_t, weight_t>(); break;
case 3: grow<uint32_t, weight_t>(); break;
case 4: grow<uint64_t, weight_t>(); break;
}
}
template <typename T>
void initialize() {
type_.set<T>();
ptr_ = nullptr;
realloc(sizeof(T));
std::fill(&at<T>(0), &at<T>(size_), T(0));
}
void realloc(unsigned d)
{
ptr_ = std::realloc(ptr_, size_ * d);
if (!ptr_ && (size_ * d > 0))
throw std::bad_alloc();
}
template <typename T>
T& at(std::size_t i) { return static_cast<T*>(ptr_)[i]; }
template <typename T>
const T& at(std::size_t i) const { return static_cast<const T*>(ptr_)[i]; }
struct type {
char id_ = 0, depth_ = 0;
template <typename T>
void set() {
id_ = mpl::at<type_to_int, T>::type::value;
depth_ = sizeof(T);
}
} type_;
std::size_t size_;
void* ptr_;
};
template <typename T>
void increase_impl(buffer& b, std::size_t i) {
auto& bi = b.at<T>(i);
if (bi < std::numeric_limits<T>::max())
++bi;
else {
buf.grow<T>();
b.grow<T>();
using U = detail::next_storage_type<T>;
auto& b = buf.at<U>(i);
++b;
++b.at<U>(i);
}
}
template <>
void increase_impl<uint64_t>(detail::buffer& buf, std::size_t i) {
auto& b = buf.at<uint64_t>(i);
if (b < std::numeric_limits<uint64_t>::max())
++b;
void increase_impl<uint64_t>(buffer& b, std::size_t i) {
auto& bi = b.at<uint64_t>(i);
if (bi < std::numeric_limits<uint64_t>::max())
++bi;
else
throw std::overflow_error("histogram overflow");
}
template <typename T>
void add_impl(detail::buffer& buf, std::size_t i, uint64_t o) {
auto& b = buf.at<T>(i);
if (static_cast<T>(std::numeric_limits<T>::max() - b) >= o)
b += o;
else {
buf.grow<T>();
add_impl<detail::next_storage_type<T>>(buf, i, o);
template <typename T, typename TO>
struct add_one_impl {
static void apply(buffer& b, std::size_t i, const TO& o) {
auto& bi = b.at<T>(i);
if (static_cast<T>(std::numeric_limits<T>::max() - bi) >= o)
bi += o;
else {
b.grow<T>();
add_one_impl<detail::next_storage_type<T>, TO>::apply(b, i, o);
}
}
};
template <typename TO>
struct add_one_impl<uint64_t, TO> {
static void apply(buffer& b, std::size_t i, const TO& o) {
auto& bi = b.at<uint64_t>(i);
if (static_cast<uint64_t>(std::numeric_limits<uint64_t>::max() - bi) >= o)
bi += o;
else
throw std::overflow_error("histogram overflow");
}
};
template <typename TO>
void add_impl(buffer& b, const buffer& o) {
for (decltype(b.size_) i = 0; i < b.size_; ++i)
switch (b.type_.id_) {
case -1: b.at<weight_t>(i) += o.at<TO>(i); break;
case 0: b.initialize<uint8_t>(); // fall through
case 1: add_one_impl<uint8_t, TO>::apply(b, i, o.at<TO>(i)); break;
case 2: add_one_impl<uint16_t, TO>::apply(b, i, o.at<TO>(i)); break;
case 3: add_one_impl<uint32_t, TO>::apply(b, i, o.at<TO>(i)); break;
case 4: add_one_impl<uint64_t, TO>::apply(b, i, o.at<TO>(i)); break;
}
}
template <>
void add_impl<uint64_t>(detail::buffer& buf, std::size_t i, uint64_t o) {
auto& b = buf.at<uint64_t>(i);
if (static_cast<uint64_t>(std::numeric_limits<uint64_t>::max() - b) >= o)
b += o;
else
throw std::overflow_error("histogram overflow");
void add_impl<weight_t>(buffer& b, const buffer& o) {
b.wconvert();
for (decltype(b.size_) i = 0; i < b.size_; ++i)
b.at<weight_t>(i) += o.at<weight_t>(i);
}
}
class dynamic_storage {
using weight_t = detail::weight_t;
} // NS detail
class dynamic_storage
{
public:
using value_t = double;
using variance_t = double;
@ -81,45 +284,37 @@ public:
dynamic_storage() = default;
dynamic_storage(const dynamic_storage&) = default;
dynamic_storage(dynamic_storage&&) = default;
dynamic_storage& operator=(const dynamic_storage&) = default;
dynamic_storage(dynamic_storage&&) = default;
dynamic_storage& operator=(dynamic_storage&&) = default;
template <typename T,
template <typename> class Storage,
typename = detail::is_standard_integral<T>>
dynamic_storage(const Storage<T>& o) :
buffer_(o)
{}
buffer_(o.size())
{
using U = detail::storage_type<T>;
buffer_.create<U>();
std::copy(o.data(), o.data() + buffer_.size_, &buffer_.at<U>(0));
}
template <typename T,
template <typename> class Storage,
typename = detail::is_standard_integral<T>>
dynamic_storage& operator=(const Storage<T>& o)
{
buffer_ = o;
buffer_.destroy_any();
buffer_.size_ = o.size();
using U = detail::storage_type<T>;
buffer_.create<U>();
std::copy(o.data(), o.data() + buffer_.size_, &buffer_.at<U>(0));
return *this;
}
template <typename T,
template <typename> class Storage,
typename = detail::is_standard_integral<T>>
dynamic_storage(Storage<T>&& o) :
buffer_(std::move(o))
{}
template <typename T,
template <typename> class Storage,
typename = detail::is_standard_integral<T>>
dynamic_storage& operator=(Storage<T>&& o)
{
buffer_ = std::move(o);
return *this;
}
std::size_t size() const { return buffer_.size(); }
unsigned depth() const { return buffer_.depth(); }
const void* data() const { return buffer_.data(); }
std::size_t size() const { return buffer_.size_; }
unsigned depth() const { return buffer_.type_.depth_; }
const void* data() const { return buffer_.ptr_; }
void increase(std::size_t i);
void increase(std::size_t i, double w);
value_t value(std::size_t i) const;
@ -136,13 +331,13 @@ private:
inline
void dynamic_storage::increase(std::size_t i)
{
switch (buffer_.id()) {
switch (buffer_.type_.id_) {
case -1: ++(buffer_.at<detail::weight_t>(i)); break;
case 0: buffer_.initialize<uint8_t>(); // and fall through
case 1: increase_impl<uint8_t> (buffer_, i); break;
case 2: increase_impl<uint16_t>(buffer_, i); break;
case 3: increase_impl<uint32_t>(buffer_, i); break;
case 4: increase_impl<uint64_t>(buffer_, i); break;
case 6: ++(buffer_.at<weight_t>(i)); break;
case 1: detail::increase_impl<uint8_t> (buffer_, i); break;
case 2: detail::increase_impl<uint16_t>(buffer_, i); break;
case 3: detail::increase_impl<uint32_t>(buffer_, i); break;
case 4: detail::increase_impl<uint64_t>(buffer_, i); break;
}
}
@ -150,39 +345,19 @@ inline
void dynamic_storage::increase(std::size_t i, double w)
{
buffer_.wconvert();
buffer_.at<weight_t>(i).add_weight(w);
buffer_.at<detail::weight_t>(i).add_weight(w);
}
inline
dynamic_storage& dynamic_storage::operator+=(const dynamic_storage& o)
{
if (o.depth()) {
if (o.buffer_.id() == 6) {
buffer_.wconvert();
for (std::size_t i = 0; i < size(); ++i)
buffer_.at<weight_t>(i) += o.buffer_.at<weight_t>(i);
}
else {
auto i = size();
while (i--) {
uint64_t n = 0;
switch (o.buffer_.id()) {
/* case 0 is already excluded by the initial if statement */
case 1: n = o.buffer_.at<uint8_t> (i); break;
case 2: n = o.buffer_.at<uint16_t>(i); break;
case 3: n = o.buffer_.at<uint32_t>(i); break;
case 4: n = o.buffer_.at<uint64_t>(i); break;
}
switch (buffer_.id()) {
case 0: buffer_.initialize<uint8_t>(); // and fall through
case 1: add_impl<uint8_t> (buffer_, i, n); break;
case 2: add_impl<uint16_t>(buffer_, i, n); break;
case 3: add_impl<uint32_t>(buffer_, i, n); break;
case 4: add_impl<uint64_t>(buffer_, i, n); break;
case 6: buffer_.at<weight_t>(i) += n; break;
}
}
}
switch (o.buffer_.type_.id_) {
case -1: detail::add_impl<detail::weight_t>(buffer_, o.buffer_); break;
case 0: /* do nothing */ break;
case 1: detail::add_impl<uint8_t>(buffer_, o.buffer_); break;
case 2: detail::add_impl<uint16_t>(buffer_, o.buffer_); break;
case 3: detail::add_impl<uint32_t>(buffer_, o.buffer_); break;
case 4: detail::add_impl<uint64_t>(buffer_, o.buffer_); break;
}
return *this;
}
@ -190,13 +365,13 @@ dynamic_storage& dynamic_storage::operator+=(const dynamic_storage& o)
inline
dynamic_storage::value_t dynamic_storage::value(std::size_t i) const
{
switch (buffer_.id()) {
case 0: break;
switch (buffer_.type_.id_) {
case -1: return buffer_.at<detail::weight_t>(i).w;
case 0: /* do nothing */ break;
case 1: return buffer_.at<uint8_t> (i);
case 2: return buffer_.at<uint16_t>(i);
case 3: return buffer_.at<uint32_t>(i);
case 4: return buffer_.at<uint64_t>(i);
case 6: return buffer_.at<weight_t>(i).w;
}
return 0.0;
}
@ -204,13 +379,13 @@ dynamic_storage::value_t dynamic_storage::value(std::size_t i) const
inline
dynamic_storage::variance_t dynamic_storage::variance(std::size_t i) const
{
switch (buffer_.id()) {
case 0: break;
switch (buffer_.type_.id_) {
case -1: return buffer_.at<detail::weight_t>(i).w2;
case 0: /* do nothing */ break;
case 1: return buffer_.at<uint8_t> (i);
case 2: return buffer_.at<uint16_t>(i);
case 3: return buffer_.at<uint32_t>(i);
case 4: return buffer_.at<uint64_t>(i);
case 6: return buffer_.at<weight_t>(i).w2;
}
return 0.0;
}

View File

@ -13,7 +13,6 @@
#include <boost/histogram/dynamic_storage.hpp>
#include <boost/histogram/detail/utility.hpp>
#include <boost/histogram/detail/weight.hpp>
#include <boost/histogram/detail/buffer.hpp>
#include <boost/histogram/detail/tiny_string.hpp>
#include <boost/serialization/variant.hpp>
#include <boost/serialization/vector.hpp>
@ -38,32 +37,6 @@ inline void serialize(Archive& ar, weight_t& wt, unsigned version)
ar & wt.w2;
}
template<class Archive>
inline void serialize(Archive& ar, buffer& buf, unsigned version)
{
ar & buf.size_;
ar & buf.type_.id_;
ar & buf.type_.depth_;
if (Archive::is_loading::value) {
buf.realloc(buf.depth());
// switch (buf.type_) {
// case 1: buf.create<uint8_t>(); break;
// case 2: buf.create<uint16_t>(); break;
// case 3: buf.create<uint32_t>(); break;
// case 4: buf.create<uint64_t>(); break;
// case 6: buf.create<weight_t>(); break;
// }
}
switch (buf.type_.id_) {
case 0: buf.ptr_ = nullptr; break;
case 1: ar & serialization::make_array(&buf.at<uint8_t>(0), buf.size_); break;
case 2: ar & serialization::make_array(&buf.at<uint16_t>(0), buf.size_); break;
case 3: ar & serialization::make_array(&buf.at<uint32_t>(0), buf.size_); break;
case 4: ar & serialization::make_array(&buf.at<uint64_t>(0), buf.size_); break;
case 6: ar & serialization::make_array(&buf.at<weight_t>(0), buf.size_); break;
}
}
template <class Archive>
inline void serialize(Archive& ar, tiny_string& s, unsigned version)
{
@ -91,7 +64,30 @@ inline void serialize(Archive& ar, static_storage<T> & store, unsigned version)
template <class Archive>
inline void serialize(Archive& ar, dynamic_storage & store, unsigned version)
{
ar & store.buffer_;
auto& b = store.buffer_;
if (Archive::is_loading::value)
b.destroy_any();
ar & b.size_;
ar & b.type_.id_;
ar & b.type_.depth_;
if (Archive::is_loading::value) {
switch (b.type_.id_) {
case -1: b.create<detail::weight_t>(); break;
case 0: b.ptr_ = nullptr; break;
case 1: b.create<uint8_t>(); break;
case 2: b.create<uint16_t>(); break;
case 3: b.create<uint32_t>(); break;
case 4: b.create<uint64_t>(); break;
}
}
switch (b.type_.id_) {
case -1: ar & serialization::make_array(&b.at<detail::weight_t>(0), b.size_); break;
case 0: /* nothing to do */ break;
case 1: ar & serialization::make_array(&b.at<uint8_t>(0), b.size_); break;
case 2: ar & serialization::make_array(&b.at<uint16_t>(0), b.size_); break;
case 3: ar & serialization::make_array(&b.at<uint32_t>(0), b.size_); break;
case 4: ar & serialization::make_array(&b.at<uint64_t>(0), b.size_); break;
}
}
template <class Archive>

View File

@ -12,8 +12,6 @@
namespace boost {
namespace histogram {
namespace detail { class buffer; }
template <typename T>
class static_storage {
public:
@ -104,7 +102,7 @@ namespace histogram {
std::size_t size() const { return size_; }
constexpr unsigned depth() const { return sizeof(T); }
const void* data() const { return static_cast<const void*>(data_); }
const T* data() const { return data_; }
void increase(std::size_t i) { ++(data_[i]); }
value_t value(std::size_t i) const { return data_[i]; }
variance_t variance(std::size_t i) const { return data_[i]; }
@ -128,8 +126,6 @@ namespace histogram {
data_ = new T[size_];
}
friend detail::buffer;
template <typename Archive, typename U>
friend void serialize(Archive&, static_storage<U>&, unsigned);
};

View File

@ -8,11 +8,40 @@
#include <boost/test/unit_test.hpp>
#include <boost/test/test_tools.hpp>
#include <boost/histogram/detail/utility.hpp>
#include <boost/histogram/detail/buffer.hpp>
#include <boost/histogram/detail/weight.hpp>
#include <boost/histogram/detail/tiny_string.hpp>
#include <sstream>
#include <algorithm>
using namespace boost::histogram::detail;
// bool operator==(const buffer& a, const buffer& b)
// {
// if (!(a.size() == b.size() &&
// a.id() == b.id() &&
// a.depth() == b.depth()))
// return false;
// switch (a.id()) {
// case -1: return std::equal(&a.at<weight_t>(0),
// &a.at<weight_t>(a.size()),
// &b.at<weight_t>(0));
// case 0: return true;
// case 1: return std::equal(&a.at<uint8_t>(0),
// &a.at<uint8_t>(a.size()),
// &b.at<uint8_t>(0));
// case 2: return std::equal(&a.at<uint16_t>(0),
// &a.at<uint16_t>(a.size()),
// &b.at<uint16_t>(0));
// case 3: return std::equal(&a.at<uint32_t>(0),
// &a.at<uint32_t>(a.size()),
// &b.at<uint32_t>(0));
// case 4: return std::equal(&a.at<uint64_t>(0),
// &a.at<uint64_t>(a.size()),
// &b.at<uint64_t>(0));
// }
// BOOST_ASSERT(!"never reach this");
// return false;
// }
BOOST_AUTO_TEST_CASE(escape_0)
{
std::ostringstream os;
@ -34,99 +63,99 @@ BOOST_AUTO_TEST_CASE(escape_2)
BOOST_CHECK_EQUAL(os.str(), std::string("'\\\'abc\\\''"));
}
BOOST_AUTO_TEST_CASE(buffer_ctor_and_get)
{
auto a = buffer(3);
a.initialize<uint8_t>();
BOOST_CHECK_EQUAL(a.size(), 3);
BOOST_CHECK_EQUAL(a.depth(), 1);
a.at<uint8_t>(0) = 0;
a.at<uint8_t>(1) = 1;
a.at<uint8_t>(2) = 0;
BOOST_CHECK_EQUAL(a.at<uint8_t>(0), 0);
BOOST_CHECK_EQUAL(a.at<uint8_t>(1), 1);
BOOST_CHECK_EQUAL(a.at<uint8_t>(2), 0);
BOOST_CHECK(a == a);
auto b = buffer(3);
b.initialize<uint8_t>();
BOOST_CHECK(!(a == b));
auto c = buffer(1);
c.initialize<uint8_t>();
BOOST_CHECK(!(a == c));
auto d = buffer();
BOOST_CHECK(!(a == d));
}
// BOOST_AUTO_TEST_CASE(buffer_ctor_and_get)
// {
// auto a = buffer(3);
// a.initialize<uint8_t>();
// BOOST_CHECK_EQUAL(a.size(), 3);
// BOOST_CHECK_EQUAL(a.depth(), 1);
// a.at<uint8_t>(0) = 0;
// a.at<uint8_t>(1) = 1;
// a.at<uint8_t>(2) = 0;
// BOOST_CHECK_EQUAL(a.at<uint8_t>(0), 0);
// BOOST_CHECK_EQUAL(a.at<uint8_t>(1), 1);
// BOOST_CHECK_EQUAL(a.at<uint8_t>(2), 0);
// BOOST_CHECK(a == a);
// auto b = buffer(3);
// b.initialize<uint8_t>();
// BOOST_CHECK(!(a == b));
// auto c = buffer(1);
// c.initialize<uint8_t>();
// BOOST_CHECK(!(a == c));
// auto d = buffer();
// BOOST_CHECK(!(a == d));
// }
BOOST_AUTO_TEST_CASE(buffer_copy_ctor)
{
auto a = buffer(3);
a.initialize<uint8_t>();
a.at<uint8_t>(1) = 1;
auto b = a;
BOOST_CHECK_EQUAL(b.at<uint8_t>(0), 0);
BOOST_CHECK_EQUAL(b.at<uint8_t>(1), 1);
BOOST_CHECK_EQUAL(b.at<uint8_t>(2), 0);
BOOST_CHECK(a == b);
}
// BOOST_AUTO_TEST_CASE(buffer_copy_ctor)
// {
// auto a = buffer(3);
// a.initialize<uint8_t>();
// a.at<uint8_t>(1) = 1;
// auto b = a;
// BOOST_CHECK_EQUAL(b.at<uint8_t>(0), 0);
// BOOST_CHECK_EQUAL(b.at<uint8_t>(1), 1);
// BOOST_CHECK_EQUAL(b.at<uint8_t>(2), 0);
// BOOST_CHECK(a == b);
// }
BOOST_AUTO_TEST_CASE(buffer_move_ctor)
{
auto a = buffer(3);
a.initialize<uint8_t>();
a.at<uint8_t>(1) = 1;
auto b = std::move(a);
BOOST_CHECK_EQUAL(a.size(), 0);
BOOST_CHECK_EQUAL(b.at<uint8_t>(0), 0);
BOOST_CHECK_EQUAL(b.at<uint8_t>(1), 1);
BOOST_CHECK_EQUAL(b.at<uint8_t>(2), 0);
BOOST_CHECK(!(a == b));
}
// BOOST_AUTO_TEST_CASE(buffer_move_ctor)
// {
// auto a = buffer(3);
// a.initialize<uint8_t>();
// a.at<uint8_t>(1) = 1;
// auto b = std::move(a);
// BOOST_CHECK_EQUAL(a.size(), 0);
// BOOST_CHECK_EQUAL(b.at<uint8_t>(0), 0);
// BOOST_CHECK_EQUAL(b.at<uint8_t>(1), 1);
// BOOST_CHECK_EQUAL(b.at<uint8_t>(2), 0);
// BOOST_CHECK(!(a == b));
// }
BOOST_AUTO_TEST_CASE(buffer_copy_assign)
{
auto a = buffer(3);
a.initialize<uint8_t>();
a.at<uint8_t>(1) = 1;
auto b = buffer(3);
b.initialize<uint8_t>();
b = a;
BOOST_CHECK_EQUAL(b.at<uint8_t>(0), 0);
BOOST_CHECK_EQUAL(b.at<uint8_t>(1), 1);
BOOST_CHECK_EQUAL(b.at<uint8_t>(2), 0);
BOOST_CHECK(a == b);
}
// BOOST_AUTO_TEST_CASE(buffer_copy_assign)
// {
// auto a = buffer(3);
// a.initialize<uint8_t>();
// a.at<uint8_t>(1) = 1;
// auto b = buffer(3);
// b.initialize<uint8_t>();
// b = a;
// BOOST_CHECK_EQUAL(b.at<uint8_t>(0), 0);
// BOOST_CHECK_EQUAL(b.at<uint8_t>(1), 1);
// BOOST_CHECK_EQUAL(b.at<uint8_t>(2), 0);
// BOOST_CHECK(a == b);
// }
BOOST_AUTO_TEST_CASE(buffer_move_assign)
{
auto a = buffer(3);
a.initialize<uint8_t>();
a.at<uint8_t>(1) = 1;
auto b = buffer(3);
b.initialize<uint8_t>();
b = std::move(a);
BOOST_CHECK_EQUAL(a.size(), 0);
BOOST_CHECK_EQUAL(b.at<uint8_t>(0), 0);
BOOST_CHECK_EQUAL(b.at<uint8_t>(1), 1);
BOOST_CHECK_EQUAL(b.at<uint8_t>(2), 0);
BOOST_CHECK(!(a == b));
}
// BOOST_AUTO_TEST_CASE(buffer_move_assign)
// {
// auto a = buffer(3);
// a.initialize<uint8_t>();
// a.at<uint8_t>(1) = 1;
// auto b = buffer(3);
// b.initialize<uint8_t>();
// b = std::move(a);
// BOOST_CHECK_EQUAL(a.size(), 0);
// BOOST_CHECK_EQUAL(b.at<uint8_t>(0), 0);
// BOOST_CHECK_EQUAL(b.at<uint8_t>(1), 1);
// BOOST_CHECK_EQUAL(b.at<uint8_t>(2), 0);
// BOOST_CHECK(!(a == b));
// }
BOOST_AUTO_TEST_CASE(buffer_realloc)
{
auto a = buffer(3);
a.initialize<uint8_t>();
BOOST_CHECK_EQUAL(a.size(), 3);
a.at<uint8_t>(0) = 1;
a.at<uint8_t>(1) = 2;
a.at<uint8_t>(2) = 3;
a.grow<uint8_t>();
BOOST_CHECK_EQUAL(a.size(), 3);
BOOST_CHECK_EQUAL(a.depth(), 2);
BOOST_CHECK_EQUAL(a.at<int16_t>(0), 1);
BOOST_CHECK_EQUAL(a.at<int16_t>(1), 2);
BOOST_CHECK_EQUAL(a.at<int16_t>(2), 3);
}
// BOOST_AUTO_TEST_CASE(buffer_realloc)
// {
// auto a = buffer(3);
// a.initialize<uint8_t>();
// BOOST_CHECK_EQUAL(a.size(), 3);
// a.at<uint8_t>(0) = 1;
// a.at<uint8_t>(1) = 2;
// a.at<uint8_t>(2) = 3;
// a.grow<uint8_t>();
// BOOST_CHECK_EQUAL(a.size(), 3);
// BOOST_CHECK_EQUAL(a.depth(), 2);
// BOOST_CHECK_EQUAL(a.at<int16_t>(0), 1);
// BOOST_CHECK_EQUAL(a.at<int16_t>(1), 2);
// BOOST_CHECK_EQUAL(a.at<int16_t>(2), 3);
// }
BOOST_AUTO_TEST_CASE(tiny_string_test)
{

View File

@ -121,7 +121,7 @@ BOOST_AUTO_TEST_CASE(dynamic_storage_equality)
template <typename T>
void convert_static_storage_impl() {
dynamic_storage a(2), b(2), c(2);
dynamic_storage a(2), b(2);
static_storage<T> s(2);
a.increase(0);
b.increase(0, 1.0);
@ -136,15 +136,17 @@ void convert_static_storage_impl() {
BOOST_CHECK(s == b);
a = dynamic_storage(2);
b = dynamic_storage(2);
BOOST_CHECK(a == b);
a += s;
b += s;
BOOST_CHECK(a == s);
BOOST_CHECK(s == a);
BOOST_CHECK(b == s);
BOOST_CHECK(s == b);
dynamic_storage c(s);
BOOST_CHECK(c == s);
BOOST_CHECK(s == c);
dynamic_storage d;
d = std::move(s);
BOOST_CHECK(a == d);
d = std::move(s); // cannot move, uses copy
BOOST_CHECK(d == s);
BOOST_CHECK(s == d);
}
BOOST_AUTO_TEST_CASE(convert_static_storage)