text: //          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