From e37883a9bba70057891bda2c08b0b5d125c6213c Mon Sep 17 00:00:00 2001 From: DankParrot Date: Sat, 22 Aug 2020 18:44:28 -0700 Subject: [PATCH] Add Assert and AssertOnce macros --- src/NetworkMessage.h | 4 ++-- src/logging/Logger.h | 50 ++++++++++++++++++++++++++++++++++++++++++-- src/world/Chunk.cpp | 2 +- 3 files changed, 51 insertions(+), 5 deletions(-) diff --git a/src/NetworkMessage.h b/src/NetworkMessage.h index 127988c..b7c031b 100644 --- a/src/NetworkMessage.h +++ b/src/NetworkMessage.h @@ -108,7 +108,7 @@ namespace Feather { #ifdef _DEBUG // You must call Finalize() first - assert(m_finalized); + Assert(m_finalized, "NetworkMessage sent or resolved before Finalize() was called."); #endif return &m_data[m_startOffset]; } @@ -117,7 +117,7 @@ namespace Feather { #ifdef _DEBUG // You must call Finalize() first - assert(m_finalized); + Assert(m_finalized, "NetworkMessage sent or resolved before Finalize() was called."); #endif return m_data.size() - m_startOffset; } diff --git a/src/logging/Logger.h b/src/logging/Logger.h index 6e2aeb0..24b0d09 100644 --- a/src/logging/Logger.h +++ b/src/logging/Logger.h @@ -8,10 +8,40 @@ //#define FEATHER_LOG_COLUMNS +#ifdef _DEBUG + +// Prints an error if 'expr' is not false. Message is optional. +#define Assert(expr,/* fmt, */...) \ +do { \ + if (!(expr)) { \ + Feather::Log::Logger::Instance().LogAssert(Feather::Log::Channels::General, __FILE__, __LINE__, #expr, ##__VA_ARGS__); \ + } \ +} while (0) + +// Asserts an expression once only. +#define AssertOnce(expr,/* fmt, */...) \ +do { \ + static bool asserted = false; \ + if (!(expr) && !asserted) { \ + asserted = true; \ + Feather::Log::Logger::Instance().LogAssert(Feather::Log::Channels::General, __FILE__, __LINE__, #expr, ##__VA_ARGS__); \ + } \ +} while (0) + +#else // !defined(_DEBUG) + +#define Assert(expr,...) ((void)0) +#define AssertOnce(expr,...) ((void)0) + +#endif + namespace Feather::Log { enum class Level { + // Failed assertions + Assert = -3, + // Serious problems Error = -2, @@ -32,6 +62,7 @@ namespace Feather::Log { switch (level) { + case Level::Assert: return "Assert"; case Level::Error: return "Error"; case Level::Warning: return "Warning"; case Level::Info: return "Info"; @@ -55,9 +86,10 @@ namespace Feather::Log switch (level) { default: - case Level::Info: return fmt::fg(fmt::color::white); + case Level::Assert: return fmt::fg(fmt::color::orange_red); case Level::Error: return fmt::fg(fmt::color::crimson); case Level::Warning: return fmt::fg(fmt::color::yellow); + case Level::Info: return fmt::fg(fmt::color::white); case Level::Debug: return fmt::fg(fmt::color::rebecca_purple); case Level::Trace: return fmt::fg(fmt::color::aquamarine); } @@ -125,7 +157,21 @@ namespace Feather::Log LogRaw(fmt, args...); LogRaw("\n"); #endif - + } + + // Prints message for a failed assertion. Use the Assert or AssertOnce macros instead of calling this directly. + template + void LogAssert(ChannelID channel, const char* file, uint64_t lineNum, const char* expr, const S& fmt, Args... args) + { + std::string msg = fmt::format("{} ({}): {}", file, lineNum, fmt); + Log(channel, Level::Assert, msg, args...); + } + + // Prints message for a failed assertion. Use the Assert or AssertOnce macros instead of calling this directly. + void LogAssert(ChannelID channel, const char* file, uint64_t lineNum, const char* expr) + { + // When no message is provided we print the asserted expression instead + Log(channel, Level::Assert, "{} ({}): Assertion failed: {}", file, lineNum, expr); } ChannelID RegisterChannel(const char* name); diff --git a/src/world/Chunk.cpp b/src/world/Chunk.cpp index cf778f2..ea0fe24 100644 --- a/src/world/Chunk.cpp +++ b/src/world/Chunk.cpp @@ -94,7 +94,7 @@ namespace Feather continue; } - assert(blockStates.GetLength() < ChunkSection::MaximumLongCount); + Assert(blockStates.GetLength() < ChunkSection::MaximumLongCount); for (size_t i = 0; i < blockStates.GetLength(); i++) section->blockStates[i] = blockStates[i];