#pragma once #include #include #include namespace NMaybe { struct TInPlace {}; template ::value> struct TStorageBase { constexpr TStorageBase() noexcept : NullState_('\0') { } template constexpr TStorageBase(TInPlace, Args&&... args) : Data_(std::forward(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 struct TStorageBase { constexpr TStorageBase() noexcept : NullState_('\0') { } template constexpr TStorageBase(TInPlace, Args&&... args) : Data_(std::forward(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 ::value> struct TCopyBase: TStorageBase { using TStorageBase::TStorageBase; }; template struct TCopyBase: TStorageBase { using TStorageBase::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 ::value> struct TMoveBase: TCopyBase { using TCopyBase::TCopyBase; }; template struct TMoveBase: TCopyBase { using TCopyBase::TCopyBase; constexpr TMoveBase() noexcept = default; constexpr TMoveBase(const TMoveBase&) = default; constexpr TMoveBase(TMoveBase&& rhs) noexcept(std::is_nothrow_move_constructible::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 ::value> struct TCopyAssignBase: TMoveBase { using TMoveBase::TMoveBase; }; template struct TCopyAssignBase: TMoveBase { using TMoveBase::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 ::value> struct TMoveAssignBase: TCopyAssignBase { using TCopyAssignBase::TCopyAssignBase; }; template struct TMoveAssignBase: TCopyAssignBase { using TCopyAssignBase::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::value && std::is_nothrow_move_constructible::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 using TMaybeBase = NMaybe::TMoveAssignBase;