Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion module-1/homework/Optional/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
248 changes: 218 additions & 30 deletions module-1/homework/Optional/optional.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,53 +2,241 @@
#include <type_traits>

#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<class T>
struct in_place_type_t {
explicit in_place_type_t() = default;
};

constexpr nullopt_t // Your code goes here;
template<class T>
constexpr in_place_type_t<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<typename T, bool>
class optional_destruct_helper {
public:
constexpr optional_destruct_helper() : isEngaged(false) {}

constexpr optional_destruct_helper(nullopt_t) : isEngaged(false) {}

template<class... _Args>
constexpr optional_destruct_helper(in_place_t, _Args&& ... __args): value(std::forward<_Args>(__args)...),
isEngaged(true) {}

template<class U = T>
constexpr optional_destruct_helper(U&& value): value(std::forward<U>(value)), isEngaged(true) {}

protected:
void _reset() {
isEngaged = false;
}

template<class U = T>
void setValue(U&& value) {
this->value = std::forward<U>(value);
isEngaged = true;
}


union {
T value;
char __nullValue;
};

bool isEngaged;
};

template<typename T>
class optional_destruct_helper<T, false> {
public:
constexpr optional_destruct_helper() : isEngaged(false) {}

constexpr optional_destruct_helper(nullopt_t) : isEngaged(false) {}

template<class... _Args>
constexpr optional_destruct_helper(in_place_t, _Args&& ... __args):
value(std::forward<_Args>(__args)...),
isEngaged(true) {}

template<class U = T>
constexpr optional_destruct_helper(U&& value):
value(std::forward<U>(value)),
isEngaged(true) {}


~optional_destruct_helper() {
if (this->isEngaged) {
value.~T();
}
}

protected:
void _reset() {
if (this->isEngaged) {
value.~T();
}
isEngaged = false;
}

template<class U = T>
void setValue(U&& value) {
if (this->isEngaged) {
this->value.~T();
}
this->value = std::forward<U>(value);
isEngaged = true;
}

union {
T value;
char __nullValue;
};

bool isEngaged;
};

template<typename T>
class optional : public optional_destruct_helper<T, std::is_trivially_destructible_v<T>> {
private:
using base = optional_destruct_helper<T, std::is_trivially_destructible<T>::value>;
public:

using value_type = T;

constexpr optional() noexcept;

template<class U = value_type>
constexpr optional(U&& value);

constexpr optional(nullopt_t) noexcept;

template<class... _Args>
constexpr explicit optional(in_place_t, _Args&& ... __args);

optional& operator=(nullopt_t) noexcept;

template<class U = T>
optional& operator=( U&& value );

void reset() noexcept;

template<typename U>
constexpr T value_or(U&& default_value) const&;

template<typename U>
constexpr T value_or(U&& default_value)&&;

constexpr bool has_value() const noexcept;

constexpr explicit operator bool() const noexcept;

constexpr std::add_pointer_t<const value_type> operator->() const;

constexpr std::add_pointer_t<value_type> operator->();

constexpr const value_type& operator*() const&;

constexpr value_type& operator*()&;

constexpr const value_type&& operator*() const&&;

constexpr value_type&& operator*()&&;
};
} // task namespace

template<typename T>
constexpr task::optional<T>::optional() noexcept: base() {}

template<typename T>
template<class U>
constexpr task::optional<T>::optional(U&& value): base(std::forward<U>(value)) {}

template<typename T>
constexpr task::optional<T>::optional(nullopt_t) noexcept: base(nullopt) {}

constexpr in_place_t // Your code goes here;
template<typename T>
template<class... _Args>
constexpr task::optional<T>::optional(in_place_t, _Args&& ... __args): base(in_place, __args...) {}

template<typename T>
class optional {
public:

using value_type = // Your code goes here;
template<typename U>
constexpr T task::optional<T>::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<class... _Args>
constexpr explicit optional(in_place_t, _Args&&... __args);

template<typename U>
constexpr T value_or(U&& default_value) const&;
template<typename T>
template<typename U>
constexpr T task::optional<T>::value_or(U&& default_value)&& {
return this->has_value() ? this->value : default_value;
}

template<typename U>
constexpr T value_or(U&& default_value) &&;
template<typename T>
constexpr bool task::optional<T>::has_value() const noexcept {
return this->isEngaged;
}

constexpr bool has_value() const noexcept;
template<typename T>
constexpr task::optional<T>::operator bool() const noexcept {
return this->has_value();
}

constexpr explicit operator bool() const noexcept;
template<typename T>
constexpr std::add_pointer_t<const typename task::optional<T>::value_type> task::optional<T>::operator->() const {
return &(this->value);
}

constexpr std::add_pointer_t<const value_type> operator->() const;
template<typename T>
constexpr std::add_pointer_t<typename task::optional<T>::value_type> task::optional<T>::operator->() {
return &(this->value);
}

constexpr std::add_pointer_t<value_type> operator->();
template<typename T>
constexpr const typename task::optional<T>::value_type& task::optional<T>::operator*() const& {
return (this->value);
}

constexpr const value_type& operator*() const&;
template<typename T>
constexpr typename task::optional<T>::value_type& task::optional<T>::operator*()& {
return (this->value);
}

constexpr value_type& operator*() &;
template<typename T>
constexpr const typename task::optional<T>::value_type&& task::optional<T>::operator*() const&& {
return this->value;
}

constexpr const value_type&& operator*() const&&;
template<typename T>
constexpr typename task::optional<T>::value_type&& task::optional<T>::operator*()&& {
return this->value;
}

constexpr value_type&& operator*() &&;
template<typename T>
task::optional<T>& task::optional<T>::operator=(task::nullopt_t) noexcept {
this->reset();
return *this;
}

private:
// Your code goes here;
};
template<typename T>
template<class U>
task::optional<T>& task::optional<T>::operator=(U&& value) {
this->setValue(std::forward<U>(value));
return *this;
}

template<typename T>
void task::optional<T>::reset() noexcept {
this->_reset();
}
31 changes: 23 additions & 8 deletions module-1/homework/Optional/tests.cpp
Original file line number Diff line number Diff line change
@@ -1,42 +1,57 @@
#include <cmath>
#include <string>

#include <optional>
//#include <optional>
#include "optional.h"

#include "gtest/gtest.h"

struct MyTestStruct {
int a;
int b;
};

TEST(Ctor, Test1) {
task::optional<MyTestStruct> 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<std::string> opt("Hello world");
task::optional<std::string> opt("Hello world");
ASSERT_EQ(opt.value_or("empty"), "Hello world");
}

TEST(ValueOR, Test2) {
std::optional<std::string> opt;
task::optional<std::string> opt;
ASSERT_EQ(opt.value_or("empty"), "empty");
}

TEST(HasValue, Test1) {
std::optional<std::string> opt("Hello world");
task::optional<std::string> opt("Hello world");
ASSERT_TRUE(opt.has_value());
}

TEST(Reset, Test1) {
std::optional<std::string> opt("Hello world");
task::optional<std::string> opt("Hello world");
opt.reset();
ASSERT_FALSE(opt.has_value());
}

TEST(ConversionToBool, Test1) {
std::optional<std::string> opt("Hello world");
task::optional<std::string> opt("Hello world");
ASSERT_TRUE(opt);
}

TEST(ArrowOperator, Test1) {
std::optional<std::string> opt("Hello world");
task::optional<std::string> opt("Hello world");
ASSERT_EQ(std::string(opt->c_str()), "Hello world");
}

TEST(IndirectionOperator, Test1) {
std::optional<int> opt(1);
task::optional<int> opt(1);
ASSERT_EQ(*opt, 1);
}