1 // Copyright 2015-2017 Hans Dembinski
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt
5 // or copy at http://www.boost.org/LICENSE_1_0.txt)
7 // String representations here evaluate correctly in Python.
9 #ifndef BOOST_HISTOGRAM_AXIS_OSTREAM_HPP
10 #define BOOST_HISTOGRAM_AXIS_OSTREAM_HPP
12 #include <boost/assert.hpp>
13 #include <boost/histogram/axis/regular.hpp>
14 #include <boost/histogram/detail/static_if.hpp>
15 #include <boost/histogram/detail/type_name.hpp>
16 #include <boost/histogram/fwd.hpp>
17 #include <boost/throw_exception.hpp>
22 #include <type_traits>
25 \file boost/histogram/axis/ostream.hpp
26 Simple streaming operators for the builtin axis types.
28 The text representation is not guaranteed to be stable between versions of
29 Boost.Histogram. This header is only included by
30 [boost/histogram/ostream.hpp](histogram/reference.html#header.boost.histogram.ostream_hpp).
31 To you use your own, include your own implementation instead of this header and do not
33 [boost/histogram/ostream.hpp](histogram/reference.html#header.boost.histogram.ostream_hpp).
36 #ifndef BOOST_HISTOGRAM_DOXYGEN_INVOKED
42 inline const char* axis_suffix(const axis::transform::id&) { return ""; }
43 inline const char* axis_suffix(const axis::transform::log&) { return "_log"; }
44 inline const char* axis_suffix(const axis::transform::sqrt&) { return "_sqrt"; }
45 inline const char* axis_suffix(const axis::transform::pow&) { return "_pow"; }
47 template <class OStream, class T>
48 void stream_metadata(OStream& os, const T& t) {
49 detail::static_if<detail::is_streamable<T>>(
50 [&os](const auto& t) {
51 std::ostringstream oss;
53 if (!oss.str().empty()) { os << ", metadata=" << std::quoted(oss.str()); }
55 [&os](const auto&) { os << ", metadata=" << detail::type_name<T>(); }, t);
58 template <class OStream>
59 void stream_options(OStream& os, const unsigned bits) {
63 #define BOOST_HISTOGRAM_AXIS_OPTION_OSTREAM(x) \
64 if (bits & axis::option::x) { \
73 BOOST_HISTOGRAM_AXIS_OPTION_OSTREAM(underflow);
74 BOOST_HISTOGRAM_AXIS_OPTION_OSTREAM(overflow);
75 BOOST_HISTOGRAM_AXIS_OPTION_OSTREAM(circular);
76 BOOST_HISTOGRAM_AXIS_OPTION_OSTREAM(growth);
78 #undef BOOST_HISTOGRAM_AXIS_OPTION_OSTREAM
80 if (first) os << "none";
83 template <class OStream, class T>
84 void stream_transform(OStream&, const T&) {}
86 template <class OStream>
87 void stream_transform(OStream& os, const axis::transform::pow& t) {
88 os << ", power=" << t.power;
91 template <class OStream, class T>
92 void stream_value(OStream& os, const T& t) {
96 template <class OStream, class... Ts>
97 void stream_value(OStream& os, const std::basic_string<Ts...>& t) {
101 } // namespace detail
106 class polymorphic_bin;
108 template <class... Ts>
109 std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os, const null_type&) {
110 return os; // do nothing
113 template <class... Ts, class U>
114 std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os,
115 const interval_view<U>& i) {
116 os << "[" << i.lower() << ", " << i.upper() << ")";
120 template <class... Ts, class U>
121 std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os,
122 const polymorphic_bin<U>& i) {
124 os << static_cast<double>(i);
126 os << "[" << i.lower() << ", " << i.upper() << ")";
130 template <class... Ts, class... Us>
131 std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os,
132 const regular<Us...>& a) {
133 os << "regular" << detail::axis_suffix(a.transform()) << "(" << a.size() << ", "
134 << a.value(0) << ", " << a.value(a.size());
135 detail::stream_metadata(os, a.metadata());
136 detail::stream_options(os, a.options());
137 detail::stream_transform(os, a.transform());
142 template <class... Ts, class... Us>
143 std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os,
144 const integer<Us...>& a) {
145 os << "integer(" << a.value(0) << ", " << a.value(a.size());
146 detail::stream_metadata(os, a.metadata());
147 detail::stream_options(os, a.options());
152 template <class... Ts, class... Us>
153 std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os,
154 const variable<Us...>& a) {
155 os << "variable(" << a.value(0);
156 for (index_type i = 1, n = a.size(); i <= n; ++i) { os << ", " << a.value(i); }
157 detail::stream_metadata(os, a.metadata());
158 detail::stream_options(os, a.options());
163 template <class... Ts, class... Us>
164 std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os,
165 const category<Us...>& a) {
167 for (index_type i = 0, n = a.size(); i < n; ++i) {
168 detail::stream_value(os, a.value(i));
169 os << (i == (a.size() - 1) ? "" : ", ");
171 detail::stream_metadata(os, a.metadata());
172 detail::stream_options(os, a.options());
177 template <class... Ts, class... Us>
178 std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os,
179 const variant<Us...>& v) {
181 [&os](const auto& x) {
182 using A = std::decay_t<decltype(x)>;
183 detail::static_if<detail::is_streamable<A>>(
184 [&os](const auto& x) { os << x; },
185 [&os](const auto&) { os << "<unstreamable>"; }, x);
192 } // namespace histogram
195 #endif // BOOST_HISTOGRAM_DOXYGEN_INVOKED