diff --git a/include/xlnt/utils/optional.hpp b/include/xlnt/utils/optional.hpp index 18d66bd3..ab9c9a7d 100644 --- a/include/xlnt/utils/optional.hpp +++ b/include/xlnt/utils/optional.hpp @@ -27,6 +27,7 @@ #include "xlnt/utils/numeric.hpp" #include "xlnt/xlnt_config.hpp" #include +#include namespace xlnt { @@ -74,28 +75,26 @@ public: /// Default contructor. is_set() will be false initially. /// optional() noexcept - : has_value_(false) + : optional_ptr() { } /// - /// Constructs this optional with a value. + /// Copy constructs this optional with a value. /// noexcept if T copy ctor is noexcept /// optional(const T &value) noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(ctor_copy_T_noexcept{})) - : has_value_(true) + : optional_ptr(new T(value)) { - new (&storage_) T(value); } /// - /// Constructs this optional with a value. + /// Move constructs this optional with a value. /// noexcept if T move ctor is noexcept /// optional(T &&value) noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(ctor_move_T_noexcept{})) - : has_value_(true) + : optional_ptr(new T(std::move(value))) { - new (&storage_) T(std::move(value)); } /// @@ -103,12 +102,13 @@ public: /// noexcept if T copy ctor is noexcept /// optional(const optional &other) noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(copy_ctor_noexcept{})) - : has_value_(other.has_value_) { - if (has_value_) + if (other.optional_ptr != nullptr) { - new (&storage_) T(other.value_ref()); - } + optional_ptr = std::make_unique(*other.optional_ptr); + } else { + optional_ptr = nullptr; + } } /// @@ -116,13 +116,8 @@ public: /// noexcept if T move ctor is noexcept /// optional(optional &&other) noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(move_ctor_noexcept{})) - : has_value_(other.has_value_) + : optional_ptr(std::move(other.optional_ptr)) { - if (has_value_) - { - new (&storage_) T(std::move(other.value_ref())); - other.clear(); - } } /// @@ -131,14 +126,12 @@ public: /// optional &operator=(const optional &other) noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(set_copy_noexcept_t{} && clear_noexcept_t{})) { - if (other.has_value_) + if (other.optional_ptr != nullptr) { - set(other.value_ref()); - } - else - { - clear(); - } + optional_ptr.reset(new T(*other.optional_ptr)); + } else { + optional_ptr = nullptr; + } return *this; } @@ -148,15 +141,7 @@ public: /// optional &operator=(optional &&other) noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(set_move_noexcept_t{} && clear_noexcept_t{})) { - if (other.has_value_) - { - set(std::move(other.value_ref())); - other.clear(); - } - else - { - clear(); - } + optional_ptr = std::move(other.optional_ptr); return *this; } @@ -165,7 +150,7 @@ public: /// ~optional() noexcept // note:: unconditional because msvc freaks out otherwise { - clear(); + optional_ptr.reset(); } /// @@ -174,7 +159,7 @@ public: /// bool is_set() const noexcept { - return has_value_; + return (optional_ptr != nullptr); } /// @@ -182,49 +167,19 @@ public: /// void set(const T &value) noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(set_copy_noexcept_t{})) { -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" -#endif - if (has_value_) - { - value_ref() = value; - } - else - { - new (&storage_) T(value); - has_value_ = true; - } -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic pop -#endif + optional_ptr.reset(new T(value)); } /// /// Moves the value into the stored value /// + // note seperate overload for two reasons (as opposed to perfect forwarding) + // 1. have to deal with implicit conversions internally with perfect forwarding + // 2. have to deal with the noexcept specfiers for all the different variations + // overload is just far and away the simpler solution void set(T &&value) noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(set_move_noexcept_t{})) { - // note seperate overload for two reasons (as opposed to perfect forwarding) - // 1. have to deal with implicit conversions internally with perfect forwarding - // 2. have to deal with the noexcept specfiers for all the different variations - // overload is just far and away the simpler solution -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" -#endif - if (has_value_) - { - value_ref() = std::move(value); - } - else - { - new (&storage_) T(std::move(value)); - has_value_ = true; - } -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic pop -#endif + optional_ptr.reset(new T(std::move(value))); } /// @@ -232,7 +187,7 @@ public: /// optional &operator=(const T &rhs) noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(set_copy_noexcept_t{})) { - set(rhs); + optional_ptr.reset(new T(rhs)); return *this; } @@ -241,7 +196,7 @@ public: /// optional &operator=(T &&rhs) noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(set_move_noexcept_t{})) { - set(std::move(rhs)); + optional_ptr.reset(new T(std::move(rhs))); return *this; } @@ -250,11 +205,7 @@ public: /// void clear() noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(clear_noexcept_t{})) { - if (has_value_) - { - reinterpret_cast(&storage_)->~T(); - } - has_value_ = false; + optional_ptr.reset(); } /// @@ -263,12 +214,11 @@ public: /// T &get() { - if (!has_value_) + if (optional_ptr == nullptr) { throw invalid_attribute(); } - - return value_ref(); + return *optional_ptr; } /// @@ -277,12 +227,11 @@ public: /// const T &get() const { - if (!has_value_) + if (optional_ptr == nullptr) { throw invalid_attribute(); } - - return value_ref(); + return *optional_ptr; } /// @@ -292,16 +241,21 @@ public: /// bool operator==(const optional &other) const noexcept { - if (has_value_ != other.has_value_) + if (optional_ptr == nullptr) { - return false; - } - if (!has_value_) - { - return true; - } - // equality is overloaded to provide fuzzy equality when T is a fp number - return compare_equal(value_ref(), other.value_ref()); + if (other.optional_ptr == nullptr) { + return true; + } else { + return false; + }; + } else { + if (other.optional_ptr == nullptr) { + return false; + } else { + // equality is overloaded to provide fuzzy equality when T is a fp number + return compare_equal(*optional_ptr, *other.optional_ptr); + }; + }; } /// @@ -315,19 +269,7 @@ public: } private: - // helpers for getting a T out of storage - T &value_ref() noexcept - { - return *reinterpret_cast(&storage_); - } - - const T &value_ref() const noexcept - { - return *reinterpret_cast(&storage_); - } - - bool has_value_; - typename std::aligned_storage::type storage_; + std::unique_ptr optional_ptr; }; #ifdef XLNT_NOEXCEPT_VALUE_COMPAT