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:
Corentin Wallez
2018-11-29 12:40:26 +00:00
committed by Commit Bot service account
parent 813bfbd061
commit df72914a60
2 changed files with 137 additions and 0 deletions

View File

@@ -20,6 +20,7 @@
#include <cstddef>
#include <cstdint>
#include <utility>
// 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;
};
// 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*>
template <typename E>
Result<void, E*>::Result() {
@@ -247,4 +280,56 @@ E* Result<T*, E*>::GetErrorFromPayload(intptr_t payload) {
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_