From 9390f4fd314530534542b232fd01378b8d517995 Mon Sep 17 00:00:00 2001 From: Riyyi Date: Fri, 22 Jul 2022 22:30:24 +0200 Subject: [PATCH] Util: Add custom assert --- src/util/meta/assert.h | 97 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 src/util/meta/assert.h diff --git a/src/util/meta/assert.h b/src/util/meta/assert.h new file mode 100644 index 0000000..47689ec --- /dev/null +++ b/src/util/meta/assert.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2022 Riyyi + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include // size_t +#include // uint32_t +#include // strlen +#include // ifstream +#include + +#include "util/format/format.h" +#include "util/meta/compiler.h" + +#define CRASH() asm volatile("int $0x03"); + +#ifndef NDEBUG + #define VERIFY(expr, ...) (static_cast(expr) ? (void)0 : Util::__assertion_failed(#expr, __FILE__, __LINE__, FUNCTION_MACRO __VA_OPT__(, ) __VA_ARGS__)) + #define VERIFY_NOT_REACHED() VERIFY(false) +#else + #define VERIFY(expr, ...) (static_cast(expr) ? (void)0 : CRASH() + #define VERIFY_NOT_REACHED() CRASH() +#endif + +#ifndef NDEBUG +namespace Util { + +template +inline void __assertion_failed(const char* assertion, const char* file, uint32_t line, const char* function, const Parameters&... parameters) +{ + // Get the line that caused the error + std::ifstream source(file); + std::string content; + if (source.is_open()) { + for (uint32_t i = 0; std::getline(source, content); ++i) { + if (i == line - 1) { + break; + } + } + } + // Replace tab indentation with spaces + size_t tabs = content.find_first_not_of('\t'); + if (tabs > 0 && tabs < content.size()) { + content = std::string(tabs * 4, ' ') + content.substr(tabs); + } + + // Find the assertion in the line + size_t column = content.find(assertion); + size_t assertionLength = strlen(assertion); + if (column == std::string::npos) { + column = content.find_first_not_of(' '); + assertionLength = content.length() - column; + } + + // Error message + fprintf(stderr, + "\033[;1m%s:%u:%zu " + "\033[31;1merror: " + "\033[0massertion failed", + file, line, column + 1); + if constexpr (sizeof...(Parameters) > 0) { + fprintf(stderr, ": "); + // Cant use the formatting library to print asserts caused by the formatting library + if (!std::string_view(function).starts_with("Util::Format::")) { + std::string message; + strln(message, parameters...); + fprintf(stderr, "%s", message.c_str()); + } + else { + fprintf(stderr, parameters...); + fprintf(stderr, "\n"); + } + } + else { + fprintf(stderr, "\n"); + } + + // Code line + fprintf(stderr, " %u | %s\033[31;1m%s\033[0m%s\n", line, + content.substr(0, column).c_str(), // Whitespace at front + content.substr(column, assertionLength).c_str(), // Error portion + content.substr(column + assertionLength).c_str()); // Rest of the line + + // Arrow pointer + fprintf(stderr, " %s | %s\033[31;1m^%s\033[0m\n", + std::string(std::to_string(line).length(), ' ').c_str(), // Line number spacing + std::string(column, ' ').c_str(), // Content spacing + std::string(assertionLength - 1, '~').c_str()); // Arrow pointer + + CRASH(); +} + +} // namespace Util +#endif