Skip to content

Commit

Permalink
feat: add soo to Error
Browse files Browse the repository at this point in the history
  • Loading branch information
OEOTYAN committed Sep 6, 2024
1 parent d9617cf commit 214fb19
Show file tree
Hide file tree
Showing 20 changed files with 347 additions and 262 deletions.
1 change: 1 addition & 0 deletions src-test/server/ConfigTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "mc/world/actor/DataItem.h"

#include "ll/api/base/Containers.h"
#include "ll/api/data/IndirectValue.h"

// [0, 8, 16, 96, 97, 98, 104, 136, 144, 160, 176, 184, 196, 208, 232, 248, 304, 328, 360, 392, 408]

Expand Down
2 changes: 1 addition & 1 deletion src-test/server/ECSTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
namespace ll::test::ecstest {

void registerTimingCommand() {
constexpr static size_t counttick = 100;
static constexpr size_t counttick = 100;
auto& cmd =
::ll::command::CommandRegistrar::getInstance()
.getOrCreateCommand("timing", "timing", CommandPermissionLevel::GameDirectors, CommandFlagValue::None);
Expand Down
63 changes: 35 additions & 28 deletions src/ll/api/Expected.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,32 @@

namespace ll {
#if defined(LL_DEBUG)
struct ErrorInfoBase::Impl {
struct DebugContext {
Stacktrace stacktrace;
};
ErrorInfoBase::ErrorInfoBase() noexcept : impl(std::make_unique<Impl>(Stacktrace::current(1))) {}

void* Error::createExtraData() noexcept { return new DebugContext{Stacktrace::current(1)}; }
void Error::destroyExtraData(void* ptr) noexcept { delete ((DebugContext*)ptr); }
void* Error::copyExtraData(void* ptr) noexcept { return new DebugContext(*(DebugContext const*)(ptr)); }

std::string Error::message() const noexcept {
if (!mInfo) {
if (!hasValue()) {
return "success";
}
auto res = mInfo->message();
auto res = dataPtr->message();
res += "\nexpected stacktrace:\n";
res += stacktrace_utils::toString(mInfo->impl->stacktrace);
res += stacktrace_utils::toString(reinterpret_cast<DebugContext*>(extraData)->stacktrace);
return res;
}

struct ExceptionError : ErrorInfoBase {
struct ExceptionError {
std::exception_ptr exc;
Stacktrace stacktrace;
ExceptionError(std::exception_ptr const& exc) noexcept
: exc(exc),
stacktrace(error_utils::stacktraceFromCurrentException()) {}
[[nodiscard]] std::string message() const noexcept override {

[[nodiscard]] std::string message() const noexcept {
auto res = error_utils::makeExceptionString(exc);
if (!stacktrace.empty()) {
res += "\nexception stacktrace:\n";
Expand All @@ -41,19 +46,20 @@ struct ExceptionError : ErrorInfoBase {
}
};
#else
struct ErrorInfoBase::Impl {};
ErrorInfoBase::ErrorInfoBase() noexcept {}
std::string Error::message() const noexcept { return mInfo ? mInfo->message() : "success"; }

struct ExceptionError : ErrorInfoBase {
void* Error::createExtraData() noexcept { return nullptr; }
void Error::destroyExtraData(void* ptr) noexcept {}
void* Error::copyExtraData(void* ptr) noexcept { return nullptr; }

std::string Error::message() const noexcept { return hasValue() ? dataPtr->message() : "success"; }

struct ExceptionError {
std::exception_ptr exc;
ExceptionError(std::exception_ptr const& exc) noexcept : exc(exc) {}
std::string message() const noexcept override { return error_utils::makeExceptionString(exc); }
std::string message() const noexcept { return error_utils::makeExceptionString(exc); }
};
#endif

ErrorInfoBase::~ErrorInfoBase() = default;

Unexpected makeExceptionError(std::exception_ptr const& exc) noexcept {
auto err = error_utils::AnyExceptionRef(exc).tryGet<nonstd::bad_expected_access<Error>>();
if (err) {
Expand All @@ -62,14 +68,13 @@ Unexpected makeExceptionError(std::exception_ptr const& exc) noexcept {
return makeError<ExceptionError>(exc);
}

struct ErrorList : ErrorInfoBase {
std::vector<std::shared_ptr<ErrorInfoBase>> errors;
struct ErrorList {
std::vector<Error> errors;
ErrorList() noexcept = default;
[[nodiscard]] std::string message() const noexcept override {
[[nodiscard]] std::string message() const noexcept {
std::string result;

for (size_t i = 0; i < errors.size(); i++) {
result += errors[i]->message();
result += errors[i].message();
if (i + 1 < errors.size()) {
result += '\n';
}
Expand All @@ -79,8 +84,9 @@ struct ErrorList : ErrorInfoBase {
};

Error& Error::join(Error err) noexcept {
if (!*this) {
mInfo = std::move(err.mInfo);
if (!hasValue()) {
tidy();
move(std::move(err));
return *this;
}
if (!err) {
Expand All @@ -90,18 +96,19 @@ Error& Error::join(Error err) noexcept {
if (err.isA<ErrorList>()) {
as<ErrorList>().errors.append_range(std::move(err.as<ErrorList>().errors));
} else {
as<ErrorList>().errors.emplace_back(std::move(err.mInfo));
as<ErrorList>().errors.emplace_back(std::move(err));
}
} else {
if (err.isA<ErrorList>()) {
auto& list = err.as<ErrorList>();
list.errors.insert(list.errors.begin(), std::move(mInfo));
mInfo = std::move(err.mInfo);
list.errors.insert(list.errors.begin(), std::move(*this));
*this = std::move(err);
} else {
auto list = std::make_unique<ErrorList>();
list->errors.emplace_back(std::move(mInfo));
list->errors.emplace_back(std::move(err.mInfo));
mInfo = std::move(list);
Error list(std::in_place_type<ErrorList>);
auto& vec = list.as<ErrorList>().errors;
vec.emplace_back(std::move(*this));
vec.emplace_back(std::move(err));
*this = std::move(list);
}
}
return *this;
Expand Down
196 changes: 141 additions & 55 deletions src/ll/api/Expected.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
#include <memory>
#include <string_view>

#include "ll/api/base/Concepts.h"
#include "ll/api/base/Macro.h"
#include "ll/api/data/AnyObjBase.h"
#include "ll/api/io/LogLevel.h"

#include "mc/server/commands/CommandOutputMessageType.h"
Expand All @@ -28,48 +30,150 @@ using Expected = ::nonstd::expected<T, ::ll::Error>;

using Unexpected = ::nonstd::unexpected_type<::ll::Error>;

class ErrorInfoBase {
friend Error;
struct Impl;
std::unique_ptr<Impl> impl;
template <class T>
concept IsErrorObj = requires(T t) {
requires requires {
{ t.message() } -> concepts::IsString;
} || requires {
{ t.what() } -> concepts::IsString;
};
} || concepts::IsString<T>;

class ErrorObjBase : public data::AnyObjBase {
public:
LLAPI ErrorInfoBase() noexcept;
LLAPI virtual ~ErrorInfoBase();
static constexpr inline size_t errorSizeNumPtrs = 7;
static constexpr inline size_t smallObjSize = ((errorSizeNumPtrs - 2) * sizeof(void*));

virtual ErrorObjBase* copy(void* to) const = 0;
virtual ErrorObjBase* move(void* to) noexcept = 0;
virtual void tidy() noexcept = 0;
virtual std::string message() noexcept = 0;
virtual std::type_info const& type() const noexcept = 0;
virtual const void* get() const noexcept = 0;
};
template <IsErrorObj Err>
class ErrorObj : public ErrorObjBase {
Err err;

public:
static constexpr inline bool nothrowMove = std::is_nothrow_move_constructible_v<Err>;

template <class... Args>
constexpr explicit ErrorObj(Args&&... args) : err(std::forward<Args>(args)...) {}

template <class... Args>
static constexpr ErrorObjBase* construct(void* to, Args&&... args) {
return constructImpl<ErrorObj>(to, std::forward<Args>(args)...);
}

virtual std::string message() const noexcept = 0;
ErrorObjBase* copy(void* to) const override { return constructImpl<ErrorObj>(to, err); }
ErrorObjBase* move(void* to) noexcept override { return constructImpl<ErrorObj>(to, std::move(err)); }
void tidy() noexcept override { destroyImpl<ErrorObj>(this); }
std::type_info const& type() const noexcept override { return typeid(Err); }
void const* get() const noexcept override { return std::addressof(err); }
std::string message() noexcept override {
if constexpr (requires {
{ err.message() } -> concepts::IsString;
}) {
return err.message();
} else if constexpr (requires {
{ err.what() } -> concepts::IsString;
}) {
return err.what();
} else {
return err;
}
}
};

class Error {
mutable std::unique_ptr<ErrorInfoBase> mInfo;
ErrorObjBase* dataPtr{};
void* extraData{};
union {
std::max_align_t dummy;
char soo[ErrorObjBase::smallObjSize];
};

constexpr bool isLarge() const noexcept { return dataPtr != static_cast<const void*>(&soo); }

constexpr bool hasValue() const noexcept { return dataPtr; }

LLAPI static void* createExtraData() noexcept;
LLAPI static void destroyExtraData(void*) noexcept;
LLAPI static void* copyExtraData(void*) noexcept;

void tidy() noexcept {
destroyExtraData(extraData);
extraData = nullptr;
if (hasValue()) {
dataPtr->tidy();
dataPtr = nullptr;
}
}
void copy(Error const& other) {
extraData = copyExtraData(other.extraData);
if (other.hasValue()) {
dataPtr = other.dataPtr->copy(&soo);
}
}
constexpr void move(Error&& other) noexcept {
extraData = other.extraData;
other.extraData = nullptr;
if (other.hasValue()) {
if (other.isLarge()) {
dataPtr = other.dataPtr;
other.dataPtr = nullptr;
} else {
dataPtr = other.dataPtr->move(&soo);
other.tidy();
}
}
}

public:
Error& operator=(Error&&) noexcept = default;
Error& operator=(Error const&) noexcept = delete;
[[nodiscard]] Error(Error&&) noexcept = default;
[[nodiscard]] Error(Error const&) noexcept = delete;
constexpr Error() noexcept {}
~Error() { tidy(); }

Error(Error const& other) { copy(other); }
Error& operator=(Error const& other) {
if (this != std::addressof(other)) {
tidy();
copy(other);
}
return *this;
}

LL_CONSTEXPR23 Error() noexcept = default;
LL_CONSTEXPR23 ~Error() noexcept = default;
constexpr Error(Error&& other) noexcept { move(std::move(other)); }
constexpr Error& operator=(Error&& other) noexcept {
if (this != std::addressof(other)) {
tidy();
move(std::move(other));
}
return *this;
}

LL_CONSTEXPR23 Error(std::unique_ptr<ErrorInfoBase> i) noexcept : mInfo(std::move(i)) {}
template <IsErrorObj Err, class... Args>
Error(std::in_place_type_t<Err>, Args&&... args)
: extraData(createExtraData()),
dataPtr(ErrorObj<Err>::construct(&soo, std::forward<Args>(args)...)) {}

LL_CONSTEXPR23 Error(::nonstd::unexpected_type<::ll::Error> i) noexcept : Error(std::move(i.value())) {}
Error(::nonstd::unexpected_type<::ll::Error> i) noexcept : Error(std::move(i.value())) {}

LL_CONSTEXPR23 operator bool() const noexcept { return mInfo != nullptr; }
constexpr operator bool() const noexcept { return hasValue(); }

LL_CONSTEXPR23 operator Unexpected() noexcept {
return ::nonstd::make_unexpected<Error>(std::in_place, std::move(mInfo));
}
operator Unexpected() noexcept { return ::nonstd::make_unexpected<Error>(std::move(*this)); }

LLNDAPI std::string message() const noexcept;

std::type_info const& type() const noexcept { return hasValue() ? dataPtr->type() : typeid(void); }

template <class T>
LL_CONSTEXPR23 bool isA() noexcept {
return mInfo ? typeid(T) == typeid(mInfo.get()) : false;
constexpr bool isA() noexcept {
return typeid(T) == type();
}
template <class T>
LL_CONSTEXPR23 T& as() noexcept {
return *static_cast<T*>(mInfo.get());
constexpr T& as() noexcept {
return *(T*)(dataPtr->get());
}
LLAPI Error& join(Error) noexcept;

Expand All @@ -78,57 +182,39 @@ class Error {
LLAPI Error const& log(CommandOutput&, CommandOutputMessageType = CommandOutputMessageType::Error) const noexcept;
};

struct StringError : ErrorInfoBase {
std::string str;
StringError(std::string str) : str(std::move(str)) {}
std::string message() const noexcept override { return str; }
};
struct ErrorCodeError : ErrorInfoBase {
std::error_code ec;
ErrorCodeError(std::error_code ec) : ec(ec) {}
std::string message() const noexcept override { return ec.message(); }
};
inline Unexpected forwardError(::ll::Error& err) noexcept { return ::nonstd::make_unexpected(std::move(err)); }

inline Unexpected makeSuccessed() noexcept { return ::nonstd::make_unexpected(Error{}); }

template <std::derived_from<::ll::ErrorInfoBase> T, class... Args>
template <IsErrorObj Err, class... Args>
inline Unexpected makeError(Args&&... args) noexcept {
return ::nonstd::make_unexpected<Error>(std::in_place, std::make_unique<T>(std::forward<Args>(args)...));
return ::nonstd::make_unexpected<Error>(std::in_place, std::in_place_type<Err>, std::forward<Args>(args)...);
}
inline Unexpected makeStringError(std::string str) noexcept { return makeError<StringError>(std::move(str)); }
inline Unexpected makeStringError(std::string str) noexcept { return makeError<std::string>(std::move(str)); }

inline Unexpected makeErrorCodeError(std::error_code ec) noexcept { return makeError<ErrorCodeError>(ec); }
inline Unexpected makeErrorCodeError(std::error_code ec) noexcept { return makeError<std::error_code>(ec); }

inline Unexpected makeErrorCodeError(std::errc ec) noexcept { return makeError<ErrorCodeError>(make_error_code(ec)); }
inline Unexpected makeErrorCodeError(std::errc ec) noexcept { return makeErrorCodeError(make_error_code(ec)); }

LLNDAPI Unexpected makeExceptionError(std::exception_ptr const& exc = std::current_exception()) noexcept;

} // namespace ll

namespace nonstd::expected_lite {
template <>
class bad_expected_access<::ll::Error> : public bad_expected_access<void> {
std::shared_ptr<::ll::Error> mError;
std::string mMessage;
class nonstd::expected_lite::bad_expected_access<::ll::Error> : public bad_expected_access<void> {
::ll::Error mError;
std::string mMessage;

public:
explicit bad_expected_access(::ll::Error& e) noexcept
: mError(::std::make_shared<::ll::Error>(::std::move(e))),
mMessage(mError->message()) {}
explicit bad_expected_access(::ll::Error e) noexcept : mError(::std::move(e)), mMessage(mError.message()) {}

char const* what() const noexcept override { return mMessage.c_str(); }

::ll::Error& error() & { return *mError; }
::ll::Error& error() & { return mError; }

::ll::Error const& error() const& { return *mError; }
::ll::Error const& error() const& { return mError; }

::ll::Error&& error() && { return ::std::move(*mError); }
::ll::Error&& error() && { return ::std::move(mError); }

::ll::Error const&& error() const&& { return ::std::move(*mError); }
};
template <>
struct error_traits<::ll::Error> {
static void rethrow(::ll::Error const& e) { throw bad_expected_access<::ll::Error>{const_cast<::ll::Error&>(e)}; }
::ll::Error const&& error() const&& { return ::std::move(mError); }
};
} // namespace nonstd::expected_lite
Loading

0 comments on commit 214fb19

Please sign in to comment.