#pragma once #define LOG_MULTITHREAD #include #include #include #include #include #ifdef LOG_MULTITHREAD #include #endif namespace gz { inline const char* boolToString(bool b) { return b ? "true" : "false"; } const int logLength = 100; constexpr unsigned int TIMESTAMP_CHAR_COUNT = 22; constexpr unsigned int POSTPREFIX_CHAR_COUNT = 2; // // CONCEPTS // /// is std::string or convertible to std::string template concept Stringy = std::same_as || std::convertible_to; /// has .to_string() member template concept HasToString = !Stringy && requires(T t) { { t.to_string() }-> Stringy; }; /// works with std::to_string(), except bool template concept WorksToString = !std::same_as && !Stringy && !HasToString && requires(T t) { { std::to_string(t) } -> Stringy; }; /// string-like, has .to_string() member, works with std::to_string() or bool template concept PrintableNoPtr = Stringy || HasToString || WorksToString || std::same_as; template concept Printable = PrintableNoPtr || requires(T t) { { *(t.get()) } -> PrintableNoPtr; }; /// Type having printable .x and .y members template concept Vector2Printable = !Printable && requires(T t) { { t.x } -> Printable; { t.y } -> Printable; }; /// Pair having printable elements template concept PairPrintable = !Vector2Printable && !Printable && requires(T p) { { p.first } -> Printable; } && (requires(T p){ { p.second } -> Printable; } || requires(T p){ { p.second } -> Vector2Printable; }); /// Container having printable elements template concept ContainerPrintable = !Printable && !Vector2Printable && !PairPrintable && std::ranges::forward_range && (Printable> || Vector2Printable>); /// Container having printable pairs template concept MapPrintable = !Printable && !Vector2Printable && !ContainerPrintable && std::ranges::forward_range && PairPrintable>; template concept LogableNotPointer = Printable || Vector2Printable || PairPrintable || ContainerPrintable || MapPrintable; template concept LogableSmartPointer = requires(T t) { { *(t.get()) } -> LogableNotPointer; }; // // COLORS // /// Colors to be used in Log::clog enum Color { RESET, BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, BBLACK, BRED, BGREEN, BYELLOW, BBLUE, BMAGENTA, BCYAN, BWHITE }; extern const char* COLORS[]; // // LOG // /** * @brief Define types that can be logged with Log * @details * As of now you can log type T with instance t: * -# Any string-like type * -# Any type that works with std::to_string() * -# Any type that has a to_string() member that returns a string * -# Any type with t.x and t.y, provided t.x and t.y satisfy one of 1-3 * -# Any type with t.first, t.second provided t.first satisfies one of 1-3 and t.second satisfies 1-4 * -# Any type that has a forward_iterator which references any one of 1-5 * * 1-6 include for example: * - int, float, bool... * - std::vector, std::list * - std::map> if A.to_string() returns a string * - ... */ template concept Logable = LogableNotPointer || LogableSmartPointer; template class vec2; // defined in gz_math.hpp /** * @brief Manages printing messages to stdout and to logfiles. * @details * @subsection log_threads Thread safety * Log can use a static mutex for thread safety. To use this feature, you have to #define LOG_MULTITHREAD at the top of log.hpp. * Note that log uses the default std::cout buffer, so you should make sure it is not being used while logging something. */ class Log { public: /** * @brief Creates a log object, which can print messages to stdout and/or write them to a log file * @details By creating multiple instances with different parameters, logs can be easily turned on/off for different usages. * * @param logfile: Name of the file in the logs folder * @param showLog: Wether to print the messages to stdout * @param storeLog: Wether to save the messages to the logfile * @param prefix: A prefix that comes between the timestamp and the message. ": " is automatically appended to the prefix * @param prefixColor: The color of the prefix * * @note Colors will only be shown when written to stdout, not in the logfile. */ Log(std::string logfile="log.log", bool showLog=true, bool storeLog=true, std::string&& prefix="", Color prefixColor=RESET); ~Log(); /** * @brief Logs a message * @details Depending on the settings of the log instance, the message will be printed to stdout and/or written to the logfile. * The current date and time is placed before the message. * The message will look like this: *