From a2bc4f428dd51fefaf6e83d6e0cf6190862c2fdf Mon Sep 17 00:00:00 2001 From: Hans Dembinski Date: Tue, 25 Apr 2017 10:10:22 +0200 Subject: [PATCH] use integral constants to access axis in histogram statically --- .../histogram/histogram_impl_dynamic.hpp | 6 --- .../boost/histogram/histogram_impl_static.hpp | 14 +++++- include/boost/histogram/literals.hpp | 45 +++++++++++++++++++ test/dynamic_histogram_test.cpp | 40 +++++++++-------- test/static_histogram_test.cpp | 39 ++++++++-------- 5 files changed, 99 insertions(+), 45 deletions(-) create mode 100644 include/boost/histogram/literals.hpp diff --git a/include/boost/histogram/histogram_impl_dynamic.hpp b/include/boost/histogram/histogram_impl_dynamic.hpp index efa3516f..72324cae 100644 --- a/include/boost/histogram/histogram_impl_dynamic.hpp +++ b/include/boost/histogram/histogram_impl_dynamic.hpp @@ -213,12 +213,6 @@ public: return axes_[i]; } - /// Return axis \a i (for conformity with histogram interface) - template const axis_type &axis() const { - BOOST_ASSERT_MSG(N < dim(), "axis index out of range"); - return axes_[N]; - } - /// Apply unary functor/function to each axis template void for_each_axis(Unary &unary) const { for (const auto &a : axes_) { diff --git a/include/boost/histogram/histogram_impl_static.hpp b/include/boost/histogram/histogram_impl_static.hpp index 3ad52509..1ed07528 100644 --- a/include/boost/histogram/histogram_impl_static.hpp +++ b/include/boost/histogram/histogram_impl_static.hpp @@ -150,14 +150,24 @@ public: /// Reset bin counters to zero void reset() { storage_ = std::move(Storage(storage_.size())); } - template + /// Get N-th axis + template + constexpr typename std::add_const< typename fusion::result_of::value_at_c::type>::type & - axis() const { + axis(std::integral_constant) const { static_assert(N < axes_size::value, "axis index out of range"); return fusion::at_c(axes_); } + // Get first axis (convenience for 1-d histograms) + constexpr + typename std::add_const< + typename fusion::result_of::value_at_c::type>::type & + axis() const { + return fusion::at_c<0>(axes_); + } + /// Apply unary functor/function to each axis template void for_each_axis(Unary &unary) const { fusion::for_each(axes_, unary); diff --git a/include/boost/histogram/literals.hpp b/include/boost/histogram/literals.hpp new file mode 100644 index 00000000..da10b9d7 --- /dev/null +++ b/include/boost/histogram/literals.hpp @@ -0,0 +1,45 @@ +// Copyright 2015-2017 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_LITERALS_HPP_ +#define _BOOST_HISTOGRAM_LITERALS_HPP_ + +#include + +namespace boost { +namespace histogram { +namespace literals { +namespace detail { + template struct char2int; + template <> struct char2int<'0'> { static constexpr unsigned value = 0; }; + template <> struct char2int<'1'> { static constexpr unsigned value = 1; }; + template <> struct char2int<'2'> { static constexpr unsigned value = 2; }; + template <> struct char2int<'3'> { static constexpr unsigned value = 3; }; + template <> struct char2int<'4'> { static constexpr unsigned value = 4; }; + template <> struct char2int<'5'> { static constexpr unsigned value = 5; }; + template <> struct char2int<'6'> { static constexpr unsigned value = 6; }; + template <> struct char2int<'7'> { static constexpr unsigned value = 7; }; + template <> struct char2int<'8'> { static constexpr unsigned value = 8; }; + template <> struct char2int<'9'> { static constexpr unsigned value = 9; }; + + template + constexpr unsigned parse() { return N; } + + template + constexpr unsigned parse() { return parse::value, Rest...>(); } +} // NS detail + +template +auto operator"" _c() -> decltype(std::integral_constant()>()) +{ + return std::integral_constant()>(); +} + +} // NS literals +} // NS histogram +} // NS boost + +#endif diff --git a/test/dynamic_histogram_test.cpp b/test/dynamic_histogram_test.cpp index 2144f23e..0dfd3460 100644 --- a/test/dynamic_histogram_test.cpp +++ b/test/dynamic_histogram_test.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -23,6 +24,7 @@ int main() { using namespace boost::histogram; + using namespace boost::histogram::literals; namespace mpl = boost::mpl; // init_0 @@ -40,7 +42,7 @@ int main() { auto h = histogram(regular_axis<>{3, -1, 1}); BOOST_TEST_EQ(h.dim(), 1u); BOOST_TEST_EQ(h.size(), 5u); - BOOST_TEST_EQ(shape(h.axis<0>()), 5); + BOOST_TEST_EQ(shape(h.axis(0_c)), 5); auto h2 = histogram>>( regular_axis<>{3, -1, 1}); @@ -53,8 +55,8 @@ int main() { integer_axis{-1, 1}); BOOST_TEST_EQ(h.dim(), 2u); BOOST_TEST_EQ(h.size(), 25u); - BOOST_TEST_EQ(shape(h.axis<0>()), 5); - BOOST_TEST_EQ(shape(h.axis<1>()), 5); + BOOST_TEST_EQ(shape(h.axis(0_c)), 5); + BOOST_TEST_EQ(shape(h.axis(1_c)), 5); auto h2 = histogram>>( regular_axis<>{3, -1, 1}, integer_axis{-1, 1}); @@ -106,8 +108,8 @@ int main() { v.push_back(regular_axis<>(100, -1, 1)); v.push_back(integer_axis(1, 6)); auto h = histogram(v.begin(), v.end()); - BOOST_TEST_EQ(h.axis<0>(), v[0]); - BOOST_TEST_EQ(h.axis<1>(), v[1]); + BOOST_TEST_EQ(h.axis(0_c), v[0]); + BOOST_TEST_EQ(h.axis(1_c), v[1]); BOOST_TEST_EQ(h.axis(0), v[0]); BOOST_TEST_EQ(h.axis(1), v[1]); } @@ -196,8 +198,8 @@ int main() { h.fill(10); BOOST_TEST_EQ(h.dim(), 1u); - BOOST_TEST_EQ(bins(h.axis<>()), 2); - BOOST_TEST_EQ(shape(h.axis<>()), 4); + BOOST_TEST_EQ(bins(h.axis()), 2); + BOOST_TEST_EQ(shape(h.axis()), 4); BOOST_TEST_EQ(h.sum(), 4.0); BOOST_TEST_THROWS(h.value(-2), std::out_of_range); @@ -224,8 +226,8 @@ int main() { h.fill(10); BOOST_TEST_EQ(h.dim(), 1u); - BOOST_TEST_EQ(bins(h.axis<>()), 2); - BOOST_TEST_EQ(shape(h.axis<>()), 2); + BOOST_TEST_EQ(bins(h.axis()), 2); + BOOST_TEST_EQ(shape(h.axis()), 2); BOOST_TEST_EQ(h.sum(), 2); BOOST_TEST_THROWS(h.value(-1), std::out_of_range); @@ -271,10 +273,10 @@ int main() { h.fill(-10, 0); BOOST_TEST_EQ(h.dim(), 2u); - BOOST_TEST_EQ(bins(h.axis<0>()), 2); - BOOST_TEST_EQ(shape(h.axis<0>()), 4); - BOOST_TEST_EQ(bins(h.axis<1>()), 3); - BOOST_TEST_EQ(shape(h.axis<1>()), 3); + BOOST_TEST_EQ(bins(h.axis(0_c)), 2); + BOOST_TEST_EQ(shape(h.axis(0_c)), 4); + BOOST_TEST_EQ(bins(h.axis(1_c)), 3); + BOOST_TEST_EQ(shape(h.axis(1_c)), 3); BOOST_TEST_EQ(h.sum(), 3); BOOST_TEST_EQ(h.value(-1, 0), 0.0); @@ -358,17 +360,17 @@ int main() { { auto h = make_dynamic_histogram(integer_axis(0, 3), integer_axis(0, 4), integer_axis(0, 5)); - for (auto i = 0; i < bins(h.axis<0>()); ++i) { - for (auto j = 0; j < bins(h.axis<1>()); ++j) { - for (auto k = 0; k < bins(h.axis<2>()); ++k) { + for (auto i = 0; i < bins(h.axis(0_c)); ++i) { + for (auto j = 0; j < bins(h.axis(1_c)); ++j) { + for (auto k = 0; k < bins(h.axis(2_c)); ++k) { h.wfill(i + j + k, i, j, k); } } } - for (auto i = 0; i < bins(h.axis<0>()); ++i) { - for (auto j = 0; j < bins(h.axis<1>()); ++j) { - for (auto k = 0; k < bins(h.axis<2>()); ++k) { + for (auto i = 0; i < bins(h.axis(0_c)); ++i) { + for (auto j = 0; j < bins(h.axis(1_c)); ++j) { + for (auto k = 0; k < bins(h.axis(2_c)); ++k) { BOOST_TEST_EQ(h.value(i, j, k), i + j + k); } } diff --git a/test/static_histogram_test.cpp b/test/static_histogram_test.cpp index 50975554..2d45b30b 100644 --- a/test/static_histogram_test.cpp +++ b/test/static_histogram_test.cpp @@ -14,12 +14,14 @@ #include #include #include +#include #include #include #include int main() { using namespace boost::histogram; + using namespace boost::histogram::literals; namespace mpl = boost::mpl; // init_0 @@ -41,7 +43,8 @@ int main() { regular_axis<>{3, -1, 1}); BOOST_TEST_EQ(h.dim(), 1); BOOST_TEST_EQ(h.size(), 5); - BOOST_TEST_EQ(shape(h.axis<0>()), 5); + BOOST_TEST_EQ(shape(h.axis(0_c)), 5); + BOOST_TEST_EQ(shape(h.axis()), 5); auto h2 = make_static_histogram_with>>( regular_axis<>{3, -1, 1}); @@ -54,8 +57,8 @@ int main() { regular_axis<>{3, -1, 1}, integer_axis{-1, 1}); BOOST_TEST_EQ(h.dim(), 2); BOOST_TEST_EQ(h.size(), 25); - BOOST_TEST_EQ(shape(h.axis<0>()), 5); - BOOST_TEST_EQ(shape(h.axis<1>()), 5); + BOOST_TEST_EQ(shape(h.axis(0_c)), 5); + BOOST_TEST_EQ(shape(h.axis(1_c)), 5); auto h2 = make_static_histogram_with>>( regular_axis<>{3, -1, 1}, integer_axis{-1, 1}); @@ -182,8 +185,8 @@ int main() { h.fill(10); BOOST_TEST_EQ(h.dim(), 1); - BOOST_TEST_EQ(bins(h.axis<0>()), 2); - BOOST_TEST_EQ(shape(h.axis<0>()), 4); + BOOST_TEST_EQ(bins(h.axis(0_c)), 2); + BOOST_TEST_EQ(shape(h.axis(0_c)), 4); BOOST_TEST_EQ(h.sum(), 4); BOOST_TEST_THROWS(h.value(-2), std::out_of_range); @@ -210,8 +213,8 @@ int main() { h.fill(10); BOOST_TEST_EQ(h.dim(), 1); - BOOST_TEST_EQ(bins(h.axis<0>()), 2); - BOOST_TEST_EQ(shape(h.axis<0>()), 2); + BOOST_TEST_EQ(bins(h.axis(0_c)), 2); + BOOST_TEST_EQ(shape(h.axis(0_c)), 2); BOOST_TEST_EQ(h.sum(), 2); BOOST_TEST_THROWS(h.value(-1), std::out_of_range); @@ -275,10 +278,10 @@ int main() { h.fill(-10, 0); BOOST_TEST_EQ(h.dim(), 2); - BOOST_TEST_EQ(bins(h.axis<0>()), 2); - BOOST_TEST_EQ(shape(h.axis<0>()), 4); - BOOST_TEST_EQ(bins(h.axis<1>()), 3); - BOOST_TEST_EQ(shape(h.axis<1>()), 3); + BOOST_TEST_EQ(bins(h.axis(0_c)), 2); + BOOST_TEST_EQ(shape(h.axis(0_c)), 4); + BOOST_TEST_EQ(bins(h.axis(1_c)), 3); + BOOST_TEST_EQ(shape(h.axis(1_c)), 3); BOOST_TEST_EQ(h.sum(), 3); BOOST_TEST_EQ(h.value(-1, 0), 0.0); @@ -362,17 +365,17 @@ int main() { { auto h = make_static_histogram(integer_axis(0, 3), integer_axis(0, 4), integer_axis(0, 5)); - for (auto i = 0; i < bins(h.axis<0>()); ++i) { - for (auto j = 0; j < bins(h.axis<1>()); ++j) { - for (auto k = 0; k < bins(h.axis<2>()); ++k) { + for (auto i = 0; i < bins(h.axis(0_c)); ++i) { + for (auto j = 0; j < bins(h.axis(1_c)); ++j) { + for (auto k = 0; k < bins(h.axis(2_c)); ++k) { h.wfill(i + j + k, i, j, k); } } } - for (auto i = 0; i < bins(h.axis<0>()); ++i) { - for (auto j = 0; j < bins(h.axis<1>()); ++j) { - for (auto k = 0; k < bins(h.axis<2>()); ++k) { + for (auto i = 0; i < bins(h.axis(0_c)); ++i) { + for (auto j = 0; j < bins(h.axis(1_c)); ++j) { + for (auto k = 0; k < bins(h.axis(2_c)); ++k) { BOOST_TEST_EQ(h.value(i, j, k), i + j + k); } } @@ -488,7 +491,7 @@ int main() { std::ostringstream os1; // access histogram counts - for (const auto &b : h.axis<0>()) { + for (const auto &b : h.axis(0_c)) { os1 << "bin " << b.idx << " x in [" << b.left << ", " << b.right << "): " << h.value(b.idx) << " +/- " << std::sqrt(h.variance(b.idx)) << "\n";