Files
nostalgia/deps/ox/src/ox/std/error.hpp

347 lines
6.6 KiB
C++

/*
* Copyright 2015 - 2025 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#if __has_include(<exception>)
#include <exception>
#else
namespace std {
class exception {
public:
virtual ~exception() = default;
[[nodiscard]]
virtual char const*what() const noexcept {
return "";
}
};
}
#endif
#include "defines.hpp"
#include "def.hpp"
#include "source_location.hpp"
#include "typetraits.hpp"
#include "utility.hpp"
namespace ox {
using ErrorCode = uint16_t;
struct [[nodiscard]] Error {
std::source_location src;
ox::CString msg = nullptr;
ErrorCode errCode = 0;
constexpr Error() noexcept = default;
explicit constexpr Error(
ErrorCode const errCode,
std::source_location const&src = std::source_location::current()) noexcept:
src{src},
errCode{errCode}
{}
explicit constexpr Error(
ErrorCode const errCode,
ox::CString msg,
std::source_location const&src = std::source_location::current()) noexcept:
src{src},
msg{msg},
errCode{errCode}
{}
constexpr operator uint64_t() const noexcept {
return errCode;
}
};
[[nodiscard]]
constexpr auto errCode(Error const&err) noexcept {
return err.errCode;
}
template<typename T = char const*>
[[nodiscard]]
constexpr auto toStr(Error const&err) noexcept {
return err.msg ? T{err.msg} : "";
}
struct Exception: public std::exception {
std::source_location src;
ox::CString msg = nullptr;
ErrorCode errCode = 0;
explicit Exception(
ErrorCode const errCode,
std::source_location const&src = std::source_location::current()) noexcept:
src{src},
errCode{errCode} {}
explicit Exception(
ErrorCode const errCode,
ox::CString msg,
std::source_location const&src = std::source_location::current()) noexcept:
src{src},
msg{msg},
errCode{errCode} {}
explicit Exception(Error const&err) noexcept:
src{err.src},
msg{err.msg ? err.msg : ""},
errCode{err.errCode} {}
constexpr Error toError() const noexcept {
return Error(errCode, msg, src);
}
[[nodiscard]]
char const*what() const noexcept override {
return msg;
}
};
[[noreturn]]
void panic(char const*file, int line, char const*panicMsg, Error const&err) noexcept;
template<typename T>
struct [[nodiscard]] Result {
using type = typename remove_reference<T>::type;
T value;
Error error;
constexpr Result() noexcept: value(), error(0) {
}
template<typename U>
constexpr Result(Result<U> const&other) noexcept: value(other.value), error(other.error) {
}
template<typename U>
constexpr Result(Result<U> &&other) noexcept: value(std::move(other.value)), error(std::move(other.error)) {
}
constexpr Result(Error const&error) noexcept: value(), error(error) {
}
constexpr Result(type const&value, Error const&error = {}) noexcept: value(value), error(error) {
}
constexpr Result(type &&value, Error const&error = {}) noexcept: value(std::move(value)), error(error) {
}
constexpr ~Result() noexcept = default;
explicit constexpr operator type const&() const noexcept {
return value;
}
explicit constexpr operator type&() noexcept {
return value;
}
[[nodiscard]]
constexpr bool ok() const noexcept {
return error == 0;
}
template<typename U>
constexpr Error copyTo(U &val) const& noexcept {
if (!error) [[likely]] {
val = value;
}
return error;
}
template<typename U>
constexpr Error copyTo(U &val) && noexcept {
if (!error) [[likely]] {
val = std::move(value);
}
return error;
}
template<typename U>
constexpr Error moveTo(U &val) noexcept {
if (!error) [[likely]] {
val = std::move(value);
}
return error;
}
[[nodiscard]]
constexpr T &unwrap() & noexcept {
if (error) {
oxPanic(error, "Failed unwrap");
}
return value;
}
[[nodiscard]]
constexpr T &&unwrap() && noexcept {
if (error) {
oxPanic(error, "Failed unwrap");
}
return std::move(value);
}
[[nodiscard]]
constexpr T const&unwrap() const & noexcept {
if (error) [[unlikely]] {
oxPanic(error, "Failed unwrap");
}
return value;
}
[[nodiscard]]
constexpr T &unwrapThrow() & {
if (error) {
throw ox::Exception(error);
}
return value;
}
[[nodiscard]]
constexpr T &&unwrapThrow() && {
if (error) {
throw ox::Exception(error);
}
return std::move(value);
}
[[nodiscard]]
constexpr T const&unwrapThrow() const & {
if (error) {
throw ox::Exception(error);
}
return value;
}
template<typename U = T>
constexpr ox::Result<U> to() & noexcept {
if (error) [[unlikely]] {
return error;
}
return U(value);
}
template<typename U = T>
constexpr ox::Result<U> to() && noexcept {
if (error) [[unlikely]] {
return error;
}
return U(std::move(value));
}
template<typename U = T>
constexpr ox::Result<U> to(auto const&f) & noexcept {
if (error) [[unlikely]] {
return error;
}
return f(value);
}
template<typename U = T>
constexpr ox::Result<U> to(auto const&f) && noexcept {
if (error) [[unlikely]] {
return error;
}
return f(std::move(value));
}
/**
* Returns parameter alt if Result contains an error.
* @param alt
* @return value of Result or alt
*/
constexpr T or_value(T &&alt) const& noexcept {
if (error) {
return std::move(alt);
}
return value;
}
/**
* Returns parameter alt if Result contains an error.
* @param alt
* @return value of Result or alt
*/
constexpr T or_value(T &&alt) && noexcept {
if (error) {
return std::move(alt);
}
return std::move(value);
}
/**
* Returns parameter alt if Result contains an error.
* @param alt
* @return value of Result or alt
*/
constexpr T or_value(T const&alt) const& noexcept {
if (error) {
return alt;
}
return value;
}
/**
* Returns parameter alt if Result contains an error.
* @param alt
* @return value of Result or alt
*/
constexpr T or_value(T const&alt) && noexcept {
if (error) {
return alt;
}
return std::move(value);
}
};
namespace detail {
constexpr Error toError(Error const&e) noexcept {
return e;
}
template<typename T>
constexpr Error toError(Result<T> const&r) noexcept {
return r.error;
}
}
constexpr void primitiveAssert(char const*file, int line, bool pass, char const*msg) noexcept {
if constexpr(ox::defines::Debug) {
if (!pass) [[unlikely]] {
panic(file, line, msg, ox::Error(1));
}
}
}
constexpr void boundsCheck(
char const*file,
int const line,
size_t const i,
size_t const sz,
char const*msg) noexcept {
if constexpr(defines::CheckBounds) {
if (i >= sz) [[unlikely]] {
panic(file, line, msg, ox::Error{1});
}
}
}
}