From b482598597d25eb29239806fe91f1853a6b54b4a Mon Sep 17 00:00:00 2001 From: Hans Dembinski Date: Thu, 30 Sep 2021 13:49:22 +0200 Subject: [PATCH] cpp17: set axis compile-time options via deduction guide (#340) --- include/boost/histogram/axis/boolean.hpp | 2 +- include/boost/histogram/axis/category.hpp | 65 +++++++++++----- include/boost/histogram/axis/integer.hpp | 23 ++++-- include/boost/histogram/axis/regular.hpp | 65 ++++++++++------ include/boost/histogram/axis/variable.hpp | 95 +++++++++++++++-------- test/deduction_guides_test.cpp | 13 ++++ 6 files changed, 180 insertions(+), 83 deletions(-) diff --git a/include/boost/histogram/axis/boolean.hpp b/include/boost/histogram/axis/boolean.hpp index d5fee96c..0549b70b 100644 --- a/include/boost/histogram/axis/boolean.hpp +++ b/include/boost/histogram/axis/boolean.hpp @@ -40,7 +40,7 @@ class boolean : public iterator_mixin>, public: /** Construct a boolean axis. * - * \param meta description of the axis. + * @param meta description of the axis. */ explicit boolean(metadata_type meta = {}) : metadata_base(std::move(meta)) {} diff --git a/include/boost/histogram/axis/category.hpp b/include/boost/histogram/axis/category.hpp index 846fa0f9..9871e9b7 100644 --- a/include/boost/histogram/axis/category.hpp +++ b/include/boost/histogram/axis/category.hpp @@ -67,14 +67,17 @@ public: /** Construct from iterator range of unique values. * - * \param begin begin of category range of unique values. - * \param end end of category range of unique values. - * \param meta description of the axis. - * \param alloc allocator instance to use. + * @param begin begin of category range of unique values. + * @param end end of category range of unique values. + * @param meta description of the axis (optional). + * @param options see boost::histogram::axis::option (optional). + * @param alloc allocator instance to use (optional). */ template > - category(It begin, It end, metadata_type meta = {}, allocator_type alloc = {}) + category(It begin, It end, metadata_type meta = {}, options_type options = {}, + allocator_type alloc = {}) : metadata_base(std::move(meta)), vec_(alloc) { + (void)options; if (std::distance(begin, end) < 0) BOOST_THROW_EXCEPTION( std::invalid_argument("end must be reachable by incrementing begin")); @@ -82,32 +85,51 @@ public: while (begin != end) vec_.emplace_back(*begin++); } + // kept for backward compatibility + template > + category(It begin, It end, metadata_type meta, allocator_type alloc) + : category(begin, end, std::move(meta), {}, std::move(alloc)) {} + /** Construct axis from iterable sequence of unique values. * - * \param iterable sequence of unique values. - * \param meta description of the axis. - * \param alloc allocator instance to use. + * @param iterable sequence of unique values. + * @param meta description of the axis. + * @param options see boost::histogram::axis::option (optional). + * @param alloc allocator instance to use. */ template > - category(const C& iterable, metadata_type meta = {}, allocator_type alloc = {}) - : category(std::begin(iterable), std::end(iterable), std::move(meta), + category(const C& iterable, metadata_type meta = {}, options_type options = {}, + allocator_type alloc = {}) + : category(std::begin(iterable), std::end(iterable), std::move(meta), options, + std::move(alloc)) {} + + // kept for backward compatibility + template > + category(const C& iterable, metadata_type meta, allocator_type alloc) + : category(std::begin(iterable), std::end(iterable), std::move(meta), {}, std::move(alloc)) {} /** Construct axis from an initializer list of unique values. * - * \param list `std::initializer_list` of unique values. - * \param meta description of the axis. - * \param alloc allocator instance to use. + * @param list `std::initializer_list` of unique values. + * @param meta description of the axis. + * @param options see boost::histogram::axis::option (optional). + * @param alloc allocator instance to use. */ template category(std::initializer_list list, metadata_type meta = {}, - allocator_type alloc = {}) - : category(list.begin(), list.end(), std::move(meta), std::move(alloc)) {} + options_type options = {}, allocator_type alloc = {}) + : category(list.begin(), list.end(), std::move(meta), options, std::move(alloc)) {} + + // kept for backward compatibility + template + category(std::initializer_list list, metadata_type meta, allocator_type alloc) + : category(list.begin(), list.end(), std::move(meta), {}, std::move(alloc)) {} /// Constructor used by algorithm::reduce to shrink and rebin (not for users). category(const category& src, index_type begin, index_type end, unsigned merge) // LCOV_EXCL_START: gcc-8 is missing the delegated ctor for no reason - : category(src.vec_.begin() + begin, src.vec_.begin() + end, src.metadata(), + : category(src.vec_.begin() + begin, src.vec_.begin() + end, src.metadata(), {}, src.get_allocator()) // LCOV_EXCL_STOP { @@ -189,12 +211,17 @@ private: template category(std::initializer_list) - ->category>, null_type>; + -> category>, null_type>; template category(std::initializer_list, M) - ->category>, - detail::replace_cstring>>; + -> category>, + detail::replace_cstring>>; + +template +category(std::initializer_list, M, const option::bitset&) + -> category>, + detail::replace_cstring>, option::bitset>; #endif diff --git a/include/boost/histogram/axis/integer.hpp b/include/boost/histogram/axis/integer.hpp index e6b3b6f4..4110875c 100644 --- a/include/boost/histogram/axis/integer.hpp +++ b/include/boost/histogram/axis/integer.hpp @@ -34,9 +34,9 @@ namespace axis { Binning is a O(1) operation. This axis bins faster than a regular axis. - @tparam Value input value type. Must be integer or floating point. - @tparam MetaData type to store meta data. - @tparam Options see boost::histogram::axis::option (all values allowed). + @tparam Value input value type. Must be integer or floating point. + @tparam MetaData type to store meta data. + @tparam Options see boost::histogram::axis::option. */ template class integer : public iterator_mixin>, @@ -73,14 +73,17 @@ public: /** Construct over semi-open integer interval [start, stop). * - * \param start first integer of covered range. - * \param stop one past last integer of covered range. - * \param meta description of the axis. + * @param start first integer of covered range. + * @param stop one past last integer of covered range. + * @param meta description of the axis (optional). + * @param options see boost::histogram::axis::option (optional). */ - integer(value_type start, value_type stop, metadata_type meta = {}) + integer(value_type start, value_type stop, metadata_type meta = {}, + options_type options = {}) : metadata_base(std::move(meta)) , size_(static_cast(stop - start)) , min_(start) { + (void)options; if (!(stop >= start)) BOOST_THROW_EXCEPTION(std::invalid_argument("stop >= start required")); } @@ -217,6 +220,12 @@ integer(T, T, M) -> integer, detail::replace_type, const char*, std::string>>; +template +integer(T, T, M, const option::bitset&) + -> integer, + detail::replace_type, const char*, std::string>, + option::bitset>; + #endif } // namespace axis diff --git a/include/boost/histogram/axis/regular.hpp b/include/boost/histogram/axis/regular.hpp index 319b2fe8..3f7df9e0 100644 --- a/include/boost/histogram/axis/regular.hpp +++ b/include/boost/histogram/axis/regular.hpp @@ -173,7 +173,7 @@ step_type step(T t) { @tparam Value input value type, must be floating point. @tparam Transform builtin or user-defined transform type. @tparam MetaData type to store meta data. - @tparam Options see boost::histogram::axis::option (all values allowed). + @tparam Options see boost::histogram::axis::option. */ template class regular : public iterator_mixin>, @@ -213,14 +213,16 @@ public: * @param start low edge of first bin. * @param stop high edge of last bin. * @param meta description of the axis (optional). + * @param options see boost::histogram::axis::option (optional). */ regular(transform_type trans, unsigned n, value_type start, value_type stop, - metadata_type meta = {}) + metadata_type meta = {}, options_type options = {}) : transform_type(std::move(trans)) , metadata_base(std::move(meta)) , size_(static_cast(n)) , min_(this->forward(detail::get_scale(start))) , delta_(this->forward(detail::get_scale(stop)) - min_) { + (void)options; if (size() == 0) BOOST_THROW_EXCEPTION(std::invalid_argument("bins > 0 required")); if (!std::isfinite(min_) || !std::isfinite(delta_)) BOOST_THROW_EXCEPTION( @@ -235,18 +237,21 @@ public: * @param start low edge of first bin. * @param stop high edge of last bin. * @param meta description of the axis (optional). + * @param options see boost::histogram::axis::option (optional). */ - regular(unsigned n, value_type start, value_type stop, metadata_type meta = {}) - : regular({}, n, start, stop, std::move(meta)) {} + regular(unsigned n, value_type start, value_type stop, metadata_type meta = {}, + options_type options = {}) + : regular({}, n, start, stop, std::move(meta), options) {} /** Construct bins with the given step size over real transformed range * [start, stop). * - * @param trans transform instance to use. - * @param step width of a single bin. - * @param start low edge of first bin. - * @param stop upper limit of high edge of last bin (see below). - * @param meta description of the axis (optional). + * @param trans transform instance to use. + * @param step width of a single bin. + * @param start low edge of first bin. + * @param stop upper limit of high edge of last bin (see below). + * @param meta description of the axis (optional). + * @param options see boost::histogram::axis::option (optional). * * The axis computes the number of bins as n = abs(stop - start) / step, * rounded down. This means that stop is an upper limit to the actual value @@ -254,27 +259,29 @@ public: */ template regular(transform_type trans, step_type step, value_type start, value_type stop, - metadata_type meta = {}) + metadata_type meta = {}, options_type options = {}) : regular(trans, static_cast(std::abs(stop - start) / step.value), start, start + static_cast(std::abs(stop - start) / step.value) * step.value, - std::move(meta)) {} + std::move(meta), options) {} /** Construct bins with the given step size over real range [start, stop). * - * @param step width of a single bin. - * @param start low edge of first bin. - * @param stop upper limit of high edge of last bin (see below). - * @param meta description of the axis (optional). + * @param step width of a single bin. + * @param start low edge of first bin. + * @param stop upper limit of high edge of last bin (see below). + * @param meta description of the axis (optional). + * @param options see boost::histogram::axis::option (optional). * * The axis computes the number of bins as n = abs(stop - start) / step, * rounded down. This means that stop is an upper limit to the actual value * (start + n * step). */ template - regular(step_type step, value_type start, value_type stop, metadata_type meta = {}) - : regular({}, step, start, stop, std::move(meta)) {} + regular(step_type step, value_type start, value_type stop, metadata_type meta = {}, + options_type options = {}) + : regular({}, step, start, stop, std::move(meta), options) {} /// Constructor used by algorithm::reduce to shrink and rebin (not for users). regular(const regular& src, index_type begin, index_type end, unsigned merge) @@ -397,20 +404,28 @@ private: template regular(unsigned, T, T) - ->regular, transform::id, null_type>; + -> regular, transform::id, null_type>; template -regular(unsigned, T, T, M) - ->regular, transform::id, - detail::replace_cstring>>; +regular(unsigned, T, T, M) -> regular, transform::id, + detail::replace_cstring>>; + +template +regular(unsigned, T, T, M, const option::bitset&) + -> regular, transform::id, + detail::replace_cstring>, option::bitset>; template > -regular(Tr, unsigned, T, T)->regular, Tr, null_type>; +regular(Tr, unsigned, T, T) -> regular, Tr, null_type>; template -regular(Tr, unsigned, T, T, M) - ->regular, Tr, - detail::replace_cstring>>; +regular(Tr, unsigned, T, T, M) -> regular, Tr, + detail::replace_cstring>>; + +template +regular(Tr, unsigned, T, T, M, const option::bitset&) + -> regular, Tr, + detail::replace_cstring>, option::bitset>; #endif diff --git a/include/boost/histogram/axis/variable.hpp b/include/boost/histogram/axis/variable.hpp index dc0cc38d..f80e54c1 100644 --- a/include/boost/histogram/axis/variable.hpp +++ b/include/boost/histogram/axis/variable.hpp @@ -40,9 +40,9 @@ namespace axis { Binning is a O(log(N)) operation. If speed matters and the problem domain allows it, prefer a regular axis, possibly with a transform. - @tparam Value input value type, must be floating point. - @tparam MetaData type to store meta data. - @tparam Options see boost::histogram::axis::option (all values allowed). + @tparam Value input value type, must be floating point. + @tparam MetaData type to store meta data. + @tparam Options see boost::histogram::axis::option. @tparam Allocator allocator to use for dynamic memory management. */ template @@ -73,14 +73,18 @@ public: /** Construct from iterator range of bin edges. * - * \param begin begin of edge sequence. - * \param end end of edge sequence. - * \param meta description of the axis. - * \param alloc allocator instance to use. + * @param begin begin of edge sequence. + * @param end end of edge sequence. + * @param meta description of the axis (optional). + * @param options see boost::histogram::axis::option (optional). + * @param alloc allocator instance to use (optional). */ template > - variable(It begin, It end, metadata_type meta = {}, allocator_type alloc = {}) + variable(It begin, It end, metadata_type meta = {}, options_type options = {}, + allocator_type alloc = {}) : metadata_base(std::move(meta)), vec_(std::move(alloc)) { + (void)options; + if (std::distance(begin, end) < 2) BOOST_THROW_EXCEPTION(std::invalid_argument("bins > 0 required")); @@ -96,27 +100,46 @@ public: std::invalid_argument("input sequence must be strictly ascending")); } + // kept for backward compatibility + template > + variable(It begin, It end, metadata_type meta, allocator_type alloc) + : variable(begin, end, std::move(meta), {}, std::move(alloc)) {} + /** Construct variable axis from iterable range of bin edges. * - * \param iterable iterable range of bin edges. - * \param meta description of the axis. - * \param alloc allocator instance to use. + * @param iterable iterable range of bin edges. + * @param meta description of the axis (optional). + * @param options see boost::histogram::axis::option (optional). + * @param alloc allocator instance to use (optional). */ template > - variable(const U& iterable, metadata_type meta = {}, allocator_type alloc = {}) - : variable(std::begin(iterable), std::end(iterable), std::move(meta), + variable(const U& iterable, metadata_type meta = {}, options_type options = {}, + allocator_type alloc = {}) + : variable(std::begin(iterable), std::end(iterable), std::move(meta), options, + std::move(alloc)) {} + + // kept for backward compatibility + template > + variable(const U& iterable, metadata_type meta, allocator_type alloc) + : variable(std::begin(iterable), std::end(iterable), std::move(meta), {}, std::move(alloc)) {} /** Construct variable axis from initializer list of bin edges. * - * @param list `std::initializer_list` of bin edges. - * @param meta description of the axis. - * @param alloc allocator instance to use. + * @param list `std::initializer_list` of bin edges. + * @param meta description of the axis (optional). + * @param options see boost::histogram::axis::option (optional). + * @param alloc allocator instance to use (optional). */ template variable(std::initializer_list list, metadata_type meta = {}, - allocator_type alloc = {}) - : variable(list.begin(), list.end(), std::move(meta), std::move(alloc)) {} + options_type options = {}, allocator_type alloc = {}) + : variable(list.begin(), list.end(), std::move(meta), options, std::move(alloc)) {} + + // kept for backward compatibility + template + variable(std::initializer_list list, metadata_type meta, allocator_type alloc) + : variable(list.begin(), list.end(), std::move(meta), {}, std::move(alloc)) {} /// Constructor used by algorithm::reduce to shrink and rebin (not for users). variable(const variable& src, index_type begin, index_type end, unsigned merge) @@ -221,26 +244,36 @@ private: template variable(std::initializer_list) - ->variable, null_type>; + -> variable, null_type>; template variable(std::initializer_list, M) - ->variable, - detail::replace_type, const char*, std::string>>; + -> variable, + detail::replace_type, const char*, std::string>>; + +template +variable(std::initializer_list, M, const option::bitset&) + -> variable, + detail::replace_type, const char*, std::string>, + option::bitset>; template > -variable(Iterable) - ->variable< - detail::convert_integer< - std::decay_t()))>, double>, - null_type>; +variable(Iterable) -> variable< + detail::convert_integer< + std::decay_t()))>, double>, + null_type>; template -variable(Iterable, M) - ->variable< - detail::convert_integer< - std::decay_t()))>, double>, - detail::replace_type, const char*, std::string>>; +variable(Iterable, M) -> variable< + detail::convert_integer< + std::decay_t()))>, double>, + detail::replace_type, const char*, std::string>>; + +template +variable(Iterable, M, const option::bitset&) -> variable< + detail::convert_integer< + std::decay_t()))>, double>, + detail::replace_type, const char*, std::string>, option::bitset>; #endif diff --git a/test/deduction_guides_test.cpp b/test/deduction_guides_test.cpp index d70d5825..9aca4f9c 100644 --- a/test/deduction_guides_test.cpp +++ b/test/deduction_guides_test.cpp @@ -21,6 +21,7 @@ using namespace boost::histogram; namespace tr = axis::transform; +namespace op = axis::option; // tests requires a C++17 compatible compiler @@ -43,6 +44,10 @@ int main() { regular); BOOST_TEST_TRAIT_SAME(decltype(regular(tr::sqrt(), 1, 0, 1, 0)), regular); + BOOST_TEST_TRAIT_SAME(decltype(regular(1, 0, 1, "x", op::growth)), + regular); + BOOST_TEST_TRAIT_SAME(decltype(regular(tr::sqrt(), 1, 0, 1, "x", op::growth)), + regular); } { @@ -53,6 +58,8 @@ int main() { 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); + BOOST_TEST_TRAIT_SAME(decltype(integer(1, 2, "foo", op::growth)), + integer); } { @@ -63,6 +70,8 @@ int main() { BOOST_TEST_TRAIT_SAME(decltype(variable({-1, 0, 1}, "foo")), variable); BOOST_TEST_TRAIT_SAME(decltype(variable({-1, 1}, 0)), variable); + BOOST_TEST_TRAIT_SAME(decltype(variable({-1, 1}, "foo", op::underflow)), + variable); BOOST_TEST_TRAIT_SAME(decltype(variable(std::vector{{-1, 1}})), variable); @@ -72,6 +81,8 @@ int main() { variable); BOOST_TEST_TRAIT_SAME(decltype(variable(std::vector{{-1, 1}}, 0)), variable); + BOOST_TEST_TRAIT_SAME(decltype(variable({-1, 1}, "foo", op::growth)), + variable); } { @@ -80,6 +91,8 @@ int main() { 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); + BOOST_TEST_TRAIT_SAME(decltype(category({1, 2}, "foo", op::growth)), + category); } {