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/histogram/axis/regular.hpp>
13 #include <boost/histogram/detail/counting_streambuf.hpp>
14 #include <boost/histogram/detail/priority.hpp>
15 #include <boost/histogram/detail/type_name.hpp>
16 #include <boost/histogram/fwd.hpp>
17 #include <boost/throw_exception.hpp>
18 #include <cassert>
19 #include <iomanip>
20 #include <iosfwd>
21 #include <sstream>
22 #include <stdexcept>
23 #include <type_traits>
24
25 /**
26 \file boost/histogram/axis/ostream.hpp
27 Simple streaming operators for the builtin axis types.
28
29 The text representation is not guaranteed to be stable between versions of
30 Boost.Histogram. This header is only included by
31 [boost/histogram/ostream.hpp](histogram/reference.html#header.boost.histogram.ostream_hpp).
32 To use your own, include your own implementation instead of this header and do not
33 include
34 [boost/histogram/ostream.hpp](histogram/reference.html#header.boost.histogram.ostream_hpp).
35 */
36
37 #ifndef BOOST_HISTOGRAM_DOXYGEN_INVOKED
38
39 namespace boost {
40 namespace histogram {
41
42 namespace detail {
43
44 template <class OStream, class T>
ostream_any_impl(OStream & os,const T & t,priority<1>)45 auto ostream_any_impl(OStream& os, const T& t, priority<1>) -> decltype(os << t) {
46 return os << t;
47 }
48
49 template <class OStream, class T>
ostream_any_impl(OStream & os,const T &,priority<0>)50 OStream& ostream_any_impl(OStream& os, const T&, priority<0>) {
51 return os << type_name<T>();
52 }
53
54 template <class OStream, class T>
ostream_any(OStream & os,const T & t)55 OStream& ostream_any(OStream& os, const T& t) {
56 return ostream_any_impl(os, t, priority<1>{});
57 }
58
59 template <class OStream, class... Ts>
ostream_any_quoted(OStream & os,const std::basic_string<Ts...> & s)60 OStream& ostream_any_quoted(OStream& os, const std::basic_string<Ts...>& s) {
61 return os << std::quoted(s);
62 }
63
64 template <class OStream, class T>
ostream_any_quoted(OStream & os,const T & t)65 OStream& ostream_any_quoted(OStream& os, const T& t) {
66 return ostream_any(os, t);
67 }
68
69 template <class... Ts, class T>
ostream_metadata(std::basic_ostream<Ts...> & os,const T & t,const char * prefix=", ")70 std::basic_ostream<Ts...>& ostream_metadata(std::basic_ostream<Ts...>& os, const T& t,
71 const char* prefix = ", ") {
72 std::streamsize count = 0;
73 {
74 auto g = make_count_guard(os, count);
75 ostream_any(os, t);
76 }
77 if (!count) return os;
78 os << prefix << "metadata=";
79 return ostream_any_quoted(os, t);
80 }
81
82 template <class OStream>
ostream_options(OStream & os,const unsigned bits)83 void ostream_options(OStream& os, const unsigned bits) {
84 bool first = true;
85 os << ", options=";
86
87 #define BOOST_HISTOGRAM_AXIS_OPTION_OSTREAM(x) \
88 if (bits & axis::option::x) { \
89 if (first) \
90 first = false; \
91 else { \
92 os << " | "; \
93 } \
94 os << #x; \
95 }
96
97 BOOST_HISTOGRAM_AXIS_OPTION_OSTREAM(underflow);
98 BOOST_HISTOGRAM_AXIS_OPTION_OSTREAM(overflow);
99 BOOST_HISTOGRAM_AXIS_OPTION_OSTREAM(circular);
100 BOOST_HISTOGRAM_AXIS_OPTION_OSTREAM(growth);
101
102 #undef BOOST_HISTOGRAM_AXIS_OPTION_OSTREAM
103
104 if (first) os << "none";
105 }
106
107 } // namespace detail
108
109 namespace axis {
110
111 template <class T>
112 class polymorphic_bin;
113
114 template <class... Ts>
operator <<(std::basic_ostream<Ts...> & os,const null_type &)115 std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os, const null_type&) {
116 return os; // do nothing
117 }
118
119 template <class... Ts, class U>
operator <<(std::basic_ostream<Ts...> & os,const interval_view<U> & i)120 std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os,
121 const interval_view<U>& i) {
122 return os << "[" << i.lower() << ", " << i.upper() << ")";
123 }
124
125 template <class... Ts, class U>
operator <<(std::basic_ostream<Ts...> & os,const polymorphic_bin<U> & i)126 std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os,
127 const polymorphic_bin<U>& i) {
128 if (i.is_discrete()) return os << static_cast<double>(i);
129 return os << "[" << i.lower() << ", " << i.upper() << ")";
130 }
131
132 namespace transform {
133 template <class... Ts>
operator <<(std::basic_ostream<Ts...> & os,const id &)134 std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os, const id&) {
135 return os;
136 }
137
138 template <class... Ts>
operator <<(std::basic_ostream<Ts...> & os,const log &)139 std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os, const log&) {
140 return os << "transform::log{}";
141 }
142
143 template <class... Ts>
operator <<(std::basic_ostream<Ts...> & os,const sqrt &)144 std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os, const sqrt&) {
145 return os << "transform::sqrt{}";
146 }
147
148 template <class... Ts>
operator <<(std::basic_ostream<Ts...> & os,const pow & p)149 std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os, const pow& p) {
150 return os << "transform::pow{" << p.power << "}";
151 }
152 } // namespace transform
153
154 template <class... Ts, class... Us>
operator <<(std::basic_ostream<Ts...> & os,const regular<Us...> & a)155 std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os,
156 const regular<Us...>& a) {
157 os << "regular(";
158 const auto pos = os.tellp();
159 os << a.transform();
160 if (os.tellp() > pos) os << ", ";
161 os << a.size() << ", " << a.value(0) << ", " << a.value(a.size());
162 detail::ostream_metadata(os, a.metadata());
163 detail::ostream_options(os, a.options());
164 return os << ")";
165 }
166
167 template <class... Ts, class... Us>
operator <<(std::basic_ostream<Ts...> & os,const integer<Us...> & a)168 std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os,
169 const integer<Us...>& a) {
170 os << "integer(" << a.value(0) << ", " << a.value(a.size());
171 detail::ostream_metadata(os, a.metadata());
172 detail::ostream_options(os, a.options());
173 return os << ")";
174 }
175
176 template <class... Ts, class... Us>
operator <<(std::basic_ostream<Ts...> & os,const variable<Us...> & a)177 std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os,
178 const variable<Us...>& a) {
179 os << "variable(" << a.value(0);
180 for (index_type i = 1, n = a.size(); i <= n; ++i) { os << ", " << a.value(i); }
181 detail::ostream_metadata(os, a.metadata());
182 detail::ostream_options(os, a.options());
183 return os << ")";
184 }
185
186 template <class... Ts, class... Us>
operator <<(std::basic_ostream<Ts...> & os,const category<Us...> & a)187 std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os,
188 const category<Us...>& a) {
189 os << "category(";
190 for (index_type i = 0, n = a.size(); i < n; ++i) {
191 detail::ostream_any_quoted(os, a.value(i));
192 os << (i == (a.size() - 1) ? "" : ", ");
193 }
194 detail::ostream_metadata(os, a.metadata());
195 detail::ostream_options(os, a.options());
196 return os << ")";
197 }
198
199 template <class... Ts, class M>
operator <<(std::basic_ostream<Ts...> & os,const boolean<M> & a)200 std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os,
201 const boolean<M>& a) {
202 os << "boolean(";
203 detail::ostream_metadata(os, a.metadata(), "");
204 return os << ")";
205 }
206
207 template <class... Ts, class... Us>
operator <<(std::basic_ostream<Ts...> & os,const variant<Us...> & v)208 std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os,
209 const variant<Us...>& v) {
210 visit([&os](const auto& x) { detail::ostream_any(os, x); }, v);
211 return os;
212 }
213
214 } // namespace axis
215 } // namespace histogram
216 } // namespace boost
217
218 #endif // BOOST_HISTOGRAM_DOXYGEN_INVOKED
219
220 #endif
221