[ox] Change panic and assert to use std::source_location

This commit is contained in:
2026-01-25 21:11:22 -06:00
parent bc05bd12e5
commit cdd574d873
12 changed files with 108 additions and 77 deletions

View File

@@ -135,7 +135,7 @@ class ModelHandlerInterface {
return m_handler->field(name, &v->template get<ModelValueArray>()); return m_handler->field(name, &v->template get<ModelValueArray>());
} }
oxErrf("invalid type: {}: {}\n", name, static_cast<int>(v->type())); oxErrf("invalid type: {}: {}\n", name, static_cast<int>(v->type()));
oxPanic(ox::Error(1), "invalid type"); ox::panic(ox::Error(1), "invalid type");
return ox::Error(1, "invalid type"); return ox::Error(1, "invalid type");
} }

View File

@@ -168,7 +168,7 @@ class ModelValue {
constexpr const auto &get() const noexcept { constexpr const auto &get() const noexcept {
constexpr auto type = getType<T>(); constexpr auto type = getType<T>();
if (m_type != type) [[unlikely]] { if (m_type != type) [[unlikely]] {
oxPanic(ox::Error(1), "invalid cast"); ox::panic(ox::Error(1), "invalid cast");
} }
return getValue<type>(*this); return getValue<type>(*this);
} }
@@ -178,7 +178,7 @@ class ModelValue {
constexpr auto &get() noexcept { constexpr auto &get() noexcept {
constexpr auto type = getType<T>(); constexpr auto type = getType<T>();
if (m_type != type) [[unlikely]] { if (m_type != type) [[unlikely]] {
oxPanic(ox::Error(1), "invalid cast"); ox::panic(ox::Error(1), "invalid cast");
} }
return getValue<type>(*this); return getValue<type>(*this);
} }

View File

@@ -181,13 +181,13 @@ constexpr Array<T, ArraySize> &Array<T, ArraySize>::operator=(Array &&other) noe
template<typename T, std::size_t ArraySize> template<typename T, std::size_t ArraySize>
constexpr T &Array<T, ArraySize>::operator[](std::size_t i) noexcept { constexpr T &Array<T, ArraySize>::operator[](std::size_t i) noexcept {
boundsCheck(__FILE__, __LINE__, i, size(), "Array access overflow"); boundsCheck(i, size(), "Array access overflow");
return m_items[i]; return m_items[i];
} }
template<typename T, std::size_t ArraySize> template<typename T, std::size_t ArraySize>
constexpr const T &Array<T, ArraySize>::operator[](std::size_t i) const noexcept { constexpr const T &Array<T, ArraySize>::operator[](std::size_t i) const noexcept {
boundsCheck(__FILE__, __LINE__, i, size(), "Array access overflow"); boundsCheck(i, size(), "Array access overflow");
return m_items[i]; return m_items[i];
} }

View File

@@ -15,8 +15,8 @@
namespace ox { namespace ox {
void panic(StringViewCR file, int const line, StringViewCR panicMsg, Error const&err) noexcept { void panic(Error const&err, StringViewCR panicMsg, std::source_location const &src) noexcept {
oxErrf("\033[31;1;1mPANIC:\033[0m [{}:{}]: {}\n", file, line, panicMsg); oxErrf("\033[31;1;1mPANIC:\033[0m [{}:{}]: {}\n", src.file_name(), src.line(), panicMsg);
if (err.msg) { if (err.msg) {
oxErrf("\tError Message:\t{}\n", err.msg); oxErrf("\tError Message:\t{}\n", err.msg);
} }
@@ -26,7 +26,7 @@ void panic(StringViewCR file, int const line, StringViewCR panicMsg, Error const
} }
#ifdef OX_USE_STDLIB #ifdef OX_USE_STDLIB
printStackTrace(2); printStackTrace(2);
oxTrace("panic").del("") << "Panic: " << panicMsg << " (" << file << ":" << line << ")"; oxTrace("panic").del("") << "Panic: " << panicMsg << " (" << src.file_name() << ":" << src.line() << ")";
std::abort(); std::abort();
#else #else
while (1); while (1);
@@ -36,34 +36,51 @@ void panic(StringViewCR file, int const line, StringViewCR panicMsg, Error const
#if __GNUC__ && !_WIN32 #if __GNUC__ && !_WIN32
__attribute__((weak)) __attribute__((weak))
#endif #endif
void panic(const char *file, int const line, char const*panicMsg, Error const&err) noexcept { void panic(Error const&err, char const*panicMsg, std::source_location const &src) noexcept {
panic(StringView{file}, line, StringView{panicMsg}, err); panic(err, StringView{panicMsg}, src);
} }
void assertFailFuncRuntime( void assertFailFuncRuntime(
StringViewCR file,
int const line,
StringViewCR assertTxt, StringViewCR assertTxt,
StringViewCR msg) noexcept { StringViewCR msg,
std::source_location const &src) noexcept {
#ifdef OX_USE_STDLIB #ifdef OX_USE_STDLIB
auto const st = genStackTrace(2); auto const st = genStackTrace(2);
oxTracef("assert", "Failed assert: {} ({}) [{}:{}]:\n{}", msg, assertTxt, file, line, st); oxTracef(
"assert", "Failed assert: {} ({}) [{}:{}]:\n{}",
msg,
assertTxt,
src.file_name(),
src.line(),
st);
abort(); abort();
#else #else
oxErrf("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, msg); oxErrf(
oxTracef("assert", "Failed assert: {} ({}) [{}:{}]", msg, assertTxt, file, line); "\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n",
constexprPanic(file, line, msg); src.file_name(),
src.line(),
msg);
oxTracef(
"assert", "Failed assert: {} ({}) [{}:{}]",
msg,
assertTxt,
src.file_name(),
src.line());
constexprPanic(msg, {}, src);
#endif #endif
} }
void assertFailFuncRuntime( void assertFailFuncRuntime(
StringViewCR file, [[maybe_unused]] Error const &err,
int const line,
[[maybe_unused]] Error const&err,
StringViewCR, StringViewCR,
StringViewCR assertMsg) noexcept { StringViewCR assertMsg,
std::source_location const &src) noexcept {
#if defined(OX_USE_STDLIB) #if defined(OX_USE_STDLIB)
auto msg = sfmt("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, assertMsg); auto msg = sfmt(
"\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n",
src.file_name(),
src.line(),
assertMsg);
if (err.msg) { if (err.msg) {
msg += sfmt("\tError Message:\t{}\n", err.msg); msg += sfmt("\tError Message:\t{}\n", err.msg);
} }
@@ -73,10 +90,10 @@ void assertFailFuncRuntime(
} }
msg += genStackTrace(2); msg += genStackTrace(2);
oxErr(msg); oxErr(msg);
oxTracef("assert", "Failed assert: {} [{}:{}]", assertMsg, file, line); oxTracef("assert", "Failed assert: {} [{}:{}]", assertMsg, src.file_name(), src.line());
abort(); abort();
#else #else
constexprPanic(file, line, assertMsg); constexprPanic(assertMsg, {}, src);
#endif #endif
} }

View File

@@ -23,42 +23,42 @@
namespace ox { namespace ox {
[[noreturn]] [[noreturn]]
void panic(StringViewCR file, int line, StringViewCR panicMsg, Error const&err = {}) noexcept; void panic(
Error const&err,
StringViewCR panicMsg,
std::source_location const &src = std::source_location::current()) noexcept;
[[noreturn]] [[noreturn]]
constexpr void constexprPanic( constexpr void constexprPanic(
StringViewCR file,
int const line,
StringViewCR panicMsg, StringViewCR panicMsg,
Error const&err = {}) noexcept { Error const&err = {},
std::source_location const &src = std::source_location::current()) noexcept {
if (!std::is_constant_evaluated()) { if (!std::is_constant_evaluated()) {
panic(file, line, panicMsg, err); panic(err, panicMsg, src);
} else { } else {
while (true); while (true);
} }
} }
void assertFailFuncRuntime( void assertFailFuncRuntime(
StringViewCR file,
int line,
StringViewCR assertTxt, StringViewCR assertTxt,
StringViewCR msg) noexcept; StringViewCR msg,
std::source_location const &src = std::source_location::current()) noexcept;
void assertFailFuncRuntime( void assertFailFuncRuntime(
StringViewCR file, Error const &err,
int line,
Error const&err,
StringViewCR, StringViewCR,
StringViewCR assertMsg) noexcept; StringViewCR assertMsg,
std::source_location const &src = std::source_location::current()) noexcept;
constexpr void assertFunc( constexpr void assertFunc(
StringViewCR file,
int const line,
bool const pass, bool const pass,
[[maybe_unused]]StringViewCR assertTxt, [[maybe_unused]]StringViewCR assertTxt,
[[maybe_unused]]StringViewCR msg) noexcept { [[maybe_unused]]StringViewCR msg,
std::source_location const &src = std::source_location::current()) noexcept {
if (!pass) { if (!pass) {
if (!std::is_constant_evaluated()) { if (!std::is_constant_evaluated()) {
assertFailFuncRuntime(file, line, assertTxt, msg); assertFailFuncRuntime(assertTxt, msg, src);
} else { } else {
while (true); while (true);
} }
@@ -66,14 +66,13 @@ constexpr void assertFunc(
} }
constexpr void assertFunc( constexpr void assertFunc(
StringViewCR file,
int const line,
Error const&err, Error const&err,
StringViewCR, StringViewCR,
StringViewCR assertMsg) noexcept { StringViewCR assertMsg,
std::source_location const &src = std::source_location::current()) noexcept {
if (err) { if (err) {
if (!std::is_constant_evaluated()) { if (!std::is_constant_evaluated()) {
assertFailFuncRuntime(file, line, err, {}, assertMsg); assertFailFuncRuntime(err, {}, assertMsg, src);
} else { } else {
while (true); while (true);
} }
@@ -81,20 +80,31 @@ constexpr void assertFunc(
} }
constexpr void expect( constexpr void expect(
StringViewCR file, auto const &actual,
int const line, auto const &expected,
auto const&actual, std::source_location const &src = std::source_location::current()) noexcept {
auto const&expected) noexcept {
if (actual != expected) { if (actual != expected) {
if (!std::is_constant_evaluated()) { if (!std::is_constant_evaluated()) {
#if defined(OX_USE_STDLIB) #if defined(OX_USE_STDLIB)
oxErrf("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, "Value incorrect"); oxErrf(
oxErrf("expected: {}\nactual: {}\n", detail::toStringView<true>(expected), detail::toStringView<true>(actual)); "\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n",
src.file_name(),
src.line(),
"Value incorrect");
oxErrf(
"expected: {}\nactual: {}\n",
detail::toStringView<true>(expected),
detail::toStringView<true>(actual));
printStackTrace(2); printStackTrace(2);
oxTracef("assert.expect", "Failed assert: {} == {} [{}:{}]", detail::toStringView<true>(actual), detail::toStringView<true>(expected), file, line); oxTracef(
"assert.expect", "Failed assert: {} == {} [{}:{}]",
detail::toStringView<true>(actual),
detail::toStringView<true>(expected),
src.file_name(),
src.line());
std::abort(); std::abort();
#else #else
constexprPanic(file, line, "Comparison failed"); constexprPanic("Comparison failed", {}, src);
#endif #endif
} else { } else {
while (true); while (true);

View File

@@ -48,9 +48,8 @@
// Asserts // Asserts
#define oxPanic(errCode, msg) ox::panic(__FILE__, __LINE__, msg, errCode)
#ifndef NDEBUG #ifndef NDEBUG
#define oxAssert(pass, msg) ox::assertFunc(__FILE__, __LINE__, pass, #pass, msg) #define oxAssert(pass, msg) ox::assertFunc(pass, #pass, msg)
#else #else
namespace ox { namespace ox {
struct [[nodiscard]] Error; struct [[nodiscard]] Error;
@@ -59,7 +58,7 @@ constexpr void oxAssert(bool, const char*) noexcept {}
constexpr void oxAssert(const ox::Error&, const char*) noexcept {} constexpr void oxAssert(const ox::Error&, const char*) noexcept {}
#endif #endif
#define oxExpect(actual, expected) ox::expect(__FILE__, __LINE__, actual, expected) #define oxExpect(actual, expected) ox::expect(actual, expected)
// Alloca // Alloca

View File

@@ -110,7 +110,10 @@ struct Exception: public std::exception {
}; };
[[noreturn]] [[noreturn]]
void panic(char const*file, int line, char const*panicMsg, Error const&err) noexcept; void panic(
Error const&err,
char const*panicMsg,
std::source_location const&src = std::source_location::current()) noexcept;
template<typename T> template<typename T>
struct [[nodiscard]] Result { struct [[nodiscard]] Result {
@@ -182,7 +185,7 @@ struct [[nodiscard]] Result {
[[nodiscard]] [[nodiscard]]
constexpr T &unwrap() & noexcept { constexpr T &unwrap() & noexcept {
if (error) { if (error) {
oxPanic(error, "Failed unwrap"); ox::panic(error, "Failed unwrap");
} }
return value; return value;
} }
@@ -190,7 +193,7 @@ struct [[nodiscard]] Result {
[[nodiscard]] [[nodiscard]]
constexpr T &&unwrap() && noexcept { constexpr T &&unwrap() && noexcept {
if (error) { if (error) {
oxPanic(error, "Failed unwrap"); ox::panic(error, "Failed unwrap");
} }
return std::move(value); return std::move(value);
} }
@@ -198,7 +201,7 @@ struct [[nodiscard]] Result {
[[nodiscard]] [[nodiscard]]
constexpr T const&unwrap() const & noexcept { constexpr T const&unwrap() const & noexcept {
if (error) [[unlikely]] { if (error) [[unlikely]] {
oxPanic(error, "Failed unwrap"); ox::panic(error, "Failed unwrap");
} }
return value; return value;
} }
@@ -329,23 +332,25 @@ constexpr Error toError(Result<T> const&r) noexcept {
} }
constexpr void primitiveAssert(char const*file, int line, bool pass, char const*msg) noexcept { constexpr void primitiveAssert(
bool const pass,
char const *msg,
std::source_location const &src = std::source_location::current()) noexcept {
if constexpr(ox::defines::Debug) { if constexpr(ox::defines::Debug) {
if (!pass) [[unlikely]] { if (!pass) [[unlikely]] {
panic(file, line, msg, ox::Error(1)); panic(ox::Error{1}, msg, src);
} }
} }
} }
constexpr void boundsCheck( constexpr void boundsCheck(
char const*file,
int const line,
size_t const i, size_t const i,
size_t const sz, size_t const sz,
char const*msg) noexcept { char const*msg,
std::source_location const &src = std::source_location::current()) noexcept {
if constexpr(defines::CheckBounds) { if constexpr(defines::CheckBounds) {
if (i >= sz) [[unlikely]] { if (i >= sz) [[unlikely]] {
panic(file, line, msg, ox::Error{1}); panic(ox::Error{1}, msg, src);
} }
} }
} }

View File

@@ -77,7 +77,7 @@ static HeapSegment *findSegmentFor(std::size_t sz) noexcept {
return s; return s;
} }
} }
oxPanic(ox::Error(1), "malloc: could not find segment"); ox::panic(ox::Error(1), "malloc: could not find segment");
return nullptr; return nullptr;
} }
@@ -102,7 +102,7 @@ void free(void *ptr) noexcept {
} else if (p.segment) { } else if (p.segment) {
p.segment->inUse = false; p.segment->inUse = false;
} else { } else {
oxPanic(ox::Error(1), "Bad heap free"); ox::panic(ox::Error(1), "Bad heap free");
} }
} }

View File

@@ -133,17 +133,17 @@ struct SpanIterator {
} }
constexpr PtrType operator->() const noexcept { constexpr PtrType operator->() const noexcept {
boundsCheck(__FILE__, __LINE__, m_offset, m_max, "SpanIterator access overflow"); boundsCheck(m_offset, m_max, "SpanIterator access overflow");
return &m_t[m_offset]; return &m_t[m_offset];
} }
constexpr RefType operator*() const noexcept { constexpr RefType operator*() const noexcept {
boundsCheck(__FILE__, __LINE__, m_offset, m_max, "SpanIterator access overflow"); boundsCheck(m_offset, m_max, "SpanIterator access overflow");
return m_t[m_offset]; return m_t[m_offset];
} }
constexpr RefType operator[](std::size_t s) const noexcept { constexpr RefType operator[](std::size_t s) const noexcept {
boundsCheck(__FILE__, __LINE__, s, m_max, "SpanIterator access overflow"); boundsCheck(s, m_max, "SpanIterator access overflow");
return m_t[s]; return m_t[s];
} }

View File

@@ -80,10 +80,10 @@ constexpr U *make(Args &&...args) noexcept {
try { try {
return new T(ox::forward<Args>(args)...); return new T(ox::forward<Args>(args)...);
} catch (std::exception const&ex) { } catch (std::exception const&ex) {
oxPanic(ox::Error(1, ex.what()), ex.what()); ox::panic(ox::Error(1, ex.what()), ex.what());
return nullptr; return nullptr;
} catch (...) { } catch (...) {
oxPanic(ox::Error(2, "Allocation or constructor failed"), "Allocation or constructor failed"); ox::panic(ox::Error(2, "Allocation or constructor failed"), "Allocation or constructor failed");
return nullptr; return nullptr;
} }
#else #else

View File

@@ -147,17 +147,17 @@ class Span {
} }
constexpr T &operator[](std::size_t i) const noexcept { constexpr T &operator[](std::size_t i) const noexcept {
boundsCheck(__FILE__, __LINE__, i, size(), "Span access overflow"); boundsCheck(i, size(), "Span access overflow");
return m_items[i]; return m_items[i];
} }
constexpr Span operator+(size_t i) const noexcept { constexpr Span operator+(size_t i) const noexcept {
boundsCheck(__FILE__, __LINE__, i, size(), "Span access overflow"); boundsCheck(i, size(), "Span access overflow");
return {m_items + i, m_size - i}; return {m_items + i, m_size - i};
} }
constexpr Span operator+=(size_t i) noexcept { constexpr Span operator+=(size_t i) noexcept {
boundsCheck(__FILE__, __LINE__, i, size(), "Span access overflow"); boundsCheck(i, size(), "Span access overflow");
m_items += i; m_items += i;
m_size -= i; m_size -= i;
return *this; return *this;

View File

@@ -419,13 +419,13 @@ constexpr Vector<T, SmallVectorSize, Allocator> &Vector<T, SmallVectorSize, Allo
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr T &Vector<T, SmallVectorSize, Allocator>::operator[](std::size_t i) noexcept { constexpr T &Vector<T, SmallVectorSize, Allocator>::operator[](std::size_t i) noexcept {
boundsCheck(__FILE__, __LINE__, i, size(), "Vector access overflow"); boundsCheck(i, size(), "Vector access overflow");
return m_items[i]; return m_items[i];
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr const T &Vector<T, SmallVectorSize, Allocator>::operator[](std::size_t i) const noexcept { constexpr const T &Vector<T, SmallVectorSize, Allocator>::operator[](std::size_t i) const noexcept {
boundsCheck(__FILE__, __LINE__, i, size(), "Vector access overflow"); boundsCheck(i, size(), "Vector access overflow");
return m_items[i]; return m_items[i];
} }