diff --git a/include/boost/histogram/adaptive_storage.hpp b/include/boost/histogram/adaptive_storage.hpp index a34e1d65..cd1b088d 100644 --- a/include/boost/histogram/adaptive_storage.hpp +++ b/include/boost/histogram/adaptive_storage.hpp @@ -15,7 +15,6 @@ #include #include #include -#include #include #if defined BOOST_CLANG #pragma clang diagnostic push diff --git a/include/boost/histogram/axis/variant.hpp b/include/boost/histogram/axis/variant.hpp index d23b9133..96b14501 100644 --- a/include/boost/histogram/axis/variant.hpp +++ b/include/boost/histogram/axis/variant.hpp @@ -34,8 +34,7 @@ struct get_polymorphic_bin_data template std::tuple operator()(const A& a) const { - return detail::static_if< - detail::has_value_method_with_return_type_convertible_to_x>( + return detail::static_if>( [this](const auto& a) { using Arg = detail::unqual>>; const auto x = a.value(idx); @@ -193,8 +192,7 @@ public: return visit( [idx](const auto& a) -> double { using A = detail::unqual; - return detail::static_if< - detail::has_value_method_with_return_type_convertible_to_x>( + return detail::static_if>( [idx](const auto& a) -> double { return static_cast(a.value(idx)); }, diff --git a/include/boost/histogram/detail/axes.hpp b/include/boost/histogram/detail/axes.hpp index 2b70c38f..4589ac95 100644 --- a/include/boost/histogram/detail/axes.hpp +++ b/include/boost/histogram/detail/axes.hpp @@ -319,13 +319,38 @@ optional_index args_to_index(const T& axes, const U& args) { return idx; } -template -constexpr int weight_index() { - const int n = sizeof...(Us) - 1; - using L = mp11::mp_list; - if (is_weight>::value) return 0; - if (is_weight>::value) return n; - return -1; +template +constexpr std::pair weight_sample_indices() { + if (is_weight::value) return std::make_pair(0, -1); + if (is_sample::value) return std::make_pair(-1, 0); + return std::make_pair(-1, -1); +} + +template +constexpr std::pair weight_sample_indices() { + using L = mp11::mp_list; + const int n = sizeof...(Us) + 1; + if (is_weight>::value) { + if (is_sample>::value) return std::make_pair(0, 1); + if (is_sample>::value) return std::make_pair(0, n); + return std::make_pair(0, -1); + } + if (is_sample>::value) { + if (is_weight>::value) return std::make_pair(1, 0); + if (is_weight>::value) return std::make_pair(n, 0); + return std::make_pair(-1, 0); + } + if (is_weight>::value) { + // 0, n already covered + if (is_sample>::value) return std::make_pair(n, n - 1); + return std::make_pair(n, -1); + } + if (is_sample>::value) { + // n, 0 already covered + if (is_weight>::value) return std::make_pair(n - 1, n); + return std::make_pair(-1, n); + } + return std::make_pair(-1, -1); } template @@ -343,22 +368,28 @@ void fill_storage_impl(mp11::mp_int, mp11::mp_int<-1>, S& storage, std::size template void fill_storage_impl(mp11::mp_int<-1>, mp11::mp_int, S& storage, std::size_t i, const T& args) { - storage(i, std::get(args).value); + mp11::tuple_apply([&](auto&&... sargs) { storage(i, sargs...); }, + std::get(args).value); } template -void fill_storage_impl(mp11::mp_int, mp11::mp_int, S& storage, std::size_t i, +void fill_storage_impl(mp11::mp_int, mp11::mp_int, S&, std::size_t i, const T& args) { - storage(i, std::get(args), std::get(args).value); + mp11::tuple_apply([&](auto&&... sargs) { storage(i, std::get(args), sargs...); }, + std::get(args).value); } template void fill_impl(S& storage, const T& axes, const std::tuple& args) { - constexpr int Iw = weight_index(); - constexpr unsigned N = Iw >= 0 ? sizeof...(Us) - 1 : sizeof...(Us); - optional_index idx = args_to_index<(Iw == 0 ? 1 : 0), N>(axes, args); + constexpr std::pair iws = weight_sample_indices(); + constexpr unsigned n = sizeof...(Us) - (iws.first > -1) - (iws.second > -1); + constexpr unsigned offset = (iws.first == 0 || iws.second == 0) + ? (iws.first == 1 || iws.second == 1 ? 2 : 1) + : 0; + optional_index idx = args_to_index(axes, args); if (idx) { - fill_storage_impl(mp11::mp_int(), mp11::mp_int<-1>(), storage, *idx, args); + fill_storage_impl(mp11::mp_int(), mp11::mp_int(), storage, + *idx, args); } } diff --git a/include/boost/histogram/detail/meta.hpp b/include/boost/histogram/detail/meta.hpp index da81f53e..fedb389e 100644 --- a/include/boost/histogram/detail/meta.hpp +++ b/include/boost/histogram/detail/meta.hpp @@ -121,14 +121,6 @@ decltype(auto) sub_tuple(const T& t) { template \ using name = typename name##_impl::type -BOOST_HISTOGRAM_MAKE_SFINAE(has_variance_support, - (std::declval().value(), std::declval().variance())); - -BOOST_HISTOGRAM_MAKE_SFINAE(has_method_value, (std::declval().value(0))); - -// TODO try casting to more specific pmf with correct return type -BOOST_HISTOGRAM_MAKE_SFINAE(has_method_options, (std::declval().options())); - BOOST_HISTOGRAM_MAKE_SFINAE(has_method_metadata, (std::declval().metadata())); // resize has two overloads, trying to get pmf in this case always fails @@ -138,6 +130,28 @@ BOOST_HISTOGRAM_MAKE_SFINAE(has_method_size, &T::size); BOOST_HISTOGRAM_MAKE_SFINAE(has_method_clear, &T::clear); +template +struct has_method_value_impl { + template ().value(0))> + static typename std::is_convertible::type Test(void*); + template + static std::false_type Test(...); + using type = decltype(Test(nullptr)); +}; +template +using has_method_value = typename has_method_value_impl::type; + +template +struct has_method_options_impl { + template ().options())> + static typename std::is_same::type Test(void*); + template + static std::false_type Test(...); + using type = decltype(Test(nullptr)); +}; +template +using has_method_options = typename has_method_options_impl::type; + BOOST_HISTOGRAM_MAKE_SFINAE(has_allocator, &T::get_allocator); BOOST_HISTOGRAM_MAKE_SFINAE(is_indexable, (std::declval()[0])); @@ -209,18 +223,6 @@ struct is_sample_impl> : std::true_type {}; template using is_sample = is_sample_impl>; -template -struct has_value_method_with_return_type_convertible_to_x_impl { - template ().value(0))> - static typename std::is_convertible::type Test(void*); - template - static std::false_type Test(...); - using type = decltype(Test(nullptr)); -}; -template -using has_value_method_with_return_type_convertible_to_x = - typename has_value_method_with_return_type_convertible_to_x_impl::type; - namespace { struct bool_mask_impl { std::vector& b; diff --git a/include/boost/histogram/sample.hpp b/include/boost/histogram/sample.hpp index c3a04d3f..041cfb38 100644 --- a/include/boost/histogram/sample.hpp +++ b/include/boost/histogram/sample.hpp @@ -7,6 +7,7 @@ #ifndef BOOST_HISTOGRAM_SAMPLE_HPP #define BOOST_HISTOGRAM_SAMPLE_HPP +#include #include namespace boost { @@ -18,10 +19,10 @@ struct sample_type { T value; }; -/// Helper function to mark argument as sample -template -sample_type sample(T&& t) { - return {std::forward(t)}; +/// Helper function to mark arguments as sample +template +sample_type> sample(Ts&&... ts) { + return {std::make_tuple(std::forward(ts)...)}; } } // namespace histogram diff --git a/include/boost/histogram/weight.hpp b/include/boost/histogram/weight.hpp index 7cfe0c51..460bb87a 100644 --- a/include/boost/histogram/weight.hpp +++ b/include/boost/histogram/weight.hpp @@ -20,8 +20,8 @@ struct weight_type { /// Helper function to mark argument as weight template -weight_type weight(T&& t) { - return {std::forward(t)}; +auto weight(T&& t) { + return weight_type{std::forward(t)}; } } // namespace histogram diff --git a/test/histogram_test.cpp b/test/histogram_test.cpp index 18dcc136..25afbbdb 100644 --- a/test/histogram_test.cpp +++ b/test/histogram_test.cpp @@ -13,7 +13,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -288,19 +290,16 @@ void run_tests() { // d1 mean { auto h = make_s(Tag(), std::vector>(), axis::integer<>(0, 2)); - // TODO - // h(0, 1); - // h(0, 2); - // h(0, 3); - // h(1, 2); - // h(1, 3); + h(0, sample(1)); + h(0, sample(2)); + h(0, sample(3)); + h(sample(2), 1); + h(sample(3), 1); - // BOOST_TEST_EQ(h[0].sum(), 3); - // BOOST_TEST_EQ(h[0].value(), 2); - // BOOST_TEST_IS_CLOSE(h[0].variance(), 0.666, 1e-2); - // BOOST_TEST_EQ(h[1].sum(), 2); - // BOOST_TEST_EQ(h[1].value(), 2.5); - // BOOST_TEST_IS_CLOSE(h[1].variance(), 0.25, 1e-2); + BOOST_TEST_EQ(h[0].sum(), 3); + BOOST_TEST_EQ(h[0].value(), 2); + BOOST_TEST_EQ(h[1].sum(), 2); + BOOST_TEST_EQ(h[1].value(), 2.5); } // d2 diff --git a/test/meta_test.cpp b/test/meta_test.cpp index f1a3d7ad..18f1ba38 100644 --- a/test/meta_test.cpp +++ b/test/meta_test.cpp @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include #include #include @@ -47,51 +49,36 @@ int main() { BOOST_TEST_EQ(decltype(j213)::value, 213); } - // has_variance_support - { - struct A {}; - - struct B { - void value() {} - }; - - struct C { - void variance() {} - }; - - struct D { - void value() {} - void variance() {} - }; - - BOOST_TEST_TRAIT_FALSE((has_variance_support)); - BOOST_TEST_TRAIT_FALSE((has_variance_support)); - BOOST_TEST_TRAIT_FALSE((has_variance_support)); - BOOST_TEST_TRAIT_TRUE((has_variance_support)); - } - // has_method_value { struct A {}; struct B { - void value(int) {} + A value(int) const { return {}; } + }; + struct C { + char value(int) const { return 0; } }; - BOOST_TEST_TRAIT_FALSE((has_method_value)); - BOOST_TEST_TRAIT_TRUE((has_method_value)); + BOOST_TEST_TRAIT_FALSE((has_method_value)); + BOOST_TEST_TRAIT_TRUE((has_method_value)); + BOOST_TEST_TRAIT_FALSE((has_method_value)); + BOOST_TEST_TRAIT_TRUE((has_method_value)); + BOOST_TEST_TRAIT_FALSE((has_method_value)); } // has_method_options { struct A {}; struct B { - bh::axis::option_type options() { return bh::axis::option_type(); } + void options() {} + }; + struct C { + bh::axis::option_type options() const { return {}; } }; - auto foo = static_cast>(&B::options); - BOOST_TEST_TRAIT_FALSE((has_method_options)); - BOOST_TEST_TRAIT_TRUE((has_method_options)); + BOOST_TEST_TRAIT_FALSE((has_method_options)); + BOOST_TEST_TRAIT_TRUE((has_method_options)); } // has_method_metadata @@ -436,5 +423,27 @@ int main() { BOOST_TEST_TRAIT_TRUE((is_axis_vector)); } + // is_weight + { + struct A {}; + using B = int; + using C = decltype(bh::weight(1)); + BOOST_TEST_TRAIT_FALSE((is_weight)); + BOOST_TEST_TRAIT_FALSE((is_weight)); + BOOST_TEST_TRAIT_TRUE((is_weight)); + } + + // is_sample + { + struct A {}; + using B = int; + using C = decltype(bh::sample(1)); + using D = decltype(bh::sample(1, 2.0)); + BOOST_TEST_TRAIT_FALSE((is_sample)); + BOOST_TEST_TRAIT_FALSE((is_sample)); + BOOST_TEST_TRAIT_TRUE((is_sample)); + BOOST_TEST_TRAIT_TRUE((is_sample)); + } + return boost::report_errors(); }