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