258 lines
8.3 KiB
C++
258 lines
8.3 KiB
C++
|
/*
|
||
|
@file
|
||
|
Defines `boost::hana::experimental::print`.
|
||
|
|
||
|
@copyright Louis Dionne 2013-2016
|
||
|
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 <boost/hana/concept/constant.hpp>
|
||
|
#include <boost/hana/concept/product.hpp>
|
||
|
#include <boost/hana/concept/sequence.hpp>
|
||
|
#include <boost/hana/config.hpp>
|
||
|
#include <boost/hana/core/to.hpp>
|
||
|
#include <boost/hana/core/dispatch.hpp>
|
||
|
#include <boost/hana/first.hpp>
|
||
|
#include <boost/hana/for_each.hpp>
|
||
|
#include <boost/hana/intersperse.hpp>
|
||
|
#include <boost/hana/second.hpp>
|
||
|
#include <boost/hana/transform.hpp>
|
||
|
#include <boost/hana/tuple.hpp>
|
||
|
|
||
|
// models for different containers
|
||
|
#include <boost/hana/fwd/map.hpp>
|
||
|
#include <boost/hana/fwd/optional.hpp>
|
||
|
#include <boost/hana/fwd/set.hpp>
|
||
|
#include <boost/hana/fwd/string.hpp>
|
||
|
#include <boost/hana/fwd/type.hpp>
|
||
|
|
||
|
#include <boost/core/demangle.hpp>
|
||
|
|
||
|
#include <iostream>
|
||
|
#include <regex>
|
||
|
#include <sstream>
|
||
|
#include <string>
|
||
|
#include <typeinfo>
|
||
|
#include <utility>
|
||
|
|
||
|
|
||
|
BOOST_HANA_NAMESPACE_BEGIN namespace experimental {
|
||
|
template <typename T>
|
||
|
struct Printable;
|
||
|
|
||
|
//! @cond
|
||
|
template <typename T, typename = void>
|
||
|
struct print_impl : print_impl<T, hana::when<true>> { };
|
||
|
|
||
|
template <typename T, bool condition>
|
||
|
struct print_impl<T, hana::when<condition>> : hana::default_ {
|
||
|
template <typename ...Args>
|
||
|
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 <typename T>
|
||
|
std::string operator()(T const& t) const {
|
||
|
using Tag = typename hana::tag_of<T>::type;
|
||
|
using Print = BOOST_HANA_DISPATCH_IF(print_impl<Tag>,
|
||
|
hana::experimental::Printable<Tag>::value
|
||
|
);
|
||
|
|
||
|
#ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS
|
||
|
static_assert(hana::experimental::Printable<Tag>::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 <typename T>
|
||
|
struct Printable {
|
||
|
using Tag = typename hana::tag_of<T>::type;
|
||
|
static constexpr bool value = !hana::is_default<print_impl<Tag>>::value;
|
||
|
};
|
||
|
|
||
|
namespace print_detail {
|
||
|
std::string strip_type_junk(std::string const& str) {
|
||
|
return std::regex_replace(str, std::regex("^([a-z_]+::)*([a-z_]*)_t<"), "$2<");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// model for Sequences
|
||
|
template <typename S>
|
||
|
struct print_impl<S, hana::when<hana::Sequence<S>::value>> {
|
||
|
template <typename Xs>
|
||
|
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 <typename S>
|
||
|
struct print_impl<S, hana::when_valid<decltype(
|
||
|
std::declval<std::ostringstream&>() << std::declval<S const&>()
|
||
|
)>> {
|
||
|
template <typename T>
|
||
|
static std::string apply(T const& t) {
|
||
|
std::ostringstream os;
|
||
|
os << t;
|
||
|
return os.str();
|
||
|
}
|
||
|
};
|
||
|
//! @endcond
|
||
|
|
||
|
// model for hana::optional
|
||
|
template <>
|
||
|
struct print_impl<hana::optional_tag> {
|
||
|
template <typename O>
|
||
|
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<hana::map_tag> {
|
||
|
template <typename M>
|
||
|
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 <template <typename ...> class F>
|
||
|
struct print_impl<hana::metafunction_t<F>> {
|
||
|
template <typename T>
|
||
|
static std::string apply(T const&) {
|
||
|
return print_detail::strip_type_junk(boost::core::demangle(typeid(T).name()));
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// model for hana::metafunction_classes
|
||
|
template <typename F>
|
||
|
struct print_impl<hana::metafunction_class_t<F>> {
|
||
|
template <typename T>
|
||
|
static std::string apply(T const&) {
|
||
|
return print_detail::strip_type_junk(boost::core::demangle(typeid(T).name()));
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// model for Constants holding a `Printable`
|
||
|
template <typename C>
|
||
|
struct print_impl<C, hana::when<
|
||
|
hana::Constant<C>::value &&
|
||
|
Printable<typename C::value_type>::value
|
||
|
>> {
|
||
|
template <typename T>
|
||
|
static std::string apply(T const&) {
|
||
|
constexpr auto value = hana::value<T>();
|
||
|
return hana::experimental::print(value);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// model for Products
|
||
|
template <typename P>
|
||
|
struct print_impl<P, hana::when<hana::Product<P>::value>> {
|
||
|
template <typename T>
|
||
|
static std::string apply(T const& t) {
|
||
|
return '(' + hana::experimental::print(hana::first(t))
|
||
|
+ ", "
|
||
|
+ hana::experimental::print(hana::second(t)) + ')';
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// model for hana::strings
|
||
|
template <>
|
||
|
struct print_impl<hana::string_tag> {
|
||
|
template <typename S>
|
||
|
static std::string apply(S const& s) {
|
||
|
return '"' + std::string{hana::to<char const*>(s)} + '"';
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// model for hana::sets
|
||
|
template <>
|
||
|
struct print_impl<hana::set_tag> {
|
||
|
template <typename S>
|
||
|
static std::string apply(S const& set) {
|
||
|
std::string result = "{";
|
||
|
auto as_tuple = hana::transform(hana::to_tuple(set),
|
||
|
hana::experimental::print);
|
||
|
auto comma_separated = hana::intersperse(as_tuple, ", ");
|
||
|
hana::for_each(comma_separated, [&result](auto const& element) {
|
||
|
result += element;
|
||
|
});
|
||
|
result += "}";
|
||
|
return result;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// model for hana::templates
|
||
|
template <template <typename ...> class F>
|
||
|
struct print_impl<template_t<F>> {
|
||
|
template <typename T>
|
||
|
static std::string apply(T const&) {
|
||
|
return print_detail::strip_type_junk(boost::core::demangle(typeid(T).name()));
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// model for hana::types
|
||
|
template <>
|
||
|
struct print_impl<hana::type_tag> {
|
||
|
template <typename T>
|
||
|
static std::string apply(T const&) {
|
||
|
using Type = typename T::type;
|
||
|
return "type<" + boost::core::demangle(typeid(Type).name()) + '>';
|
||
|
}
|
||
|
};
|
||
|
} BOOST_HANA_NAMESPACE_END
|
||
|
|
||
|
#endif // !BOOST_HANA_EXPERIMENTAL_PRINTABLE_HPP
|