diff options
Diffstat (limited to 'third_party/immer/tools/include/prettyprint.hpp')
-rw-r--r-- | third_party/immer/tools/include/prettyprint.hpp | 445 |
1 files changed, 445 insertions, 0 deletions
diff --git a/third_party/immer/tools/include/prettyprint.hpp b/third_party/immer/tools/include/prettyprint.hpp new file mode 100644 index 000000000000..f75683ccdd51 --- /dev/null +++ b/third_party/immer/tools/include/prettyprint.hpp @@ -0,0 +1,445 @@ +// Copyright Louis Delacroix 2010 - 2014. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// A pretty printing library for C++ +// +// Usage: +// Include this header, and operator<< will "just work". + +#ifndef H_PRETTY_PRINT +#define H_PRETTY_PRINT + +#include <cstddef> +#include <iterator> +#include <memory> +#include <ostream> +#include <set> +#include <tuple> +#include <type_traits> +#include <unordered_set> +#include <utility> +#include <valarray> + +namespace pretty_print +{ + namespace detail + { + // SFINAE type trait to detect whether T::const_iterator exists. + + struct sfinae_base + { + using yes = char; + using no = yes[2]; + }; + + template <typename T> + struct has_const_iterator : private sfinae_base + { + private: + template <typename C> static yes & test(typename C::const_iterator*); + template <typename C> static no & test(...); + public: + static const bool value = sizeof(test<T>(nullptr)) == sizeof(yes); + using type = T; + }; + + template <typename T> + struct has_begin_end : private sfinae_base + { + private: + template <typename C> + static yes & f(typename std::enable_if< + std::is_same<decltype(static_cast<typename C::const_iterator(C::*)() const>(&C::begin)), + typename C::const_iterator(C::*)() const>::value>::type *); + + template <typename C> static no & f(...); + + template <typename C> + static yes & g(typename std::enable_if< + std::is_same<decltype(static_cast<typename C::const_iterator(C::*)() const>(&C::end)), + typename C::const_iterator(C::*)() const>::value, void>::type*); + + template <typename C> static no & g(...); + + public: + static bool const beg_value = sizeof(f<T>(nullptr)) == sizeof(yes); + static bool const end_value = sizeof(g<T>(nullptr)) == sizeof(yes); + }; + + } // namespace detail + + + // Holds the delimiter values for a specific character type + + template <typename TChar> + struct delimiters_values + { + using char_type = TChar; + const char_type * prefix; + const char_type * delimiter; + const char_type * postfix; + }; + + + // Defines the delimiter values for a specific container and character type + + template <typename T, typename TChar> + struct delimiters + { + using type = delimiters_values<TChar>; + static const type values; + }; + + + // Functor to print containers. You can use this directly if you want + // to specificy a non-default delimiters type. The printing logic can + // be customized by specializing the nested template. + + template <typename T, + typename TChar = char, + typename TCharTraits = ::std::char_traits<TChar>, + typename TDelimiters = delimiters<T, TChar>> + struct print_container_helper + { + using delimiters_type = TDelimiters; + using ostream_type = std::basic_ostream<TChar, TCharTraits>; + + template <typename U> + struct printer + { + static void print_body(const U & c, ostream_type & stream) + { + using std::begin; + using std::end; + + auto it = begin(c); + const auto the_end = end(c); + + if (it != the_end) + { + for ( ; ; ) + { + stream << *it; + + if (++it == the_end) break; + + if (delimiters_type::values.delimiter != NULL) + stream << delimiters_type::values.delimiter; + } + } + } + }; + + print_container_helper(const T & container) + : container_(container) + { } + + inline void operator()(ostream_type & stream) const + { + if (delimiters_type::values.prefix != NULL) + stream << delimiters_type::values.prefix; + + printer<T>::print_body(container_, stream); + + if (delimiters_type::values.postfix != NULL) + stream << delimiters_type::values.postfix; + } + + private: + const T & container_; + }; + + // Specialization for pairs + + template <typename T, typename TChar, typename TCharTraits, typename TDelimiters> + template <typename T1, typename T2> + struct print_container_helper<T, TChar, TCharTraits, TDelimiters>::printer<std::pair<T1, T2>> + { + using ostream_type = typename print_container_helper<T, TChar, TCharTraits, TDelimiters>::ostream_type; + + static void print_body(const std::pair<T1, T2> & c, ostream_type & stream) + { + stream << c.first; + if (print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter != NULL) + stream << print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter; + stream << c.second; + } + }; + + // Specialization for tuples + + template <typename T, typename TChar, typename TCharTraits, typename TDelimiters> + template <typename ...Args> + struct print_container_helper<T, TChar, TCharTraits, TDelimiters>::printer<std::tuple<Args...>> + { + using ostream_type = typename print_container_helper<T, TChar, TCharTraits, TDelimiters>::ostream_type; + using element_type = std::tuple<Args...>; + + template <std::size_t I> struct Int { }; + + static void print_body(const element_type & c, ostream_type & stream) + { + tuple_print(c, stream, Int<0>()); + } + + static void tuple_print(const element_type &, ostream_type &, Int<sizeof...(Args)>) + { + } + + static void tuple_print(const element_type & c, ostream_type & stream, + typename std::conditional<sizeof...(Args) != 0, Int<0>, std::nullptr_t>::type) + { + stream << std::get<0>(c); + tuple_print(c, stream, Int<1>()); + } + + template <std::size_t N> + static void tuple_print(const element_type & c, ostream_type & stream, Int<N>) + { + if (print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter != NULL) + stream << print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter; + + stream << std::get<N>(c); + + tuple_print(c, stream, Int<N + 1>()); + } + }; + + // Prints a print_container_helper to the specified stream. + + template<typename T, typename TChar, typename TCharTraits, typename TDelimiters> + inline std::basic_ostream<TChar, TCharTraits> & operator<<( + std::basic_ostream<TChar, TCharTraits> & stream, + const print_container_helper<T, TChar, TCharTraits, TDelimiters> & helper) + { + helper(stream); + return stream; + } + + + // Basic is_container template; specialize to derive from std::true_type for all desired container types + + template <typename T> + struct is_container : public std::integral_constant<bool, + detail::has_const_iterator<T>::value && + detail::has_begin_end<T>::beg_value && + detail::has_begin_end<T>::end_value> { }; + + template <typename T, std::size_t N> + struct is_container<T[N]> : std::true_type { }; + + template <std::size_t N> + struct is_container<char[N]> : std::false_type { }; + + template <typename T> + struct is_container<std::valarray<T>> : std::true_type { }; + + template <typename T1, typename T2> + struct is_container<std::pair<T1, T2>> : std::true_type { }; + + template <typename ...Args> + struct is_container<std::tuple<Args...>> : std::true_type { }; + + + // Default delimiters + + template <typename T> struct delimiters<T, char> { static const delimiters_values<char> values; }; + template <typename T> const delimiters_values<char> delimiters<T, char>::values = { "[", ", ", "]" }; + template <typename T> struct delimiters<T, wchar_t> { static const delimiters_values<wchar_t> values; }; + template <typename T> const delimiters_values<wchar_t> delimiters<T, wchar_t>::values = { L"[", L", ", L"]" }; + + + // Delimiters for (multi)set and unordered_(multi)set + + template <typename T, typename TComp, typename TAllocator> + struct delimiters< ::std::set<T, TComp, TAllocator>, char> { static const delimiters_values<char> values; }; + + template <typename T, typename TComp, typename TAllocator> + const delimiters_values<char> delimiters< ::std::set<T, TComp, TAllocator>, char>::values = { "{", ", ", "}" }; + + template <typename T, typename TComp, typename TAllocator> + struct delimiters< ::std::set<T, TComp, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; }; + + template <typename T, typename TComp, typename TAllocator> + const delimiters_values<wchar_t> delimiters< ::std::set<T, TComp, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" }; + + template <typename T, typename TComp, typename TAllocator> + struct delimiters< ::std::multiset<T, TComp, TAllocator>, char> { static const delimiters_values<char> values; }; + + template <typename T, typename TComp, typename TAllocator> + const delimiters_values<char> delimiters< ::std::multiset<T, TComp, TAllocator>, char>::values = { "{", ", ", "}" }; + + template <typename T, typename TComp, typename TAllocator> + struct delimiters< ::std::multiset<T, TComp, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; }; + + template <typename T, typename TComp, typename TAllocator> + const delimiters_values<wchar_t> delimiters< ::std::multiset<T, TComp, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" }; + + template <typename T, typename THash, typename TEqual, typename TAllocator> + struct delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, char> { static const delimiters_values<char> values; }; + + template <typename T, typename THash, typename TEqual, typename TAllocator> + const delimiters_values<char> delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, char>::values = { "{", ", ", "}" }; + + template <typename T, typename THash, typename TEqual, typename TAllocator> + struct delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; }; + + template <typename T, typename THash, typename TEqual, typename TAllocator> + const delimiters_values<wchar_t> delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" }; + + template <typename T, typename THash, typename TEqual, typename TAllocator> + struct delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, char> { static const delimiters_values<char> values; }; + + template <typename T, typename THash, typename TEqual, typename TAllocator> + const delimiters_values<char> delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, char>::values = { "{", ", ", "}" }; + + template <typename T, typename THash, typename TEqual, typename TAllocator> + struct delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; }; + + template <typename T, typename THash, typename TEqual, typename TAllocator> + const delimiters_values<wchar_t> delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" }; + + + // Delimiters for pair and tuple + + template <typename T1, typename T2> struct delimiters<std::pair<T1, T2>, char> { static const delimiters_values<char> values; }; + template <typename T1, typename T2> const delimiters_values<char> delimiters<std::pair<T1, T2>, char>::values = { "(", ", ", ")" }; + template <typename T1, typename T2> struct delimiters< ::std::pair<T1, T2>, wchar_t> { static const delimiters_values<wchar_t> values; }; + template <typename T1, typename T2> const delimiters_values<wchar_t> delimiters< ::std::pair<T1, T2>, wchar_t>::values = { L"(", L", ", L")" }; + + template <typename ...Args> struct delimiters<std::tuple<Args...>, char> { static const delimiters_values<char> values; }; + template <typename ...Args> const delimiters_values<char> delimiters<std::tuple<Args...>, char>::values = { "(", ", ", ")" }; + template <typename ...Args> struct delimiters< ::std::tuple<Args...>, wchar_t> { static const delimiters_values<wchar_t> values; }; + template <typename ...Args> const delimiters_values<wchar_t> delimiters< ::std::tuple<Args...>, wchar_t>::values = { L"(", L", ", L")" }; + + + // Type-erasing helper class for easy use of custom delimiters. + // Requires TCharTraits = std::char_traits<TChar> and TChar = char or wchar_t, and MyDelims needs to be defined for TChar. + // Usage: "cout << pretty_print::custom_delims<MyDelims>(x)". + + struct custom_delims_base + { + virtual ~custom_delims_base() { } + virtual std::ostream & stream(::std::ostream &) = 0; + virtual std::wostream & stream(::std::wostream &) = 0; + }; + + template <typename T, typename Delims> + struct custom_delims_wrapper : custom_delims_base + { + custom_delims_wrapper(const T & t_) : t(t_) { } + + std::ostream & stream(std::ostream & s) + { + return s << print_container_helper<T, char, std::char_traits<char>, Delims>(t); + } + + std::wostream & stream(std::wostream & s) + { + return s << print_container_helper<T, wchar_t, std::char_traits<wchar_t>, Delims>(t); + } + + private: + const T & t; + }; + + template <typename Delims> + struct custom_delims + { + template <typename Container> + custom_delims(const Container & c) : base(new custom_delims_wrapper<Container, Delims>(c)) { } + + std::unique_ptr<custom_delims_base> base; + }; + + template <typename TChar, typename TCharTraits, typename Delims> + inline std::basic_ostream<TChar, TCharTraits> & operator<<(std::basic_ostream<TChar, TCharTraits> & s, const custom_delims<Delims> & p) + { + return p.base->stream(s); + } + + + // A wrapper for a C-style array given as pointer-plus-size. + // Usage: std::cout << pretty_print_array(arr, n) << std::endl; + + template<typename T> + struct array_wrapper_n + { + typedef const T * const_iterator; + typedef T value_type; + + array_wrapper_n(const T * const a, size_t n) : _array(a), _n(n) { } + inline const_iterator begin() const { return _array; } + inline const_iterator end() const { return _array + _n; } + + private: + const T * const _array; + size_t _n; + }; + + + // A wrapper for hash-table based containers that offer local iterators to each bucket. + // Usage: std::cout << bucket_print(m, 4) << std::endl; (Prints bucket 5 of container m.) + + template <typename T> + struct bucket_print_wrapper + { + typedef typename T::const_local_iterator const_iterator; + typedef typename T::size_type size_type; + + const_iterator begin() const + { + return m_map.cbegin(n); + } + + const_iterator end() const + { + return m_map.cend(n); + } + + bucket_print_wrapper(const T & m, size_type bucket) : m_map(m), n(bucket) { } + + private: + const T & m_map; + const size_type n; + }; + +} // namespace pretty_print + + +// Global accessor functions for the convenience wrappers + +template<typename T> +inline pretty_print::array_wrapper_n<T> pretty_print_array(const T * const a, size_t n) +{ + return pretty_print::array_wrapper_n<T>(a, n); +} + +template <typename T> pretty_print::bucket_print_wrapper<T> +bucket_print(const T & m, typename T::size_type n) +{ + return pretty_print::bucket_print_wrapper<T>(m, n); +} + + +// Main magic entry point: An overload snuck into namespace std. +// Can we do better? + +namespace std +{ + // Prints a container to the stream using default delimiters + + template<typename T, typename TChar, typename TCharTraits> + inline typename enable_if< ::pretty_print::is_container<T>::value, + basic_ostream<TChar, TCharTraits> &>::type + operator<<(basic_ostream<TChar, TCharTraits> & stream, const T & container) + { + return stream << ::pretty_print::print_container_helper<T, TChar, TCharTraits>(container); + } +} + + + +#endif // H_PRETTY_PRINT |