Merge pull request #1455 from yuriks/ResultVal-union

core: Use unrestricted union to hold storage of ResultVal value
This commit is contained in:
Mathew Maidment 2016-03-05 23:29:14 -05:00
commit 8ee230fe1c
1 changed files with 16 additions and 42 deletions

View File

@ -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));
}
};
/**