Skip to content

Instantly share code, notes, and snippets.

@louisdx
Created June 6, 2011 12:33
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save louisdx/1010166 to your computer and use it in GitHub Desktop.
Save louisdx/1010166 to your computer and use it in GitHub Desktop.
#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