Merge pull request #1455 from yuriks/ResultVal-union
core: Use unrestricted union to hold storage of ResultVal value
This commit is contained in:
commit
8ee230fe1c
|
@ -269,7 +269,6 @@ public:
|
|||
: result_code(error_code)
|
||||
{
|
||||
ASSERT(error_code.IsError());
|
||||
UpdateDebugPtr();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -287,40 +286,37 @@ public:
|
|||
: result_code(o.result_code)
|
||||
{
|
||||
if (!o.empty()) {
|
||||
new (&storage) T(*o.GetPointer());
|
||||
new (&object) T(o.object);
|
||||
}
|
||||
UpdateDebugPtr();
|
||||
}
|
||||
|
||||
ResultVal(ResultVal&& o)
|
||||
: result_code(o.result_code)
|
||||
{
|
||||
if (!o.empty()) {
|
||||
new (&storage) T(std::move(*o.GetPointer()));
|
||||
new (&object) T(std::move(o.object));
|
||||
}
|
||||
UpdateDebugPtr();
|
||||
}
|
||||
|
||||
~ResultVal() {
|
||||
if (!empty()) {
|
||||
GetPointer()->~T();
|
||||
object.~T();
|
||||
}
|
||||
}
|
||||
|
||||
ResultVal& operator=(const ResultVal& o) {
|
||||
if (!empty()) {
|
||||
if (!o.empty()) {
|
||||
*GetPointer() = *o.GetPointer();
|
||||
object = o.object;
|
||||
} else {
|
||||
GetPointer()->~T();
|
||||
object.~T();
|
||||
}
|
||||
} else {
|
||||
if (!o.empty()) {
|
||||
new (&storage) T(*o.GetPointer());
|
||||
new (&object) T(o.object);
|
||||
}
|
||||
}
|
||||
result_code = o.result_code;
|
||||
UpdateDebugPtr();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
@ -333,11 +329,10 @@ public:
|
|||
void emplace(ResultCode success_code, Args&&... args) {
|
||||
ASSERT(success_code.IsSuccess());
|
||||
if (!empty()) {
|
||||
GetPointer()->~T();
|
||||
object.~T();
|
||||
}
|
||||
new (&storage) T(std::forward<Args>(args)...);
|
||||
new (&object) T(std::forward<Args>(args)...);
|
||||
result_code = success_code;
|
||||
UpdateDebugPtr();
|
||||
}
|
||||
|
||||
/// Returns true if the `ResultVal` contains an error code and no value.
|
||||
|
@ -350,15 +345,15 @@ public:
|
|||
|
||||
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.
|
||||
template <typename U>
|
||||
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.
|
||||
|
@ -372,31 +367,10 @@ public:
|
|||
}
|
||||
|
||||
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;
|
||||
#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));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
Reference in New Issue