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 6061aeb
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 22 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_
62 changes: 40 additions & 22 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,7 @@
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <tuple>

#ifndef LOG_LEVEL
#ifdef NDEBUG
Expand Down Expand Up @@ -94,6 +95,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,9 +241,32 @@ class Logger {
/**
* Default function to add messages
*/
template <typename T> Logger &operator<<(T t) {
stream->buffer << t;
return maybeSpace();
template <typename T> Logger &operator<<(const T &data) {
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 << ']';

return space();
} else if constexpr (IsGettable<T>::Value) {
nospace() << '{';
printTuple(*this, data);
*this << '}';

return space();
} else {
static_assert(false, "Output for the given type not implemented.");
}
}

/**
Expand Down Expand Up @@ -309,24 +345,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 6061aeb

Please sign in to comment.