diff --git a/include/boost/histogram/axis/category.hpp b/include/boost/histogram/axis/category.hpp index 27405a6d..857000d4 100644 --- a/include/boost/histogram/axis/category.hpp +++ b/include/boost/histogram/axis/category.hpp @@ -166,15 +166,13 @@ private: #if __cpp_deduction_guides >= 201606 template -category(std::initializer_list)->category; - -category(std::initializer_list)->category; - -template -category(std::initializer_list, const char*)->category; +category(std::initializer_list) + ->category>, null_type>; template -category(std::initializer_list, const M&)->category; +category(std::initializer_list, M) + ->category>, + detail::replace_cstring>>; #endif diff --git a/include/boost/histogram/axis/integer.hpp b/include/boost/histogram/axis/integer.hpp index 5111454f..28d7dca3 100644 --- a/include/boost/histogram/axis/integer.hpp +++ b/include/boost/histogram/axis/integer.hpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include @@ -200,13 +200,12 @@ private: #if __cpp_deduction_guides >= 201606 template -integer(T, T)->integer>; - -template -integer(T, T, const char*)->integer>; +integer(T, T)->integer, null_type>; template -integer(T, T, M)->integer, M>; +integer(T, T, M) + ->integer, + detail::replace_type, const char*, std::string>>; #endif diff --git a/include/boost/histogram/axis/metadata_base.hpp b/include/boost/histogram/axis/metadata_base.hpp index aedc8473..ff3d99d3 100644 --- a/include/boost/histogram/axis/metadata_base.hpp +++ b/include/boost/histogram/axis/metadata_base.hpp @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include diff --git a/include/boost/histogram/axis/regular.hpp b/include/boost/histogram/axis/regular.hpp index 121559ab..e01c662f 100644 --- a/include/boost/histogram/axis/regular.hpp +++ b/include/boost/histogram/axis/regular.hpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include @@ -68,13 +68,13 @@ namespace transform { /// Identity transform for equidistant bins. struct id { /// Pass-through. - template + template static T forward(T&& x) noexcept { return std::forward(x); } /// Pass-through. - template + template static T inverse(T&& x) noexcept { return std::forward(x); } @@ -86,13 +86,13 @@ struct id { /// Log transform for equidistant bins in log-space. struct log { /// Returns log(x) of external value x. - template + template static T forward(T x) { return std::log(x); } /// Returns exp(x) for internal value x. - template + template static T inverse(T x) { return std::exp(x); } @@ -104,13 +104,13 @@ struct log { /// Sqrt transform for equidistant bins in sqrt-space. struct sqrt { /// Returns sqrt(x) of external value x. - template + template static T forward(T x) { return std::sqrt(x); } /// Returns x^2 of internal value x. - template + template static T inverse(T x) { return x * x; } @@ -128,13 +128,13 @@ struct pow { pow() = default; /// Returns pow(x, power) of external value x. - template + template auto forward(T x) const { return std::pow(x, power); } /// Returns pow(x, 1/power) of external value x. - template + template auto inverse(T x) const { return std::pow(x, 1.0 / power); } @@ -151,7 +151,7 @@ struct pow { #ifndef BOOST_HISTOGRAM_DOXYGEN_INVOKED // Type envelope to mark value as step size -template +template struct step_type { T value; }; @@ -160,7 +160,7 @@ struct step_type { /** Helper function to mark argument as step size. */ -template +template step_type step(T t) { return step_type{t}; } @@ -391,22 +391,21 @@ private: #if __cpp_deduction_guides >= 201606 template -regular(unsigned, T, T)->regular>; - -template -regular(unsigned, T, T, const char*)->regular>; +regular(unsigned, T, T) + ->regular, transform::id, null_type>; template -regular(unsigned, T, T, M)->regular, transform::id, M>; +regular(unsigned, T, T, M) + ->regular, transform::id, + detail::replace_cstring>>; -template -regular(Tr, unsigned, T, T)->regular, Tr>; - -template -regular(Tr, unsigned, T, T, const char*)->regular, Tr>; +template > +regular(Tr, unsigned, T, T)->regular, Tr, null_type>; template -regular(Tr, unsigned, T, T, M)->regular, Tr, M>; +regular(Tr, unsigned, T, T, M) + ->regular, Tr, + detail::replace_cstring>>; #endif diff --git a/include/boost/histogram/axis/variable.hpp b/include/boost/histogram/axis/variable.hpp index 3ca0ebfd..46feb0ad 100644 --- a/include/boost/histogram/axis/variable.hpp +++ b/include/boost/histogram/axis/variable.hpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -213,29 +213,28 @@ private: #if __cpp_deduction_guides >= 201606 -template > -variable(std::initializer_list)->variable; +template +variable(std::initializer_list) + ->variable, null_type>; -template > -variable(std::initializer_list, const char*)->variable; +template +variable(std::initializer_list, M) + ->variable, + detail::replace_type, const char*, std::string>>; -template > -variable(std::initializer_list, M)->variable; +template > +variable(Iterable) + ->variable< + detail::convert_integer< + std::decay_t()))>, double>, + null_type>; -template ()))>, double>> -variable(Iterable)->variable; - -template ()))>, double>> -variable(Iterable, const char*)->variable; - -template ()))>, double>> -variable(Iterable, M)->variable; +template +variable(Iterable, M) + ->variable< + detail::convert_integer< + std::decay_t()))>, double>, + detail::replace_type, const char*, std::string>>; #endif diff --git a/include/boost/histogram/detail/detect.hpp b/include/boost/histogram/detail/detect.hpp index ee25befe..b5b9fe46 100644 --- a/include/boost/histogram/detail/detect.hpp +++ b/include/boost/histogram/detail/detect.hpp @@ -57,7 +57,9 @@ BOOST_HISTOGRAM_DETAIL_DETECT(has_allocator, &T::get_allocator); BOOST_HISTOGRAM_DETAIL_DETECT(is_indexable, (std::declval()[0])); -BOOST_HISTOGRAM_DETAIL_DETECT(is_transform, (&T::forward, &T::inverse)); +BOOST_HISTOGRAM_DETAIL_DETECT_BINARY( + is_transform, + (std::declval().inverse(std::declval().forward(std::declval())))); BOOST_HISTOGRAM_DETAIL_DETECT(is_indexable_container, (std::declval()[0], &T::size, std::begin(std::declval()), @@ -135,7 +137,9 @@ using is_storage = mp11::mp_and, has_method_reset, has_threading_support>; template -using is_adaptible = mp11::mp_or, is_array_like, is_map_like>; +using is_adaptible = + mp11::mp_and>, + mp11::mp_or, is_array_like, is_map_like>>; template struct is_tuple_impl : mp11::mp_false {}; @@ -179,6 +183,9 @@ using is_sequence_of_any_axis = mp11::mp_and, is_any_axis>>; // poor-mans concept checks +template >::value>> +struct requires_storage {}; + template , class = std::enable_if_t<(is_storage<_>::value || is_adaptible<_>::value)>> struct requires_storage_or_adaptible {}; @@ -214,6 +221,10 @@ struct requires_axes {}; template ::value>> struct requires_convertible {}; +template , U>::value>> +struct requires_transform {}; + } // namespace detail } // namespace histogram } // namespace boost diff --git a/include/boost/histogram/detail/replace_default.hpp b/include/boost/histogram/detail/replace_default.hpp deleted file mode 100644 index 16c4c071..00000000 --- a/include/boost/histogram/detail/replace_default.hpp +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2015-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_REPLACE_DEFAULT_HPP -#define BOOST_HISTOGRAM_DETAIL_REPLACE_DEFAULT_HPP - -#include -#include - -namespace boost { -namespace histogram { -namespace detail { - -template -using replace_default = - std::conditional_t::value, Default, T>; - -} // namespace detail -} // namespace histogram -} // namespace boost - -#endif diff --git a/include/boost/histogram/detail/replace_type.hpp b/include/boost/histogram/detail/replace_type.hpp new file mode 100644 index 00000000..affe5b3d --- /dev/null +++ b/include/boost/histogram/detail/replace_type.hpp @@ -0,0 +1,31 @@ +// 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_REPLACE_TYPE_HPP +#define BOOST_HISTOGRAM_DETAIL_REPLACE_TYPE_HPP + +#include +#include +#include + +namespace boost { +namespace histogram { +namespace detail { + +template +using replace_type = std::conditional_t::value, To, T>; + +template +using replace_default = replace_type; + +template +using replace_cstring = replace_type; + +} // namespace detail +} // namespace histogram +} // namespace boost + +#endif diff --git a/include/boost/histogram/histogram.hpp b/include/boost/histogram/histogram.hpp index 590022cc..0e8224a8 100644 --- a/include/boost/histogram/histogram.hpp +++ b/include/boost/histogram/histogram.hpp @@ -99,17 +99,21 @@ public: return *this; } - template - histogram(A&& a, S&& s) + template > + histogram(A&& a, Storage s) : axes_(std::forward(a)) - , storage_(std::forward(s)) + , storage_(std::move(s)) , offset_(detail::offset(axes_)) { detail::throw_if_axes_is_too_large(axes_); storage_.reset(detail::bincount(axes_)); } - template > - explicit histogram(A&& a) : histogram(std::forward(a), storage_type()) {} + explicit histogram(Axes axes) : histogram(axes, storage_type()) {} + + template ...>>> + explicit histogram(As&&... as) + : histogram(std::tuple...>(std::forward(as)...), + storage_type()) {} /// Number of axes (dimensions). constexpr unsigned rank() const noexcept { return detail::axes_rank(axes_); } @@ -571,12 +575,25 @@ auto operator/(const histogram& h, double x) { #if __cpp_deduction_guides >= 201606 -template -histogram(Axes&& axes)->histogram, default_storage>; +template ...>>> +histogram(Axes...)->histogram...>>; -template -histogram(Axes&& axes, Storage&& storage) - ->histogram, std::decay_t>; +template > +histogram(std::tuple, S) + ->histogram, std::conditional_t::value, + storage_adaptor, S>>; + +template , + class = detail::requires_any_axis> +histogram(Iterable)->histogram>; + +template , + class = detail::requires_any_axis, + class = detail::requires_storage_or_adaptible> +histogram(Iterable, S) + ->histogram< + std::vector, + std::conditional_t::value, storage_adaptor, S>>; #endif diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b2e244e3..debac596 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -102,7 +102,7 @@ boost_test(TYPE run SOURCES detail_operators_test.cpp LIBRARIES Boost::histogram Boost::core) boost_test(TYPE run SOURCES detail_relaxed_equal_test.cpp LIBRARIES Boost::histogram Boost::core) -boost_test(TYPE run SOURCES detail_replace_default_test.cpp +boost_test(TYPE run SOURCES detail_replace_type_test.cpp LIBRARIES Boost::histogram Boost::core) boost_test(TYPE run SOURCES detail_safe_comparison_test.cpp LIBRARIES Boost::histogram Boost::core) diff --git a/test/Jamfile b/test/Jamfile index a68e6338..5616e585 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -62,7 +62,7 @@ alias cxx14 : [ run detail_large_int_test.cpp ] [ run detail_operators_test.cpp ] [ run detail_relaxed_equal_test.cpp ] - [ run detail_replace_default_test.cpp ] + [ run detail_replace_type_test.cpp ] [ run detail_safe_comparison_test.cpp ] [ run detail_static_if_test.cpp ] [ run detail_tuple_slice_test.cpp ] diff --git a/test/deduction_guides_test.cpp b/test/deduction_guides_test.cpp index 8e6ad547..2bd0f8bc 100644 --- a/test/deduction_guides_test.cpp +++ b/test/deduction_guides_test.cpp @@ -9,7 +9,6 @@ #include #include #include -#include "throw_exception.hpp" #include #include #include @@ -18,101 +17,129 @@ #include #include #include "std_ostream.hpp" +#include "throw_exception.hpp" using namespace boost::histogram; namespace tr = axis::transform; // tests requires a C++17 compatible compiler +#define TEST BOOST_TEST_TRAIT_SAME + int main() { - { - axis::regular a(1, 0.0, 1.0); - axis::regular b(1, 0, 1); - axis::regular c(1, 0.0f, 1.0f); - axis::regular d(1, 0, 1, "foo"); - axis::regular e(1, 0, 1, axis::null_type{}); - axis::regular f(tr::sqrt(), 1, 0, 1); - axis::regular g(tr::sqrt(), 1, 0, 1, "foo"); - axis::regular h(tr::sqrt(), 1, 0, 1, axis::null_type{}); + using axis::null_type; - BOOST_TEST_TRAIT_SAME(decltype(a), axis::regular<>); - BOOST_TEST_TRAIT_SAME(decltype(b), axis::regular<>); - BOOST_TEST_TRAIT_SAME(decltype(c), axis::regular); - BOOST_TEST_TRAIT_SAME(decltype(d), axis::regular<>); - BOOST_TEST_TRAIT_SAME(decltype(e), axis::regular); - BOOST_TEST_TRAIT_SAME(decltype(f), axis::regular); - BOOST_TEST_TRAIT_SAME(decltype(g), axis::regular); - BOOST_TEST_TRAIT_SAME(decltype(h), axis::regular); + { + using axis::regular; + BOOST_TEST_TRAIT_SAME(decltype(regular(1, 0.0, 1.0)), + regular); + BOOST_TEST_TRAIT_SAME(decltype(regular(1, 0, 1)), regular); + BOOST_TEST_TRAIT_SAME(decltype(regular(1, 0.0f, 1.0f)), + regular); + BOOST_TEST_TRAIT_SAME(decltype(regular(1, 0, 1, 0)), regular); + BOOST_TEST_TRAIT_SAME(decltype(regular(1, 0.0f, 1.0f, "x")), + regular); + BOOST_TEST_TRAIT_SAME(decltype(regular(tr::sqrt(), 1, 0, 1)), + regular); + BOOST_TEST_TRAIT_SAME(decltype(regular(tr::sqrt(), 1, 0.0f, 1.0f, "x")), + regular); + BOOST_TEST_TRAIT_SAME(decltype(regular(tr::sqrt(), 1, 0, 1, 0)), + regular); } { - axis::integer a(1, 2); - axis::integer b(1l, 2l); - axis::integer c(1.0, 2.0); - axis::integer d(1.0f, 2.0f); - axis::integer e(1, 2, "foo"); - axis::integer f(1, 2, axis::null_type{}); - - BOOST_TEST_TRAIT_SAME(decltype(a), axis::integer); - BOOST_TEST_TRAIT_SAME(decltype(b), axis::integer); - BOOST_TEST_TRAIT_SAME(decltype(c), axis::integer); - BOOST_TEST_TRAIT_SAME(decltype(d), axis::integer); - BOOST_TEST_TRAIT_SAME(decltype(e), axis::integer); - BOOST_TEST_TRAIT_SAME(decltype(f), axis::integer); + using axis::integer; + BOOST_TEST_TRAIT_SAME(decltype(integer(1, 2)), integer); + BOOST_TEST_TRAIT_SAME(decltype(integer(1l, 2l)), integer); + BOOST_TEST_TRAIT_SAME(decltype(integer(1.0, 2.0)), integer); + BOOST_TEST_TRAIT_SAME(decltype(integer(1.0f, 2.0f)), integer); + BOOST_TEST_TRAIT_SAME(decltype(integer(1, 2, "foo")), integer); + BOOST_TEST_TRAIT_SAME(decltype(integer(1, 2, 0)), integer); } { - axis::variable a{-1, 1}; - axis::variable b{-1.f, 1.f}; - axis::variable c{-1.0, 1.0}; - axis::variable d({-1, 1}, "foo"); - axis::variable e({-1, 1}, axis::null_type{}); + using axis::variable; + BOOST_TEST_TRAIT_SAME(decltype(variable{-1.0f, 1.0f}), variable); + BOOST_TEST_TRAIT_SAME(decltype(variable{-1, 0, 1, 2}), variable); + BOOST_TEST_TRAIT_SAME(decltype(variable{-1.0, 1.0}), variable); + BOOST_TEST_TRAIT_SAME(decltype(variable({-1, 0, 1}, "foo")), + variable); + BOOST_TEST_TRAIT_SAME(decltype(variable({-1, 1}, 0)), variable); - std::vector vi{{-1, 1}}; - std::vector vf{{-1.f, 1.f}}; - axis::variable f(vi); - axis::variable g(vf); - axis::variable h(vi, "foo"); - axis::variable i(vi, axis::null_type{}); - - BOOST_TEST_TRAIT_SAME(decltype(a), axis::variable<>); - BOOST_TEST_TRAIT_SAME(decltype(b), axis::variable); - BOOST_TEST_TRAIT_SAME(decltype(c), axis::variable<>); - BOOST_TEST_TRAIT_SAME(decltype(d), axis::variable<>); - BOOST_TEST_TRAIT_SAME(decltype(e), axis::variable); - BOOST_TEST_TRAIT_SAME(decltype(f), axis::variable<>); - BOOST_TEST_TRAIT_SAME(decltype(g), axis::variable); - BOOST_TEST_TRAIT_SAME(decltype(h), axis::variable<>); - BOOST_TEST_TRAIT_SAME(decltype(i), axis::variable); + BOOST_TEST_TRAIT_SAME(decltype(variable(std::vector{{-1, 1}})), + variable); + BOOST_TEST_TRAIT_SAME(decltype(variable(std::vector{{-1.0f, 1.0f}})), + variable); + BOOST_TEST_TRAIT_SAME(decltype(variable(std::vector{{-1, 1}}, "foo")), + variable); + BOOST_TEST_TRAIT_SAME(decltype(variable(std::vector{{-1, 1}}, 0)), + variable); } { - axis::category a{1, 2}; - axis::category b{"x", "y"}; - axis::category c({1, 2}, "foo"); - axis::category d({1, 2}, axis::null_type{}); - - BOOST_TEST_TRAIT_SAME(decltype(a), axis::category); - BOOST_TEST_TRAIT_SAME(decltype(b), axis::category); - BOOST_TEST_TRAIT_SAME(decltype(c), axis::category); - BOOST_TEST_TRAIT_SAME(decltype(d), axis::category); + using axis::category; + BOOST_TEST_TRAIT_SAME(decltype(category{1, 2}), category); + BOOST_TEST_TRAIT_SAME(decltype(category{"x", "y"}), category); + BOOST_TEST_TRAIT_SAME(decltype(category({1, 2}, "foo")), category); + BOOST_TEST_TRAIT_SAME(decltype(category({1, 2}, 0)), category); } { - auto a0 = axis::regular(3, -1, 1, axis::null_type{}); - auto a1 = axis::integer(0, 4, axis::null_type{}); - auto a = histogram(std::make_tuple(a0, a1)); - BOOST_TEST_EQ(a.rank(), 2); - BOOST_TEST_EQ(a.axis(0), a0); - BOOST_TEST_EQ(a.axis(1), a1); - - auto a2 = axis::regular(5, 0, 5, axis::null_type{}); - // don't use deduction guides for vector, support depends on stdc++ version - std::vector axes{{a0, a2}}; - auto b = histogram(axes, weight_storage()); - BOOST_TEST_EQ(b.rank(), 2); - BOOST_TEST_EQ(b.axis(0), a0); - BOOST_TEST_EQ(b.axis(1), a2); + auto h = histogram(axis::regular(3, -1, 1), axis::integer(0, 4)); + BOOST_TEST_TRAIT_SAME(decltype(h), + histogram, + axis::integer>>); + BOOST_TEST_EQ(h.axis(0), axis::regular(3, -1, 1)); + BOOST_TEST_EQ(h.axis(1), axis::integer(0, 4)); } + + { + auto h = histogram(std::tuple(axis::regular(3, -1, 1), axis::integer(0, 4)), + weight_storage()); + BOOST_TEST_TRAIT_SAME(decltype(h), + histogram, + axis::integer>, + weight_storage>); + BOOST_TEST_EQ(h.axis(0), axis::regular(3, -1, 1)); + BOOST_TEST_EQ(h.axis(1), axis::integer(0, 4)); + } + + { + auto a0 = axis::regular(5, 0, 5); + auto a1 = axis::regular(3, -1, 1); + auto axes = {a0, a1}; + auto h = histogram(axes); + BOOST_TEST_TRAIT_SAME( + decltype(h), histogram>>); + BOOST_TEST_EQ(h.rank(), 2); + BOOST_TEST_EQ(h.axis(0), a0); + BOOST_TEST_EQ(h.axis(1), a1); + } + + { + auto a0 = axis::regular(5, 0, 5); + auto a1 = axis::regular(3, -1, 1); + auto axes = {a0, a1}; + auto h = histogram(axes, weight_storage()); + BOOST_TEST_TRAIT_SAME( + decltype(h), + histogram>, weight_storage>); + BOOST_TEST_EQ(h.rank(), 2); + BOOST_TEST_EQ(h.axis(0), a0); + BOOST_TEST_EQ(h.axis(1), a1); + } + + { + auto a0 = axis::regular(5, 0, 5); + auto a1 = axis::regular(3, -1, 1); + auto axes = std::vector{{a0, a1}}; + auto h = histogram(axes); + BOOST_TEST_TRAIT_SAME( + decltype(h), histogram>>); + BOOST_TEST_EQ(h.rank(), 2); + BOOST_TEST_EQ(h.axis(0), a0); + BOOST_TEST_EQ(h.axis(1), a1); + } + return boost::report_errors(); } diff --git a/test/detail_detect_test.cpp b/test/detail_detect_test.cpp index 83252f3d..48e98ab6 100644 --- a/test/detail_detect_test.cpp +++ b/test/detail_detect_test.cpp @@ -155,12 +155,13 @@ int main() { { struct A {}; struct B { - double forward(double); - double inverse(double); + double forward(A); + A inverse(double); }; - BOOST_TEST_TRAIT_FALSE((is_transform)); - BOOST_TEST_TRAIT_TRUE((is_transform)); + BOOST_TEST_TRAIT_FALSE((is_transform)); + BOOST_TEST_TRAIT_TRUE((is_transform)); + BOOST_TEST_TRAIT_TRUE((is_transform)); } // is_vector_like diff --git a/test/detail_replace_default_test.cpp b/test/detail_replace_type_test.cpp similarity index 75% rename from test/detail_replace_default_test.cpp rename to test/detail_replace_type_test.cpp index bc9197c6..6318e11f 100644 --- a/test/detail_replace_default_test.cpp +++ b/test/detail_replace_type_test.cpp @@ -6,13 +6,15 @@ #include #include -#include +#include #include "std_ostream.hpp" using namespace boost::histogram::detail; int main() { + BOOST_TEST_TRAIT_SAME(replace_type, long); + BOOST_TEST_TRAIT_SAME(replace_type, int); BOOST_TEST_TRAIT_SAME(replace_default, char); BOOST_TEST_TRAIT_SAME(replace_default, int);