From 44aa8d060aa207ba44b1fc756641fd0e5238dad7 Mon Sep 17 00:00:00 2001 From: Johannes Kapfhammer Date: Sun, 6 Oct 2019 16:45:29 +0200 Subject: [PATCH] initial commit --- README.md | 32 +++ example.cpp | 16 ++ include/prettyprint.hpp | 444 ++++++++++++++++++++++++++++++++++++++ include/soi | 103 +++++++++ include/soi-dbg.hpp | 294 +++++++++++++++++++++++++ include/soi-deprecate.hpp | 62 ++++++ include/soi-pretty.hpp | 76 +++++++ 7 files changed, 1027 insertions(+) create mode 100644 README.md create mode 100644 example.cpp create mode 100644 include/prettyprint.hpp create mode 100644 include/soi create mode 100644 include/soi-dbg.hpp create mode 100644 include/soi-deprecate.hpp create mode 100644 include/soi-pretty.hpp diff --git a/README.md b/README.md new file mode 100644 index 0000000..ba9bbb6 --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ +# `#include ` + +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 + +signed main() { + // your code goes here +} +``` + +It requires at least c++11 to function. diff --git a/example.cpp b/example.cpp new file mode 100644 index 0000000..0568cef --- /dev/null +++ b/example.cpp @@ -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 + +signed main() { + dbg("hi"); + string s="world"; + dbg(s); + dbg(false); + dbg(true); + dbg('c'); + vector pi{3,1,4,1,5,9,2,6}; + dbg(pi); + dbg(vector{3,1,4,1,5,9,2,6}); + dbg(pi); + cout << "hi\n"; +} diff --git a/include/prettyprint.hpp b/include/prettyprint.hpp new file mode 100644 index 0000000..5c8d127 --- /dev/null +++ b/include/prettyprint.hpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 + 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; + }; + + 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 & f(...); + + template + static yes & g(typename std::enable_if< + std::is_same(&C::end)), + typename C::const_iterator(C::*)() const>::value, void>::type*); + + 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); + }; + + } // namespace detail + + + // 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 + + template + struct delimiters + { + using type = delimiters_values; + 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 TDelimiters = delimiters> + struct print_container_helper + { + using delimiters_type = TDelimiters; + using ostream_type = std::basic_ostream; + + 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); + + 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::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; + } + + + // 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_print::array_wrapper_n pretty_print_array(const T * const a, size_t n) +{ + return pretty_print::array_wrapper_n(a, n); +} + +template pretty_print::bucket_print_wrapper +bucket_print(const T & m, typename T::size_type 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); + } +} +*/ + +#endif // SOI_H_PRETTY_PRINT diff --git a/include/soi b/include/soi new file mode 100644 index 0000000..1836aec --- /dev/null +++ b/include/soi @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 { + static const mask* get_table() { + static const std::array table = []() { + std::array 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; + diff --git a/include/soi-dbg.hpp b/include/soi-dbg.hpp new file mode 100644 index 0000000..a24b149 --- /dev/null +++ b/include/soi-dbg.hpp @@ -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(); +// initialize with dbg_init() to enable colorized output +// + +#ifndef SOI_H_DBG +#define SOI_H_DBG + +#include +#include +#include +#include + +#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) +#include +#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 + 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 +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 +CONSTEXPR14_TN +static_string_no_std +sanitized_type_name() { + CONSTEXPR14_TN static_string t = type_name(); + 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(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 +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(value); +} + +template +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 +T&& identity(T&& t) { + return std::forward(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(), \ + __FILE__, \ + __LINE__, \ + __func__, \ + #__VA_ARGS__) +#endif + +#endif // SOI_H_DBG diff --git a/include/soi-deprecate.hpp b/include/soi-deprecate.hpp new file mode 100644 index 0000000..eae61d3 --- /dev/null +++ b/include/soi-deprecate.hpp @@ -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(" 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 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); + +#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; diff --git a/include/soi-pretty.hpp b/include/soi-pretty.hpp new file mode 100644 index 0000000..a2266f3 --- /dev/null +++ b/include/soi-pretty.hpp @@ -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 +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) { + return stream << (x ? "true" : "false"); +} + +namespace detail { +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; + } +} +} + +template +std::basic_ostream & +pretty_print(std::basic_ostream & stream, const std::string& x) { + stream << "\""; + for (char c : x) + detail::escape_char(stream, c); + return stream << "\""; +} + +template +std::basic_ostream & +pretty_print(std::basic_ostream & stream, char c) { + stream << "'"; + detail::escape_char(stream, c); + return stream << "'"; +} + +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; +} + +} + +#endif // SOI_H_PRETTY