1 // Copyright 2015-2017 Hans Dembinski
2 //
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)
6 //
7 // String representations here evaluate correctly in Python.
8
9 #ifndef BOOST_HISTOGRAM_AXIS_OSTREAM_HPP
10 #define BOOST_HISTOGRAM_AXIS_OSTREAM_HPP
11
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>
18 #include <iomanip>
19 #include <iosfwd>
20 #include <sstream>
21 #include <stdexcept>
22 #include <type_traits>
23
24 /**
25 \file boost/histogram/axis/ostream.hpp
26 Simple streaming operators for the builtin axis types.
27
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
32 include
33 [boost/histogram/ostream.hpp](histogram/reference.html#header.boost.histogram.ostream_hpp).
34 */
35
36 #ifndef BOOST_HISTOGRAM_DOXYGEN_INVOKED
37
38 namespace boost {
39 namespace histogram {
40
41 namespace detail {
axis_suffix(const axis::transform::id &)42 inline const char* axis_suffix(const axis::transform::id&) { return ""; }
axis_suffix(const axis::transform::log &)43 inline const char* axis_suffix(const axis::transform::log&) { return "_log"; }
axis_suffix(const axis::transform::sqrt &)44 inline const char* axis_suffix(const axis::transform::sqrt&) { return "_sqrt"; }
axis_suffix(const axis::transform::pow &)45 inline const char* axis_suffix(const axis::transform::pow&) { return "_pow"; }
46
47 template <class OStream, class T>
stream_metadata(OStream & os,const T & 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;
52 oss << t;
53 if (!oss.str().empty()) { os << ", metadata=" << std::quoted(oss.str()); }
54 },
55 [&os](const auto&) { os << ", metadata=" << detail::type_name<T>(); }, t);
56 }
57
58 template <class OStream>
stream_options(OStream & os,const unsigned bits)59 void stream_options(OStream& os, const unsigned bits) {
60 os << ", options=";
61 bool first = true;
62
63 #define BOOST_HISTOGRAM_AXIS_OPTION_OSTREAM(x) \
64 if (bits & axis::option::x) { \
65 if (first) \
66 first = false; \
67 else { \
68 os << " | "; \
69 } \
70 os << #x; \
71 }
72
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);
77
78 #undef BOOST_HISTOGRAM_AXIS_OPTION_OSTREAM
79
80 if (first) os << "none";
81 }
82
83 template <class OStream, class T>
stream_transform(OStream &,const T &)84 void stream_transform(OStream&, const T&) {}
85
86 template <class OStream>
stream_transform(OStream & os,const axis::transform::pow & t)87 void stream_transform(OStream& os, const axis::transform::pow& t) {
88 os << ", power=" << t.power;
89 }
90
91 template <class OStream, class T>
stream_value(OStream & os,const T & t)92 void stream_value(OStream& os, const T& t) {
93 os << t;
94 }
95
96 template <class OStream, class... Ts>
stream_value(OStream & os,const std::basic_string<Ts...> & t)97 void stream_value(OStream& os, const std::basic_string<Ts...>& t) {
98 os << std::quoted(t);
99 }
100
101 } // namespace detail
102
103 namespace axis {
104
105 template <class T>
106 class polymorphic_bin;
107
108 template <class... Ts>
operator <<(std::basic_ostream<Ts...> & os,const null_type &)109 std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os, const null_type&) {
110 return os; // do nothing
111 }
112
113 template <class... Ts, class U>
operator <<(std::basic_ostream<Ts...> & os,const interval_view<U> & i)114 std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os,
115 const interval_view<U>& i) {
116 os << "[" << i.lower() << ", " << i.upper() << ")";
117 return os;
118 }
119
120 template <class... Ts, class U>
operator <<(std::basic_ostream<Ts...> & os,const polymorphic_bin<U> & i)121 std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os,
122 const polymorphic_bin<U>& i) {
123 if (i.is_discrete())
124 os << static_cast<double>(i);
125 else
126 os << "[" << i.lower() << ", " << i.upper() << ")";
127 return os;
128 }
129
130 template <class... Ts, class... Us>
operator <<(std::basic_ostream<Ts...> & os,const regular<Us...> & a)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());
138 os << ")";
139 return os;
140 }
141
142 template <class... Ts, class... Us>
operator <<(std::basic_ostream<Ts...> & os,const integer<Us...> & a)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());
148 os << ")";
149 return os;
150 }
151
152 template <class... Ts, class... Us>
operator <<(std::basic_ostream<Ts...> & os,const variable<Us...> & a)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());
159 os << ")";
160 return os;
161 }
162
163 template <class... Ts, class... Us>
operator <<(std::basic_ostream<Ts...> & os,const category<Us...> & a)164 std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os,
165 const category<Us...>& a) {
166 os << "category(";
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) ? "" : ", ");
170 }
171 detail::stream_metadata(os, a.metadata());
172 detail::stream_options(os, a.options());
173 os << ")";
174 return os;
175 }
176
177 template <class... Ts, class... Us>
operator <<(std::basic_ostream<Ts...> & os,const variant<Us...> & v)178 std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os,
179 const variant<Us...>& v) {
180 visit(
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);
186 },
187 v);
188 return os;
189 }
190
191 } // namespace axis
192 } // namespace histogram
193 } // namespace boost
194
195 #endif // BOOST_HISTOGRAM_DOXYGEN_INVOKED
196
197 #endif
198