ostream.hpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  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. #ifndef BOOST_HISTOGRAM_AXIS_OSTREAM_HPP
  9. #define BOOST_HISTOGRAM_AXIS_OSTREAM_HPP
  10. #include <boost/assert.hpp>
  11. #include <boost/histogram/axis/regular.hpp>
  12. #include <boost/histogram/detail/static_if.hpp>
  13. #include <boost/histogram/detail/type_name.hpp>
  14. #include <boost/histogram/fwd.hpp>
  15. #include <boost/throw_exception.hpp>
  16. #include <iomanip>
  17. #include <iosfwd>
  18. #include <sstream>
  19. #include <stdexcept>
  20. #include <type_traits>
  21. /**
  22. \file boost/histogram/axis/ostream.hpp
  23. Simple streaming operators for the builtin axis types.
  24. The text representation is not guaranteed to be stable between versions of
  25. Boost.Histogram. This header is only included by
  26. [boost/histogram/ostream.hpp](histogram/reference.html#header.boost.histogram.ostream_hpp).
  27. To you use your own, include your own implementation instead of this header and do not
  28. include
  29. [boost/histogram/ostream.hpp](histogram/reference.html#header.boost.histogram.ostream_hpp).
  30. */
  31. #ifndef BOOST_HISTOGRAM_DOXYGEN_INVOKED
  32. namespace boost {
  33. namespace histogram {
  34. namespace detail {
  35. inline const char* axis_suffix(const axis::transform::id&) { return ""; }
  36. inline const char* axis_suffix(const axis::transform::log&) { return "_log"; }
  37. inline const char* axis_suffix(const axis::transform::sqrt&) { return "_sqrt"; }
  38. inline const char* axis_suffix(const axis::transform::pow&) { return "_pow"; }
  39. template <class OStream, class T>
  40. void stream_metadata(OStream& os, const T& t) {
  41. detail::static_if<detail::is_streamable<T>>(
  42. [&os](const auto& t) {
  43. std::ostringstream oss;
  44. oss << t;
  45. if (!oss.str().empty()) { os << ", metadata=" << std::quoted(oss.str()); }
  46. },
  47. [&os](const auto&) { os << ", metadata=" << detail::type_name<T>(); }, t);
  48. }
  49. template <class OStream>
  50. void stream_options(OStream& os, const unsigned bits) {
  51. os << ", options=";
  52. bool first = true;
  53. #define BOOST_HISTOGRAM_AXIS_OPTION_OSTREAM(x) \
  54. if (bits & axis::option::x) { \
  55. if (first) \
  56. first = false; \
  57. else { \
  58. os << " | "; \
  59. } \
  60. os << #x; \
  61. }
  62. BOOST_HISTOGRAM_AXIS_OPTION_OSTREAM(underflow);
  63. BOOST_HISTOGRAM_AXIS_OPTION_OSTREAM(overflow);
  64. BOOST_HISTOGRAM_AXIS_OPTION_OSTREAM(circular);
  65. BOOST_HISTOGRAM_AXIS_OPTION_OSTREAM(growth);
  66. #undef BOOST_HISTOGRAM_AXIS_OPTION_OSTREAM
  67. if (first) os << "none";
  68. }
  69. template <class OStream, class T>
  70. void stream_transform(OStream&, const T&) {}
  71. template <class OStream>
  72. void stream_transform(OStream& os, const axis::transform::pow& t) {
  73. os << ", power=" << t.power;
  74. }
  75. template <class OStream, class T>
  76. void stream_value(OStream& os, const T& t) {
  77. os << t;
  78. }
  79. template <class OStream, class... Ts>
  80. void stream_value(OStream& os, const std::basic_string<Ts...>& t) {
  81. os << std::quoted(t);
  82. }
  83. } // namespace detail
  84. namespace axis {
  85. template <class T>
  86. class polymorphic_bin;
  87. template <class... Ts>
  88. std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os, const null_type&) {
  89. return os; // do nothing
  90. }
  91. template <class... Ts, class U>
  92. std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os,
  93. const interval_view<U>& i) {
  94. os << "[" << i.lower() << ", " << i.upper() << ")";
  95. return os;
  96. }
  97. template <class... Ts, class U>
  98. std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os,
  99. const polymorphic_bin<U>& i) {
  100. if (i.is_discrete())
  101. os << static_cast<double>(i);
  102. else
  103. os << "[" << i.lower() << ", " << i.upper() << ")";
  104. return os;
  105. }
  106. template <class... Ts, class... Us>
  107. std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os,
  108. const regular<Us...>& a) {
  109. os << "regular" << detail::axis_suffix(a.transform()) << "(" << a.size() << ", "
  110. << a.value(0) << ", " << a.value(a.size());
  111. detail::stream_metadata(os, a.metadata());
  112. detail::stream_options(os, a.options());
  113. detail::stream_transform(os, a.transform());
  114. os << ")";
  115. return os;
  116. }
  117. template <class... Ts, class... Us>
  118. std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os,
  119. const integer<Us...>& a) {
  120. os << "integer(" << a.value(0) << ", " << a.value(a.size());
  121. detail::stream_metadata(os, a.metadata());
  122. detail::stream_options(os, a.options());
  123. os << ")";
  124. return os;
  125. }
  126. template <class... Ts, class... Us>
  127. std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os,
  128. const variable<Us...>& a) {
  129. os << "variable(" << a.value(0);
  130. for (index_type i = 1, n = a.size(); i <= n; ++i) { os << ", " << a.value(i); }
  131. detail::stream_metadata(os, a.metadata());
  132. detail::stream_options(os, a.options());
  133. os << ")";
  134. return os;
  135. }
  136. template <class... Ts, class... Us>
  137. std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os,
  138. const category<Us...>& a) {
  139. os << "category(";
  140. for (index_type i = 0, n = a.size(); i < n; ++i) {
  141. detail::stream_value(os, a.value(i));
  142. os << (i == (a.size() - 1) ? "" : ", ");
  143. }
  144. detail::stream_metadata(os, a.metadata());
  145. detail::stream_options(os, a.options());
  146. os << ")";
  147. return os;
  148. }
  149. template <class... Ts, class... Us>
  150. std::basic_ostream<Ts...>& operator<<(std::basic_ostream<Ts...>& os,
  151. const variant<Us...>& v) {
  152. visit(
  153. [&os](const auto& x) {
  154. using A = std::decay_t<decltype(x)>;
  155. detail::static_if<detail::is_streamable<A>>(
  156. [&os](const auto& x) { os << x; },
  157. [&os](const auto&) { os << "<unstreamable>"; }, x);
  158. },
  159. v);
  160. return os;
  161. }
  162. } // namespace axis
  163. } // namespace histogram
  164. } // namespace boost
  165. #endif // BOOST_HISTOGRAM_DOXYGEN_INVOKED
  166. #endif