|
|
@ -269,7 +269,6 @@ public: |
|
|
: result_code(error_code) |
|
|
: result_code(error_code) |
|
|
{ |
|
|
{ |
|
|
ASSERT(error_code.IsError()); |
|
|
ASSERT(error_code.IsError()); |
|
|
UpdateDebugPtr(); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
@ -287,40 +286,37 @@ public: |
|
|
: result_code(o.result_code) |
|
|
: result_code(o.result_code) |
|
|
{ |
|
|
{ |
|
|
if (!o.empty()) { |
|
|
if (!o.empty()) { |
|
|
new (&storage) T(*o.GetPointer()); |
|
|
|
|
|
|
|
|
new (&object) T(o.object); |
|
|
} |
|
|
} |
|
|
UpdateDebugPtr(); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
ResultVal(ResultVal&& o) |
|
|
ResultVal(ResultVal&& o) |
|
|
: result_code(o.result_code) |
|
|
: result_code(o.result_code) |
|
|
{ |
|
|
{ |
|
|
if (!o.empty()) { |
|
|
if (!o.empty()) { |
|
|
new (&storage) T(std::move(*o.GetPointer())); |
|
|
|
|
|
|
|
|
new (&object) T(std::move(o.object)); |
|
|
} |
|
|
} |
|
|
UpdateDebugPtr(); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
~ResultVal() { |
|
|
~ResultVal() { |
|
|
if (!empty()) { |
|
|
if (!empty()) { |
|
|
GetPointer()->~T(); |
|
|
|
|
|
|
|
|
object.~T(); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
ResultVal& operator=(const ResultVal& o) { |
|
|
ResultVal& operator=(const ResultVal& o) { |
|
|
if (!empty()) { |
|
|
if (!empty()) { |
|
|
if (!o.empty()) { |
|
|
if (!o.empty()) { |
|
|
*GetPointer() = *o.GetPointer(); |
|
|
|
|
|
|
|
|
object = o.object; |
|
|
} else { |
|
|
} else { |
|
|
GetPointer()->~T(); |
|
|
|
|
|
|
|
|
object.~T(); |
|
|
} |
|
|
} |
|
|
} else { |
|
|
} else { |
|
|
if (!o.empty()) { |
|
|
if (!o.empty()) { |
|
|
new (&storage) T(*o.GetPointer()); |
|
|
|
|
|
|
|
|
new (&object) T(o.object); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
result_code = o.result_code; |
|
|
result_code = o.result_code; |
|
|
UpdateDebugPtr(); |
|
|
|
|
|
|
|
|
|
|
|
return *this; |
|
|
return *this; |
|
|
} |
|
|
} |
|
|
@ -333,11 +329,10 @@ public: |
|
|
void emplace(ResultCode success_code, Args&&... args) { |
|
|
void emplace(ResultCode success_code, Args&&... args) { |
|
|
ASSERT(success_code.IsSuccess()); |
|
|
ASSERT(success_code.IsSuccess()); |
|
|
if (!empty()) { |
|
|
if (!empty()) { |
|
|
GetPointer()->~T(); |
|
|
|
|
|
|
|
|
object.~T(); |
|
|
} |
|
|
} |
|
|
new (&storage) T(std::forward<Args>(args)...); |
|
|
|
|
|
|
|
|
new (&object) T(std::forward<Args>(args)...); |
|
|
result_code = success_code; |
|
|
result_code = success_code; |
|
|
UpdateDebugPtr(); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/// Returns true if the `ResultVal` contains an error code and no value. |
|
|
/// Returns true if the `ResultVal` contains an error code and no value. |
|
|
@ -350,15 +345,15 @@ public: |
|
|
|
|
|
|
|
|
ResultCode Code() const { return result_code; } |
|
|
ResultCode Code() const { return result_code; } |
|
|
|
|
|
|
|
|
const T& operator* () const { return *GetPointer(); } |
|
|
|
|
|
T& operator* () { return *GetPointer(); } |
|
|
|
|
|
const T* operator->() const { return GetPointer(); } |
|
|
|
|
|
T* operator->() { return GetPointer(); } |
|
|
|
|
|
|
|
|
const T& operator* () const { return object; } |
|
|
|
|
|
T& operator* () { return object; } |
|
|
|
|
|
const T* operator->() const { return &object; } |
|
|
|
|
|
T* operator->() { return &object; } |
|
|
|
|
|
|
|
|
/// Returns the value contained in this `ResultVal`, or the supplied default if it is missing. |
|
|
/// Returns the value contained in this `ResultVal`, or the supplied default if it is missing. |
|
|
template <typename U> |
|
|
template <typename U> |
|
|
T ValueOr(U&& value) const { |
|
|
T ValueOr(U&& value) const { |
|
|
return !empty() ? *GetPointer() : std::move(value); |
|
|
|
|
|
|
|
|
return !empty() ? object : std::move(value); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/// Asserts that the result succeeded and returns a reference to it. |
|
|
/// Asserts that the result succeeded and returns a reference to it. |
|
|
@ -372,31 +367,10 @@ public: |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private: |
|
|
private: |
|
|
typedef typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type StorageType; |
|
|
|
|
|
|
|
|
|
|
|
StorageType storage; |
|
|
|
|
|
|
|
|
// A union is used to allocate the storage for the value, while allowing us to construct and |
|
|
|
|
|
// destruct it at will. |
|
|
|
|
|
union { T object; }; |
|
|
ResultCode result_code; |
|
|
ResultCode result_code; |
|
|
#ifdef _DEBUG |
|
|
|
|
|
// The purpose of this pointer is to aid inspecting the type with a debugger, eliminating the |
|
|
|
|
|
// need to cast `storage` to a pointer or pay attention to `result_code`. |
|
|
|
|
|
const T* debug_ptr; |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
void UpdateDebugPtr() { |
|
|
|
|
|
#ifdef _DEBUG |
|
|
|
|
|
debug_ptr = empty() ? nullptr : static_cast<const T*>(static_cast<const void*>(&storage)); |
|
|
|
|
|
#endif |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const T* GetPointer() const { |
|
|
|
|
|
ASSERT(!empty()); |
|
|
|
|
|
return static_cast<const T*>(static_cast<const void*>(&storage)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
T* GetPointer() { |
|
|
|
|
|
ASSERT(!empty()); |
|
|
|
|
|
return static_cast<T*>(static_cast<void*>(&storage)); |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
|