• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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