Merge 45eadf567432c6220f689477b933fffe5b2294f8 into 297b331435d6dee09bf89c8a5ad974b01f18039b

This commit is contained in:
Teebonne 2022-12-06 10:09:27 +00:00 committed by GitHub
commit cbc8bdca94
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -27,6 +27,7 @@
#include "xlnt/utils/numeric.hpp" #include "xlnt/utils/numeric.hpp"
#include "xlnt/xlnt_config.hpp" #include "xlnt/xlnt_config.hpp"
#include <type_traits> #include <type_traits>
#include <memory>
namespace xlnt { namespace xlnt {
@ -74,28 +75,26 @@ public:
/// Default contructor. is_set() will be false initially. /// Default contructor. is_set() will be false initially.
/// </summary> /// </summary>
optional() noexcept optional() noexcept
: has_value_(false) : optional_ptr()
{ {
} }
/// <summary> /// <summary>
/// Constructs this optional with a value. /// Copy constructs this optional with a value.
/// noexcept if T copy ctor is noexcept /// noexcept if T copy ctor is noexcept
/// </summary> /// </summary>
optional(const T &value) noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(ctor_copy_T_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);
} }
/// <summary> /// <summary>
/// Constructs this optional with a value. /// Move constructs this optional with a value.
/// noexcept if T move ctor is noexcept /// noexcept if T move ctor is noexcept
/// </summary> /// </summary>
optional(T &&value) noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(ctor_move_T_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));
} }
/// <summary> /// <summary>
@ -103,12 +102,13 @@ public:
/// noexcept if T copy ctor is noexcept /// noexcept if T copy ctor is noexcept
/// </summary> /// </summary>
optional(const optional &other) noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(copy_ctor_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<T>(*other.optional_ptr);
} } else {
optional_ptr = nullptr;
}
} }
/// <summary> /// <summary>
@ -116,13 +116,8 @@ public:
/// noexcept if T move ctor is noexcept /// noexcept if T move ctor is noexcept
/// </summary> /// </summary>
optional(optional &&other) noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(move_ctor_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();
}
} }
/// <summary> /// <summary>
@ -131,14 +126,12 @@ public:
/// </summary> /// </summary>
optional &operator=(const optional &other) noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(set_copy_noexcept_t{} && clear_noexcept_t{})) 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()); optional_ptr.reset(new T(*other.optional_ptr));
} } else {
else optional_ptr = nullptr;
{ }
clear();
}
return *this; return *this;
} }
@ -148,15 +141,7 @@ public:
/// </summary> /// </summary>
optional &operator=(optional &&other) noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(set_move_noexcept_t{} && clear_noexcept_t{})) optional &operator=(optional &&other) noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(set_move_noexcept_t{} && clear_noexcept_t{}))
{ {
if (other.has_value_) optional_ptr = std::move(other.optional_ptr);
{
set(std::move(other.value_ref()));
other.clear();
}
else
{
clear();
}
return *this; return *this;
} }
@ -165,7 +150,7 @@ public:
/// </summary> /// </summary>
~optional() noexcept // note:: unconditional because msvc freaks out otherwise ~optional() noexcept // note:: unconditional because msvc freaks out otherwise
{ {
clear(); optional_ptr.reset();
} }
/// <summary> /// <summary>
@ -174,7 +159,7 @@ public:
/// </summary> /// </summary>
bool is_set() const noexcept bool is_set() const noexcept
{ {
return has_value_; return (optional_ptr != nullptr);
} }
/// <summary> /// <summary>
@ -182,49 +167,19 @@ public:
/// </summary> /// </summary>
void set(const T &value) noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(set_copy_noexcept_t{})) void set(const T &value) noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(set_copy_noexcept_t{}))
{ {
#if defined(__GNUC__) && !defined(__clang__) optional_ptr.reset(new T(value));
#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
} }
/// <summary> /// <summary>
/// Moves the value into the stored value /// Moves the value into the stored value
/// </summary> /// </summary>
// 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{})) void set(T &&value) noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(set_move_noexcept_t{}))
{ {
// note seperate overload for two reasons (as opposed to perfect forwarding) optional_ptr.reset(new T(std::move(value)));
// 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
} }
/// <summary> /// <summary>
@ -232,7 +187,7 @@ public:
/// </summary> /// </summary>
optional &operator=(const T &rhs) noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(set_copy_noexcept_t{})) optional &operator=(const T &rhs) noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(set_copy_noexcept_t{}))
{ {
set(rhs); optional_ptr.reset(new T(rhs));
return *this; return *this;
} }
@ -241,7 +196,7 @@ public:
/// </summary> /// </summary>
optional &operator=(T &&rhs) noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(set_move_noexcept_t{})) 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; return *this;
} }
@ -250,11 +205,7 @@ public:
/// </summary> /// </summary>
void clear() noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(clear_noexcept_t{})) void clear() noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(clear_noexcept_t{}))
{ {
if (has_value_) optional_ptr.reset();
{
reinterpret_cast<T *>(&storage_)->~T();
}
has_value_ = false;
} }
/// <summary> /// <summary>
@ -263,12 +214,11 @@ public:
/// </summary> /// </summary>
T &get() T &get()
{ {
if (!has_value_) if (optional_ptr == nullptr)
{ {
throw invalid_attribute(); throw invalid_attribute();
} }
return *optional_ptr;
return value_ref();
} }
/// <summary> /// <summary>
@ -277,12 +227,11 @@ public:
/// </summary> /// </summary>
const T &get() const const T &get() const
{ {
if (!has_value_) if (optional_ptr == nullptr)
{ {
throw invalid_attribute(); throw invalid_attribute();
} }
return *optional_ptr;
return value_ref();
} }
/// <summary> /// <summary>
@ -292,16 +241,21 @@ public:
/// </summary> /// </summary>
bool operator==(const optional<T> &other) const noexcept bool operator==(const optional<T> &other) const noexcept
{ {
if (has_value_ != other.has_value_) if (optional_ptr == nullptr)
{ {
return false; if (other.optional_ptr == nullptr) {
} return true;
if (!has_value_) } else {
{ return false;
return true; };
} } else {
// equality is overloaded to provide fuzzy equality when T is a fp number if (other.optional_ptr == nullptr) {
return compare_equal(value_ref(), other.value_ref()); return false;
} else {
// equality is overloaded to provide fuzzy equality when T is a fp number
return compare_equal(*optional_ptr, *other.optional_ptr);
};
};
} }
/// <summary> /// <summary>
@ -315,19 +269,7 @@ public:
} }
private: private:
// helpers for getting a T out of storage std::unique_ptr<T> optional_ptr;
T &value_ref() noexcept
{
return *reinterpret_cast<T *>(&storage_);
}
const T &value_ref() const noexcept
{
return *reinterpret_cast<const T *>(&storage_);
}
bool has_value_;
typename std::aligned_storage<sizeof(T), alignof(T)>::type storage_;
}; };
#ifdef XLNT_NOEXCEPT_VALUE_COMPAT #ifdef XLNT_NOEXCEPT_VALUE_COMPAT