Option, Result: Propagate caller locations when erroring out
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
apio 2023-01-22 12:00:52 +01:00
parent 0126a8fb6e
commit 34a9b35037
Signed by: apio
GPG Key ID: B8A7D06E42258954
3 changed files with 44 additions and 34 deletions

View File

@ -14,12 +14,22 @@
if (!(expr)) [[unlikely]] { __check_failed(SourceLocation::current(), message); } \ if (!(expr)) [[unlikely]] { __check_failed(SourceLocation::current(), message); } \
} while (0) } while (0)
#define expect_at(expr, location, message) \
do { \
if (!(expr)) [[unlikely]] { __check_failed(location, message); } \
} while (0)
// Like assert(), but always enabled. // Like assert(), but always enabled.
#define check(expr) \ #define check(expr) \
do { \ do { \
if (!(expr)) [[unlikely]] { __check_failed(SourceLocation::current(), #expr); } \ if (!(expr)) [[unlikely]] { __check_failed(SourceLocation::current(), #expr); } \
} while (0) } while (0)
#define check_at(expr, location) \
do { \
if (!(expr)) [[unlikely]] { __check_failed(location, #expr); } \
} while (0)
#define unreachable() __check_failed(SourceLocation::current(), "Reached unreachable code") #define unreachable() __check_failed(SourceLocation::current(), "Reached unreachable code")
#define todo() __check_failed(SourceLocation::current(), "Reached a TODO!") #define todo() __check_failed(SourceLocation::current(), "Reached a TODO!")

View File

@ -64,9 +64,9 @@ template <typename T> class Option
return m_has_value; return m_has_value;
} }
T value() const T value(SourceLocation caller = SourceLocation::current()) const
{ {
expect(has_value(), "Option::value called on an empty Option"); expect_at(has_value(), caller, "Option::value called on an empty Option");
return m_storage.fetch_reference(); return m_storage.fetch_reference();
} }
@ -75,9 +75,9 @@ template <typename T> class Option
return m_storage.fetch_reference(); return m_storage.fetch_reference();
} }
T release_value() T release_value(SourceLocation caller = SourceLocation::current())
{ {
expect(has_value(), "Option::release_value called on an empty Option"); expect_at(has_value(), caller, "Option::release_value called on an empty Option");
m_has_value = false; m_has_value = false;
return move(m_storage.fetch_reference()); return move(m_storage.fetch_reference());
} }
@ -129,9 +129,9 @@ template <typename T> class Option
{ {
} }
ErrorHandle release_error() ErrorHandle release_error(SourceLocation caller = SourceLocation::current())
{ {
expect(!has_value(), "Option::release_error called on a non-empty Option"); expect_at(!has_value(), caller, "Option::release_error called on a non-empty Option");
return ErrorHandle {}; return ErrorHandle {};
} }

View File

@ -70,33 +70,33 @@ template <typename T> class Result
return m_value.has_value(); return m_value.has_value();
} }
int error() const int error(SourceLocation caller = SourceLocation::current()) const
{ {
expect(has_error(), "Result::error() called on a Result that holds a value"); expect_at(has_error(), caller, "Result::error() called on a Result that holds a value");
return m_error; return m_error;
} }
Error release_error() const Error release_error(SourceLocation caller = SourceLocation::current()) const
{ {
expect(has_error(), "Result::release_error() called on a Result that holds a value"); expect_at(has_error(), caller, "Result::release_error() called on a Result that holds a value");
return { m_error }; return { m_error };
} }
const char* error_string() const const char* error_string(SourceLocation caller = SourceLocation::current()) const
{ {
expect(has_error(), "Result::error_string() called on a Result that holds a value"); expect_at(has_error(), caller, "Result::error_string() called on a Result that holds a value");
return ::error_string(m_error); return ::error_string(m_error);
} }
T value() const T value(SourceLocation caller = SourceLocation::current()) const
{ {
expect(has_value(), "Result::value() called on a Result that holds an error"); expect_at(has_value(), caller, "Result::value() called on a Result that holds an error");
return m_value.unchecked_value({}); return m_value.unchecked_value({});
} }
T expect_value(const char* reason) const T expect_value(const char* reason, SourceLocation caller = SourceLocation::current()) const
{ {
expect(has_value(), reason); expect_at(has_value(), caller, reason);
return m_value.unchecked_value({}); return m_value.unchecked_value({});
} }
@ -115,15 +115,15 @@ template <typename T> class Result
return m_value.try_move_value(ref); return m_value.try_move_value(ref);
} }
T release_value() T release_value(SourceLocation caller = SourceLocation::current())
{ {
expect(has_value(), "Result::release_value() called on a Result that holds an error"); expect_at(has_value(), caller, "Result::release_value() called on a Result that holds an error");
return m_value.unchecked_release_value({}); return m_value.unchecked_release_value({});
} }
T expect_release_value(const char* reason) T expect_release_value(const char* reason, SourceLocation caller = SourceLocation::current())
{ {
expect(has_value(), reason); expect_at(has_value(), caller, reason);
return m_value.unchecked_release_value({}); return m_value.unchecked_release_value({});
} }
@ -188,45 +188,45 @@ template <> class Result<void>
return !m_has_error; return !m_has_error;
} }
int error() const int error(SourceLocation caller = SourceLocation::current()) const
{ {
expect(has_error(), "Result::error() called on a Result that holds a value"); expect_at(has_error(), caller, "Result::error() called on a Result that holds a value");
return m_error; return m_error;
} }
Error release_error() const Error release_error(SourceLocation caller = SourceLocation::current()) const
{ {
expect(has_error(), "Result::release_error() called on a Result that holds a value"); expect_at(has_error(), caller, "Result::release_error() called on a Result that holds a value");
return { m_error }; return { m_error };
} }
const char* error_string() const const char* error_string(SourceLocation caller = SourceLocation::current()) const
{ {
expect(has_error(), "Result::error_string() called on a Result that holds a value"); expect_at(has_error(), caller, "Result::error_string() called on a Result that holds a value");
return ::error_string(m_error); return ::error_string(m_error);
} }
void value() const void value(SourceLocation caller = SourceLocation::current()) const
{ {
expect(has_value(), "Result::value() called on a Result that holds an error"); expect_at(has_value(), caller, "Result::value() called on a Result that holds an error");
return; return;
} }
void expect_value(const char* reason) const void expect_value(const char* reason, SourceLocation caller = SourceLocation::current()) const
{ {
expect(has_value(), reason); expect_at(has_value(), caller, reason);
return; return;
} }
void release_value() const void release_value(SourceLocation caller = SourceLocation::current()) const
{ {
expect(has_value(), "Result::release_value() called on a Result that holds an error"); expect_at(has_value(), caller, "Result::release_value() called on a Result that holds an error");
return; return;
} }
void expect_release_value(const char* reason) const void expect_release_value(const char* reason, SourceLocation caller = SourceLocation::current()) const
{ {
expect(has_value(), reason); expect_at(has_value(), caller, reason);
return; return;
} }