/* @file Defines `boost::hana::experimental::print`. @copyright Louis Dionne 2013-2017 Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) */ #ifndef BOOST_HANA_EXPERIMENTAL_PRINTABLE_HPP #define BOOST_HANA_EXPERIMENTAL_PRINTABLE_HPP #include #include #include #include #include #include #include #include #include #include #include #include // models for different containers #include #include #include #include #include #include #include #include #include #include #include #include BOOST_HANA_NAMESPACE_BEGIN namespace experimental { template struct Printable; //! @cond template struct print_impl : print_impl> { }; template struct print_impl> : hana::default_ { template static constexpr auto apply(Args&& ...) = delete; }; //! @endcond //! @ingroup group-experimental //! Returns a string representation of the given object. //! //! This function is defined for most containers provided by Hana, and //! also for objects that define an `operator<<` that can be used with //! a `std::basic_ostream`. It can recursively print containers within //! containers, but do not expect any kind of proper indentation. //! //! This function requires (the rest of) Boost to be available on the //! system. It also requires RTTI to be enabled. #ifdef BOOST_HANA_DOXYGEN_INVOKED auto print = [](auto const& x) -> std::string { return tag-dispatched; }; #else struct print_t { template std::string operator()(T const& t) const { using Tag = typename hana::tag_of::type; using Print = BOOST_HANA_DISPATCH_IF(print_impl, hana::experimental::Printable::value ); #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS static_assert(hana::experimental::Printable::value, "hana::experimental::print(t) requires 't' to be Printable"); #endif return Print::apply(t); } }; constexpr print_t print{}; #endif // Define the `Printable` concept template struct Printable { using Tag = typename hana::tag_of::type; static constexpr bool value = !hana::is_default>::value; }; namespace print_detail { inline std::string strip_type_junk(std::string const& str) { return std::regex_replace(str, std::regex("(?:struct )?([a-z_]+::)*([a-z_]*)_t<((?:struct )?[a-z:<>_]*)>"), "$2<$3>"); } } // model for Sequences template struct print_impl::value>> { template static std::string apply(Xs const& xs) { std::string result = "("; auto comma_separated = hana::intersperse(xs, ", "); hana::for_each(comma_separated, [&result](auto const& x) { result += hana::experimental::print(x); }); result += ")"; return result; } }; // model for OutputStreamable types //! @cond template struct print_impl() << std::declval() )>> { template static std::string apply(T const& t) { std::ostringstream os; os << t; return os.str(); } }; //! @endcond // model for hana::optional template <> struct print_impl { template static std::string apply(O const& optional) { return hana::maybe("nothing", [](auto const& x) { return "just(" + hana::experimental::print(x) + ")"; }, optional); } }; // model for hana::maps template <> struct print_impl { template static std::string apply(M const& map) { std::string result = "{"; auto pairs = hana::transform(hana::to_tuple(map), [](auto const& pair) { return hana::experimental::print(hana::first(pair)) + " => " + hana::experimental::print(hana::second(pair)); }); auto comma_separated = hana::intersperse(pairs, ", "); hana::for_each(comma_separated, [&result](auto const& element) { result += element; }); result += "}"; return result; } }; // model for hana::metafunctions template