diff options
Diffstat (limited to 'zen/optional.h')
-rwxr-xr-x[-rw-r--r--] | zen/optional.h | 190 |
1 files changed, 100 insertions, 90 deletions
diff --git a/zen/optional.h b/zen/optional.h index 83915110..a4c67984 100644..100755 --- a/zen/optional.h +++ b/zen/optional.h @@ -1,90 +1,100 @@ -// ***************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl-3.0 * -// * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved * -// ***************************************************************************** - -#ifndef OPTIONAL_H_2857428578342203589 -#define OPTIONAL_H_2857428578342203589 - -#include <cassert> -#include <type_traits> - -namespace zen -{ -/* -Optional return value without heap memory allocation! - -> interface like a pointer, performance like a value - - Usage: - ------ - Opt<MyEnum> someFunction(); -{ - if (allIsWell) - return enumVal; - else - return NoValue(); -} - - Opt<MyEnum> optValue = someFunction(); - if (optValue) - ... use *optValue ... -*/ - -struct NoValue {}; - -template <class T> -class Opt -{ -public: - Opt() {} - Opt(NoValue) {} - Opt(const T& val) : valid(true) { new (&rawMem) T(val); } //throw X - - Opt(const Opt& other) : valid(other.valid) - { - if (const T* val = other.get()) - new (&rawMem) T(*val); //throw X - } - - ~Opt() { if (T* val = get()) val->~T(); } - - Opt& operator=(const Opt& other) //strong exception-safety iff T::operator=() is strongly exception-safe - { - if (T* val = get()) - { - if (const T* valOther = other.get()) - *val = *valOther; //throw X - else - { - valid = false; - val->~T(); - } - } - else if (const T* valOther = other.get()) - { - new (&rawMem) T(*valOther); //throw X - valid = true; - } - return *this; - } - - explicit operator bool() const { return valid; } //thank you C++11!!! - - const T* get() const { return valid ? reinterpret_cast<const T*>(&rawMem) : nullptr; } - T* get() { return valid ? reinterpret_cast< T*>(&rawMem) : nullptr; } - - const T& operator*() const { return *get(); } - /**/ T& operator*() { return *get(); } - - const T* operator->() const { return get(); } - /**/ T* operator->() { return get(); } - -private: - std::aligned_storage_t<sizeof(T), alignof(T)> rawMem; //don't require T to be default-constructible! - bool valid = false; -}; - -} - -#endif //OPTIONAL_H_2857428578342203589 +// *****************************************************************************
+// * This file is part of the FreeFileSync project. It is distributed under *
+// * GNU General Public License: http://www.gnu.org/licenses/gpl-3.0 *
+// * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved *
+// *****************************************************************************
+
+#ifndef OPTIONAL_H_2857428578342203589
+#define OPTIONAL_H_2857428578342203589
+
+#include <cassert>
+#include <type_traits>
+
+namespace zen
+{
+/*
+Optional return value without heap memory allocation!
+ -> interface like a pointer, performance like a value
+
+ Usage:
+ ------
+ Opt<MyEnum> someFunction();
+{
+ if (allIsWell)
+ return enumVal;
+ else
+ return NoValue();
+}
+
+ Opt<MyEnum> optValue = someFunction();
+ if (optValue)
+ ... use *optValue ...
+*/
+
+struct NoValue {};
+
+template <class T>
+class Opt
+{
+public:
+ Opt() {}
+ Opt(NoValue) {}
+ Opt(const T& val) : valid_(true) { new (&rawMem_) T(val); } //throw X
+ Opt( T&& tmp) : valid_(true) { new (&rawMem_) T(std::move(tmp)); }
+
+ Opt(const Opt& other) : valid_(other.valid_)
+ {
+ if (const T* val = other.get())
+ new (&rawMem_) T(*val); //throw X
+ }
+
+ ~Opt() { if (T* val = get()) val->~T(); }
+
+ Opt& operator=(NoValue) //support assignment to Opt<const T>
+ {
+ if (T* val = get())
+ {
+ valid_ = false;
+ val->~T();
+ }
+ return *this;
+ }
+
+ Opt& operator=(const Opt& other) //strong exception-safety iff T::operator=() is strongly exception-safe
+ {
+ if (T* val = get())
+ {
+ if (const T* valOther = other.get())
+ *val = *valOther; //throw X
+ else
+ {
+ valid_ = false;
+ val->~T();
+ }
+ }
+ else if (const T* valOther = other.get())
+ {
+ new (&rawMem_) T(*valOther); //throw X
+ valid_ = true;
+ }
+ return *this;
+ }
+
+ explicit operator bool() const { return valid_; } //thank you, C++11!!!
+
+ const T* get() const { return valid_ ? reinterpret_cast<const T*>(&rawMem_) : nullptr; }
+ T* get() { return valid_ ? reinterpret_cast< T*>(&rawMem_) : nullptr; }
+
+ const T& operator*() const { return *get(); }
+ /**/ T& operator*() { return *get(); }
+
+ const T* operator->() const { return get(); }
+ /**/ T* operator->() { return get(); }
+
+private:
+ std::aligned_storage_t<sizeof(T), alignof(T)> rawMem_; //don't require T to be default-constructible!
+ bool valid_ = false;
+};
+}
+
+#endif //OPTIONAL_H_2857428578342203589
|