123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- #pragma once
- #include <memory>
- #include <type_traits>
- #include <initializer_list>
- namespace NMaybe {
- struct TInPlace {};
- template <class T, bool = std::is_trivially_destructible<T>::value>
- struct TStorageBase {
- constexpr TStorageBase() noexcept
- : NullState_('\0')
- {
- }
- template <class... Args>
- constexpr TStorageBase(TInPlace, Args&&... args)
- : Data_(std::forward<Args>(args)...)
- , Defined_(true)
- {
- }
- constexpr TStorageBase(TStorageBase&&) = default;
- constexpr TStorageBase(const TStorageBase&) = default;
- ~TStorageBase() = default;
- TStorageBase& operator=(const TStorageBase&) = default;
- TStorageBase& operator=(TStorageBase&&) = default;
- union {
- char NullState_;
- T Data_;
- };
- bool Defined_ = false;
- };
- template <class T>
- struct TStorageBase<T, false> {
- constexpr TStorageBase() noexcept
- : NullState_('\0')
- {
- }
- template <class... Args>
- constexpr TStorageBase(TInPlace, Args&&... args)
- : Data_(std::forward<Args>(args)...)
- , Defined_(true)
- {
- }
- constexpr TStorageBase(TStorageBase&&) = default;
- constexpr TStorageBase(const TStorageBase&) = default;
- ~TStorageBase() {
- if (this->Defined_) {
- this->Data_.~T();
- }
- }
- TStorageBase& operator=(const TStorageBase&) = default;
- TStorageBase& operator=(TStorageBase&&) = default;
- union {
- char NullState_;
- T Data_;
- };
- bool Defined_ = false;
- };
- // -------------------- COPY CONSTRUCT --------------------
- template <class T, bool = std::is_trivially_copy_constructible<T>::value>
- struct TCopyBase: TStorageBase<T> {
- using TStorageBase<T>::TStorageBase;
- };
- template <class T>
- struct TCopyBase<T, false>: TStorageBase<T> {
- using TStorageBase<T>::TStorageBase;
- constexpr TCopyBase() = default;
- constexpr TCopyBase(const TCopyBase& rhs) {
- if (rhs.Defined_) {
- new (std::addressof(this->Data_)) T(rhs.Data_);
- this->Defined_ = true;
- }
- }
- constexpr TCopyBase(TCopyBase&&) = default;
- TCopyBase& operator=(const TCopyBase&) = default;
- TCopyBase& operator=(TCopyBase&&) = default;
- };
- // -------------------- MOVE CONSTRUCT --------------------
- template <class T, bool = std::is_trivially_move_constructible<T>::value>
- struct TMoveBase: TCopyBase<T> {
- using TCopyBase<T>::TCopyBase;
- };
- template <class T>
- struct TMoveBase<T, false>: TCopyBase<T> {
- using TCopyBase<T>::TCopyBase;
- constexpr TMoveBase() noexcept = default;
- constexpr TMoveBase(const TMoveBase&) = default;
- constexpr TMoveBase(TMoveBase&& rhs) noexcept(std::is_nothrow_move_constructible<T>::value) {
- if (rhs.Defined_) {
- new (std::addressof(this->Data_)) T(std::move(rhs.Data_));
- this->Defined_ = true;
- }
- }
- TMoveBase& operator=(const TMoveBase&) = default;
- TMoveBase& operator=(TMoveBase&&) = default;
- };
- // -------------------- COPY ASSIGN --------------------
- template <class T, bool = std::is_trivially_copy_assignable<T>::value>
- struct TCopyAssignBase: TMoveBase<T> {
- using TMoveBase<T>::TMoveBase;
- };
- template <class T>
- struct TCopyAssignBase<T, false>: TMoveBase<T> {
- using TMoveBase<T>::TMoveBase;
- constexpr TCopyAssignBase() noexcept = default;
- constexpr TCopyAssignBase(const TCopyAssignBase&) = default;
- constexpr TCopyAssignBase(TCopyAssignBase&&) = default;
- TCopyAssignBase& operator=(const TCopyAssignBase& rhs) {
- if (this->Defined_) {
- if (rhs.Defined_) {
- this->Data_ = rhs.Data_;
- } else {
- this->Data_.~T();
- this->Defined_ = false;
- }
- } else if (rhs.Defined_) {
- new (std::addressof(this->Data_)) T(rhs.Data_);
- this->Defined_ = true;
- }
- return *this;
- }
- TCopyAssignBase& operator=(TCopyAssignBase&&) = default;
- };
- // -------------------- MOVE ASSIGN --------------------
- template <class T, bool = std::is_trivially_move_assignable<T>::value>
- struct TMoveAssignBase: TCopyAssignBase<T> {
- using TCopyAssignBase<T>::TCopyAssignBase;
- };
- template <class T>
- struct TMoveAssignBase<T, false>: TCopyAssignBase<T> {
- using TCopyAssignBase<T>::TCopyAssignBase;
- constexpr TMoveAssignBase() noexcept = default;
- constexpr TMoveAssignBase(const TMoveAssignBase&) = default;
- constexpr TMoveAssignBase(TMoveAssignBase&&) = default;
- TMoveAssignBase& operator=(const TMoveAssignBase&) = default;
- TMoveAssignBase& operator=(TMoveAssignBase&& rhs) noexcept(
- std::is_nothrow_move_assignable<T>::value &&
- std::is_nothrow_move_constructible<T>::value)
- {
- if (this->Defined_) {
- if (rhs.Defined_) {
- this->Data_ = std::move(rhs.Data_);
- } else {
- this->Data_.~T();
- this->Defined_ = false;
- }
- } else if (rhs.Defined_) {
- new (std::addressof(this->Data_)) T(std::move(rhs.Data_));
- this->Defined_ = true;
- }
- return *this;
- }
- };
- } // namespace NMaybe
- template <class T>
- using TMaybeBase = NMaybe::TMoveAssignBase<T>;
|