// ***************************************************************************** // * This file is part of the FreeFileSync project. It is distributed under * // * GNU General Public License: https://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 namespace zen { /* Optional return value without heap memory allocation! -> interface like a pointer, performance like a value Usage: ------ Opt someFunction(); { if (allIsWell) return enumVal; else return NoValue(); } Opt optValue = someFunction(); if (optValue) ... use *optValue ... */ struct NoValue {}; template 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=(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; } Opt& operator=(NoValue) //support assignment to Opt { if (T* val = get()) { valid_ = false; val->~T(); } return *this; } explicit operator bool() const { return valid_; } //thank you, C++11!!! const T* get() const { return valid_ ? reinterpret_cast(&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 rawMem_; //don't require T to be default-constructible! bool valid_ = false; }; template inline bool operator==(const Opt& lhs, const Opt& rhs) { if (static_cast(lhs) != static_cast(rhs)) return false; if (!lhs) return true; return *lhs == *rhs; } template inline bool operator!=(const Opt& lhs, const Opt& rhs) { return !(lhs == rhs); } } #endif //OPTIONAL_H_2857428578342203589