Created
June 6, 2011 12:33
-
-
Save louisdx/1010166 to your computer and use it in GitHub Desktop.
Container pretty printer (cf. http://stackoverflow.com/questions/4850473/pretty-print-c-stl-containers)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef H_PRETTY_PRINT | |
#define H_PRETTY_PRINT | |
#define HAVE_VARIADIC_TEMPLATES 0 | |
#define HAVE_TEMPLATE_ALIASES 0 | |
#include <iostream> | |
#include <iterator> | |
#include <utility> | |
#include <tuple> | |
#include <algorithm> | |
#include <type_traits> | |
// This works similar to ostream_iterator, but doesn't print a delimiter after the final item | |
template<typename T, typename TChar = char, typename TCharTraits = std::char_traits<TChar>> | |
class pretty_ostream_iterator : public std::iterator<std::output_iterator_tag, void, void, void, void> | |
{ | |
public: | |
typedef TChar char_type; | |
typedef TCharTraits traits_type; | |
typedef std::basic_ostream<TChar, TCharTraits> ostream_type; | |
pretty_ostream_iterator(ostream_type & stream, const char_type * delim = NULL) | |
: _stream(&stream), _delim(delim), _insertDelim(false) | |
{ | |
} | |
pretty_ostream_iterator<T, TChar, TCharTraits> & operator=(const T & value) | |
{ | |
if (_delim != NULL) | |
{ | |
// Don't insert a delimiter if this is the first time the function is called | |
if (_insertDelim) | |
(*_stream) << _delim; | |
else | |
_insertDelim = true; | |
} | |
(*_stream) << value; | |
return *this; | |
} | |
pretty_ostream_iterator<T, TChar, TCharTraits> & operator*() | |
{ | |
return *this; | |
} | |
pretty_ostream_iterator<T, TChar, TCharTraits> & operator++() | |
{ | |
return *this; | |
} | |
pretty_ostream_iterator<T, TChar, TCharTraits> & operator++(int) | |
{ | |
return *this; | |
} | |
private: | |
ostream_type *_stream; | |
const char_type *_delim; | |
bool _insertDelim; | |
}; | |
#if _MSC_VER >= 1400 | |
// Declare pretty_ostream_iterator as checked | |
template<typename T, typename TChar, typename TCharTraits> | |
struct std::_Is_checked_helper<pretty_ostream_iterator<T, TChar, TCharTraits>> : public std::true_type | |
{ | |
}; | |
#endif // _MSC_VER >= 1400 | |
namespace std | |
{ | |
// Pre-declarations of container types so we don't actually have to include the relevant headers if not needed, speeding up compilation time. | |
template<typename T, typename TTraits, typename TAllocator> class set; | |
} | |
template<typename T> | |
struct is_container_helper | |
{ | |
private: | |
template<typename C> static char test(typename C::const_iterator*); | |
template<typename C> static int test(...); | |
public: | |
static const bool value = sizeof(test<T>(0)) == sizeof(char); | |
}; | |
// 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, is_container_helper<T>::value> { }; | |
// Holds the delimiter values for a specific character type | |
template<typename TChar> | |
struct delimiters_values | |
{ | |
typedef TChar char_type; | |
const TChar *prefix; | |
const TChar *delimiter; | |
const TChar *postfix; | |
}; | |
// Defines the delimiter values for a specific container and character type (default values in container_delimiters.h) | |
template<typename T, typename TChar> | |
struct delimiters | |
{ | |
static const delimiters_values<TChar> values; | |
}; | |
#if HAVE_TEMPLATE_ALIASES > 0 | |
// Template aliases for char and wchar_t delimiters | |
template<typename T> using sdelims = delimiters<T, char>; | |
template<typename T> using wsdelims = delimiters<T, wchar_t>; | |
#endif | |
// 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 set | |
template<typename T, typename TTraits, typename TAllocator> struct delimiters<std::set<T, TTraits, TAllocator>, char> { static const delimiters_values<char> values; }; | |
template<typename T, typename TTraits, typename TAllocator> const delimiters_values<char> delimiters<std::set<T, TTraits, TAllocator>, char>::values = { "{", ", ", "}" }; | |
template<typename T, typename TTraits, typename TAllocator> struct delimiters<std::set<T, TTraits, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; }; | |
template<typename T, typename TTraits, typename TAllocator> const delimiters_values<wchar_t> delimiters<std::set<T, TTraits, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" }; | |
// Delimiters for pair (reused for tuple, see below) | |
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")" }; | |
// Functor to print containers. You can use this directly if you want to specificy a non-default delimiters type. | |
template<typename T, typename TChar = char, typename TCharTraits = std::char_traits<TChar>, typename TDelimiters = delimiters<T, TChar>> | |
struct print_container_helper | |
{ | |
typedef TChar char_type; | |
typedef TDelimiters delimiters_type; | |
typedef std::basic_ostream<TChar, TCharTraits> & ostream_type; | |
print_container_helper(const T & container) | |
: _container(container) | |
{ | |
} | |
void operator()(ostream_type & stream) const | |
{ | |
if (delimiters_type::values.prefix != NULL) | |
stream << delimiters_type::values.prefix; | |
std::copy(_container.begin(), _container.end(), | |
pretty_ostream_iterator<typename T::value_type, TChar, TCharTraits>(stream, delimiters_type::values.delimiter)); | |
if (delimiters_type::values.postfix != NULL) | |
stream << delimiters_type::values.postfix; | |
} | |
private: | |
const T & _container; | |
}; | |
// Prints a print_container_helper to the specified stream. | |
template<typename T, typename TChar, typename TCharTraits, typename TDelimiters> | |
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; | |
} | |
// Prints a container to the stream using default delimiters | |
template<typename T, typename TChar, typename TCharTraits> | |
typename std::enable_if<is_container<T>::value, std::basic_ostream<TChar, TCharTraits>&>::type | |
operator<<(std::basic_ostream<TChar, TCharTraits> & stream, const T & container) | |
{ | |
return stream << print_container_helper<T, TChar, TCharTraits>(container); | |
} | |
// Prints a pair to the stream using delimiters from delimiters<std::pair<T1, T2>>. | |
template<typename T1, typename T2, typename TChar, typename TCharTraits> | |
std::basic_ostream<TChar, TCharTraits> & operator<<(std::basic_ostream<TChar, TCharTraits> & stream, const std::pair<T1, T2> & value) | |
{ | |
if (delimiters<std::pair<T1, T2>, TChar>::values.prefix != NULL) | |
stream << delimiters<std::pair<T1, T2>, TChar>::values.prefix; | |
stream << value.first; | |
if (delimiters<std::pair<T1, T2>, TChar>::values.delimiter != NULL) | |
stream << delimiters<std::pair<T1, T2>, TChar>::values.delimiter; | |
stream << value.second; | |
if (delimiters<std::pair<T1, T2>, TChar>::values.postfix != NULL) | |
stream << delimiters<std::pair<T1, T2>, TChar>::values.postfix; | |
return stream; | |
} | |
#if HAVE_VARIADIC_TEMPLATES > 0 | |
// Prints a tuple to the stream using delimiters from delimiters<std::pair<tuple_dummy_t, tuple_dummy_t>>. | |
struct tuple_dummy_t { }; // Just if you want special delimiters for tuples. | |
typedef std::pair<tuple_dummy_t, tuple_dummy_t> tuple_dummy_pair; | |
template<typename Tuple, size_t N, typename TChar, typename TCharTraits> | |
struct pretty_tuple_helper | |
{ | |
static inline void print(std::basic_ostream<TChar, TCharTraits> & stream, const Tuple & value) | |
{ | |
pretty_tuple_helper<Tuple, N - 1, TChar, TCharTraits>::print(stream, value); | |
if (delimiters<tuple_dummy_pair, TChar>::values.delimiter != NULL) | |
stream << delimiters<tuple_dummy_pair, TChar>::values.delimiter; | |
stream << std::get<N - 1>(value); | |
} | |
}; | |
template<typename Tuple, typename TChar, typename TCharTraits> | |
struct pretty_tuple_helper<Tuple, 1, TChar, TCharTraits> | |
{ | |
static inline void print(std::basic_ostream<TChar, TCharTraits> & stream, const Tuple & value) { stream << std::get<0>(value); } | |
}; | |
template<typename TChar, typename TCharTraits, typename ...Args> | |
std::basic_ostream<TChar, TCharTraits> & operator<<(std::basic_ostream<TChar, TCharTraits> & stream, const std::tuple<Args...> & value) | |
{ | |
if (delimiters<tuple_dummy_pair, TChar>::values.prefix != NULL) | |
stream << delimiters<tuple_dummy_pair, TChar>::values.prefix; | |
pretty_tuple_helper<const std::tuple<Args...> &, sizeof...(Args), TChar, TCharTraits>::print(stream, value); | |
if (delimiters<tuple_dummy_pair, TChar>::values.postfix != NULL) | |
stream << delimiters<tuple_dummy_pair, TChar>::values.postfix; | |
return stream; | |
} | |
#endif | |
// A wrapper for raw C-style arrays. Usage: int arr[] = { 1, 2, 4, 8, 16 }; std::cout << wrap_array(arr) << ... | |
template <typename T, size_t N> | |
struct array_wrapper | |
{ | |
typedef const T * const_iterator; | |
typedef T value_type; | |
array_wrapper(const T (& a)[N]) : _array(a) { } | |
inline const_iterator begin() const { return _array; } | |
inline const_iterator end() const { return _array + N; } | |
private: | |
const T * const _array; | |
}; | |
template <typename T, size_t N> | |
inline array_wrapper<T, N> wrap_array(const T (& a)[N]) | |
{ | |
return array_wrapper<T, N>(a); | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment