printable.hpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. /*
  2. @file
  3. Defines `boost::hana::experimental::print`.
  4. @copyright Louis Dionne 2013-2016
  5. Distributed under the Boost Software License, Version 1.0.
  6. (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
  7. */
  8. #ifndef BOOST_HANA_EXPERIMENTAL_PRINTABLE_HPP
  9. #define BOOST_HANA_EXPERIMENTAL_PRINTABLE_HPP
  10. #include <boost/hana/concept/constant.hpp>
  11. #include <boost/hana/concept/product.hpp>
  12. #include <boost/hana/concept/sequence.hpp>
  13. #include <boost/hana/config.hpp>
  14. #include <boost/hana/core/to.hpp>
  15. #include <boost/hana/core/dispatch.hpp>
  16. #include <boost/hana/first.hpp>
  17. #include <boost/hana/for_each.hpp>
  18. #include <boost/hana/intersperse.hpp>
  19. #include <boost/hana/second.hpp>
  20. #include <boost/hana/transform.hpp>
  21. #include <boost/hana/tuple.hpp>
  22. // models for different containers
  23. #include <boost/hana/fwd/map.hpp>
  24. #include <boost/hana/fwd/optional.hpp>
  25. #include <boost/hana/fwd/set.hpp>
  26. #include <boost/hana/fwd/string.hpp>
  27. #include <boost/hana/fwd/type.hpp>
  28. #include <boost/core/demangle.hpp>
  29. #include <iostream>
  30. #include <regex>
  31. #include <sstream>
  32. #include <string>
  33. #include <typeinfo>
  34. #include <utility>
  35. BOOST_HANA_NAMESPACE_BEGIN namespace experimental {
  36. //! @cond
  37. template <typename T, typename = void>
  38. struct print_impl : print_impl<T, hana::when<true>> { };
  39. template <typename T, bool condition>
  40. struct print_impl<T, hana::when<condition>> : hana::default_ {
  41. template <typename ...Args>
  42. static constexpr auto apply(Args&& ...) = delete;
  43. };
  44. //! @endcond
  45. //! @ingroup group-experimental
  46. //! Returns a string representation of the given object.
  47. //!
  48. //! This function is defined for most containers provided by Hana, and
  49. //! also for objects that define an `operator<<` that can be used with
  50. //! a `std::basic_ostream`. It can recursively print containers within
  51. //! containers, but do not expect any kind of proper indentation.
  52. //!
  53. //! This function requires (the rest of) Boost to be available on the
  54. //! system. It also requires RTTI to be enabled.
  55. #ifdef BOOST_HANA_DOXYGEN_INVOKED
  56. auto print = [](auto const& x) -> std::string {
  57. return tag-dispatched;
  58. };
  59. #else
  60. struct print_t {
  61. template <typename T>
  62. std::string operator()(T const& t) const {
  63. using Print = print_impl<typename hana::tag_of<T>::type>;
  64. return Print::apply(t);
  65. }
  66. };
  67. constexpr print_t print{};
  68. #endif
  69. // Define the `Printable` concept
  70. template <typename T>
  71. struct Printable {
  72. using Tag = typename hana::tag_of<T>::type;
  73. static constexpr bool value = !hana::is_default<print_impl<Tag>>::value;
  74. };
  75. namespace print_detail {
  76. std::string strip_type_junk(std::string const& str) {
  77. return std::regex_replace(str, std::regex("^([a-z_]+::)*([a-z_]*)_t<"), "$2<");
  78. }
  79. }
  80. // model for Sequences
  81. template <typename S>
  82. struct print_impl<S, hana::when<hana::Sequence<S>::value>> {
  83. template <typename Xs>
  84. static std::string apply(Xs const& xs) {
  85. std::string result = "(";
  86. auto comma_separated = hana::intersperse(xs, ", ");
  87. hana::for_each(comma_separated, [&result](auto const& x) {
  88. result += hana::experimental::print(x);
  89. });
  90. result += ")";
  91. return result;
  92. }
  93. };
  94. // model for OutputStreamable types
  95. template <typename S>
  96. struct print_impl<S, hana::when_valid<decltype(
  97. std::declval<std::ostringstream&>() << std::declval<S const&>()
  98. )>> {
  99. template <typename T>
  100. static std::string apply(T const& t) {
  101. std::ostringstream os;
  102. os << t;
  103. return os.str();
  104. }
  105. };
  106. // model for hana::optional
  107. template <>
  108. struct print_impl<hana::optional_tag> {
  109. template <typename O>
  110. static std::string apply(O const& optional) {
  111. return hana::maybe("nothing",
  112. [](auto const& x) {
  113. return "just(" + hana::experimental::print(x) + ")";
  114. }, optional);
  115. }
  116. };
  117. // model for hana::maps
  118. template <>
  119. struct print_impl<hana::map_tag> {
  120. template <typename M>
  121. static std::string apply(M const& map) {
  122. std::string result = "{";
  123. auto pairs = hana::transform(hana::to_tuple(map),
  124. [](auto const& pair) {
  125. return hana::experimental::print(hana::first(pair))
  126. + " => "
  127. + hana::experimental::print(hana::second(pair));
  128. });
  129. auto comma_separated = hana::intersperse(pairs, ", ");
  130. hana::for_each(comma_separated, [&result](auto const& element) {
  131. result += element;
  132. });
  133. result += "}";
  134. return result;
  135. }
  136. };
  137. // model for hana::metafunctions
  138. template <template <typename ...> class F>
  139. struct print_impl<hana::metafunction_t<F>> {
  140. template <typename T>
  141. static std::string apply(T const&) {
  142. return print_detail::strip_type_junk(boost::core::demangle(typeid(T).name()));
  143. }
  144. };
  145. // model for hana::metafunction_classes
  146. template <typename F>
  147. struct print_impl<hana::metafunction_class_t<F>> {
  148. template <typename T>
  149. static std::string apply(T const&) {
  150. return print_detail::strip_type_junk(boost::core::demangle(typeid(T).name()));
  151. }
  152. };
  153. // model for Constants holding a `Printable`
  154. template <typename C>
  155. struct print_impl<C, hana::when<
  156. hana::Constant<C>::value &&
  157. Printable<typename C::value_type>::value
  158. >> {
  159. template <typename T>
  160. static std::string apply(T const&) {
  161. constexpr auto value = hana::value<T>();
  162. return hana::experimental::print(value);
  163. }
  164. };
  165. // model for Products
  166. template <typename P>
  167. struct print_impl<P, hana::when<hana::Product<P>::value>> {
  168. template <typename T>
  169. static std::string apply(T const& t) {
  170. return '(' + hana::experimental::print(hana::first(t))
  171. + ", "
  172. + hana::experimental::print(hana::second(t)) + ')';
  173. }
  174. };
  175. // model for hana::strings
  176. template <>
  177. struct print_impl<hana::string_tag> {
  178. template <typename S>
  179. static std::string apply(S const& s) {
  180. return '"' + std::string{hana::to<char const*>(s)} + '"';
  181. }
  182. };
  183. // model for hana::sets
  184. template <>
  185. struct print_impl<hana::set_tag> {
  186. template <typename S>
  187. static std::string apply(S const& set) {
  188. std::string result = "{";
  189. auto as_tuple = hana::transform(hana::to_tuple(set),
  190. hana::experimental::print);
  191. auto comma_separated = hana::intersperse(as_tuple, ", ");
  192. hana::for_each(comma_separated, [&result](auto const& element) {
  193. result += element;
  194. });
  195. result += "}";
  196. return result;
  197. }
  198. };
  199. // model for hana::templates
  200. template <template <typename ...> class F>
  201. struct print_impl<template_t<F>> {
  202. template <typename T>
  203. static std::string apply(T const&) {
  204. return print_detail::strip_type_junk(boost::core::demangle(typeid(T).name()));
  205. }
  206. };
  207. // model for hana::types
  208. template <>
  209. struct print_impl<hana::type_tag> {
  210. template <typename T>
  211. static std::string apply(T const&) {
  212. using Type = typename T::type;
  213. return "type<" + boost::core::demangle(typeid(Type).name()) + '>';
  214. }
  215. };
  216. } BOOST_HANA_NAMESPACE_END
  217. #endif // !BOOST_HANA_EXPERIMENTAL_PRINTABLE_HPP