aboutsummaryrefslogtreecommitdiff
path: root/src/crepe/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/crepe/util')
-rw-r--r--src/crepe/util/CMakeLists.txt12
-rw-r--r--src/crepe/util/Log.cpp38
-rw-r--r--src/crepe/util/Log.h63
-rw-r--r--src/crepe/util/Log.hpp17
-rw-r--r--src/crepe/util/LogColor.cpp46
-rw-r--r--src/crepe/util/LogColor.h80
-rw-r--r--src/crepe/util/OptionalRef.h66
-rw-r--r--src/crepe/util/OptionalRef.hpp44
-rw-r--r--src/crepe/util/Proxy.h34
-rw-r--r--src/crepe/util/Proxy.hpp27
-rw-r--r--src/crepe/util/color.h41
-rw-r--r--src/crepe/util/dbg.h18
-rw-r--r--src/crepe/util/log.cpp50
-rw-r--r--src/crepe/util/log.h36
14 files changed, 442 insertions, 130 deletions
diff --git a/src/crepe/util/CMakeLists.txt b/src/crepe/util/CMakeLists.txt
index 100f028..94ed906 100644
--- a/src/crepe/util/CMakeLists.txt
+++ b/src/crepe/util/CMakeLists.txt
@@ -1,9 +1,15 @@
target_sources(crepe PUBLIC
- log.cpp
+ LogColor.cpp
+ Log.cpp
)
target_sources(crepe PUBLIC FILE_SET HEADERS FILES
- color.h
- log.h
+ LogColor.h
+ Log.h
+ Log.hpp
+ Proxy.h
+ Proxy.hpp
+ OptionalRef.h
+ OptionalRef.hpp
)
diff --git a/src/crepe/util/Log.cpp b/src/crepe/util/Log.cpp
new file mode 100644
index 0000000..ce25a1d
--- /dev/null
+++ b/src/crepe/util/Log.cpp
@@ -0,0 +1,38 @@
+#include <iostream>
+#include <string>
+
+#include "../api/Config.h"
+
+#include "Log.h"
+#include "LogColor.h"
+
+using namespace crepe;
+using namespace std;
+
+string Log::prefix(const Level & level) {
+ switch (level) {
+ case Level::TRACE:
+ return LogColor().fg_white().str("[TRACE]") + " ";
+ case Level::DEBUG:
+ return LogColor().fg_magenta().str("[DEBUG]") + " ";
+ case Level::INFO:
+ return LogColor().fg_blue().str("[INFO]") + " ";
+ case Level::WARNING:
+ return LogColor().fg_yellow().str("[WARN]") + " ";
+ case Level::ERROR:
+ return LogColor().fg_red().str("[ERROR]") + " ";
+ }
+ return "";
+}
+
+void Log::log(const Level & level, const string & msg) {
+ auto & cfg = Config::get_instance();
+ if (level < cfg.log.level) return;
+
+ string out = Log::prefix(level) + msg;
+ if (!out.ends_with("\n")) out += "\n";
+
+ // TODO: also log to file or smth
+ cout.write(out.data(), out.size());
+ cout.flush();
+}
diff --git a/src/crepe/util/Log.h b/src/crepe/util/Log.h
new file mode 100644
index 0000000..b43fe30
--- /dev/null
+++ b/src/crepe/util/Log.h
@@ -0,0 +1,63 @@
+#pragma once
+
+#include <format>
+
+namespace crepe {
+
+/**
+ * \brief Logging utility
+ *
+ * This class is used to output log messages to the console and/or log files.
+ */
+class Log {
+public:
+ //! Log message severity
+ enum Level {
+ TRACE, //!< Include (internal) function calls
+ DEBUG, //!< Include dbg_logf output
+ INFO, //!< General-purpose messages
+ WARNING, //!< Non-fatal errors
+ ERROR, //!< Fatal errors
+ };
+
+ /**
+ * \brief Log a formatted message
+ *
+ * \param level Message severity
+ * \param msg Formatted message
+ */
+ static void log(const Level & level, const std::string & msg);
+
+ /**
+ * \brief Format a message and log it
+ *
+ * \param level Message severity
+ * \param fmt Message format
+ * \param args Format arguments
+ */
+ template <class... Args>
+ static void logf(const Level & level, std::format_string<Args...> fmt, Args &&... args);
+
+ /**
+ * \brief Format a message and log it (with default severity \c INFO)
+ *
+ * \param fmt Message format
+ * \param args Format arguments
+ */
+ template <class... Args>
+ static void logf(std::format_string<Args...> fmt, Args &&... args);
+
+private:
+ /**
+ * \brief Output a message prefix depending on the log level
+ *
+ * \param level Message severity
+ *
+ * \return Colored message severity prefix string
+ */
+ static std::string prefix(const Level & level);
+};
+
+} // namespace crepe
+
+#include "Log.hpp"
diff --git a/src/crepe/util/Log.hpp b/src/crepe/util/Log.hpp
new file mode 100644
index 0000000..c2156cd
--- /dev/null
+++ b/src/crepe/util/Log.hpp
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "Log.h"
+
+namespace crepe {
+
+template <class... Args>
+void Log::logf(std::format_string<Args...> fmt, Args &&... args) {
+ Log::logf(Level::INFO, fmt, std::forward<Args>(args)...);
+}
+
+template <class... Args>
+void Log::logf(const Level & level, std::format_string<Args...> fmt, Args &&... args) {
+ Log::log(level, std::format(fmt, std::forward<Args>(args)...));
+}
+
+} // namespace crepe
diff --git a/src/crepe/util/LogColor.cpp b/src/crepe/util/LogColor.cpp
new file mode 100644
index 0000000..5411898
--- /dev/null
+++ b/src/crepe/util/LogColor.cpp
@@ -0,0 +1,46 @@
+#include <cstdarg>
+
+#include "../api/Config.h"
+
+#include "LogColor.h"
+
+using namespace crepe;
+using namespace std;
+
+static constexpr const char * RESET_CODE = "\e[0m";
+
+const string LogColor::str(const string & content) const {
+ auto & cfg = Config::get_instance();
+ string out = content;
+ if (cfg.log.color) out = this->code + out;
+ if (content.size() == 0) return out;
+ if (cfg.log.color) out = out + RESET_CODE;
+ return out;
+}
+
+LogColor & LogColor::add_code(unsigned int code) {
+ this->code += format("\e[{}m", code);
+ return *this;
+}
+
+LogColor & LogColor::reset() {
+ this->code = RESET_CODE;
+ return *this;
+}
+
+LogColor & LogColor::fg_black(bool bright) { return this->add_code(bright ? 90 : 30); }
+LogColor & LogColor::fg_red(bool bright) { return this->add_code(bright ? 91 : 31); }
+LogColor & LogColor::fg_green(bool bright) { return this->add_code(bright ? 92 : 32); }
+LogColor & LogColor::fg_yellow(bool bright) { return this->add_code(bright ? 93 : 33); }
+LogColor & LogColor::fg_blue(bool bright) { return this->add_code(bright ? 94 : 34); }
+LogColor & LogColor::fg_magenta(bool bright) { return this->add_code(bright ? 95 : 35); }
+LogColor & LogColor::fg_cyan(bool bright) { return this->add_code(bright ? 96 : 36); }
+LogColor & LogColor::fg_white(bool bright) { return this->add_code(bright ? 97 : 37); }
+LogColor & LogColor::bg_black(bool bright) { return this->add_code(bright ? 100 : 40); }
+LogColor & LogColor::bg_red(bool bright) { return this->add_code(bright ? 101 : 41); }
+LogColor & LogColor::bg_green(bool bright) { return this->add_code(bright ? 102 : 42); }
+LogColor & LogColor::bg_yellow(bool bright) { return this->add_code(bright ? 103 : 43); }
+LogColor & LogColor::bg_blue(bool bright) { return this->add_code(bright ? 104 : 44); }
+LogColor & LogColor::bg_magenta(bool bright) { return this->add_code(bright ? 105 : 45); }
+LogColor & LogColor::bg_cyan(bool bright) { return this->add_code(bright ? 106 : 46); }
+LogColor & LogColor::bg_white(bool bright) { return this->add_code(bright ? 107 : 47); }
diff --git a/src/crepe/util/LogColor.h b/src/crepe/util/LogColor.h
new file mode 100644
index 0000000..132fb94
--- /dev/null
+++ b/src/crepe/util/LogColor.h
@@ -0,0 +1,80 @@
+#pragma once
+
+#include <string>
+
+namespace crepe {
+
+/**
+ * \brief Utility class for coloring text using ANSI escape codes
+ *
+ * \note Most methods in this class return a reference to \c this, which may be
+ * used to chain multiple display attributes.
+ */
+class LogColor {
+public:
+ /**
+ * \brief Get color code as STL string
+ *
+ * \param content If given, color this string and append a color reset escape sequence.
+ *
+ * \returns Color escape sequence
+ */
+ const std::string str(const std::string & content = "") const;
+
+public:
+ //! Reset color to default foreground and background color
+ LogColor & reset();
+
+public:
+ /**
+ * \name Foreground colors
+ *
+ * These functions set the foreground (text) color. The \c bright parameter
+ * makes the color brighter, or bold on some terminals.
+ * \{
+ */
+ LogColor & fg_black(bool bright = false);
+ LogColor & fg_red(bool bright = false);
+ LogColor & fg_green(bool bright = false);
+ LogColor & fg_yellow(bool bright = false);
+ LogColor & fg_blue(bool bright = false);
+ LogColor & fg_magenta(bool bright = false);
+ LogColor & fg_cyan(bool bright = false);
+ LogColor & fg_white(bool bright = false);
+ /// \}
+
+public:
+ /**
+ * \name Background colors
+ *
+ * These functions set the background color. The \c bright parameter makes
+ * the color brighter.
+ * \{
+ */
+ LogColor & bg_black(bool bright = false);
+ LogColor & bg_red(bool bright = false);
+ LogColor & bg_green(bool bright = false);
+ LogColor & bg_yellow(bool bright = false);
+ LogColor & bg_blue(bool bright = false);
+ LogColor & bg_magenta(bool bright = false);
+ LogColor & bg_cyan(bool bright = false);
+ LogColor & bg_white(bool bright = false);
+ /// \}
+
+private:
+ /**
+ * \brief Append SGR escape sequence to \c this->code
+ *
+ * \param code SGR attribute number
+ *
+ * See <https://en.wikipedia.org/wiki/ANSI_escape_code> for magic number
+ * reference.
+ */
+ LogColor & add_code(unsigned int code);
+
+private:
+ //! Color escape sequence
+ std::string code = "";
+};
+
+} // namespace crepe
diff --git a/src/crepe/util/OptionalRef.h b/src/crepe/util/OptionalRef.h
new file mode 100644
index 0000000..1b2cb3f
--- /dev/null
+++ b/src/crepe/util/OptionalRef.h
@@ -0,0 +1,66 @@
+#pragma once
+
+namespace crepe {
+
+/**
+ * \brief Optional reference utility
+ *
+ * This class doesn't need to know the full definition of \c T to be used.
+ *
+ * \tparam T Value type
+ */
+template <typename T>
+class OptionalRef {
+public:
+ //! Initialize empty (nonexistant) reference
+ OptionalRef() = default;
+ //! Initialize reference with value
+ OptionalRef(T & ref);
+ /**
+ * \brief Assign new reference
+ *
+ * \param ref Reference to assign
+ *
+ * \return Reference to this (required for operator)
+ */
+ OptionalRef<T> & operator=(T & ref);
+ /**
+ * \brief Retrieve this reference (cast)
+ *
+ * \returns Internal reference if it is set
+ *
+ * \throws std::runtime_error if this function is called while the reference it not set
+ */
+ operator T &() const;
+ /**
+ * \brief Retrieve this reference (member access)
+ *
+ * \returns Internal reference if it is set
+ *
+ * \throws std::runtime_error if this function is called while the reference it not set
+ */
+ T * operator->() const;
+ /**
+ * \brief Check if this reference is not empty
+ *
+ * \returns `true` if reference is set, or `false` if it is not
+ */
+ explicit operator bool() const noexcept;
+
+ /**
+ * \brief Make this reference empty
+ */
+ void clear() noexcept;
+
+private:
+ /**
+ * \brief Reference to the value of type \c T
+ *
+ * \note This raw pointer is *not* managed, and only used as a reference!
+ */
+ T * ref = nullptr;
+};
+
+} // namespace crepe
+
+#include "OptionalRef.hpp"
diff --git a/src/crepe/util/OptionalRef.hpp b/src/crepe/util/OptionalRef.hpp
new file mode 100644
index 0000000..5e36b3a
--- /dev/null
+++ b/src/crepe/util/OptionalRef.hpp
@@ -0,0 +1,44 @@
+#pragma once
+
+#include <stdexcept>
+
+#include "OptionalRef.h"
+
+namespace crepe {
+
+template <typename T>
+OptionalRef<T>::OptionalRef(T & ref) {
+ this->ref = &ref;
+}
+
+template <typename T>
+OptionalRef<T>::operator T &() const {
+ if (this->ref == nullptr)
+ throw std::runtime_error("OptionalRef: attempt to dereference nullptr");
+ return *this->ref;
+}
+
+template <typename T>
+T * OptionalRef<T>::operator->() const {
+ if (this->ref == nullptr)
+ throw std::runtime_error("OptionalRef: attempt to dereference nullptr");
+ return this->ref;
+}
+
+template <typename T>
+OptionalRef<T> & OptionalRef<T>::operator=(T & ref) {
+ this->ref = &ref;
+ return *this;
+}
+
+template <typename T>
+OptionalRef<T>::operator bool() const noexcept {
+ return this->ref != nullptr;
+}
+
+template <typename T>
+void OptionalRef<T>::clear() noexcept {
+ this->ref = nullptr;
+}
+
+} // namespace crepe
diff --git a/src/crepe/util/Proxy.h b/src/crepe/util/Proxy.h
new file mode 100644
index 0000000..789144a
--- /dev/null
+++ b/src/crepe/util/Proxy.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include "ValueBroker.h"
+
+namespace crepe {
+
+/**
+ * \brief Utility wrapper for \c ValueBroker
+ *
+ * This class can be used to to wrap a ValueBroker instance so it behaves like a regular
+ * variable.
+ *
+ * \tparam T Type of the underlying variable
+ */
+template <typename T>
+class Proxy {
+public:
+ //! Set operator
+ Proxy & operator=(Proxy &);
+ //! Set operator
+ Proxy & operator=(const T &);
+ //! Get operator
+ operator const T &();
+
+public:
+ Proxy(ValueBroker<T>);
+
+private:
+ ValueBroker<T> broker;
+};
+
+} // namespace crepe
+
+#include "Proxy.hpp"
diff --git a/src/crepe/util/Proxy.hpp b/src/crepe/util/Proxy.hpp
new file mode 100644
index 0000000..ef2b69f
--- /dev/null
+++ b/src/crepe/util/Proxy.hpp
@@ -0,0 +1,27 @@
+#pragma once
+
+#include "Proxy.h"
+
+namespace crepe {
+
+template <typename T>
+Proxy<T>::Proxy(ValueBroker<T> broker) : broker(broker) {}
+
+template <typename T>
+Proxy<T> & Proxy<T>::operator=(const T & val) {
+ this->broker.set(val);
+ return *this;
+}
+
+template <typename T>
+Proxy<T> & Proxy<T>::operator=(Proxy & proxy) {
+ this->broker.set(T(proxy));
+ return *this;
+}
+
+template <typename T>
+Proxy<T>::operator const T &() {
+ return this->broker.get();
+}
+
+} // namespace crepe
diff --git a/src/crepe/util/color.h b/src/crepe/util/color.h
deleted file mode 100644
index 066c9d3..0000000
--- a/src/crepe/util/color.h
+++ /dev/null
@@ -1,41 +0,0 @@
-#pragma once
-
-namespace crepe::util::color {
-
-constexpr const char * RESET = "\e[0m";
-
-constexpr const char * FG_BLACK = "\e[30m";
-constexpr const char * FG_RED = "\e[31m";
-constexpr const char * FG_GREEN = "\e[32m";
-constexpr const char * FG_YELLOW = "\e[33m";
-constexpr const char * FG_BLUE = "\e[34m";
-constexpr const char * FG_MAGENTA = "\e[35m";
-constexpr const char * FG_CYAN = "\e[36m";
-constexpr const char * FG_WHITE = "\e[37m";
-constexpr const char * BG_BLACK = "\e[40m";
-constexpr const char * BG_RED = "\e[41m";
-constexpr const char * BG_GREEN = "\e[42m";
-constexpr const char * BG_YELLOW = "\e[43m";
-constexpr const char * BG_BLUE = "\e[44m";
-constexpr const char * BG_MAGENTA = "\e[45m";
-constexpr const char * BG_CYAN = "\e[46m";
-constexpr const char * BG_WHITE = "\e[47m";
-
-constexpr const char * FG_BLACK_BRIGHT = "\e[90m";
-constexpr const char * FG_RED_BRIGHT = "\e[91m";
-constexpr const char * FG_GREEN_BRIGHT = "\e[92m";
-constexpr const char * FG_YELLOW_BRIGHT = "\e[93m";
-constexpr const char * FG_BLUE_BRIGHT = "\e[94m";
-constexpr const char * FG_MAGENTA_BRIGHT = "\e[95m";
-constexpr const char * FG_CYAN_BRIGHT = "\e[96m";
-constexpr const char * FG_WHITE_BRIGHT = "\e[97m";
-constexpr const char * BG_BLACK_BRIGHT = "\e[100m";
-constexpr const char * BG_RED_BRIGHT = "\e[101m";
-constexpr const char * BG_GREEN_BRIGHT = "\e[102m";
-constexpr const char * BG_YELLOW_BRIGHT = "\e[103m";
-constexpr const char * BG_BLUE_BRIGHT = "\e[104m";
-constexpr const char * BG_MAGENTA_BRIGHT = "\e[105m";
-constexpr const char * BG_CYAN_BRIGHT = "\e[106m";
-constexpr const char * BG_WHITE_BRIGHT = "\e[107m";
-
-} // namespace crepe::util::color
diff --git a/src/crepe/util/dbg.h b/src/crepe/util/dbg.h
new file mode 100644
index 0000000..c7283ee
--- /dev/null
+++ b/src/crepe/util/dbg.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "Log.h"
+#include "LogColor.h"
+
+// utility macros
+#define _crepe_logf_here(level, fmt, ...) \
+ crepe::Log::logf(level, "{}" fmt, \
+ crepe::LogColor().fg_white(false).str(std::format( \
+ "{} ({}:{})", __PRETTY_FUNCTION__, __FILE_NAME__, __LINE__)), \
+ __VA_ARGS__)
+
+// very illegal global function-style macros
+// NOLINTBEGIN
+#define dbg_logf(fmt, ...) _crepe_logf_here(crepe::Log::Level::DEBUG, ": " fmt, __VA_ARGS__)
+#define dbg_log(str) _crepe_logf_here(crepe::Log::Level::DEBUG, ": {}", str)
+#define dbg_trace() _crepe_logf_here(crepe::Log::Level::TRACE, "", "")
+// NOLINTEND
diff --git a/src/crepe/util/log.cpp b/src/crepe/util/log.cpp
deleted file mode 100644
index f91d52c..0000000
--- a/src/crepe/util/log.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-#include <cstdarg>
-#include <cstdio>
-#include <cstdlib>
-#include <string>
-
-#include "log.h"
-
-using namespace crepe::util;
-
-static const char * const LOG_PREFIX[] = {
- [log_level::DEBUG] = "[DBG] ",
- [log_level::INFO] = "[INFO] ",
- [log_level::WARNING] = "[WARN] ",
- [log_level::ERROR] = "[ERR] ",
-};
-
-static void va_logf(enum log_level level, va_list args, const std::string fmt) {
- va_list args_copy;
- va_copy(args_copy, args);
-
- // prepend log level and ensure newline
- std::string format_fixed = LOG_PREFIX[level] + fmt;
- if (!format_fixed.ends_with("\n")) format_fixed += "\n";
-
- size_t sz = vsnprintf(NULL, 0, format_fixed.c_str(), args_copy) + 1;
- char * msg = (char *) malloc(sz);
- va_end(args_copy);
-
- vsnprintf(msg, sz, format_fixed.c_str(), args);
-
- // TODO: also log to file or smth
- printf("%s", msg);
- fflush(stdout);
-
- free(msg);
-}
-
-void crepe::util::logf(const char * fmt, ...) {
- va_list args;
- va_start(args, fmt);
- va_logf(crepe::util::log_level::DEBUG, args, fmt);
- va_end(args);
-}
-
-void crepe::util::logf(log_level level, const char * fmt, ...) {
- va_list args;
- va_start(args, fmt);
- va_logf(level, args, fmt);
- va_end(args);
-}
diff --git a/src/crepe/util/log.h b/src/crepe/util/log.h
deleted file mode 100644
index fa5f633..0000000
--- a/src/crepe/util/log.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#pragma once
-
-// allow user to disable debug macros
-#ifndef CREPE_DISABLE_MACROS
-
-#include "color.h"
-
-// utility macros
-#define _crepe_logf_here(fmt, ...) \
- crepe::util::logf(util::log_level::DEBUG, "%s%s (%s:%d)" fmt "\n", \
- crepe::util::color::FG_WHITE, __PRETTY_FUNCTION__, \
- __FILE_NAME__, __LINE__, crepe::util::color::RESET, \
- __VA_ARGS__)
-
-// very illegal global function-style macros
-// NOLINTBEGIN
-#define dbg_logf(fmt, ...) _crepe_logf_here(": " fmt, __VA_ARGS__)
-#define dbg_log(str) _crepe_logf_here("%s: " str, "")
-#define dbg_trace() _crepe_logf_here("%s", "")
-// NOLINTEND
-
-#endif
-
-namespace crepe::util {
-
-enum log_level {
- DEBUG,
- INFO,
- WARNING,
- ERROR,
-};
-
-void logf(const char * fmt, ...);
-void logf(enum log_level level, const char * fmt, ...);
-
-} // namespace crepe::util