printable.hpp 8.2 KB

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