mirror of
https://github.com/boostorg/histogram.git
synced 2025-05-09 23:04:07 +00:00
Better error messages when fill arguments do not match accumulator requirements
This commit is contained in:
parent
3b495bb1d0
commit
b7fc900e3b
@ -7,7 +7,6 @@
|
||||
#ifndef BOOST_HISTOGRAM_AXIS_OPTION_HPP
|
||||
#define BOOST_HISTOGRAM_AXIS_OPTION_HPP
|
||||
|
||||
#include <boost/mp11.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
/**
|
||||
|
64
include/boost/histogram/detail/accumulator_traits.hpp
Normal file
64
include/boost/histogram/detail/accumulator_traits.hpp
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright 2019 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_ACCUMULATOR_TRAITS_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_ACCUMULATOR_TRAITS_HPP
|
||||
|
||||
#include <boost/histogram/fwd.hpp>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace accumulators {
|
||||
template <class, class, class>
|
||||
struct accumulator_set;
|
||||
}
|
||||
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
template <bool WeightSupport, class... Ts>
|
||||
struct accumulator_traits_holder {
|
||||
using wsupport = std::integral_constant<bool, WeightSupport>;
|
||||
using args = std::tuple<Ts...>;
|
||||
};
|
||||
|
||||
template <class R, class T, class U, class... Ts>
|
||||
accumulator_traits_holder<true, Ts...> accumulator_traits_impl_2(
|
||||
R (T::*)(boost::histogram::weight_type<U>, Ts...));
|
||||
|
||||
template <class R, class T, class U, class... Ts>
|
||||
accumulator_traits_holder<true, Ts...> accumulator_traits_impl_2(
|
||||
R (T::*)(boost::histogram::weight_type<U>&&, Ts...));
|
||||
|
||||
template <class R, class T, class U, class... Ts>
|
||||
accumulator_traits_holder<true, Ts...> accumulator_traits_impl_2(
|
||||
R (T::*)(const boost::histogram::weight_type<U>&, Ts...));
|
||||
|
||||
template <class R, class T, class... Ts>
|
||||
accumulator_traits_holder<false, Ts...> accumulator_traits_impl_2(R (T::*)(Ts...));
|
||||
|
||||
template <class T>
|
||||
auto accumulator_traits_impl(T&)
|
||||
-> decltype(std::declval<T&>() += 0, accumulator_traits_holder<true>{});
|
||||
|
||||
template <class T>
|
||||
auto accumulator_traits_impl(T&) -> decltype(accumulator_traits_impl_2(&T::operator()));
|
||||
|
||||
// for boost.accumulators compatibility
|
||||
template <class S, class F, class W>
|
||||
accumulator_traits_holder<false, S> accumulator_traits_impl(
|
||||
boost::accumulators::accumulator_set<S, F, W>&);
|
||||
|
||||
template <class T>
|
||||
using accumulator_traits = decltype(accumulator_traits_impl(std::declval<T&>()));
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
83
include/boost/histogram/detail/argument_traits.hpp
Normal file
83
include/boost/histogram/detail/argument_traits.hpp
Normal file
@ -0,0 +1,83 @@
|
||||
// Copyright 2019 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_ARGUMENT_TRAITS_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_ARGUMENT_TRAITS_HPP
|
||||
|
||||
#include <boost/histogram/fwd.hpp>
|
||||
#include <boost/mp11/algorithm.hpp>
|
||||
#include <boost/mp11/integral.hpp>
|
||||
#include <boost/mp11/list.hpp>
|
||||
#include <tuple>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
template <class T>
|
||||
struct is_weight_impl : mp11::mp_false {};
|
||||
|
||||
template <class T>
|
||||
struct is_weight_impl<weight_type<T>> : mp11::mp_true {};
|
||||
|
||||
template <class T>
|
||||
using is_weight = is_weight_impl<T>;
|
||||
|
||||
template <class T>
|
||||
struct is_sample_impl : mp11::mp_false {};
|
||||
|
||||
template <class T>
|
||||
struct is_sample_impl<sample_type<T>> : mp11::mp_true {};
|
||||
|
||||
template <class T>
|
||||
using is_sample = is_sample_impl<T>;
|
||||
|
||||
template <int Idx, class L>
|
||||
struct sample_args_impl {
|
||||
using type = mp11::mp_first<std::decay_t<mp11::mp_at_c<L, (Idx >= 0 ? Idx : 0)>>>;
|
||||
};
|
||||
|
||||
template <class L>
|
||||
struct sample_args_impl<-1, L> {
|
||||
using type = std::tuple<>;
|
||||
};
|
||||
|
||||
template <std::size_t NArgs, std::size_t Start, int WeightPos, int SamplePos,
|
||||
class SampleArgs>
|
||||
struct argument_traits_holder {
|
||||
using nargs = mp11::mp_size_t<NArgs>;
|
||||
using start = mp11::mp_size_t<Start>;
|
||||
using wpos = mp11::mp_int<WeightPos>;
|
||||
using spos = mp11::mp_int<SamplePos>;
|
||||
using sargs = SampleArgs;
|
||||
};
|
||||
|
||||
template <class... Ts>
|
||||
struct argument_traits_impl {
|
||||
using list_ = mp11::mp_list<Ts...>;
|
||||
static constexpr std::size_t size_ = sizeof...(Ts);
|
||||
static constexpr std::size_t weight_ = mp11::mp_find_if<list_, is_weight>::value;
|
||||
static constexpr std::size_t sample_ = mp11::mp_find_if<list_, is_sample>::value;
|
||||
static constexpr int spos_ = (sample_ < size_ ? static_cast<int>(sample_) : -1);
|
||||
static constexpr int wpos_ = (weight_ < size_ ? static_cast<int>(weight_) : -1);
|
||||
|
||||
using type =
|
||||
argument_traits_holder<(size_ - (weight_ < size_) - (sample_ < size_)),
|
||||
(weight_ < size_ && sample_ < size_ &&
|
||||
(weight_ + sample_ < 2)
|
||||
? 2
|
||||
: ((weight_ == 0 || sample_ == 0) ? 1 : 0)),
|
||||
wpos_, spos_, typename sample_args_impl<spos_, list_>::type>;
|
||||
};
|
||||
|
||||
template <class... Ts>
|
||||
using argument_traits = typename argument_traits_impl<Ts...>::type;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
@ -12,7 +12,7 @@
|
||||
#include <boost/histogram/detail/axes.hpp>
|
||||
#include <boost/histogram/detail/linearize.hpp>
|
||||
#include <boost/histogram/fwd.hpp>
|
||||
#include <boost/mp11.hpp>
|
||||
#include <boost/mp11/algorithm.hpp>
|
||||
#include <tuple>
|
||||
|
||||
namespace boost {
|
||||
|
@ -114,24 +114,6 @@ BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(
|
||||
|
||||
BOOST_HISTOGRAM_DETAIL_DETECT(has_threading_support, (T::has_threading_support));
|
||||
|
||||
template <class T>
|
||||
struct is_weight_impl : mp11::mp_false {};
|
||||
|
||||
template <class T>
|
||||
struct is_weight_impl<weight_type<T>> : mp11::mp_true {};
|
||||
|
||||
template <class T>
|
||||
using is_weight = is_weight_impl<T>;
|
||||
|
||||
template <class T>
|
||||
struct is_sample_impl : mp11::mp_false {};
|
||||
|
||||
template <class T>
|
||||
struct is_sample_impl<sample_type<T>> : mp11::mp_true {};
|
||||
|
||||
template <class T>
|
||||
using is_sample = is_sample_impl<T>;
|
||||
|
||||
template <class T>
|
||||
using is_storage = mp11::mp_and<is_indexable_container<T>, has_method_reset<T>,
|
||||
has_threading_support<T>>;
|
||||
|
@ -12,13 +12,18 @@
|
||||
#include <boost/config/workaround.hpp>
|
||||
#include <boost/histogram/axis/traits.hpp>
|
||||
#include <boost/histogram/axis/variant.hpp>
|
||||
#include <boost/histogram/detail/accumulator_traits.hpp>
|
||||
#include <boost/histogram/detail/argument_traits.hpp>
|
||||
#include <boost/histogram/detail/axes.hpp>
|
||||
#include <boost/histogram/detail/linearize.hpp>
|
||||
#include <boost/histogram/detail/make_default.hpp>
|
||||
#include <boost/histogram/detail/optional_index.hpp>
|
||||
#include <boost/histogram/detail/tuple_slice.hpp>
|
||||
#include <boost/histogram/fwd.hpp>
|
||||
#include <boost/mp11.hpp>
|
||||
#include <boost/mp11/algorithm.hpp>
|
||||
#include <boost/mp11/integral.hpp>
|
||||
#include <boost/mp11/tuple.hpp>
|
||||
#include <boost/mp11/utility.hpp>
|
||||
#include <mutex>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
@ -27,6 +32,23 @@ namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
template <class T, class U>
|
||||
struct sample_args_passed_vs_expected;
|
||||
|
||||
template <class... Passed, class... Expected>
|
||||
struct sample_args_passed_vs_expected<std::tuple<Passed...>, std::tuple<Expected...>> {
|
||||
static_assert(!(sizeof...(Expected) > 0 && sizeof...(Passed) == 0),
|
||||
"error: accumulator requires samples, but sample argument is missing");
|
||||
static_assert(
|
||||
!(sizeof...(Passed) > 0 && sizeof...(Expected) == 0),
|
||||
"error: accumulator does not accept samples, but sample argument is passed");
|
||||
static_assert(sizeof...(Passed) == sizeof...(Expected),
|
||||
"error: numbers of passed and expected sample arguments differ");
|
||||
static_assert(
|
||||
std::is_convertible<std::tuple<Passed...>, std::tuple<Expected...>>::value,
|
||||
"error: sample argument(s) not convertible to accumulator argument(s)");
|
||||
};
|
||||
|
||||
template <class A>
|
||||
struct storage_grower {
|
||||
const A& axes_;
|
||||
@ -168,21 +190,6 @@ auto fill_storage(IW, IS, Storage& s, const Index idx, const Args& a) noexcept {
|
||||
return s.end();
|
||||
}
|
||||
|
||||
template <class L>
|
||||
struct args_indices {
|
||||
static constexpr int _size = static_cast<int>(mp11::mp_size<L>::value);
|
||||
static constexpr int _weight = static_cast<int>(mp11::mp_find_if<L, is_weight>::value);
|
||||
static constexpr int _sample = static_cast<int>(mp11::mp_find_if<L, is_sample>::value);
|
||||
|
||||
static constexpr unsigned nargs = _size - (_weight < _size) - (_sample < _size);
|
||||
static constexpr int start =
|
||||
_weight < _size && _sample < _size && (_weight + _sample < 2)
|
||||
? 2
|
||||
: ((_weight == 0 || _sample == 0) ? 1 : 0);
|
||||
using weight = mp11::mp_int<(_weight < _size ? _weight : -1)>;
|
||||
using sample = mp11::mp_int<(_sample < _size ? _sample : -1)>;
|
||||
};
|
||||
|
||||
template <int S, int N>
|
||||
struct linearize_args {
|
||||
template <class Index, class A, class Args>
|
||||
@ -216,54 +223,56 @@ constexpr unsigned min(const unsigned n) noexcept {
|
||||
}
|
||||
|
||||
// not growing
|
||||
template <class Storage, class Axes, class Args>
|
||||
auto fill_2(mp11::mp_false, const std::size_t offset, Storage& st, const Axes& axes,
|
||||
const Args& args) {
|
||||
using pos = args_indices<mp11::mp_transform<std::decay_t, Args>>;
|
||||
template <class ArgTraits, class Storage, class Axes, class Args>
|
||||
auto fill_2(ArgTraits, mp11::mp_false, const std::size_t offset, Storage& st,
|
||||
const Axes& axes, const Args& args) {
|
||||
mp11::mp_if<has_non_inclusive_axis<Axes>, optional_index, std::size_t> idx{offset};
|
||||
linearize_args<pos::start, min<Axes>(pos::nargs)>::apply(idx, axes, args);
|
||||
return fill_storage(typename pos::weight{}, typename pos::sample{}, st, idx, args);
|
||||
linearize_args<ArgTraits::start::value, min<Axes>(ArgTraits::nargs::value)>::apply(
|
||||
idx, axes, args);
|
||||
return fill_storage(typename ArgTraits::wpos{}, typename ArgTraits::spos{}, st, idx,
|
||||
args);
|
||||
}
|
||||
|
||||
// at least one axis is growing
|
||||
template <class Storage, class A, class Args>
|
||||
auto fill_2(mp11::mp_true, const std::size_t, Storage& st, A& axes, const Args& args) {
|
||||
using pos = args_indices<mp11::mp_transform<std::decay_t, Args>>;
|
||||
std::array<axis::index_type, pos::nargs> shifts;
|
||||
template <class ArgTraits, class Storage, class Axes, class Args>
|
||||
auto fill_2(ArgTraits, mp11::mp_true, const std::size_t, Storage& st, Axes& axes,
|
||||
const Args& args) {
|
||||
std::array<axis::index_type, ArgTraits::nargs::value> shifts;
|
||||
// offset must be zero for linearize_growth
|
||||
mp11::mp_if<has_non_inclusive_axis<A>, optional_index, std::size_t> idx{0};
|
||||
mp11::mp_if<has_non_inclusive_axis<Axes>, optional_index, std::size_t> idx{0};
|
||||
std::size_t stride = 1;
|
||||
bool update_needed = false;
|
||||
mp11::mp_for_each<mp11::mp_iota_c<min<A>(pos::nargs)>>([&](auto i) {
|
||||
mp11::mp_for_each<mp11::mp_iota_c<min<Axes>(ArgTraits::nargs::value)>>([&](auto i) {
|
||||
auto& ax = axis_get<i>(axes);
|
||||
const auto extent =
|
||||
linearize_growth(idx, shifts[i], stride, ax, std::get<(pos::start + i)>(args));
|
||||
const auto extent = linearize_growth(idx, shifts[i], stride, ax,
|
||||
std::get<(ArgTraits::start::value + i)>(args));
|
||||
update_needed |= shifts[i] != 0;
|
||||
stride *= extent;
|
||||
});
|
||||
if (update_needed) {
|
||||
storage_grower<A> g(axes);
|
||||
storage_grower<Axes> g(axes);
|
||||
g.from_shifts(shifts.data());
|
||||
g.apply(st, shifts.data());
|
||||
}
|
||||
return fill_storage(typename pos::weight{}, typename pos::sample{}, st, idx, args);
|
||||
return fill_storage(typename ArgTraits::wpos{}, typename ArgTraits::spos{}, st, idx,
|
||||
args);
|
||||
}
|
||||
|
||||
// pack original args tuple into another tuple (which is unpacked later)
|
||||
template <int Start, int Size, class IW, class IS, class Args>
|
||||
decltype(auto) pack_args(IW, IS, const Args& args) noexcept {
|
||||
return std::make_tuple(std::get<IW::value>(args), std::get<IS::value>(args),
|
||||
tuple_slice<Start, Size>(args));
|
||||
return std::make_tuple(tuple_slice<Start, Size>(args), std::get<IW::value>(args),
|
||||
std::get<IS::value>(args));
|
||||
}
|
||||
|
||||
template <int Start, int Size, class IW, class Args>
|
||||
decltype(auto) pack_args(IW, mp11::mp_int<-1>, const Args& args) noexcept {
|
||||
return std::make_tuple(std::get<IW::value>(args), tuple_slice<Start, Size>(args));
|
||||
return std::make_tuple(tuple_slice<Start, Size>(args), std::get<IW::value>(args));
|
||||
}
|
||||
|
||||
template <int Start, int Size, class IS, class Args>
|
||||
decltype(auto) pack_args(mp11::mp_int<-1>, IS, const Args& args) noexcept {
|
||||
return std::make_tuple(std::get<IS::value>(args), tuple_slice<Start, Size>(args));
|
||||
return std::make_tuple(tuple_slice<Start, Size>(args), std::get<IS::value>(args));
|
||||
}
|
||||
|
||||
template <int Start, int Size, class Args>
|
||||
@ -275,9 +284,9 @@ decltype(auto) pack_args(mp11::mp_int<-1>, mp11::mp_int<-1>, const Args& args) n
|
||||
#pragma warning(disable : 4702) // fixing warning would reduce code readability a lot
|
||||
#endif
|
||||
|
||||
template <class S, class A, class Args>
|
||||
auto fill(const std::size_t offset, S& storage, A& axes, const Args& args) {
|
||||
using pos = args_indices<mp11::mp_transform<std::decay_t, Args>>;
|
||||
template <class ArgTraits, class S, class A, class Args>
|
||||
auto fill(std::true_type, ArgTraits, const std::size_t offset, S& storage, A& axes,
|
||||
const Args& args) {
|
||||
using growing = has_growing_axis<A>;
|
||||
|
||||
// Sometimes we need to pack the tuple into another tuple:
|
||||
@ -292,12 +301,18 @@ auto fill(const std::size_t offset, S& storage, A& axes, const Args& args) {
|
||||
// interface), so we throw at runtime if incompatible argument is passed (e.g.
|
||||
// 3d tuple)
|
||||
|
||||
if (axes_rank(axes) == pos::nargs)
|
||||
return fill_2(growing{}, offset, storage, axes, args);
|
||||
else if (axes_rank(axes) == 1 && axis::traits::rank(axis_get<0>(axes)) == pos::nargs)
|
||||
return fill_2(growing{}, offset, storage, axes,
|
||||
pack_args<pos::start, pos::nargs>(typename pos::weight{},
|
||||
typename pos::sample{}, args));
|
||||
if (axes_rank(axes) == ArgTraits::nargs::value)
|
||||
return fill_2(ArgTraits{}, growing{}, offset, storage, axes, args);
|
||||
else if (axes_rank(axes) == 1 &&
|
||||
axis::traits::rank(axis_get<0>(axes)) == ArgTraits::nargs::value)
|
||||
return fill_2(
|
||||
argument_traits_holder<
|
||||
1, 0, (ArgTraits::wpos::value >= 0 ? 1 : -1),
|
||||
(ArgTraits::spos::value >= 0 ? (ArgTraits::wpos::value >= 0 ? 2 : 1) : -1),
|
||||
typename ArgTraits::sargs>{},
|
||||
growing{}, offset, storage, axes,
|
||||
pack_args<ArgTraits::start::value, ArgTraits::nargs::value>(
|
||||
typename ArgTraits::wpos{}, typename ArgTraits::spos{}, args));
|
||||
return (BOOST_THROW_EXCEPTION(
|
||||
std::invalid_argument("number of arguments != histogram rank")),
|
||||
storage.end());
|
||||
@ -307,6 +322,12 @@ auto fill(const std::size_t offset, S& storage, A& axes, const Args& args) {
|
||||
#pragma warning(default : 4702)
|
||||
#endif
|
||||
|
||||
// empty implementation for bad arguments to stop compiler from showing internals
|
||||
template <class ArgTraits, class S, class A, class Args>
|
||||
auto fill(std::false_type, ArgTraits, const std::size_t, S& storage, A&, const Args&) {
|
||||
return storage.end();
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
@ -20,7 +20,9 @@
|
||||
#include <boost/histogram/detail/span.hpp>
|
||||
#include <boost/histogram/detail/static_if.hpp>
|
||||
#include <boost/histogram/fwd.hpp>
|
||||
#include <boost/mp11.hpp>
|
||||
#include <boost/mp11/algorithm.hpp>
|
||||
#include <boost/mp11/bind.hpp>
|
||||
#include <boost/mp11/utility.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/variant2/variant.hpp>
|
||||
#include <stdexcept>
|
||||
@ -278,7 +280,7 @@ void fill_n_check_extra_args(std::size_t n, weight_type<T>&& w, Ts&&... ts) {
|
||||
inline void fill_n_check_extra_args(std::size_t) noexcept {}
|
||||
|
||||
template <class S, class A, class T, std::size_t N, class... Us>
|
||||
void fill_n(const std::size_t offset, S& storage, A& axes,
|
||||
void fill_n(std::true_type, const std::size_t offset, S& storage, A& axes,
|
||||
const dtl::span<const T, N> values, Us&&... us) {
|
||||
static_assert(!std::is_pointer<T>::value,
|
||||
"passing iterable of pointers not allowed (cannot determine lengths); "
|
||||
@ -303,6 +305,10 @@ void fill_n(const std::size_t offset, S& storage, A& axes,
|
||||
values, std::forward<Us>(us)...);
|
||||
}
|
||||
|
||||
// empty implementation for bad arguments to stop compiler from showing internals
|
||||
template <class... Ts>
|
||||
void fill_n(std::false_type, Ts...) {}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
@ -7,19 +7,24 @@
|
||||
#ifndef BOOST_HISTOGRAM_HISTOGRAM_HPP
|
||||
#define BOOST_HISTOGRAM_HISTOGRAM_HPP
|
||||
|
||||
#include <boost/histogram/detail/accumulator_traits.hpp>
|
||||
#include <boost/histogram/detail/argument_traits.hpp>
|
||||
#include <boost/histogram/detail/at.hpp>
|
||||
#include <boost/histogram/detail/axes.hpp>
|
||||
#include <boost/histogram/detail/common_type.hpp>
|
||||
#include <boost/histogram/detail/fill.hpp>
|
||||
#include <boost/histogram/detail/fill_n.hpp>
|
||||
#include <boost/histogram/detail/mutex_base.hpp>
|
||||
#include <boost/histogram/detail/non_member_container_access.hpp>
|
||||
#include <boost/histogram/detail/span.hpp>
|
||||
#include <boost/histogram/fwd.hpp>
|
||||
#include <boost/histogram/sample.hpp>
|
||||
#include <boost/histogram/storage_adaptor.hpp>
|
||||
#include <boost/histogram/unsafe_access.hpp>
|
||||
#include <boost/histogram/weight.hpp>
|
||||
#include <boost/mp11/integral.hpp>
|
||||
#include <boost/mp11/list.hpp>
|
||||
#include <boost/mp11/tuple.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
@ -51,12 +56,9 @@ namespace histogram {
|
||||
*/
|
||||
template <class Axes, class Storage>
|
||||
class histogram : detail::mutex_base<Axes, Storage> {
|
||||
using mutex_base_t = typename detail::mutex_base<Axes, Storage>;
|
||||
|
||||
public:
|
||||
static_assert(mp11::mp_size<Axes>::value > 0, "at least one axis required");
|
||||
static_assert(std::is_same<std::decay_t<Storage>, Storage>::value,
|
||||
"Storage may not be a reference or const or volatile");
|
||||
static_assert(mp11::mp_size<Axes>::value > 0, "at least one axis required");
|
||||
|
||||
public:
|
||||
using axes_type = Axes;
|
||||
@ -66,6 +68,10 @@ public:
|
||||
using iterator = typename storage_type::iterator;
|
||||
using const_iterator = typename storage_type::const_iterator;
|
||||
|
||||
private:
|
||||
using mutex_base = typename detail::mutex_base<axes_type, storage_type>;
|
||||
|
||||
public:
|
||||
histogram() = default;
|
||||
|
||||
template <class A, class S>
|
||||
@ -174,16 +180,28 @@ public:
|
||||
`std::make_tuple(1.2, 2.3)`. If the histogram contains only this axis and no other,
|
||||
the arguments can be passed directly.
|
||||
*/
|
||||
template <class... Args>
|
||||
iterator operator()(const Args&... args) {
|
||||
return operator()(std::forward_as_tuple(args...));
|
||||
template <class Arg0, class... Args>
|
||||
std::enable_if_t<(detail::is_tuple<Arg0>::value == false || sizeof...(Args) > 0),
|
||||
iterator>
|
||||
operator()(const Arg0& arg0, const Args&... args) {
|
||||
return operator()(std::forward_as_tuple(arg0, args...));
|
||||
}
|
||||
|
||||
/// Fill histogram with values, an optional weight, and/or a sample from a `std::tuple`.
|
||||
template <class... Ts>
|
||||
iterator operator()(const std::tuple<Ts...>& args) {
|
||||
std::lock_guard<typename mutex_base_t::type> guard{mutex_base_t::get()};
|
||||
return detail::fill(offset_, storage_, axes_, args);
|
||||
using arg_traits = detail::argument_traits<std::decay_t<Ts>...>;
|
||||
using acc_traits = detail::accumulator_traits<value_type>;
|
||||
constexpr bool weight_valid =
|
||||
arg_traits::wpos::value == -1 || acc_traits::wsupport::value;
|
||||
static_assert(weight_valid, "error: accumulator does not support weights");
|
||||
detail::sample_args_passed_vs_expected<typename arg_traits::sargs,
|
||||
typename acc_traits::args>();
|
||||
constexpr bool sample_valid =
|
||||
std::is_convertible<typename arg_traits::sargs, typename acc_traits::args>::value;
|
||||
std::lock_guard<typename mutex_base::type> guard{mutex_base::get()};
|
||||
return detail::fill(mp11::mp_bool<(weight_valid && sample_valid)>{}, arg_traits{},
|
||||
offset_, storage_, axes_, args);
|
||||
}
|
||||
|
||||
/** Fill histogram with several values at once.
|
||||
@ -203,8 +221,14 @@ public:
|
||||
*/
|
||||
template <class Iterable, class = detail::requires_iterable<Iterable>>
|
||||
void fill(const Iterable& args) {
|
||||
std::lock_guard<typename mutex_base_t::type> guard{mutex_base_t::get()};
|
||||
detail::fill_n(offset_, storage_, axes_, detail::make_span(args));
|
||||
using acc_traits = detail::accumulator_traits<value_type>;
|
||||
constexpr unsigned n_sample_args_expected =
|
||||
std::tuple_size<typename acc_traits::args>::value;
|
||||
static_assert(n_sample_args_expected == 0,
|
||||
"sample argument is missing but required by accumulator");
|
||||
std::lock_guard<typename mutex_base::type> guard{mutex_base::get()};
|
||||
detail::fill_n(mp11::mp_bool<(n_sample_args_expected == 0)>{}, offset_, storage_,
|
||||
axes_, detail::make_span(args));
|
||||
}
|
||||
|
||||
/** Fill histogram with several values and weights at once.
|
||||
@ -214,8 +238,15 @@ public:
|
||||
*/
|
||||
template <class Iterable, class T, class = detail::requires_iterable<Iterable>>
|
||||
void fill(const Iterable& args, const weight_type<T>& weights) {
|
||||
std::lock_guard<typename mutex_base_t::type> guard{mutex_base_t::get()};
|
||||
detail::fill_n(offset_, storage_, axes_, detail::make_span(args),
|
||||
using acc_traits = detail::accumulator_traits<value_type>;
|
||||
constexpr bool weight_valid = acc_traits::wsupport::value;
|
||||
static_assert(weight_valid, "error: accumulator does not support weights");
|
||||
detail::sample_args_passed_vs_expected<std::tuple<>, typename acc_traits::args>();
|
||||
constexpr bool sample_valid =
|
||||
std::is_convertible<std::tuple<>, typename acc_traits::args>::value;
|
||||
std::lock_guard<typename mutex_base::type> guard{mutex_base::get()};
|
||||
detail::fill_n(mp11::mp_bool<(weight_valid && sample_valid)>{}, offset_, storage_,
|
||||
axes_, detail::make_span(args),
|
||||
weight(detail::to_ptr_size(weights.value)));
|
||||
}
|
||||
|
||||
@ -234,13 +265,20 @@ public:
|
||||
@param args iterable of values.
|
||||
@param samples single sample or an iterable of samples.
|
||||
*/
|
||||
template <class Iterable, class T, class = detail::requires_iterable<Iterable>>
|
||||
void fill(const Iterable& args, const sample_type<T>& samples) {
|
||||
std::lock_guard<typename mutex_base_t::type> guard{mutex_base_t::get()};
|
||||
template <class Iterable, class... Ts, class = detail::requires_iterable<Iterable>,
|
||||
class = mp11::mp_list<detail::requires_iterable<Ts>...>>
|
||||
void fill(const Iterable& args, const sample_type<std::tuple<Ts...>>& samples) {
|
||||
using acc_traits = detail::accumulator_traits<value_type>;
|
||||
using sample_args_passed = std::tuple<decltype(*detail::data(std::declval<Ts>()))...>;
|
||||
detail::sample_args_passed_vs_expected<sample_args_passed,
|
||||
typename acc_traits::args>();
|
||||
std::lock_guard<typename mutex_base::type> guard{mutex_base::get()};
|
||||
mp11::tuple_apply(
|
||||
[&](const auto&... sargs) {
|
||||
detail::fill_n(offset_, storage_, axes_, detail::make_span(args),
|
||||
detail::to_ptr_size(sargs)...);
|
||||
constexpr bool sample_valid =
|
||||
std::is_convertible<sample_args_passed, typename acc_traits::args>::value;
|
||||
detail::fill_n(mp11::mp_bool<(sample_valid)>{}, offset_, storage_, axes_,
|
||||
detail::make_span(args), detail::to_ptr_size(sargs)...);
|
||||
},
|
||||
samples.value);
|
||||
}
|
||||
@ -255,13 +293,23 @@ public:
|
||||
fill(args, samples);
|
||||
}
|
||||
|
||||
template <class Iterable, class T, class U, class = detail::requires_iterable<Iterable>>
|
||||
template <class Iterable, class T, class... Ts,
|
||||
class = detail::requires_iterable<Iterable>,
|
||||
class = mp11::mp_list<detail::requires_iterable<Ts>...>>
|
||||
void fill(const Iterable& args, const weight_type<T>& weights,
|
||||
const sample_type<U>& samples) {
|
||||
std::lock_guard<typename mutex_base_t::type> guard{mutex_base_t::get()};
|
||||
const sample_type<std::tuple<Ts...>>& samples) {
|
||||
using acc_traits = detail::accumulator_traits<value_type>;
|
||||
using sample_args = std::tuple<decltype(*detail::data(std::declval<Ts>()))...>;
|
||||
detail::sample_args_passed_vs_expected<sample_args, typename acc_traits::args>();
|
||||
std::lock_guard<typename mutex_base::type> guard{mutex_base::get()};
|
||||
mp11::tuple_apply(
|
||||
[&](const auto&... sargs) {
|
||||
detail::fill_n(offset_, storage_, axes_, detail::make_span(args),
|
||||
constexpr bool weight_valid = acc_traits::wsupport::value;
|
||||
static_assert(weight_valid, "error: accumulator does not support weights");
|
||||
constexpr bool sample_valid =
|
||||
std::is_convertible<sample_args, typename acc_traits::args>::value;
|
||||
detail::fill_n(mp11::mp_bool<(weight_valid && sample_valid)>{}, offset_,
|
||||
storage_, axes_, detail::make_span(args),
|
||||
weight(detail::to_ptr_size(weights.value)),
|
||||
detail::to_ptr_size(sargs)...);
|
||||
},
|
||||
|
@ -54,16 +54,19 @@ boost_test(TYPE compile-fail SOURCES make_histogram_fail0.cpp
|
||||
boost_test(TYPE compile-fail SOURCES make_histogram_fail1.cpp
|
||||
LIBRARIES Boost::histogram
|
||||
)
|
||||
boost_test(TYPE compile-fail SOURCES profile_fail0.cpp
|
||||
boost_test(TYPE compile-fail SOURCES histogram_fail0.cpp
|
||||
LIBRARIES Boost::histogram
|
||||
)
|
||||
boost_test(TYPE compile-fail SOURCES profile_fail1.cpp
|
||||
boost_test(TYPE compile-fail SOURCES histogram_fail1.cpp
|
||||
LIBRARIES Boost::histogram
|
||||
)
|
||||
boost_test(TYPE compile-fail SOURCES profile_fail2.cpp
|
||||
boost_test(TYPE compile-fail SOURCES histogram_fail2.cpp
|
||||
LIBRARIES Boost::histogram
|
||||
)
|
||||
boost_test(TYPE compile-fail SOURCES profile_fail3.cpp
|
||||
boost_test(TYPE compile-fail SOURCES histogram_fail3.cpp
|
||||
LIBRARIES Boost::histogram
|
||||
)
|
||||
boost_test(TYPE compile-fail SOURCES histogram_fail4.cpp
|
||||
LIBRARIES Boost::histogram
|
||||
)
|
||||
boost_test(TYPE run SOURCES accumulators_test.cpp
|
||||
@ -92,6 +95,10 @@ boost_test(TYPE run SOURCES axis_variable_test.cpp
|
||||
LIBRARIES Boost::histogram Boost::core)
|
||||
boost_test(TYPE run SOURCES axis_variant_test.cpp
|
||||
LIBRARIES Boost::histogram Boost::core)
|
||||
boost_test(TYPE run SOURCES detail_accumulator_traits_test.cpp
|
||||
LIBRARIES Boost::histogram Boost::core)
|
||||
boost_test(TYPE run SOURCES detail_argument_traits_test.cpp
|
||||
LIBRARIES Boost::histogram Boost::core)
|
||||
boost_test(TYPE run SOURCES detail_args_type_test.cpp
|
||||
LIBRARIES Boost::histogram Boost::core)
|
||||
boost_test(TYPE run SOURCES detail_axes_test.cpp
|
||||
|
11
test/Jamfile
11
test/Jamfile
@ -51,6 +51,8 @@ alias cxx14 :
|
||||
[ run axis_traits_test.cpp ]
|
||||
[ run axis_variable_test.cpp ]
|
||||
[ run axis_variant_test.cpp ]
|
||||
[ run detail_accumulator_traits_test.cpp ]
|
||||
[ run detail_argument_traits_test.cpp ]
|
||||
[ run detail_args_type_test.cpp ]
|
||||
[ run detail_axes_test.cpp ]
|
||||
[ run detail_convert_integer_test.cpp ]
|
||||
@ -101,10 +103,11 @@ alias failure :
|
||||
[ compile-fail axis_variable_fail1.cpp ]
|
||||
[ compile-fail make_histogram_fail0.cpp ]
|
||||
[ compile-fail make_histogram_fail1.cpp ]
|
||||
[ compile-fail profile_fail0.cpp ]
|
||||
[ compile-fail profile_fail1.cpp ]
|
||||
[ compile-fail profile_fail2.cpp ]
|
||||
[ compile-fail profile_fail3.cpp ]
|
||||
[ compile-fail histogram_fail0.cpp ]
|
||||
[ compile-fail histogram_fail1.cpp ]
|
||||
[ compile-fail histogram_fail2.cpp ]
|
||||
[ compile-fail histogram_fail3.cpp ]
|
||||
[ compile-fail histogram_fail4.cpp ]
|
||||
;
|
||||
|
||||
alias threading :
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include <boost/core/lightweight_test_trait.hpp>
|
||||
#include <boost/histogram/axis.hpp>
|
||||
#include <boost/histogram/axis/traits.hpp>
|
||||
#include <boost/mp11.hpp>
|
||||
#include "std_ostream.hpp"
|
||||
#include "throw_exception.hpp"
|
||||
#include "utility_axis.hpp"
|
||||
|
82
test/detail_accumulator_traits_test.cpp
Normal file
82
test/detail_accumulator_traits_test.cpp
Normal file
@ -0,0 +1,82 @@
|
||||
// Copyright 2019 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)
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test_trait.hpp>
|
||||
#include <boost/histogram/detail/accumulator_traits.hpp>
|
||||
#include <boost/histogram/weight.hpp>
|
||||
#include <tuple>
|
||||
|
||||
namespace dtl = boost::histogram::detail;
|
||||
|
||||
int main() {
|
||||
using boost::histogram::weight_type;
|
||||
|
||||
struct A1 {
|
||||
void operator()(){};
|
||||
};
|
||||
|
||||
BOOST_TEST_NOT(dtl::accumulator_traits<A1>::wsupport::value);
|
||||
BOOST_TEST_TRAIT_SAME(typename dtl::accumulator_traits<A1>::args, std::tuple<>);
|
||||
|
||||
struct A2 {
|
||||
void operator()(int, double) {}
|
||||
};
|
||||
|
||||
BOOST_TEST_NOT(dtl::accumulator_traits<A2>::wsupport::value);
|
||||
BOOST_TEST_TRAIT_SAME(typename dtl::accumulator_traits<A2>::args,
|
||||
std::tuple<int, double>);
|
||||
|
||||
struct A3 {
|
||||
void operator()() {}
|
||||
void operator()(weight_type<int>) {}
|
||||
};
|
||||
|
||||
BOOST_TEST(dtl::accumulator_traits<A3>::wsupport::value);
|
||||
BOOST_TEST_TRAIT_SAME(typename dtl::accumulator_traits<A3>::args, std::tuple<>);
|
||||
|
||||
struct A4 {
|
||||
void operator()(int, double, char) {}
|
||||
void operator()(weight_type<int>, int, double, char) {}
|
||||
};
|
||||
|
||||
BOOST_TEST(dtl::accumulator_traits<A4>::wsupport::value);
|
||||
BOOST_TEST_TRAIT_SAME(typename dtl::accumulator_traits<A4>::args,
|
||||
std::tuple<int, double, char>);
|
||||
|
||||
struct A5 {
|
||||
void operator()(const weight_type<int>, int) {}
|
||||
};
|
||||
|
||||
BOOST_TEST(dtl::accumulator_traits<A5>::wsupport::value);
|
||||
BOOST_TEST_TRAIT_SAME(typename dtl::accumulator_traits<A5>::args, std::tuple<int>);
|
||||
|
||||
struct A6 {
|
||||
void operator()(const weight_type<int>&, const int) {}
|
||||
};
|
||||
|
||||
BOOST_TEST(dtl::accumulator_traits<A6>::wsupport::value);
|
||||
BOOST_TEST_TRAIT_SAME(typename dtl::accumulator_traits<A6>::args, std::tuple<int>);
|
||||
|
||||
struct A7 {
|
||||
void operator()(weight_type<int>&&, int&&) {}
|
||||
};
|
||||
|
||||
BOOST_TEST(dtl::accumulator_traits<A7>::wsupport::value);
|
||||
BOOST_TEST_TRAIT_SAME(typename dtl::accumulator_traits<A7>::args, std::tuple<int&&>);
|
||||
|
||||
struct B {
|
||||
int operator+=(int) { return 0; }
|
||||
};
|
||||
|
||||
BOOST_TEST(dtl::accumulator_traits<B>::wsupport::value);
|
||||
BOOST_TEST_TRAIT_SAME(typename dtl::accumulator_traits<B>::args, std::tuple<>);
|
||||
|
||||
BOOST_TEST(dtl::accumulator_traits<int>::wsupport::value);
|
||||
BOOST_TEST_TRAIT_SAME(dtl::accumulator_traits<int>::args, std::tuple<>);
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
61
test/detail_argument_traits_test.cpp
Normal file
61
test/detail_argument_traits_test.cpp
Normal file
@ -0,0 +1,61 @@
|
||||
// Copyright 2019 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)
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test_trait.hpp>
|
||||
#include <boost/histogram/detail/argument_traits.hpp>
|
||||
#include <boost/histogram/sample.hpp>
|
||||
#include <boost/histogram/weight.hpp>
|
||||
|
||||
namespace dtl = boost::histogram::detail;
|
||||
|
||||
int main() {
|
||||
using boost::histogram::sample;
|
||||
using boost::histogram::weight;
|
||||
|
||||
// is_weight
|
||||
{
|
||||
struct A {};
|
||||
using B = int;
|
||||
BOOST_TEST_NOT(dtl::is_weight<A>::value);
|
||||
BOOST_TEST_NOT(dtl::is_weight<B>::value);
|
||||
BOOST_TEST_NOT(dtl::is_weight<decltype(sample(0))>::value);
|
||||
BOOST_TEST(dtl::is_weight<decltype(weight(0))>::value);
|
||||
}
|
||||
|
||||
// is_sample
|
||||
{
|
||||
struct A {};
|
||||
using B = int;
|
||||
BOOST_TEST_NOT(dtl::is_sample<A>::value);
|
||||
BOOST_TEST_NOT(dtl::is_sample<B>::value);
|
||||
BOOST_TEST_NOT(dtl::is_sample<decltype(weight(0))>::value);
|
||||
BOOST_TEST(dtl::is_sample<decltype(sample(0))>::value);
|
||||
BOOST_TEST(dtl::is_sample<decltype(sample(0, A{}))>::value);
|
||||
}
|
||||
|
||||
using T1 = dtl::argument_traits<int>;
|
||||
using E1 = dtl::argument_traits_holder<1, 0, -1, -1, std::tuple<>>;
|
||||
BOOST_TEST_TRAIT_SAME(T1, E1);
|
||||
|
||||
using T2 = dtl::argument_traits<int, int>;
|
||||
using E2 = dtl::argument_traits_holder<2, 0, -1, -1, std::tuple<>>;
|
||||
BOOST_TEST_TRAIT_SAME(T2, E2);
|
||||
|
||||
using T3 = dtl::argument_traits<decltype(weight(0)), int, int>;
|
||||
using E3 = dtl::argument_traits_holder<2, 1, 0, -1, std::tuple<>>;
|
||||
BOOST_TEST_TRAIT_SAME(T3, E3);
|
||||
|
||||
using T4 = dtl::argument_traits<decltype(weight(0)), int, int, decltype(sample(0))>;
|
||||
using E4 = dtl::argument_traits_holder<2, 1, 0, 3, std::tuple<int>>;
|
||||
BOOST_TEST_TRAIT_SAME(T4, E4);
|
||||
|
||||
using T5 = dtl::argument_traits<int, decltype(sample(0, 0.0))>;
|
||||
using E5 = dtl::argument_traits_holder<1, 0, -1, 1, std::tuple<int, double>>;
|
||||
BOOST_TEST_TRAIT_SAME(T5, E5);
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
@ -269,26 +269,6 @@ int main() {
|
||||
BOOST_TEST_TRAIT_TRUE((is_sequence_of_any_axis<decltype(v)>));
|
||||
}
|
||||
|
||||
// is_weight
|
||||
{
|
||||
struct A {};
|
||||
using B = int;
|
||||
using C = weight_type<int>;
|
||||
BOOST_TEST_TRAIT_FALSE((is_weight<A>));
|
||||
BOOST_TEST_TRAIT_FALSE((is_weight<B>));
|
||||
BOOST_TEST_TRAIT_TRUE((is_weight<C>));
|
||||
}
|
||||
|
||||
// is_sample
|
||||
{
|
||||
struct A {};
|
||||
using B = int;
|
||||
using C = sample_type<int>;
|
||||
BOOST_TEST_TRAIT_FALSE((is_sample<A>));
|
||||
BOOST_TEST_TRAIT_FALSE((is_sample<B>));
|
||||
BOOST_TEST_TRAIT_TRUE((is_sample<C>));
|
||||
}
|
||||
|
||||
// has_operator_equal
|
||||
{
|
||||
struct A {};
|
||||
|
@ -5,10 +5,16 @@
|
||||
// or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/histogram/axis/integer.hpp>
|
||||
#include <boost/histogram/make_profile.hpp>
|
||||
#include <boost/histogram/make_histogram.hpp>
|
||||
|
||||
int main() {
|
||||
using namespace boost::histogram;
|
||||
auto h = make_profile(axis::integer<>(0, 5));
|
||||
h(0, weight(1)); // profile requires a sample
|
||||
|
||||
auto h = make_histogram(axis::integer<>(0, 5));
|
||||
|
||||
// invalid sample argument
|
||||
h(0, sample(1));
|
||||
|
||||
auto values = {0, 1};
|
||||
h.fill(values, sample(values)); // invalid sample argument
|
||||
}
|
@ -5,10 +5,20 @@
|
||||
// or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/histogram/axis/integer.hpp>
|
||||
#include <boost/histogram/make_profile.hpp>
|
||||
#include <boost/histogram/make_histogram.hpp>
|
||||
|
||||
int main() {
|
||||
using namespace boost::histogram;
|
||||
auto h = make_weighted_profile(axis::integer<>(0, 5));
|
||||
h(0); // weighted profile requires a sample
|
||||
|
||||
struct accumulator {
|
||||
void operator()() {}
|
||||
};
|
||||
|
||||
auto h = make_histogram_with(dense_storage<accumulator>(), axis::integer<>(0, 5));
|
||||
|
||||
// invalid weight argument
|
||||
h(0, weight(1));
|
||||
|
||||
auto values = {0, 1};
|
||||
h.fill(values, weight(1));
|
||||
}
|
@ -9,6 +9,17 @@
|
||||
|
||||
int main() {
|
||||
using namespace boost::histogram;
|
||||
auto h = make_profile(axis::integer<>(0, 5));
|
||||
h(0, sample(1, 2)); // profile requires one sample
|
||||
|
||||
struct accumulator {
|
||||
void operator()(double) {}
|
||||
void operator()(weight_type<double>, double) {}
|
||||
};
|
||||
|
||||
auto h = make_histogram_with(dense_storage<accumulator>(), axis::integer<>(0, 5));
|
||||
|
||||
// accumulator requires sample
|
||||
h(0, weight(1));
|
||||
|
||||
auto values = {1, 2};
|
||||
h.fill(values, weight(1));
|
||||
}
|
23
test/histogram_fail3.cpp
Normal file
23
test/histogram_fail3.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright 2019 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)
|
||||
|
||||
#include <boost/histogram/axis/integer.hpp>
|
||||
#include <boost/histogram/make_histogram.hpp>
|
||||
|
||||
int main() {
|
||||
struct accumulator {
|
||||
void operator()(double) {}
|
||||
};
|
||||
|
||||
using namespace boost::histogram;
|
||||
auto h = make_histogram_with(dense_storage<accumulator>(), axis::integer<>(0, 5));
|
||||
|
||||
// wrong number of sample arguments
|
||||
h(0, sample(1, 2));
|
||||
|
||||
auto values = {0, 1};
|
||||
h.fill(values, sample(values, values));
|
||||
}
|
24
test/histogram_fail4.cpp
Normal file
24
test/histogram_fail4.cpp
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright 2019 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)
|
||||
|
||||
#include <boost/histogram/axis/integer.hpp>
|
||||
#include <boost/histogram/make_histogram.hpp>
|
||||
|
||||
int main() {
|
||||
using namespace boost::histogram;
|
||||
|
||||
struct accumulator {
|
||||
void operator()(std::string) {}
|
||||
};
|
||||
|
||||
auto h = make_histogram_with(dense_storage<accumulator>(), axis::integer<>(0, 5));
|
||||
|
||||
// invalid weight argument
|
||||
h(0, sample(1));
|
||||
|
||||
auto values = {1, 2};
|
||||
h.fill(values, sample(values));
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
// Copyright 2019 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)
|
||||
|
||||
#include <boost/histogram/axis/integer.hpp>
|
||||
#include <boost/histogram/make_profile.hpp>
|
||||
|
||||
int main() {
|
||||
using namespace boost::histogram;
|
||||
auto h = make_profile(axis::integer<>(0, 5));
|
||||
h(0, sample(1, 2)); // weighted profile requires one sample
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user