diff --git a/module-1/homework/Optional/optional.h b/module-1/homework/Optional/optional.h index 1c2bbf91..f10ad2da 100644 --- a/module-1/homework/Optional/optional.h +++ b/module-1/homework/Optional/optional.h @@ -6,21 +6,114 @@ namespace task { struct NullOpt { - // Your code goes here; + explicit constexpr NullOpt(int) { + } }; -constexpr NullOpt kNullOpt = // Your code goes here; - +constexpr NullOpt kNullOpt = NullOpt(0); struct InPlace { - // Your code goes here; + explicit InPlace() = default; }; -constexpr InPlace kInPlace = //Your code goes here; +constexpr InPlace kInPlace = InPlace(); + +template +class OptionalBase { +public: + constexpr OptionalBase() { + } + + constexpr OptionalBase(NullOpt) // NOLINT + { + } + + template + constexpr OptionalBase(InPlace, Args&&... args) // NOLINT + : value_{std::forward(args)...}, is_none_{false} { + } + + template + constexpr OptionalBase(U&& value) // NOLINT + : value_{std::forward(value)}, is_none_{false} { + } + +protected: + template + void Set(U&& value) { + value_ = std::forward(value); + is_none_ = false; + } + + void Reset() { + is_none_ = true; + } + + union { + T value_; + char none_; + }; + + bool is_none_ = true; +}; template -class Optional : public // Your code goes here; { +class OptionalBase { public: - using value_type = // Your code goes here; + constexpr OptionalBase() { + } + + constexpr OptionalBase(NullOpt) // NOLINT + { + } + + template + constexpr OptionalBase(InPlace, Args&&... args) // NOLINT + : value_{std::forward(args)...}, is_none_{false} { + } + + template + constexpr OptionalBase(U&& value) // NOLINT + : value_{std::forward(value)}, is_none_{false} { + } + + ~OptionalBase() { + if (!is_none_) { + value_.~T(); + } + } + +protected: + template + void Set(U&& value) { + if (!is_none_) { + value_.~T(); + } + value_ = std::forward(value); + is_none_ = false; + } + + void Reset() { + if (!is_none_) { + value_.~T(); + } + is_none_ = true; + } + + union { + T value_; + char none_; + }; + + bool is_none_ = true; +}; + +template +class Optional : public OptionalBase> { +private: + using base = OptionalBase::value>; + +public: + using value_type = T; constexpr Optional() noexcept; @@ -61,4 +154,100 @@ class Optional : public // Your code goes here; { constexpr value_type&& operator*() &&; }; + +template +constexpr Optional::Optional() noexcept { +} + +template +template +constexpr Optional::Optional(U&& value) : base{std::forward(value)} { +} + +template +constexpr Optional::Optional(NullOpt) noexcept { +} + +template +template +constexpr Optional::Optional(InPlace, Args&&... args) + : base{kInPlace, std::forward(args)...} { +} + +template +Optional& Optional::operator=(NullOpt) noexcept { + base::Reset(); + return *this; +} + +template +template +Optional& Optional::operator=(U&& value) { + base::Set(std::forward(value)); + return *this; +} + +template +void Optional::Reset() noexcept { + base::Reset(); +} + +template +template +constexpr T Optional::ValueOr(U&& default_value) const& { + if (!base::is_none_) { + return base::value_; + } + return default_value; +} + +template +template +constexpr T Optional::ValueOr(U&& default_value) && { + if (!base::is_none_) { + return base::value_; + } + return default_value; +} + +template +constexpr bool Optional::HasValue() const noexcept { + return !base::is_none_; +} + +template +constexpr Optional::operator bool() const noexcept { + return HasValue(); +} + +template +constexpr std::add_pointer_t::value_type> Optional::operator->() + const { + return base::value_; +} + +template +constexpr std::add_pointer_t::value_type> Optional::operator->() { + return &(base::value_); +} + +template +constexpr const typename Optional::value_type& Optional::operator*() const& { + return base::value_; +} + +template +constexpr typename Optional::value_type& Optional::operator*() & { + return base::value_; +} + +template +constexpr const typename Optional::value_type&& Optional::operator*() const&& { + return std::move(base::value_); +} + +template +constexpr typename Optional::value_type&& Optional::operator*() && { + return std::move(base::value_); +} } // namespace task \ No newline at end of file