diff --git a/module-1/homework/Optional/CMakeLists.txt b/module-1/homework/Optional/CMakeLists.txt index 7097fd40..cea3b7a6 100644 --- a/module-1/homework/Optional/CMakeLists.txt +++ b/module-1/homework/Optional/CMakeLists.txt @@ -4,7 +4,7 @@ include(GoogleTest) project("runner") -set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt) diff --git a/module-1/homework/Optional/optional.h b/module-1/homework/Optional/optional.h index 77153ec7..b4338bec 100644 --- a/module-1/homework/Optional/optional.h +++ b/module-1/homework/Optional/optional.h @@ -2,53 +2,241 @@ #include #pragma once + +namespace task { + struct nullopt_t { - // Your code goes here; + explicit constexpr nullopt_t(int) {} +}; + +constexpr nullopt_t nullopt = nullopt_t{0}; // Your code goes here; + +template +struct in_place_type_t { + explicit in_place_type_t() = default; }; -constexpr nullopt_t // Your code goes here; +template +constexpr in_place_type_t in_place_type{}; struct in_place_t { - // Your code goes here; + explicit in_place_t() = default; +}; + +constexpr in_place_t in_place = in_place_t{}; // Your code goes here; + +template +class optional_destruct_helper { +public: + constexpr optional_destruct_helper() : isEngaged(false) {} + + constexpr optional_destruct_helper(nullopt_t) : isEngaged(false) {} + + template + constexpr optional_destruct_helper(in_place_t, _Args&& ... __args): value(std::forward<_Args>(__args)...), + isEngaged(true) {} + + template + constexpr optional_destruct_helper(U&& value): value(std::forward(value)), isEngaged(true) {} + +protected: + void _reset() { + isEngaged = false; + } + + template + void setValue(U&& value) { + this->value = std::forward(value); + isEngaged = true; + } + + + union { + T value; + char __nullValue; + }; + + bool isEngaged; +}; + +template +class optional_destruct_helper { +public: + constexpr optional_destruct_helper() : isEngaged(false) {} + + constexpr optional_destruct_helper(nullopt_t) : isEngaged(false) {} + + template + constexpr optional_destruct_helper(in_place_t, _Args&& ... __args): + value(std::forward<_Args>(__args)...), + isEngaged(true) {} + + template + constexpr optional_destruct_helper(U&& value): + value(std::forward(value)), + isEngaged(true) {} + + + ~optional_destruct_helper() { + if (this->isEngaged) { + value.~T(); + } + } + +protected: + void _reset() { + if (this->isEngaged) { + value.~T(); + } + isEngaged = false; + } + + template + void setValue(U&& value) { + if (this->isEngaged) { + this->value.~T(); + } + this->value = std::forward(value); + isEngaged = true; + } + + union { + T value; + char __nullValue; + }; + + bool isEngaged; +}; + +template +class optional : public optional_destruct_helper> { +private: + using base = optional_destruct_helper::value>; +public: + + using value_type = T; + + constexpr optional() noexcept; + + template + constexpr optional(U&& value); + + constexpr optional(nullopt_t) noexcept; + + template + constexpr explicit optional(in_place_t, _Args&& ... __args); + + optional& operator=(nullopt_t) noexcept; + + template + optional& operator=( U&& value ); + + void reset() noexcept; + + template + constexpr T value_or(U&& default_value) const&; + + template + constexpr T value_or(U&& default_value)&&; + + constexpr bool has_value() const noexcept; + + constexpr explicit operator bool() const noexcept; + + constexpr std::add_pointer_t operator->() const; + + constexpr std::add_pointer_t operator->(); + + constexpr const value_type& operator*() const&; + + constexpr value_type& operator*()&; + + constexpr const value_type&& operator*() const&&; + + constexpr value_type&& operator*()&&; }; +} // task namespace + +template +constexpr task::optional::optional() noexcept: base() {} + +template +template +constexpr task::optional::optional(U&& value): base(std::forward(value)) {} + +template +constexpr task::optional::optional(nullopt_t) noexcept: base(nullopt) {} -constexpr in_place_t // Your code goes here; +template +template +constexpr task::optional::optional(in_place_t, _Args&& ... __args): base(in_place, __args...) {} template -class optional { - public: - - using value_type = // Your code goes here; +template +constexpr T task::optional::value_or(U&& default_value) const& { + return this->has_value() ? this->value : default_value; +} - constexpr optional() noexcept; - template < class U = value_type > - constexpr optional( U&& value ); - constexpr optional(nullopt_t) noexcept; - template - constexpr explicit optional(in_place_t, _Args&&... __args); - - template - constexpr T value_or(U&& default_value) const&; +template +template +constexpr T task::optional::value_or(U&& default_value)&& { + return this->has_value() ? this->value : default_value; +} - template - constexpr T value_or(U&& default_value) &&; +template +constexpr bool task::optional::has_value() const noexcept { + return this->isEngaged; +} - constexpr bool has_value() const noexcept; +template +constexpr task::optional::operator bool() const noexcept { + return this->has_value(); +} - constexpr explicit operator bool() const noexcept; +template +constexpr std::add_pointer_t::value_type> task::optional::operator->() const { + return &(this->value); +} - constexpr std::add_pointer_t operator->() const; +template +constexpr std::add_pointer_t::value_type> task::optional::operator->() { + return &(this->value); +} - constexpr std::add_pointer_t operator->(); +template +constexpr const typename task::optional::value_type& task::optional::operator*() const& { + return (this->value); +} - constexpr const value_type& operator*() const&; +template +constexpr typename task::optional::value_type& task::optional::operator*()& { + return (this->value); +} - constexpr value_type& operator*() &; +template +constexpr const typename task::optional::value_type&& task::optional::operator*() const&& { + return this->value; +} - constexpr const value_type&& operator*() const&&; +template +constexpr typename task::optional::value_type&& task::optional::operator*()&& { + return this->value; +} - constexpr value_type&& operator*() &&; +template +task::optional& task::optional::operator=(task::nullopt_t) noexcept { + this->reset(); + return *this; +} - private: - // Your code goes here; -}; \ No newline at end of file +template +template +task::optional& task::optional::operator=(U&& value) { + this->setValue(std::forward(value)); + return *this; +} + +template +void task::optional::reset() noexcept { + this->_reset(); +} diff --git a/module-1/homework/Optional/tests.cpp b/module-1/homework/Optional/tests.cpp index 4c25c3c8..088e5198 100644 --- a/module-1/homework/Optional/tests.cpp +++ b/module-1/homework/Optional/tests.cpp @@ -1,42 +1,57 @@ #include #include -#include +//#include +#include "optional.h" #include "gtest/gtest.h" +struct MyTestStruct { + int a; + int b; +}; + +TEST(Ctor, Test1) { + task::optional testStruct(task::nullopt); + ASSERT_FALSE(testStruct.has_value()); + testStruct = {1, 2}; + ASSERT_TRUE(testStruct.has_value()); + ASSERT_EQ(testStruct->a, 1); + ASSERT_EQ(testStruct->b, 2); +} + TEST(ValueOR, Test1) { - std::optional opt("Hello world"); + task::optional opt("Hello world"); ASSERT_EQ(opt.value_or("empty"), "Hello world"); } TEST(ValueOR, Test2) { - std::optional opt; + task::optional opt; ASSERT_EQ(opt.value_or("empty"), "empty"); } TEST(HasValue, Test1) { - std::optional opt("Hello world"); + task::optional opt("Hello world"); ASSERT_TRUE(opt.has_value()); } TEST(Reset, Test1) { - std::optional opt("Hello world"); + task::optional opt("Hello world"); opt.reset(); ASSERT_FALSE(opt.has_value()); } TEST(ConversionToBool, Test1) { - std::optional opt("Hello world"); + task::optional opt("Hello world"); ASSERT_TRUE(opt); } TEST(ArrowOperator, Test1) { - std::optional opt("Hello world"); + task::optional opt("Hello world"); ASSERT_EQ(std::string(opt->c_str()), "Hello world"); } TEST(IndirectionOperator, Test1) { - std::optional opt(1); + task::optional opt(1); ASSERT_EQ(*opt, 1); } \ No newline at end of file