Skip to content

Commit

Permalink
Extend logger to print iterables and structured bindings
Browse files Browse the repository at this point in the history
  • Loading branch information
davschneller committed Nov 6, 2024
1 parent e060973 commit d0a9698
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 52 deletions.
37 changes: 37 additions & 0 deletions common.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#ifndef UTILS_COMMON_H_
#define UTILS_COMMON_H_

#include <ostream>
#include <utility>

namespace utils {
Expand All @@ -18,6 +19,42 @@ template <typename T> struct has_size {
static constexpr bool value = test<T>(int());
};

template <typename T> struct IsIterable {
template <typename U>
static constexpr decltype(std::begin(std::declval<U>()), bool())
beginTest(int) {
return true;
}
template <typename U> static constexpr bool beginTest(...) { return false; }
template <typename U>
static constexpr decltype(std::end(std::declval<U>()), bool()) endTest(int) {
return true;
}
template <typename U> static constexpr bool endTest(...) { return false; }
static constexpr bool Value = beginTest<T>(int()) && endTest<T>(int());
};

template <typename T> struct CanOutput {
template <typename U>
static constexpr decltype(operator<<(std::declval<std::ostream>(),
std::declval<U>()),
bool())
test(int) {
return true;
}
template <typename U> static constexpr bool test(...) { return false; }
static constexpr bool Value = test<T>(int());
};

template <typename T> struct IsGettable {
template <typename U>
static constexpr decltype(std::tuple_size<U>::value, bool()) test(int) {
return true;
}
template <typename U> static constexpr bool test(...) { return false; }
static constexpr bool Value = test<T>(int());
};

} // namespace utils

#endif // UTILS_COMMON_H_
96 changes: 44 additions & 52 deletions logger.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#ifndef UTILS_LOGGER_H_
#define UTILS_LOGGER_H_

#include "utils/common.h"
#include "utils/stringutils.h"
#include "utils/timeutils.h"

Expand All @@ -17,7 +18,8 @@
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <tuple>
#include <type_traits>

#ifndef LOG_LEVEL
#ifdef NDEBUG
Expand Down Expand Up @@ -94,6 +96,18 @@ class Logger {
/**
* Pointer to all information about the message
*/

template <typename T, std::size_t Idx>
static void printTuple(Logger &logger, const T &data) {
if constexpr (Idx < std::tuple_size_v<T>) {
if constexpr (Idx > 0) {
logger << ", ";
}
logger << std::get<Idx>(data);
printTuple<T, Idx + 1>(logger, data);
}
}

public:
static void setRank(int rank) { Logger::rank = rank; }
static void setLogAll(bool logAll) { Logger::logAll = logAll; }
Expand Down Expand Up @@ -228,41 +242,37 @@ class Logger {
/**
* Default function to add messages
*/
template <typename T> 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 <typename T> Logger &operator<<(const T &data) {
if constexpr (std::is_invocable_r_v<Logger &, T, Logger &>) {
return std::invoke(data);
} else if constexpr (std::is_same_v<T, std::string>) {
stream->buffer << '"' << data << '"';
return maybeSpace();
} else if constexpr (CanOutput<T>::Value) {
stream->buffer << data;
return maybeSpace();
} else if constexpr (IsIterable<T>::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<T>::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.");
}
}
};

Expand Down Expand Up @@ -309,24 +319,6 @@ class NoLogger {
NoLogger &operator<<(Logger &(*func)(Logger &)) { return *this; }
};

/**
* Add a std::vector<T> to the message
*
* @relates utils::Logger
*/
template <typename T>
inline Logger &operator<<(Logger debug, const std::vector<T> &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
Expand Down

0 comments on commit d0a9698

Please sign in to comment.