#pragma once #include #define LOG(fmt, ...) Log(ELogType::Log, __FILE__, __LINE__, fmt, ##__VA_ARGS__) #define LOG_WARN(fmt, ...) Log(ELogType::Warn, __FILE__, __LINE__, fmt, ##__VA_ARGS__) #define LOG_ERROR(fmt, ...) Log(ELogType::Error, __FILE__, __LINE__, fmt, ##__VA_ARGS__) #define LOG_ONCE(fmt, ...) \ if (!WasLogged(ELogType::Log, __FILE__, __LINE__, fmt)) \ { \ Log(ELogType::Log, __FILE__, __LINE__, fmt, ##__VA_ARGS__); \ } #define WARN_ONCE(fmt, ...) \ if (!WasLogged(ELogType::Warn, __FILE__, __LINE__, fmt)) \ { \ Log(ELogType::Warn, __FILE__, __LINE__, fmt, ##__VA_ARGS__); \ } #define ERROR_ONCE(fmt, ...) \ if (!WasLogged(ELogType::Error, __FILE__, __LINE__, fmt)) \ { \ Log(ELogType::Error, __FILE__, __LINE__, fmt, ##__VA_ARGS__); \ } enum class ELogType { Log, Warn, Error, }; namespace LogInternal { constexpr int32_t MaxLineSize = 1024; constexpr int32_t LogHistorySize = 1024; } // namespace LogInternal struct LogHistory { char LogBuffer[LogInternal::MaxLineSize * LogInternal::LogHistorySize]{0}; char FileBuffer[LogInternal::MaxLineSize * LogInternal::LogHistorySize]{0}; uint32_t LineBuffer[LogInternal::LogHistorySize]{0}; int32_t WriteIdx = 0; int64_t WriteTime[LogInternal::LogHistorySize]{0}; }; void Log(ELogType logType, const char* file, uint32_t line, const char* format, ...); bool WasLogged(ELogType logType, const char* file, uint32_t line, const char* format); LogHistory& GetLogHistory();