Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / histogram / axis / ostream.hpp
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 {
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"; }
46
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;
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>
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>
84 void stream_transform(OStream&, const T&) {}
85
86 template <class OStream>
87 void stream_transform(OStream& os, const axis::transform::pow& t) {
88   os << ", power=" << t.power;
89 }
90
91 template <class OStream, class T>
92 void stream_value(OStream& os, const T& t) {
93   os << t;
94 }
95
96 template <class OStream, class... Ts>
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>
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>
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>
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>
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>
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>
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>
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>
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