From d0a96981aa597875743aca72d9587487ef11abf4 Mon Sep 17 00:00:00 2001 From: David Schneller Date: Wed, 6 Nov 2024 19:41:37 +0100 Subject: [PATCH] Extend logger to print iterables and structured bindings --- common.h | 37 ++++++++++++++++++++++ logger.h | 96 ++++++++++++++++++++++++++------------------------------ 2 files changed, 81 insertions(+), 52 deletions(-) diff --git a/common.h b/common.h index ff4be51..d529a4e 100644 --- a/common.h +++ b/common.h @@ -5,6 +5,7 @@ #ifndef UTILS_COMMON_H_ #define UTILS_COMMON_H_ +#include #include namespace utils { @@ -18,6 +19,42 @@ template struct has_size { static constexpr bool value = test(int()); }; +template struct IsIterable { + template + static constexpr decltype(std::begin(std::declval()), bool()) + beginTest(int) { + return true; + } + template static constexpr bool beginTest(...) { return false; } + template + static constexpr decltype(std::end(std::declval()), bool()) endTest(int) { + return true; + } + template static constexpr bool endTest(...) { return false; } + static constexpr bool Value = beginTest(int()) && endTest(int()); +}; + +template struct CanOutput { + template + static constexpr decltype(operator<<(std::declval(), + std::declval()), + bool()) + test(int) { + return true; + } + template static constexpr bool test(...) { return false; } + static constexpr bool Value = test(int()); +}; + +template struct IsGettable { + template + static constexpr decltype(std::tuple_size::value, bool()) test(int) { + return true; + } + template static constexpr bool test(...) { return false; } + static constexpr bool Value = test(int()); +}; + } // namespace utils #endif // UTILS_COMMON_H_ diff --git a/logger.h b/logger.h index 7b61715..fa4c2db 100644 --- a/logger.h +++ b/logger.h @@ -5,6 +5,7 @@ #ifndef UTILS_LOGGER_H_ #define UTILS_LOGGER_H_ +#include "utils/common.h" #include "utils/stringutils.h" #include "utils/timeutils.h" @@ -17,7 +18,8 @@ #include #include #include -#include +#include +#include #ifndef LOG_LEVEL #ifdef NDEBUG @@ -94,6 +96,18 @@ class Logger { /** * Pointer to all information about the message */ + + template + static void printTuple(Logger &logger, const T &data) { + if constexpr (Idx < std::tuple_size_v) { + if constexpr (Idx > 0) { + logger << ", "; + } + logger << std::get(data); + printTuple(logger, data); + } + } + public: static void setRank(int rank) { Logger::rank = rank; } static void setLogAll(bool logAll) { Logger::logAll = logAll; } @@ -228,41 +242,37 @@ class Logger { /** * Default function to add messages */ - template Logger &operator<<(T t) { - stream->buffer << t; - return maybeSpace(); - } - - /** - * Add a string variable to the message - */ - Logger &operator<<(const std::string &t) { - stream->buffer << '"' << t << '"'; - return maybeSpace(); - } - - /** - * Add a string variable to the message - */ - Logger &operator<<(std::string &t) { - stream->buffer << '"' << t << '"'; - return maybeSpace(); - } + template Logger &operator<<(const T &data) { + if constexpr (std::is_invocable_r_v) { + return std::invoke(data); + } else if constexpr (std::is_same_v) { + stream->buffer << '"' << data << '"'; + return maybeSpace(); + } else if constexpr (CanOutput::Value) { + stream->buffer << data; + return maybeSpace(); + } else if constexpr (IsIterable::Value) { + nospace() << '['; + auto it = std::begin(data); + if (it != std::end(data)) { + *this << *it; + ++it; + } + for (; it != std::end(data); ++it) { + *this << ", " << *it; + } + *this << ']'; - /** - * Operator to add functions like std::endl - */ - Logger &operator<<(std::ostream &(*func)(std::ostream &)) { - stream->buffer << func; - return *this; // No space in this case - } + return space(); + } else if constexpr (IsGettable::Value) { + nospace() << '{'; + printTuple(*this, data); + *this << '}'; - /** - * Operator for enabling/disabling automatic spacing - */ - Logger &operator<<(Logger &(*func)(Logger &)) { - func(*this); - return *this; + return space(); + } else { + static_assert(false, "Output for the given type not implemented."); + } } }; @@ -309,24 +319,6 @@ class NoLogger { NoLogger &operator<<(Logger &(*func)(Logger &)) { return *this; } }; -/** - * Add a std::vector to the message - * - * @relates utils::Logger - */ -template -inline Logger &operator<<(Logger debug, const std::vector &list) { - debug.nospace() << '('; - for (size_t i = 0; i < list.size(); i++) { - if (i) - debug << ", "; - debug << list[i]; - } - debug << ')'; - - return debug.space(); -} - } // namespace utils // Define global functions