initial commit
This commit is contained in:
commit
44aa8d060a
|
@ -0,0 +1,32 @@
|
||||||
|
# `#include <soi>`
|
||||||
|
|
||||||
|
Include soi and you're ready to go!
|
||||||
|
|
||||||
|
## dbg(...)
|
||||||
|
|
||||||
|
You can debug any expressions using the macro dbg().
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
You can set the following environment variables to customize the behaviour.
|
||||||
|
|
||||||
|
`SOI_H_COLOR`: By default, colored output is shown in case a terminal is connected.
|
||||||
|
You can force colors with `SOI_H_COLOR=1` and shut them off with `SOI_H_COLOR=0`.
|
||||||
|
|
||||||
|
`SOI_H_EOFCHECK`: By default, it is *not* checked, whether you have read all the
|
||||||
|
input. In case you pipe the input from a file or want to issue a proper EOF
|
||||||
|
character (Control D under linux or Control Z under Windows), you can enable
|
||||||
|
this check using `SOI_H_COLOR=1`.
|
||||||
|
|
||||||
|
## Template
|
||||||
|
Using this header is as simple as:
|
||||||
|
|
||||||
|
```
|
||||||
|
#include <soi>
|
||||||
|
|
||||||
|
signed main() {
|
||||||
|
// your code goes here
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
It requires at least c++11 to function.
|
|
@ -0,0 +1,16 @@
|
||||||
|
// compile-command: "g++ -Iinclude -D_GLIBCXX_DEBUG -fsanitize=address,undefined -g3 -ggdb3 -std=c++17 example.cpp -o example && SOI_H_COLOR=1 SOI_H_EOFCHECK=1 ./example <<< ''"
|
||||||
|
#include <soi>
|
||||||
|
|
||||||
|
signed main() {
|
||||||
|
dbg("hi");
|
||||||
|
string s="world";
|
||||||
|
dbg(s);
|
||||||
|
dbg(false);
|
||||||
|
dbg(true);
|
||||||
|
dbg('c');
|
||||||
|
vector<int> pi{3,1,4,1,5,9,2,6};
|
||||||
|
dbg(pi);
|
||||||
|
dbg(vector<int>{3,1,4,1,5,9,2,6});
|
||||||
|
dbg(pi);
|
||||||
|
cout << "hi\n";
|
||||||
|
}
|
|
@ -0,0 +1,444 @@
|
||||||
|
// 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++
|
||||||
|
//
|
||||||
|
// The global operator<< overload hs been removed
|
||||||
|
|
||||||
|
#ifndef SOI_H_PRETTY_PRINT
|
||||||
|
#define SOI_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 // SOI_H_PRETTY_PRINT
|
|
@ -0,0 +1,103 @@
|
||||||
|
// -*- c++ -*-
|
||||||
|
/*
|
||||||
|
Students: please don't try to understand the details of headers just
|
||||||
|
yet. All will be explained. This header is primarily used so that you don't
|
||||||
|
have to understand every concept all at once.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <iostream>
|
||||||
|
#include <iterator>
|
||||||
|
#include <list>
|
||||||
|
#include <memory>
|
||||||
|
#include <ostream>
|
||||||
|
#include <set>
|
||||||
|
#include <sstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <tuple>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <utility>
|
||||||
|
#include <valarray>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "soi-dbg.hpp"
|
||||||
|
|
||||||
|
namespace soi_h {
|
||||||
|
|
||||||
|
void check_for_eof() {
|
||||||
|
if (!(std::cin >> std::ws).eof())
|
||||||
|
std::cerr << "WARNING: didn't read the whole input\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void noninteractive_check_eof() {
|
||||||
|
// make symbol 0x1A (Ctrl+Z) a whitespace
|
||||||
|
struct console_ctype : std::ctype<char> {
|
||||||
|
static const mask* get_table() {
|
||||||
|
static const std::array<mask, table_size> table = []() {
|
||||||
|
std::array<mask, table_size> table;
|
||||||
|
std::copy(classic_table(), classic_table() + table_size, table.begin());
|
||||||
|
table['\x1a'] |= space;
|
||||||
|
return table;
|
||||||
|
}();
|
||||||
|
return table.data();
|
||||||
|
}
|
||||||
|
console_ctype(std::size_t refs = 0) : ctype(get_table(), false, refs) {}
|
||||||
|
};
|
||||||
|
std::cin.imbue(std::locale(std::cin.getloc(), new console_ctype));
|
||||||
|
check_for_eof();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool should_check_for_eof() {
|
||||||
|
if (const char* eofcheck_enabled = std::getenv("SOI_H_EOFCHECK")) {
|
||||||
|
if (!std::strcmp(eofcheck_enabled, "1"))
|
||||||
|
return true;
|
||||||
|
if (!std::strcmp(eofcheck_enabled, "0"))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void initialize_debug() {
|
||||||
|
std::cout << std::unitbuf; // enable automatic flushing
|
||||||
|
std::cin.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
||||||
|
std::ios::sync_with_stdio(false);
|
||||||
|
|
||||||
|
if (should_check_for_eof() &&
|
||||||
|
std::atexit(noninteractive_check_eof) != 0) {
|
||||||
|
std::cerr << "WARNING: soi.h -- registration of sanity check at exit failed\n";
|
||||||
|
}
|
||||||
|
soi_h::detail::dbg_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct soi_h_initializer {
|
||||||
|
soi_h_initializer(bool release) {
|
||||||
|
if (release) {
|
||||||
|
std::ios::sync_with_stdio(false);
|
||||||
|
std::cin.tie(0);
|
||||||
|
} else {
|
||||||
|
initialize_debug();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef SOI_RELEASE
|
||||||
|
soi_h_initializer soi_h_initializer_{true};
|
||||||
|
#else
|
||||||
|
soi_h_initializer soi_h_initializer_{false};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // end namespace soi_h
|
||||||
|
|
||||||
|
#include "soi-deprecate.hpp"
|
||||||
|
|
||||||
|
#define int int64_t
|
||||||
|
using namespace std;
|
||||||
|
|
|
@ -0,0 +1,294 @@
|
||||||
|
// Copyright Johannes Kapfhammer 2019.
|
||||||
|
// 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 debug macro: allows debugging with dbg(<expression>);
|
||||||
|
// initialize with dbg_init() to enable colorized output
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SOI_H_DBG
|
||||||
|
#define SOI_H_DBG
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <cstring>
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "soi-pretty.hpp"
|
||||||
|
|
||||||
|
namespace soi_h {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// detecting the type name: https://stackoverflow.com/a/20170989
|
||||||
|
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
# if __cplusplus < 201103
|
||||||
|
# define CONSTEXPR11_TN
|
||||||
|
# define CONSTEXPR14_TN
|
||||||
|
# define NOEXCEPT_TN
|
||||||
|
# elif __cplusplus < 201402
|
||||||
|
# define CONSTEXPR11_TN constexpr
|
||||||
|
# define CONSTEXPR14_TN
|
||||||
|
# define NOEXCEPT_TN noexcept
|
||||||
|
# else
|
||||||
|
# define CONSTEXPR11_TN constexpr
|
||||||
|
# define CONSTEXPR14_TN constexpr
|
||||||
|
# define NOEXCEPT_TN noexcept
|
||||||
|
# endif
|
||||||
|
#else // _MSC_VER
|
||||||
|
# if _MSC_VER < 1900
|
||||||
|
# define CONSTEXPR11_TN
|
||||||
|
# define CONSTEXPR14_TN
|
||||||
|
# define NOEXCEPT_TN
|
||||||
|
# elif _MSC_VER < 2000
|
||||||
|
# define CONSTEXPR11_TN constexpr
|
||||||
|
# define CONSTEXPR14_TN
|
||||||
|
# define NOEXCEPT_TN noexcept
|
||||||
|
# else
|
||||||
|
# define CONSTEXPR11_TN constexpr
|
||||||
|
# define CONSTEXPR14_TN constexpr
|
||||||
|
# define NOEXCEPT_TN noexcept
|
||||||
|
# endif
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
class static_string {
|
||||||
|
const char* const p_;
|
||||||
|
const std::size_t sz_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef const char* const_iterator;
|
||||||
|
|
||||||
|
template <std::size_t N>
|
||||||
|
CONSTEXPR11_TN static_string(const char(&a)[N]) NOEXCEPT_TN
|
||||||
|
: p_(a)
|
||||||
|
, sz_(N-1)
|
||||||
|
{}
|
||||||
|
|
||||||
|
CONSTEXPR11_TN static_string(const char* p, std::size_t N) NOEXCEPT_TN
|
||||||
|
: p_(p)
|
||||||
|
, sz_(N)
|
||||||
|
{}
|
||||||
|
|
||||||
|
CONSTEXPR11_TN const char* data() const NOEXCEPT_TN {return p_;}
|
||||||
|
CONSTEXPR11_TN std::size_t size() const NOEXCEPT_TN {return sz_;}
|
||||||
|
|
||||||
|
CONSTEXPR11_TN const_iterator begin() const NOEXCEPT_TN {return p_;}
|
||||||
|
CONSTEXPR11_TN const_iterator end() const NOEXCEPT_TN {return p_ + sz_;}
|
||||||
|
|
||||||
|
CONSTEXPR11_TN char operator[](std::size_t n) const
|
||||||
|
{
|
||||||
|
return n < sz_ ? p_[n] : throw std::out_of_range("static_string");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct static_string_no_std {
|
||||||
|
bool is_debug;
|
||||||
|
bool is_std;
|
||||||
|
static_string type;
|
||||||
|
CONSTEXPR11_TN static_string_no_std(bool is_debug,
|
||||||
|
bool is_std,
|
||||||
|
static_string type)
|
||||||
|
: is_debug(is_debug), is_std(is_std), type(type) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline
|
||||||
|
std::ostream&
|
||||||
|
operator<<(std::ostream& os, static_string const& s)
|
||||||
|
{
|
||||||
|
return os.write(s.data(), s.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
std::ostream&
|
||||||
|
operator<<(std::ostream& os, static_string_no_std const& s) {
|
||||||
|
if (s.is_debug) {
|
||||||
|
const int k = sizeof("std::__debug::") - 1;
|
||||||
|
return os.write(s.type.data()+k, s.type.size()-k);
|
||||||
|
} else if (s.is_std) {
|
||||||
|
const int k = sizeof("std::") - 1;
|
||||||
|
return os.write(s.type.data()+k, s.type.size()-k);
|
||||||
|
} else {
|
||||||
|
return os.write(s.type.data(), s.type.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
CONSTEXPR14_TN
|
||||||
|
static_string
|
||||||
|
type_name()
|
||||||
|
{
|
||||||
|
const int k = sizeof("constexpr soi_h::detail:: T =")/sizeof(char);
|
||||||
|
#ifdef __clang__
|
||||||
|
static_string p = __PRETTY_FUNCTION__;
|
||||||
|
return static_string(p.data() + 31 + k, p.size() - 31 - k - 1);
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
static_string p = __PRETTY_FUNCTION__;
|
||||||
|
# if __cplusplus < 201402
|
||||||
|
return static_string(p.data() + 36 + k, p.size() - 36 - k - 1);
|
||||||
|
# else
|
||||||
|
return static_string(p.data() + 46 + k, p.size() - 46 - k - 1);
|
||||||
|
# endif
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
static_string p = __FUNCSIG__;
|
||||||
|
return static_string(p.data() + 38 + k, p.size() - 38 - k - 7);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
CONSTEXPR14_TN
|
||||||
|
static_string_no_std
|
||||||
|
sanitized_type_name() {
|
||||||
|
CONSTEXPR14_TN static_string t = type_name<T>();
|
||||||
|
CONSTEXPR14_TN bool is_std =
|
||||||
|
t.size() >= sizeof("std::") &&
|
||||||
|
t[ 0] == 's' &&
|
||||||
|
t[ 1] == 't' &&
|
||||||
|
t[ 2] == 'd' &&
|
||||||
|
t[ 3] == ':' &&
|
||||||
|
t[ 4] == ':';
|
||||||
|
CONSTEXPR14_TN bool is_debug =
|
||||||
|
is_std &&
|
||||||
|
t.size() >= sizeof("std::__debug::") &&
|
||||||
|
t[ 5] == '_' &&
|
||||||
|
t[ 6] == '_' &&
|
||||||
|
t[ 7] == 'd' &&
|
||||||
|
t[ 8] == 'e' &&
|
||||||
|
t[ 9] == 'b' &&
|
||||||
|
t[10] == 'u' &&
|
||||||
|
t[11] == 'g';
|
||||||
|
return static_string_no_std(is_debug, is_std, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// colorized output
|
||||||
|
|
||||||
|
bool tty_supports_colors() {
|
||||||
|
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
|
||||||
|
return isatty(STDERR_FILENO);
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int has_environment_color_overwrite() {
|
||||||
|
if (const char* color_enabled = std::getenv("SOI_H_COLOR")) {
|
||||||
|
if (!std::strcmp(color_enabled, "1"))
|
||||||
|
return 1;
|
||||||
|
if (!std::strcmp(color_enabled, "0"))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool are_colors_enabled() {
|
||||||
|
int c = has_environment_color_overwrite();
|
||||||
|
if (c == -1)
|
||||||
|
return tty_supports_colors();
|
||||||
|
return static_cast<bool>(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// init and static variables
|
||||||
|
|
||||||
|
static bool colors_enabled = false;
|
||||||
|
static const char* ANSI_DEBUG = "";
|
||||||
|
static const char* ANSI_EXPRESSION = "";
|
||||||
|
static const char* ANSI_VALUE = "";
|
||||||
|
static const char* ANSI_TYPE = "";
|
||||||
|
static const char* ANSI_MESSAGE = "";
|
||||||
|
static const char* ANSI_RESET = "";
|
||||||
|
|
||||||
|
void dbg_init(bool with_colors) {
|
||||||
|
if (with_colors) {
|
||||||
|
bool colors_enabled = true;
|
||||||
|
ANSI_DEBUG = "\x1b[02m";
|
||||||
|
ANSI_EXPRESSION = "\x1b[36m";
|
||||||
|
ANSI_VALUE = "\x1b[01m";
|
||||||
|
ANSI_TYPE = "\x1b[32m";
|
||||||
|
ANSI_MESSAGE = "\x1b[31m\x1b[01m";
|
||||||
|
ANSI_RESET = "\x1b[0m";
|
||||||
|
} else {
|
||||||
|
bool colors_enabled = false;
|
||||||
|
ANSI_DEBUG = "";
|
||||||
|
ANSI_EXPRESSION = "";
|
||||||
|
ANSI_VALUE = "";
|
||||||
|
ANSI_TYPE = "";
|
||||||
|
ANSI_MESSAGE = "";
|
||||||
|
ANSI_RESET = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dbg_init() {
|
||||||
|
dbg_init(are_colors_enabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// printer
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T&& dbg_print(T&& value,
|
||||||
|
static_string_no_std const& type,
|
||||||
|
char const* file,
|
||||||
|
int line,
|
||||||
|
char const* function_name,
|
||||||
|
char const* expression) {
|
||||||
|
const T& ref = value;
|
||||||
|
std::stringstream value_buffer; // avoid nesting of dbg macros within print functinos
|
||||||
|
soi_h::pretty_print(value_buffer, ref);
|
||||||
|
|
||||||
|
std::cerr << ANSI_DEBUG
|
||||||
|
<< "[" << file << ":" << line
|
||||||
|
<< " (" << function_name << ")] " << ANSI_RESET
|
||||||
|
<< ANSI_EXPRESSION << expression << ANSI_RESET
|
||||||
|
<< " = "
|
||||||
|
<< ANSI_VALUE << value_buffer.rdbuf() << ANSI_RESET
|
||||||
|
<< " (" << ANSI_TYPE << type << ANSI_RESET << ")"
|
||||||
|
<< '\n';
|
||||||
|
|
||||||
|
return std::forward<T>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<unsigned int N>
|
||||||
|
auto dbg_print(const char (&msg)[N],
|
||||||
|
static_string_no_std const&,
|
||||||
|
char const* file,
|
||||||
|
int line,
|
||||||
|
char const* function_name,
|
||||||
|
char const* expression) -> decltype(msg) {
|
||||||
|
std::cerr << ANSI_DEBUG
|
||||||
|
<< "[" << file << ":" << line
|
||||||
|
<< " (" << function_name << ")] " << ANSI_RESET
|
||||||
|
<< ANSI_MESSAGE << msg << ANSI_RESET
|
||||||
|
<< '\n';
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T&& identity(T&& t) {
|
||||||
|
return std::forward<T>(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end namespace detail
|
||||||
|
|
||||||
|
} // end namespace dbg_macro
|
||||||
|
|
||||||
|
#ifdef SOI_H_RELEASE
|
||||||
|
#define dbg(...) dbg_macro::identity(__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define dbg(...) \
|
||||||
|
soi_h::detail::dbg_print((__VA_ARGS__), \
|
||||||
|
soi_h::detail::sanitized_type_name<decltype(__VA_ARGS__)>(), \
|
||||||
|
__FILE__, \
|
||||||
|
__LINE__, \
|
||||||
|
__func__, \
|
||||||
|
#__VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // SOI_H_DBG
|
|
@ -0,0 +1,62 @@
|
||||||
|
#pragma GCC diagnostic error "-Wdeprecated-declarations"
|
||||||
|
|
||||||
|
struct endl_is_evil_t {} endl_is_evil;
|
||||||
|
[[deprecated("endl is evil. Use '\\n' to print a newline.")]] std::ostream & operator<<(std::ostream &os, endl_is_evil_t);
|
||||||
|
#define endl endl_is_evil
|
||||||
|
|
||||||
|
#define printf printf_is_evil
|
||||||
|
#define fprintf fprintf_is_evil
|
||||||
|
#define sprintf sprintf_is_evil
|
||||||
|
#define snprintf snprintf_is_evil
|
||||||
|
[[deprecated("printf is evil. Use cout.")]] int printf(const char *format, ...);
|
||||||
|
[[deprecated("printf is evil. Use cout.")]] int fprintf(std::FILE *stream, const char *format, ...);
|
||||||
|
[[deprecated("printf is evil. Use cout.")]] int sprintf(char *buffer, const char *format, ...);
|
||||||
|
[[deprecated("printf is evil. Use cout.")]] int snprintf(char *buffer, std::size_t buf_size, const char *format, ...);
|
||||||
|
|
||||||
|
#define scanf scanf_is_evil
|
||||||
|
#define fscanf fscanf_is_evil
|
||||||
|
#define sscanf sscanf_is_evil
|
||||||
|
[[deprecated("scanf is evil. Use cin.")]] int scanf(const char *format, ...);
|
||||||
|
[[deprecated("scanf is evil. Use cin.")]] int fscanf(std::FILE *stream, const char *format, ...);
|
||||||
|
[[deprecated("scanf is evil. Use cin.")]] int sscanf(const char *buffer, const char *format, ...);
|
||||||
|
|
||||||
|
#define puts puts_is_evil
|
||||||
|
#define fputs fputs_is_evil
|
||||||
|
#define fgets fgets_is_evil
|
||||||
|
#define freopen freopen_is_evil
|
||||||
|
#define fopen fopen_is_evil
|
||||||
|
#define fclose fclose_is_evil
|
||||||
|
#define fflush fflush_is_evil
|
||||||
|
#define getchar getchar_is_evil
|
||||||
|
#define fgetc fgetc_is_evil
|
||||||
|
#define getc getc_is_evil
|
||||||
|
#define setbuf setbuf_is_evil
|
||||||
|
#define setvbuf setvbuf_is_evil
|
||||||
|
#define fread fread_is_evil
|
||||||
|
#define fwrite fwrite_is_evil
|
||||||
|
[[deprecated("<cstdio> is evil. Use cin/cout.")]] int puts(const char *str);
|
||||||
|
[[deprecated("<cstdio> is evil. Use cin/cout.")]] int fputs(const char *str, FILE *stream);
|
||||||
|
[[deprecated("<cstdio> is evil. Use cin/cout.")]] char *fgets(char *str, int count, FILE *stream);
|
||||||
|
[[deprecated("<cstdio> is evil. Use cin/cout.")]] std::FILE *freopen(const char *filename, const char *mode, std::FILE *stream);
|
||||||
|
[[deprecated("<cstdio> is evil. Use cin/cout.")]] std::FILE *fopen(const char *filename, const char *mode);
|
||||||
|
[[deprecated("<cstdio> is evil. Use cin/cout.")]] int fclose(std::FILE *stream);
|
||||||
|
[[deprecated("<cstdio> is evil. Use cin/cout.")]] int fflush(std::FILE *stream);
|
||||||
|
[[deprecated("<cstdio> is evil. Use cin/cout.")]] int getchar();
|
||||||
|
[[deprecated("<cstdio> is evil. Use cin/cout.")]] int fgetc(std::FILE *stream);
|
||||||
|
[[deprecated("<cstdio> is evil. Use cin/cout.")]] int getc(std::FILE *stream);
|
||||||
|
[[deprecated("<cstdio> is evil. Use cin/cout.")]] void setbuf(std::FILE *stream, char *buffer);
|
||||||
|
[[deprecated("<cstdio> is evil. Use cin/cout.")]] int setvbuf(std::FILE *stream, char *buffer, int mode, std::size_t size);
|
||||||
|
[[deprecated("<cstdio> is evil. Use cin/cout.")]] std::size_t fread(void *buffer, std::size_t size, std::size_t count, std::FILE *stream);
|
||||||
|
[[deprecated("<cstdio> is evil. Use cin/cout.")]] std::size_t fwrite(const void *buffer, std::size_t size, std::size_t count, std::FILE *stream);
|
||||||
|
|
||||||
|
#define malloc malloc_is_evil
|
||||||
|
#define calloc calloc_is_evil
|
||||||
|
#define realloc realloc_is_evil
|
||||||
|
#define free free_is_evil
|
||||||
|
[[deprecated("malloc/free is evil. Use a vector.")]] void *malloc(std::size_t size);
|
||||||
|
[[deprecated("malloc/free is evil. Use a vector.")]] void *calloc(std::size_t num, std::size_t size);
|
||||||
|
[[deprecated("malloc/free is evil. Use a vector.")]] void *realloc(void *ptr, std::size_t new_size);
|
||||||
|
[[deprecated("malloc/free is evil. Use a vector.")]] void *free(void *ptr, std::size_t new_size);
|
||||||
|
|
||||||
|
[[deprecated("new is evil. Use a vector.")]] void *operator new(std::size_t sz);
|
||||||
|
[[deprecated("delete is evil. Use a vector.")]] void operator delete(void *ptr) noexcept;
|
|
@ -0,0 +1,76 @@
|
||||||
|
// Copyright Johannes Kapfhammer 2019.
|
||||||
|
// 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)
|
||||||
|
//
|
||||||
|
// pretty printing with c++
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SOI_H_PRETTY
|
||||||
|
#define SOI_H_PRETTY
|
||||||
|
|
||||||
|
#include "prettyprint.hpp"
|
||||||
|
|
||||||
|
namespace soi_h {
|
||||||
|
|
||||||
|
template<typename T, typename TChar, typename TCharTraits>
|
||||||
|
inline typename std::enable_if< ::pretty_print::is_container<T>::value,
|
||||||
|
std::basic_ostream<TChar, TCharTraits> &>::type
|
||||||
|
pretty_print(std::basic_ostream<TChar, TCharTraits> & stream, const T & container) {
|
||||||
|
return stream << ::pretty_print::print_container_helper<T, TChar, TCharTraits>(container);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TChar, typename TCharTraits>
|
||||||
|
std::basic_ostream<TChar, TCharTraits> &
|
||||||
|
pretty_print(std::basic_ostream<TChar, TCharTraits> & stream, const bool& x) {
|
||||||
|
return stream << (x ? "true" : "false");
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
template<typename TChar, typename TCharTraits>
|
||||||
|
void escape_char(std::basic_ostream<TChar, TCharTraits> & stream, char c) {
|
||||||
|
switch (c) {
|
||||||
|
case '\a': stream << "\\a"; break;
|
||||||
|
case '\b': stream << "\\b"; break;
|
||||||
|
case '\t': stream << "\\t"; break;
|
||||||
|
case '\n': stream << "\\n"; break;
|
||||||
|
case '\v': stream << "\\v"; break;
|
||||||
|
case '\f': stream << "\\f"; break;
|
||||||
|
case '\r': stream << "\\r"; break;
|
||||||
|
case '\e': stream << "\\e"; break;
|
||||||
|
case '\"': stream << "\\\""; break;
|
||||||
|
case '\'': stream << "\\'"; break;
|
||||||
|
case '\?': stream << "\\?"; break;
|
||||||
|
case '\\': stream << "\\\\"; break;
|
||||||
|
default: stream << c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TChar, typename TCharTraits>
|
||||||
|
std::basic_ostream<TChar, TCharTraits> &
|
||||||
|
pretty_print(std::basic_ostream<TChar, TCharTraits> & stream, const std::string& x) {
|
||||||
|
stream << "\"";
|
||||||
|
for (char c : x)
|
||||||
|
detail::escape_char(stream, c);
|
||||||
|
return stream << "\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TChar, typename TCharTraits>
|
||||||
|
std::basic_ostream<TChar, TCharTraits> &
|
||||||
|
pretty_print(std::basic_ostream<TChar, TCharTraits> & stream, char c) {
|
||||||
|
stream << "'";
|
||||||
|
detail::escape_char(stream, c);
|
||||||
|
return stream << "'";
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename TChar, typename TCharTraits>
|
||||||
|
inline typename std::enable_if< !::pretty_print::is_container<T>::value,
|
||||||
|
std::basic_ostream<TChar, TCharTraits> &>::type
|
||||||
|
pretty_print(std::basic_ostream<TChar, TCharTraits> & stream, const T& x) {
|
||||||
|
return stream << x;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // SOI_H_PRETTY
|
Loading…
Reference in New Issue