diff --git a/example.cpp b/example.cpp index 9281c42..0568cef 100644 --- a/example.cpp +++ b/example.cpp @@ -1,7 +1,7 @@ // 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 -signed main() { +signed main() { dbg("hi"); string s="world"; dbg(s); @@ -11,9 +11,6 @@ signed main() { vector pi{3,1,4,1,5,9,2,6}; dbg(pi); dbg(vector{3,1,4,1,5,9,2,6}); - dbg(vector>{{3,1},{4,1}}); - dbg(vector>>{{3,{"hi"}},{4,{"hello", "world"}}}); - dbg(set{3,1,4}); - dbg(map{{3,"three"},{1,"one"}}); + dbg(pi); cout << "hi\n"; } diff --git a/include/bits/include-all.hpp b/include/bits/include-all.hpp index b75e18e..639d3df 100644 --- a/include/bits/include-all.hpp +++ b/include/bits/include-all.hpp @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/include/bits/prettyprint.hpp b/include/bits/prettyprint.hpp index 862ee3d..a480c97 100644 --- a/include/bits/prettyprint.hpp +++ b/include/bits/prettyprint.hpp @@ -21,476 +21,424 @@ #include #include -namespace soi { +namespace pretty_print +{ + namespace detail + { + // SFINAE type trait to detect whether T::const_iterator exists. -template -std::basic_ostream & -print(std::basic_ostream &stream, const T &x); + struct sfinae_base + { + using yes = char; + using no = yes[2]; + }; -namespace detail { -// SFINAE type trait to detect whether T::const_iterator exists. + template + struct has_const_iterator : private sfinae_base + { + private: + template static yes & test(typename C::const_iterator*); + template static no & test(...); + public: + static const bool value = sizeof(test(nullptr)) == sizeof(yes); + using type = T; + }; -struct sfinae_base { - using yes = char; - using no = yes[2]; -}; + template + struct has_begin_end : private sfinae_base + { + private: + template + static yes & f(typename std::enable_if< + std::is_same(&C::begin)), + typename C::const_iterator(C::*)() const>::value>::type *); -template struct has_const_iterator : private sfinae_base { -private: - template static yes &test(typename C::const_iterator *); - template static no &test(...); + template static no & f(...); -public: - static const bool value = sizeof(test(nullptr)) == sizeof(yes); - using type = T; -}; + template + static yes & g(typename std::enable_if< + std::is_same(&C::end)), + typename C::const_iterator(C::*)() const>::value, void>::type*); -template struct has_begin_end : private sfinae_base { -private: - template - static yes & - f(typename std::enable_if< - std::is_same(&C::begin)), - typename C::const_iterator (C::*)() const>::value>::type *); + template static no & g(...); - template static no &f(...); + public: + static bool const beg_value = sizeof(f(nullptr)) == sizeof(yes); + static bool const end_value = sizeof(g(nullptr)) == sizeof(yes); + }; - template - static yes & - g(typename std::enable_if< - std::is_same(&C::end)), - typename C::const_iterator (C::*)() const>::value, - void>::type *); + } // namespace detail - template static no &g(...); -public: - static bool const beg_value = sizeof(f(nullptr)) == sizeof(yes); - static bool const end_value = sizeof(g(nullptr)) == sizeof(yes); -}; + // Holds the delimiter values for a specific character type -} // namespace detail + template + struct delimiters_values + { + using char_type = TChar; + const char_type * prefix; + const char_type * delimiter; + const char_type * postfix; + }; -// Holds the delimiter values for a specific character type -template 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 -// Defines the delimiter values for a specific container and character type + template + struct delimiters + { + using type = delimiters_values; + static const type values; + }; -template struct delimiters { - using type = delimiters_values; - static const type values; -}; -// Functor to pretty_print containers. You can use this directly if you want -// to specificy a non-default delimiters type. The pretty_printing logic can -// be customized by specializing the nested template. + // 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 TDelimiters = delimiters> -struct pretty_print_container_helper { - using delimiters_type = TDelimiters; - using ostream_type = std::basic_ostream; + template , + typename TDelimiters = delimiters> + struct print_container_helper + { + using delimiters_type = TDelimiters; + using ostream_type = std::basic_ostream; - template struct pretty_printer { - static void pretty_print_body(const U &c, ostream_type &stream) { - using std::begin; - using std::end; + template + 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); + auto it = begin(c); + const auto the_end = end(c); - if (it != the_end) { - for (;;) { - ::soi::print(stream, *it); + if (it != the_end) + { + for ( ; ; ) + { + stream << *it; - if (++it == the_end) - break; + if (++it == the_end) break; - if (delimiters_type::values.delimiter != NULL) - ::soi::print(stream, delimiters_type::values.delimiter); + 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::print_body(container_, stream); + + if (delimiters_type::values.postfix != NULL) + stream << delimiters_type::values.postfix; } - } + + private: + const T & container_; + }; + + // Specialization for pairs + + template + template + struct print_container_helper::printer> + { + using ostream_type = typename print_container_helper::ostream_type; + + static void print_body(const std::pair & c, ostream_type & stream) + { + stream << c.first; + if (print_container_helper::delimiters_type::values.delimiter != NULL) + stream << print_container_helper::delimiters_type::values.delimiter; + stream << c.second; + } + }; + + // Specialization for tuples + + template + template + struct print_container_helper::printer> + { + using ostream_type = typename print_container_helper::ostream_type; + using element_type = std::tuple; + + template 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) + { + } + + static void tuple_print(const element_type & c, ostream_type & stream, + typename std::conditional, std::nullptr_t>::type) + { + stream << std::get<0>(c); + tuple_print(c, stream, Int<1>()); + } + + template + static void tuple_print(const element_type & c, ostream_type & stream, Int) + { + if (print_container_helper::delimiters_type::values.delimiter != NULL) + stream << print_container_helper::delimiters_type::values.delimiter; + + stream << std::get(c); + + tuple_print(c, stream, Int()); + } + }; + + // Prints a print_container_helper to the specified stream. + + template + inline std::basic_ostream & operator<<( + std::basic_ostream & stream, + const print_container_helper & helper) + { + helper(stream); + return stream; } - }; - - pretty_print_container_helper(const T &container) : container_(container) {} - - inline void operator()(ostream_type &stream) const { - if (delimiters_type::values.prefix != NULL) - ::soi::print(stream, delimiters_type::values.prefix); - - pretty_printer::pretty_print_body(container_, stream); - - if (delimiters_type::values.postfix != NULL) - ::soi::print(stream, delimiters_type::values.postfix); - } - -private: - const T &container_; -}; - -// Specialization for pairs - -template -template -struct pretty_print_container_helper< - T, TChar, TCharTraits, TDelimiters>::pretty_printer> { - using ostream_type = - typename pretty_print_container_helper::ostream_type; - - static void pretty_print_body(const std::pair &c, - ostream_type &stream) { - ::soi::print(stream, c.first); - if (pretty_print_container_helper::delimiters_type::values - .delimiter != NULL) - ::soi::print( - stream, - pretty_print_container_helper::delimiters_type::values - .delimiter); - ::soi::print(stream, c.second); - } -}; - -// Specialization for tuples - -template -template -struct pretty_print_container_helper< - T, TChar, TCharTraits, TDelimiters>::pretty_printer> { - using ostream_type = - typename pretty_print_container_helper::ostream_type; - using element_type = std::tuple; - - template struct Int {}; - - static void pretty_print_body(const element_type &c, ostream_type &stream) { - tuple_pretty_print(c, stream, Int<0>()); - } - - static void tuple_pretty_print(const element_type &, ostream_type &, - Int) {} - - static void - tuple_pretty_print(const element_type &c, ostream_type &stream, - typename std::conditional, - std::nullptr_t>::type) { - ::soi::print(stream, std::get<0>(c)); - tuple_pretty_print(c, stream, Int<1>()); - } - - template - static void tuple_pretty_print(const element_type &c, ostream_type &stream, - Int) { - if (pretty_print_container_helper::delimiters_type::values - .delimiter != NULL) - ::soi::print( - stream, - pretty_print_container_helper::delimiters_type::values - .delimiter); - - ::soi::print(stream, std::get(c)); - - tuple_pretty_print(c, stream, Int()); - } -}; - -// Pretty_Prints a pretty_print_container_helper to the specified stream. - -template -inline std::basic_ostream & -pretty_print(std::basic_ostream &stream, - const pretty_print_container_helper &helper) { - helper(stream); - return stream; -} - -// Basic is_container template; specialize to derive from std::true_type for all -// desired container types - -template -struct is_container - : public std::integral_constant::value && - detail::has_begin_end::beg_value && - detail::has_begin_end::end_value> {}; - -template -struct is_container : std::true_type {}; - -template struct is_container : std::false_type {}; - -template struct is_container> : std::true_type {}; - -template -struct is_container> : std::true_type {}; - -template -struct is_container> : std::true_type {}; - -// Default delimiters - -template struct delimiters { - static const delimiters_values values; -}; -template -const delimiters_values delimiters::values = {"[", ", ", "]"}; -template struct delimiters { - static const delimiters_values values; -}; -template -const delimiters_values delimiters::values = {L"[", L", ", - L"]"}; - -// Delimiters for (multi)set and unordered_(multi)set - -template -struct delimiters<::std::set, char> { - static const delimiters_values values; -}; - -template -const delimiters_values - delimiters<::std::set, char>::values = {"{", ", ", - "}"}; - -template -struct delimiters<::std::set, wchar_t> { - static const delimiters_values values; -}; - -template -const delimiters_values - delimiters<::std::set, wchar_t>::values = { - L"{", L", ", L"}"}; - -template -struct delimiters<::std::multiset, char> { - static const delimiters_values values; -}; - -template -const delimiters_values delimiters<::std::multiset, - char>::values = {"{", ", ", "}"}; - -template -struct delimiters<::std::multiset, wchar_t> { - static const delimiters_values values; -}; - -template -const delimiters_values - delimiters<::std::multiset, wchar_t>::values = { - L"{", L", ", L"}"}; - -template -struct delimiters<::std::unordered_set, char> { - static const delimiters_values values; -}; - -template -const delimiters_values delimiters< - ::std::unordered_set, char>::values = { - "{", ", ", "}"}; - -template -struct delimiters<::std::unordered_set, wchar_t> { - static const delimiters_values values; -}; - -template -const delimiters_values delimiters< - ::std::unordered_set, wchar_t>::values = { - L"{", L", ", L"}"}; - -template -struct delimiters<::std::unordered_multiset, - char> { - static const delimiters_values values; -}; - -template -const delimiters_values delimiters< - ::std::unordered_multiset, char>::values = { - "{", ", ", "}"}; - -template -struct delimiters<::std::unordered_multiset, - wchar_t> { - static const delimiters_values values; -}; - -template -const delimiters_values - delimiters<::std::unordered_multiset, - wchar_t>::values = {L"{", L", ", L"}"}; - -// Delimiters for pair and tuple - -template struct delimiters, char> { - static const delimiters_values values; -}; -template -const delimiters_values delimiters, char>::values = { - "(", ", ", ")"}; -template -struct delimiters<::std::pair, wchar_t> { - static const delimiters_values values; -}; -template -const delimiters_values - delimiters<::std::pair, wchar_t>::values = {L"(", L", ", L")"}; - -template struct delimiters, char> { - static const delimiters_values values; -}; -template -const delimiters_values delimiters, char>::values = { - "(", ", ", ")"}; -template struct delimiters<::std::tuple, wchar_t> { - static const delimiters_values values; -}; -template -const delimiters_values - delimiters<::std::tuple, wchar_t>::values = {L"(", L", ", L")"}; - -// Type-erasing helper class for easy use of custom delimiters. -// Requires TCharTraits = std::char_traits and TChar = char or wchar_t, -// and MyDelims needs to be defined for TChar. Usage: "cout << -// pretty_pretty_print::custom_delims(x)". - -struct custom_delims_base { - virtual ~custom_delims_base() {} - virtual std::ostream &stream(::std::ostream &) = 0; - virtual std::wostream &stream(::std::wostream &) = 0; -}; - -template -struct custom_delims_wrapper : custom_delims_base { - custom_delims_wrapper(const T &t_) : t(t_) {} - - std::ostream &stream(std::ostream &s) { - return pretty_print( - s, - pretty_print_container_helper, Delims>( - t)); - } - - std::wostream &stream(std::wostream &s) { - return pretty_print( - s, pretty_print_container_helper, - Delims>(t)); - } - -private: - const T &t; -}; - -template struct custom_delims { - template - custom_delims(const Container &c) - : base(new custom_delims_wrapper(c)) {} - - std::unique_ptr base; -}; - -template -inline std::basic_ostream & -pretty_print(std::basic_ostream &s, - const custom_delims &p) { - return p.base->stream(s); -} - -// A wrapper for a C-style array given as pointer-plus-size. -// Usage: std::cout << pretty_pretty_print_array(arr, n) << std::endl; - -template 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_pretty_print(m, 4) << std::endl; -// (Pretty_Prints bucket 5 of container m.) - -template struct bucket_pretty_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_pretty_print_wrapper(const T &m, size_type bucket) - : m_map(m), n(bucket) {} - -private: - const T &m_map; - const size_type n; -}; - -} // namespace soi + + + // Basic is_container template; specialize to derive from std::true_type for all desired container types + + template + struct is_container : public std::integral_constant::value && + detail::has_begin_end::beg_value && + detail::has_begin_end::end_value> { }; + + template + struct is_container : std::true_type { }; + + template + struct is_container : std::false_type { }; + + template + struct is_container> : std::true_type { }; + + template + struct is_container> : std::true_type { }; + + template + struct is_container> : std::true_type { }; + + + // Default delimiters + + template struct delimiters { static const delimiters_values values; }; + template const delimiters_values delimiters::values = { "[", ", ", "]" }; + template struct delimiters { static const delimiters_values values; }; + template const delimiters_values delimiters::values = { L"[", L", ", L"]" }; + + + // Delimiters for (multi)set and unordered_(multi)set + + template + struct delimiters< ::std::set, char> { static const delimiters_values values; }; + + template + const delimiters_values delimiters< ::std::set, char>::values = { "{", ", ", "}" }; + + template + struct delimiters< ::std::set, wchar_t> { static const delimiters_values values; }; + + template + const delimiters_values delimiters< ::std::set, wchar_t>::values = { L"{", L", ", L"}" }; + + template + struct delimiters< ::std::multiset, char> { static const delimiters_values values; }; + + template + const delimiters_values delimiters< ::std::multiset, char>::values = { "{", ", ", "}" }; + + template + struct delimiters< ::std::multiset, wchar_t> { static const delimiters_values values; }; + + template + const delimiters_values delimiters< ::std::multiset, wchar_t>::values = { L"{", L", ", L"}" }; + + template + struct delimiters< ::std::unordered_set, char> { static const delimiters_values values; }; + + template + const delimiters_values delimiters< ::std::unordered_set, char>::values = { "{", ", ", "}" }; + + template + struct delimiters< ::std::unordered_set, wchar_t> { static const delimiters_values values; }; + + template + const delimiters_values delimiters< ::std::unordered_set, wchar_t>::values = { L"{", L", ", L"}" }; + + template + struct delimiters< ::std::unordered_multiset, char> { static const delimiters_values values; }; + + template + const delimiters_values delimiters< ::std::unordered_multiset, char>::values = { "{", ", ", "}" }; + + template + struct delimiters< ::std::unordered_multiset, wchar_t> { static const delimiters_values values; }; + + template + const delimiters_values delimiters< ::std::unordered_multiset, wchar_t>::values = { L"{", L", ", L"}" }; + + + // Delimiters for pair and tuple + + template struct delimiters, char> { static const delimiters_values values; }; + template const delimiters_values delimiters, char>::values = { "(", ", ", ")" }; + template struct delimiters< ::std::pair, wchar_t> { static const delimiters_values values; }; + template const delimiters_values delimiters< ::std::pair, wchar_t>::values = { L"(", L", ", L")" }; + + template struct delimiters, char> { static const delimiters_values values; }; + template const delimiters_values delimiters, char>::values = { "(", ", ", ")" }; + template struct delimiters< ::std::tuple, wchar_t> { static const delimiters_values values; }; + template const delimiters_values delimiters< ::std::tuple, wchar_t>::values = { L"(", L", ", L")" }; + + + // Type-erasing helper class for easy use of custom delimiters. + // Requires TCharTraits = std::char_traits and TChar = char or wchar_t, and MyDelims needs to be defined for TChar. + // Usage: "cout << pretty_print::custom_delims(x)". + + struct custom_delims_base + { + virtual ~custom_delims_base() { } + virtual std::ostream & stream(::std::ostream &) = 0; + virtual std::wostream & stream(::std::wostream &) = 0; + }; + + template + 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, Delims>(t); + } + + std::wostream & stream(std::wostream & s) + { + return s << print_container_helper, Delims>(t); + } + + private: + const T & t; + }; + + template + struct custom_delims + { + template + custom_delims(const Container & c) : base(new custom_delims_wrapper(c)) { } + + std::unique_ptr base; + }; + + template + inline std::basic_ostream & operator<<(std::basic_ostream & s, const custom_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 + 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 + 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 -inline pretty_pretty_print::array_wrapper_n pretty_pretty_print_array(const T -* const a, size_t n) +inline pretty_print::array_wrapper_n pretty_print_array(const T * const a, size_t n) { -return pretty_pretty_print::array_wrapper_n(a, n); + return pretty_print::array_wrapper_n(a, n); } -template pretty_pretty_print::bucket_pretty_print_wrapper -bucket_pretty_print(const T & m, typename T::size_type n) +template pretty_print::bucket_print_wrapper +bucket_print(const T & m, typename T::size_type n) { -return pretty_pretty_print::bucket_pretty_print_wrapper(m, n); + return pretty_print::bucket_print_wrapper(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 + inline typename enable_if< ::pretty_print::is_container::value, + basic_ostream &>::type + operator<<(basic_ostream & stream, const T & container) + { + return stream << ::pretty_print::print_container_helper(container); + } +} */ -namespace soi { -// Pretty_Prints a container to the stream using default delimiters - -template -inline typename std::enable_if<::soi::is_container::value, - std::basic_ostream &>::type -pretty_print(std::basic_ostream &stream, - const T &container) { - return ::soi::print( - stream, - ::soi::pretty_print_container_helper(container)); -} -} // namespace soi - -#endif // SOI_PRETTY_PRETTY_PRINT +#endif // SOI_PRETTY_PRINT diff --git a/include/bits/soi-dbg.hpp b/include/bits/soi-dbg.hpp index cbb47a4..b45b678 100644 --- a/include/bits/soi-dbg.hpp +++ b/include/bits/soi-dbg.hpp @@ -11,11 +11,11 @@ #define SOI_DBG #include -#include -#include -#include -#include #include +#include +#include +#include +#include #if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) #include @@ -23,7 +23,7 @@ #include "soi-pretty.hpp" -namespace soi { +namespace soi_h { namespace detail { @@ -31,99 +31,113 @@ 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 +# 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_; + const char* const p_; + const std::size_t sz_; public: - typedef const char *const_iterator; + typedef const char* const_iterator; - template - CONSTEXPR11_TN static_string(const char (&a)[N]) NOEXCEPT_TN : p_(a), - sz_(N - 1) {} + template + 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 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 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 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"); - } + CONSTEXPR11_TN char operator[](std::size_t n) const + { + return n < sz_ ? p_[n] : throw std::out_of_range("static_string"); + } }; -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 const& s) +{ + return os.write(s.data(), s.size()); } -template CONSTEXPR14_TN static_string type_name() { - const int k = sizeof("constexpr soi::detail:: T") / sizeof(char); +template +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); + 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 + 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); + static_string p = __FUNCSIG__; + return static_string(p.data() + 38 + k, p.size() - 38 - k - 7); #endif } constexpr bool is_prefix_of(char const *suffix, char const *s) { - return suffix[0] == '\0' || - (suffix[0] == s[0] && is_prefix_of(suffix + 1, s + 1)); + return suffix[0]=='\0' || (suffix[0] == s[0] && is_prefix_of(suffix + 1, s + 1)); } -static char const *const type_string = "string"; +static char const* const type_string = "string"; -template CONSTEXPR14_TN static_string sanitized_type_name() { +template +CONSTEXPR14_TN +static_string +sanitized_type_name() { CONSTEXPR14_TN static_string t = type_name(); CONSTEXPR14_TN std::size_t offset = - is_prefix_of("std::__debug::", t.data()) - ? sizeof("std::__debug::") - 1 - : is_prefix_of("std::", t.data()) ? sizeof("std::") - 1 : 0; - return is_prefix_of("std::__cxx11::basic_string", t.data()) - ? static_string(type_string, sizeof(type_string) - 2) - : static_string(t.data() + offset, t.size() - offset); + is_prefix_of("std::__debug::", t.data()) ? sizeof("std::__debug::")-1 : + is_prefix_of("std::", t.data()) ? sizeof("std::")-1 : + 0; + return + is_prefix_of("std::__cxx11::basic_string", t.data()) ? + static_string(type_string, sizeof(type_string)-2) : + static_string(t.data()+offset, t.size()-offset); } // ---------------------------------------------------------------------------- @@ -138,7 +152,7 @@ bool tty_supports_colors() { } int has_environment_color_overwrite() { - if (const char *color_enabled = std::getenv("SOI_COLOR")) { + if (const char* color_enabled = std::getenv("SOI_COLOR")) { if (!std::strcmp(color_enabled, "1")) return 1; if (!std::strcmp(color_enabled, "0")) @@ -158,12 +172,12 @@ bool are_colors_enabled() { // 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 = ""; +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) { @@ -185,51 +199,70 @@ void dbg_init(bool with_colors) { } } -void dbg_init() { dbg_init(are_colors_enabled()); } +void dbg_init() { + dbg_init(are_colors_enabled()); +} // ---------------------------------------------------------------------------- // printer template -T &&dbg_print(T &&value, static_string 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::print(value_buffer, ref); +T&& dbg_print(T&& value, + static_string 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 << ")" + 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(value); } -template -auto dbg_print(const char (&msg)[N], static_string 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'; +template +auto dbg_print(const char (&msg)[N], + static_string 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 T &&identity(T &&t) { return std::forward(t); } +template +T&& identity(T&& t) { + return std::forward(t); +} } // end namespace detail -} // namespace soi +} // end namespace dbg_macro #ifdef SOI_RELEASE #define dbg(...) dbg_macro::identity(__VA_ARGS__) #else -#define dbg(...) \ - soi::detail::dbg_print( \ - (__VA_ARGS__), \ - soi::detail::sanitized_type_name(), __FILE__, \ - __LINE__, __func__, #__VA_ARGS__) +#define dbg(...) \ + soi_h::detail::dbg_print((__VA_ARGS__), \ + soi_h::detail::sanitized_type_name(), \ + __FILE__, \ + __LINE__, \ + __func__, \ + #__VA_ARGS__) #endif -#endif // SOI_DBG +#endif // SOI_DBG diff --git a/include/bits/soi-deprecate.hpp b/include/bits/soi-deprecate.hpp index e6676ae..eae61d3 100644 --- a/include/bits/soi-deprecate.hpp +++ b/include/bits/soi-deprecate.hpp @@ -1,32 +1,24 @@ #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); +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, ...); +[[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, ...); +[[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 @@ -43,45 +35,28 @@ snprintf(char *buffer, std::size_t buf_size, const char *format, ...); #define fread fread_is_evil #define fwrite fwrite_is_evil [[deprecated(" is evil. Use cin/cout.")]] int puts(const char *str); -[[deprecated(" is evil. Use cin/cout.")]] int fputs(const char *str, - FILE *stream); -[[deprecated(" is evil. Use cin/cout.")]] char * -fgets(char *str, int count, FILE *stream); -[[deprecated(" is evil. Use cin/cout.")]] std::FILE * -freopen(const char *filename, const char *mode, std::FILE *stream); -[[deprecated(" is evil. Use cin/cout.")]] std::FILE * -fopen(const char *filename, const char *mode); -[[deprecated(" is evil. Use cin/cout.")]] int -fclose(std::FILE *stream); -[[deprecated(" is evil. Use cin/cout.")]] int -fflush(std::FILE *stream); +[[deprecated(" is evil. Use cin/cout.")]] int fputs(const char *str, FILE *stream); +[[deprecated(" is evil. Use cin/cout.")]] char *fgets(char *str, int count, FILE *stream); +[[deprecated(" is evil. Use cin/cout.")]] std::FILE *freopen(const char *filename, const char *mode, std::FILE *stream); +[[deprecated(" is evil. Use cin/cout.")]] std::FILE *fopen(const char *filename, const char *mode); +[[deprecated(" is evil. Use cin/cout.")]] int fclose(std::FILE *stream); +[[deprecated(" is evil. Use cin/cout.")]] int fflush(std::FILE *stream); [[deprecated(" is evil. Use cin/cout.")]] int getchar(); [[deprecated(" is evil. Use cin/cout.")]] int fgetc(std::FILE *stream); [[deprecated(" is evil. Use cin/cout.")]] int getc(std::FILE *stream); -[[deprecated(" is evil. Use cin/cout.")]] void -setbuf(std::FILE *stream, char *buffer); -[[deprecated(" is evil. Use cin/cout.")]] int -setvbuf(std::FILE *stream, char *buffer, int mode, std::size_t size); -[[deprecated(" is evil. Use cin/cout.")]] std::size_t -fread(void *buffer, std::size_t size, std::size_t count, std::FILE *stream); -[[deprecated(" is evil. Use cin/cout.")]] std::size_t -fwrite(const void *buffer, std::size_t size, std::size_t count, - std::FILE *stream); +[[deprecated(" is evil. Use cin/cout.")]] void setbuf(std::FILE *stream, char *buffer); +[[deprecated(" is evil. Use cin/cout.")]] int setvbuf(std::FILE *stream, char *buffer, int mode, std::size_t size); +[[deprecated(" is evil. Use cin/cout.")]] std::size_t fread(void *buffer, std::size_t size, std::size_t count, std::FILE *stream); +[[deprecated(" 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("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; +[[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; diff --git a/include/bits/soi-pretty.hpp b/include/bits/soi-pretty.hpp index 0cd802e..116bdf5 100644 --- a/include/bits/soi-pretty.hpp +++ b/include/bits/soi-pretty.hpp @@ -3,7 +3,7 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // -// pretty pretty_printing with c++ +// pretty printing with c++ // #ifndef SOI_PRETTY @@ -11,90 +11,66 @@ #include "prettyprint.hpp" -namespace soi { +namespace soi_h { -template +template +inline typename std::enable_if< ::pretty_print::is_container::value, + std::basic_ostream &>::type +pretty_print(std::basic_ostream & stream, const T & container) { + return stream << ::pretty_print::print_container_helper(container); +} + +template std::basic_ostream & -pretty_print(std::basic_ostream &stream, const bool &x) { +pretty_print(std::basic_ostream & stream, const bool& x) { return stream << (x ? "true" : "false"); } namespace detail { -template -void escape_char(std::basic_ostream &stream, char c) { +template +void escape_char(std::basic_ostream & 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; + 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; } } -} // namespace detail +} -template +template std::basic_ostream & -pretty_print(std::basic_ostream &stream, - const std::string &x) { +pretty_print(std::basic_ostream & stream, const std::string& x) { stream << "\""; for (char c : x) detail::escape_char(stream, c); return stream << "\""; } -template +template std::basic_ostream & -pretty_print(std::basic_ostream &stream, char c) { +pretty_print(std::basic_ostream & stream, char c) { stream << "'"; detail::escape_char(stream, c); return stream << "'"; } -template -inline typename std::enable_if::value, - std::basic_ostream &>::type -pretty_print(std::basic_ostream &stream, const T &x) { +template +inline typename std::enable_if< !::pretty_print::is_container::value, + std::basic_ostream &>::type +pretty_print(std::basic_ostream & stream, const T& x) { return stream << x; } -template -std::basic_ostream & -print(std::basic_ostream &stream, const T &x) { - return pretty_print(stream, x); } -} // namespace soi #endif // SOI_PRETTY diff --git a/include/soi b/include/soi index 8e3c092..5e4d9e6 100644 --- a/include/soi +++ b/include/soi @@ -5,20 +5,20 @@ have to understand every concept all at once. */ -#include "bits/soi-dbg.hpp" #include +#include "bits/soi-dbg.hpp" -namespace soi { +namespace soi_h { void check_for_eof() { - if (!(std::cin >> std::ws).eof()) - std::cerr << "WARNING: didn't read the whole input\n"; + 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 { - static const mask *get_table() { + static const mask* get_table() { static const std::array table = []() { std::array table; std::copy(classic_table(), classic_table() + table_size, table.begin()); @@ -27,14 +27,14 @@ void noninteractive_check_eof() { }(); return table.data(); } - console_ctype(std::size_t refs = 0) : ctype(get_table(), false, refs) {} + 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_EOFCHECK")) { + if (const char* eofcheck_enabled = std::getenv("SOI_EOFCHECK")) { if (!std::strcmp(eofcheck_enabled, "1")) return true; if (!std::strcmp(eofcheck_enabled, "0")) @@ -48,15 +48,15 @@ void initialize_debug() { 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"; + 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::detail::dbg_init(); + soi_h::detail::dbg_init(); } -struct soi_initializer { - soi_initializer(bool release) { +struct soi_h_initializer { + soi_h_initializer(bool release) { if (release) { std::ios::sync_with_stdio(false); std::cin.tie(0); @@ -67,12 +67,12 @@ struct soi_initializer { }; #ifdef SOI_RELEASE -soi_initializer soi_initializer_{true}; +soi_h_initializer soi_h_initializer_{true}; #else -soi_initializer soi_initializer_{false}; +soi_h_initializer soi_h_initializer_{false}; #endif -} // end namespace soi +} // end namespace soi_h #include "bits/soi-deprecate.hpp"