mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-07-07 05:36:04 +00:00
Result: Add default template for Result<T, E>
It currently is a tagged pair instead of a tagged union because it was much easier to write and the optimization can come later. BUG=dawn:19 Change-Id: Idbfd86d559655b38871c2d1768bdd758e797dfbd Reviewed-on: https://dawn-review.googlesource.com/c/2701 Commit-Queue: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Stephen White <senorblanco@chromium.org> Reviewed-by: Kai Ninomiya <kainino@chromium.org>
This commit is contained in:
parent
813bfbd061
commit
df72914a60
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
// Result<T, E> is the following sum type (Haskell notation):
|
// Result<T, E> is the following sum type (Haskell notation):
|
||||||
//
|
//
|
||||||
@ -124,6 +125,38 @@ class DAWN_NO_DISCARD Result<T*, E*> {
|
|||||||
intptr_t mPayload = kEmptyPayload;
|
intptr_t mPayload = kEmptyPayload;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Catchall definition of Result<T, E> implemented as a tagged struct. It could be improved to use
|
||||||
|
// a tagged union instead if it turns out to be a hotspot. T and E must be movable and default
|
||||||
|
// constructible.
|
||||||
|
template <typename T, typename E>
|
||||||
|
class DAWN_NO_DISCARD Result {
|
||||||
|
public:
|
||||||
|
Result(T&& success);
|
||||||
|
Result(E&& error);
|
||||||
|
|
||||||
|
Result(Result<T, E>&& other);
|
||||||
|
Result<T, E>& operator=(Result<T, E>&& other);
|
||||||
|
|
||||||
|
~Result();
|
||||||
|
|
||||||
|
bool IsError() const;
|
||||||
|
bool IsSuccess() const;
|
||||||
|
|
||||||
|
T&& AcquireSuccess();
|
||||||
|
E&& AcquireError();
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum PayloadType {
|
||||||
|
Success = 0,
|
||||||
|
Error = 1,
|
||||||
|
Acquired = 2,
|
||||||
|
};
|
||||||
|
PayloadType mType;
|
||||||
|
|
||||||
|
E mError;
|
||||||
|
T mSuccess;
|
||||||
|
};
|
||||||
|
|
||||||
// Implementation of Result<void, E*>
|
// Implementation of Result<void, E*>
|
||||||
template <typename E>
|
template <typename E>
|
||||||
Result<void, E*>::Result() {
|
Result<void, E*>::Result() {
|
||||||
@ -247,4 +280,56 @@ E* Result<T*, E*>::GetErrorFromPayload(intptr_t payload) {
|
|||||||
return reinterpret_cast<E*>(payload ^ 1);
|
return reinterpret_cast<E*>(payload ^ 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Implementation of Result<T, E>
|
||||||
|
template <typename T, typename E>
|
||||||
|
Result<T, E>::Result(T&& success) : mType(Success), mSuccess(success) {
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename E>
|
||||||
|
Result<T, E>::Result(E&& error) : mType(Error), mError(error) {
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename E>
|
||||||
|
Result<T, E>::~Result() {
|
||||||
|
ASSERT(mType == Acquired);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename E>
|
||||||
|
Result<T, E>::Result(Result<T, E>&& other)
|
||||||
|
: mType(other.mType), mError(std::move(other.mError)), mSuccess(other.mSuccess) {
|
||||||
|
other.mType = Acquired;
|
||||||
|
}
|
||||||
|
template <typename T, typename E>
|
||||||
|
Result<T, E>& Result<T, E>::operator=(Result<T, E>&& other) {
|
||||||
|
mType = other.mType;
|
||||||
|
mError = std::move(other.mError);
|
||||||
|
mSuccess = std::move(other.mSuccess);
|
||||||
|
other.mType = Acquired;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename E>
|
||||||
|
bool Result<T, E>::IsError() const {
|
||||||
|
return mType == Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename E>
|
||||||
|
bool Result<T, E>::IsSuccess() const {
|
||||||
|
return mType == Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename E>
|
||||||
|
T&& Result<T, E>::AcquireSuccess() {
|
||||||
|
ASSERT(mType == Success);
|
||||||
|
mType = Acquired;
|
||||||
|
return std::move(mSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename E>
|
||||||
|
E&& Result<T, E>::AcquireError() {
|
||||||
|
ASSERT(mType == Error);
|
||||||
|
mType = Acquired;
|
||||||
|
return std::move(mError);
|
||||||
|
}
|
||||||
|
|
||||||
#endif // COMMON_RESULT_H_
|
#endif // COMMON_RESULT_H_
|
||||||
|
@ -39,6 +39,8 @@ void TestSuccess(Result<T, E>* result, T expectedSuccess) {
|
|||||||
static int dummyError = 0xbeef;
|
static int dummyError = 0xbeef;
|
||||||
static float dummySuccess = 42.0f;
|
static float dummySuccess = 42.0f;
|
||||||
|
|
||||||
|
// Result<void, E*>
|
||||||
|
|
||||||
// Test constructing an error Result<void, E*>
|
// Test constructing an error Result<void, E*>
|
||||||
TEST(ResultOnlyPointerError, ConstructingError) {
|
TEST(ResultOnlyPointerError, ConstructingError) {
|
||||||
Result<void, int*> result(&dummyError);
|
Result<void, int*> result(&dummyError);
|
||||||
@ -88,6 +90,8 @@ TEST(ResultOnlyPointerError, ReturningSuccess) {
|
|||||||
ASSERT_FALSE(result.IsError());
|
ASSERT_FALSE(result.IsError());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Result<T*, E*>
|
||||||
|
|
||||||
// Test constructing an error Result<T*, E*>
|
// Test constructing an error Result<T*, E*>
|
||||||
TEST(ResultBothPointer, ConstructingError) {
|
TEST(ResultBothPointer, ConstructingError) {
|
||||||
Result<float*, int*> result(&dummyError);
|
Result<float*, int*> result(&dummyError);
|
||||||
@ -134,4 +138,52 @@ TEST(ResultBothPointer, ReturningSuccess) {
|
|||||||
TestSuccess(&result, &dummySuccess);
|
TestSuccess(&result, &dummySuccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Result<T, E>
|
||||||
|
|
||||||
|
// Test constructing an error Result<T, E>
|
||||||
|
TEST(ResultGeneric, ConstructingError) {
|
||||||
|
Result<std::vector<float>, int*> result(&dummyError);
|
||||||
|
TestError(&result, &dummyError);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test moving an error Result<T, E>
|
||||||
|
TEST(ResultGeneric, MovingError) {
|
||||||
|
Result<std::vector<float>, int*> result(&dummyError);
|
||||||
|
Result<std::vector<float>, int*> movedResult(std::move(result));
|
||||||
|
TestError(&movedResult, &dummyError);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test returning an error Result<T, E>
|
||||||
|
TEST(ResultGeneric, ReturningError) {
|
||||||
|
auto CreateError = []() -> Result<std::vector<float>, int*> {
|
||||||
|
return {&dummyError};
|
||||||
|
};
|
||||||
|
|
||||||
|
Result<std::vector<float>, int*> result = CreateError();
|
||||||
|
TestError(&result, &dummyError);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test constructing a success Result<T, E>
|
||||||
|
TEST(ResultGeneric, ConstructingSuccess) {
|
||||||
|
Result<std::vector<float>, int*> result({1.0f});
|
||||||
|
TestSuccess(&result, {1.0f});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test moving a success Result<T, E>
|
||||||
|
TEST(ResultGeneric, MovingSuccess) {
|
||||||
|
Result<std::vector<float>, int*> result({1.0f});
|
||||||
|
Result<std::vector<float>, int*> movedResult(std::move(result));
|
||||||
|
TestSuccess(&movedResult, {1.0f});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test returning a success Result<T, E>
|
||||||
|
TEST(ResultGeneric, ReturningSuccess) {
|
||||||
|
auto CreateSuccess = []() -> Result<std::vector<float>, int*> {
|
||||||
|
return {{1.0f}};
|
||||||
|
};
|
||||||
|
|
||||||
|
Result<std::vector<float>, int*> result = CreateSuccess();
|
||||||
|
TestSuccess(&result, {1.0f});
|
||||||
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
Loading…
x
Reference in New Issue
Block a user