diff --git a/include/boost/histogram/axis.hpp b/include/boost/histogram/axis.hpp index 4105ae99..d5615db7 100644 --- a/include/boost/histogram/axis.hpp +++ b/include/boost/histogram/axis.hpp @@ -22,70 +22,67 @@ namespace boost { namespace histogram { -namespace detail { +template +struct bin +{ + int idx; + Value value; +}; +template <> +struct bin +{ + int idx; + boost::string_ref value; +}; + +template +struct real_bin +{ + int idx; + Value left, right; +}; + +template +using axis_bin = typename std::conditional< + std::is_floating_point::value, + real_bin, + bin +>::type; + +template +class axis_iterator : public iterator_facade< + axis_iterator, + const axis_bin, + random_access_traversal_tag + > +{ + using bin_type = axis_bin; + +public: + explicit axis_iterator(const Axis& axis, int idx) : + axis_(axis), value_() + { value_.idx = idx; set_impl(value_); } + +private: + void increment() { ++value_.idx; set_impl(value_); } + void decrement() { --value_.idx; set_impl(value_); } + void advance(int n) { value_.idx += n; set_impl(value_); } + int distance_to(const axis_iterator& other) const + { return other.value_.idx - value_.idx; } + bool equal(const axis_iterator& other) const + { return value_.idx == other.value_.idx; } + const bin_type& dereference() const { return value_; } template - struct bin - { - int idx; - Value value; - }; - - template <> - struct bin - { - int idx; - boost::string_ref value; - }; - + void set_impl(bin& v) + { v.value = axis_[v.idx]; } template - struct real_bin - { - int idx; - Value left, right; - }; - - template - using axis_bin = typename std::conditional< - std::is_floating_point::value, - real_bin, - bin - >::type; - - template - class axis_iterator : public iterator_facade< - axis_iterator, - const axis_bin, - random_access_traversal_tag - > - { - using bin_type = axis_bin; - - public: - explicit axis_iterator(const Axis& axis, int idx) : - axis_(axis), value_() - { value_.idx = idx; set_impl(value_); } - - private: - void increment() { ++value_.idx; set_impl(value_); } - void decrement() { --value_.idx; set_impl(value_); } - void advance(int n) { value_.idx += n; set_impl(value_); } - int distance_to(const axis_iterator& other) const - { return other.value_.idx - value_.idx; } - bool equal(const axis_iterator& other) const - { return value_.idx == other.value_.idx; } - const bin_type& dereference() const { return value_; } - template - void set_impl(bin& v) - { v.value = axis_[v.idx]; } - template - void set_impl(real_bin& v) - { v.left = axis_[v.idx]; v.right = axis_[v.idx + 1]; } - const Axis& axis_; - bin_type value_; - friend class boost::iterator_core_access; - }; -} // NS detail + void set_impl(real_bin& v) + { v.left = axis_[v.idx]; v.right = axis_[v.idx + 1]; } + const Axis& axis_; + bin_type value_; + friend class boost::iterator_core_access; +}; /// Common base class for axes. template @@ -204,7 +201,7 @@ template class regular_axis: public axis_base { public: using value_type = RealType; - using const_iterator = detail::axis_iterator; + using const_iterator = axis_iterator; /** Construct axis with n bins over range [min, max). * @@ -280,7 +277,7 @@ template class circular_axis: public axis_base { public: using value_type = RealType; - using const_iterator = detail::axis_iterator; + using const_iterator = axis_iterator; /** Constructor for n bins with an optional offset. * @@ -349,7 +346,7 @@ template class variable_axis : public axis_base { public: using value_type = RealType; - using const_iterator = detail::axis_iterator; + using const_iterator = axis_iterator; /** Construct an axis from bin edges. * @@ -454,7 +451,7 @@ private: class integer_axis: public axis_base { public: using value_type = int; - using const_iterator = detail::axis_iterator; + using const_iterator = axis_iterator; /** Construct axis over integer range [min, max]. * @@ -515,7 +512,7 @@ private: class category_axis : public axis_base { public: using value_type = const std::string&; - using const_iterator = detail::axis_iterator; + using const_iterator = axis_iterator; template category_axis(Iterator begin, Iterator end, diff --git a/include/boost/histogram/dynamic_histogram.hpp b/include/boost/histogram/dynamic_histogram.hpp index f9a076e2..d928c0c2 100644 --- a/include/boost/histogram/dynamic_histogram.hpp +++ b/include/boost/histogram/dynamic_histogram.hpp @@ -275,6 +275,8 @@ public: return axes_[N]; } + const axes_type& axes() const { return axes_; } + private: axes_type axes_; Storage storage_; diff --git a/include/boost/histogram/histogram_ostream_operators.hpp b/include/boost/histogram/histogram_ostream_operators.hpp new file mode 100644 index 00000000..59d542ab --- /dev/null +++ b/include/boost/histogram/histogram_ostream_operators.hpp @@ -0,0 +1,57 @@ +// Copyright 2015-2016 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_HISTOGRAM_STREAMER_HPP_ +#define _BOOST_HISTOGRAM_HISTOGRAM_STREAMER_HPP_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace histogram { + +namespace detail { + struct axis_ostream_visitor : public static_visitor { + std::ostream& os_; + axis_ostream_visitor(std::ostream& os) : os_(os) {} + template + void operator()(const Axis& a) const + { os_ << "\n " << a << ","; } + }; +} + +template +inline std::ostream& operator<<(std::ostream& os, const static_histogram& h) +{ + os << "histogram("; + detail::axis_ostream_visitor sh(os); + fusion::for_each(h.axes(), sh); + os << (h.dim() ? "\n)" : ")"); + return os; +} + +template +inline std::ostream& operator<<(std::ostream& os, const dynamic_histogram& h) +{ + os << "histogram("; + detail::axis_ostream_visitor sh(os); + for (const auto& a : h.axes()) + apply_visitor(sh, a); + os << (h.dim() ? "\n)" : ")"); + return os; +} + +} // NS histogram +} // NS boost + +#endif diff --git a/include/boost/histogram/static_histogram.hpp b/include/boost/histogram/static_histogram.hpp index 6d2f6ec7..2a45505c 100644 --- a/include/boost/histogram/static_histogram.hpp +++ b/include/boost/histogram/static_histogram.hpp @@ -257,6 +257,8 @@ public: return fusion::at_c(axes_); } + const axes_type& axes() const { return axes_; } + private: axes_type axes_; Storage storage_; diff --git a/src/python/axis.cpp b/src/python/axis.cpp index 8cf3ed48..bdf99627 100644 --- a/src/python/axis.cpp +++ b/src/python/axis.cpp @@ -93,19 +93,7 @@ category_axis_init(python::tuple args, python::dict kwargs) { template int axis_len(const T& t) { - return t.bins() + 1; -} - -template <> -int -axis_len(const category_axis& t) { - return t.bins(); -} - -template <> -int -axis_len(const integer_axis& t) { - return t.bins(); + return t.bins() + int(std::is_floating_point::value); } template diff --git a/src/python/histogram.cpp b/src/python/histogram.cpp index 59ff392f..697fc3fc 100644 --- a/src/python/histogram.cpp +++ b/src/python/histogram.cpp @@ -9,9 +9,12 @@ #include #include #include +#include #include #include #include +#include +#include #ifdef HAVE_NUMPY # define NO_IMPORT_ARRAY # define PY_ARRAY_UNIQUE_SYMBOL boost_histogram_ARRAY_API @@ -29,7 +32,7 @@ namespace histogram { struct axis_visitor : public static_visitor { template - python::object operator()(const T& t) const { return python::object(T(t)); } + python::object operator()(const T& t) const { return python::object(t); } }; python::object @@ -252,6 +255,13 @@ histogram_variance(python::tuple args, python::dict kwargs) { return object(self.variance(idx + 0, idx + self.dim())); } +std::string +histogram_repr(const dynamic_histogram<>& h) { + std::ostringstream os; + os << h; + return os.str(); +} + struct storage_access { static python::object @@ -334,6 +344,8 @@ void register_histogram() .def("variance", raw_function(histogram_variance), ":param int args: indices of the bin" "\n:return: variance estimate for the bin") + .def("__repr__", histogram_repr, + ":returns: string representation of the histogram") .def(self == self) .def(self += self) .def_pickle(serialization_suite>()) diff --git a/test/dynamic_histogram_test.cpp b/test/dynamic_histogram_test.cpp index 764df664..e32cf802 100644 --- a/test/dynamic_histogram_test.cpp +++ b/test/dynamic_histogram_test.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -540,5 +541,19 @@ int main() { BOOST_TEST(a == b); } + // histogram_ostream + { + auto a = make_dynamic_histogram(regular_axis<>(3, -1, 1, "r"), + integer_axis(0, 1, "i")); + std::ostringstream os; + os << a; + BOOST_TEST_EQ(os.str(), + "histogram(" + "\n regular_axis(3, -1, 1, label='r')," + "\n integer_axis(0, 1, label='i')," + "\n)" + ); + } + return boost::report_errors(); } diff --git a/test/static_histogram_test.cpp b/test/static_histogram_test.cpp index 507f25e4..12704aec 100644 --- a/test/static_histogram_test.cpp +++ b/test/static_histogram_test.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -539,5 +540,19 @@ int main() { BOOST_TEST(a == b); } + // histogram_ostream + { + auto a = make_static_histogram(regular_axis<>(3, -1, 1, "r"), + integer_axis(0, 1, "i")); + std::ostringstream os; + os << a; + BOOST_TEST_EQ(os.str(), + "histogram(" + "\n regular_axis(3, -1, 1, label='r')," + "\n integer_axis(0, 1, label='i')," + "\n)" + ); + } + return boost::report_errors(); }