Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -----------------------------------------------------------------------
- optional.h
- -----------------------------------------------------------------------
- #include <stdexcept>
- #include <utility>
- class BadOptionalAccess : public std::exception {
- public:
- using exception::exception;
- virtual const char* what() const noexcept override {
- return "Bad optional access";
- }
- };
- template <typename T>
- class Optional {
- public:
- Optional() = default;
- Optional(const T& item) {
- buff_ = new (&data_[0]) T(item);
- is_initialized_ = true;
- }
- Optional(T&& item) {
- buff_ = new (&data_[0]) T(std::forward<T>(item));
- is_initialized_ = true;
- }
- Optional(const Optional& other) {
- (!other.HasValue() && HasValue()) ? Reset() :
- (other.HasValue() && !this->HasValue()) ? (void)(buff_ = new (&data_[0]) T(other.Value()), is_initialized_ = true) :
- (other.HasValue() && HasValue()) ? (void)(*buff_ = other.Value(), is_initialized_ = true) : void();
- }
- Optional(Optional&& other) noexcept {
- (!other.HasValue() && this->HasValue()) ? Reset() :
- (other.HasValue() && !HasValue()) ? (void)(buff_ = new (&data_[0]) T(std::forward<T>(other.Value())), is_initialized_ = true) :
- (other.HasValue() && HasValue()) ? (void)(*buff_ = std::forward<T>(other.Value()), is_initialized_ = true) : void();
- }
- ~Optional() {
- is_initialized_ ? buff_->~T() : void();
- }
- bool HasValue() const {return is_initialized_;}
- T& Value() {if (!is_initialized_) {throw BadOptionalAccess();} else {return *buff_;}}
- const T& Value() const {if (!is_initialized_) {throw BadOptionalAccess();} else {return *buff_;}}
- void Reset() {is_initialized_ ? (is_initialized_ = false, buff_->~T()) : void();}
- Optional& operator=(const T& item) {
- HasValue() ? (void)(*buff_ = item ) : (void)(buff_ = new (&data_[0]) T(item), is_initialized_ = true);
- return *this;
- }
- Optional& operator=(T&& item) {
- HasValue() ? (void)(*buff_ = std::forward<T>(item))
- : (void)(buff_ = new (&data_[0]) T(std::forward<T>(item)), is_initialized_ = true);
- return *this;
- }
- Optional& operator=(const Optional& other) {
- (!other.HasValue() && HasValue()) ? Reset() :
- (other.HasValue() && !HasValue()) ? (void)(buff_ = new (&data_[0]) T(other.Value()), is_initialized_ = true) :
- (other.HasValue() && HasValue()) ? (void)(*buff_ = other.Value(), is_initialized_ = true) : void();
- return *this;
- }
- Optional& operator=(Optional&& other) noexcept {
- (!other.HasValue() && HasValue()) ? Reset() :
- (other.HasValue() && !HasValue()) ? (void)(buff_ = new (&data_[0]) T(std::forward<T>(other.Value())), is_initialized_ = true) :
- (other.HasValue() && HasValue()) ? (void)(*buff_ = std::forward<T>(other.Value()), is_initialized_ = true) : void();
- return *this;
- }
- T& operator*() {return Value();}
- const T& operator*() const {return Value();}
- T* operator->() {return &Value();}
- const T* operator->() const {return &Value();}
- private:
- T* buff_ = nullptr;
- alignas(T) char data_[sizeof(T)]{};
- bool is_initialized_ = false;
- };
- -----------------------------------------------------------------------
- main.cpp
- -----------------------------------------------------------------------
- #include "optional.h"
- #include <cassert>
- struct C {
- C() noexcept {++def_ctor;}
- C(const C& /*other*/) noexcept {++copy_ctor; }
- C(C&& /*other*/) noexcept {++move_ctor;}
- C& operator=(const C& other) noexcept {
- if (this != &other) {
- ++copy_assign;
- }
- return *this;
- }
- C& operator=(C&& /*other*/) noexcept {
- ++move_assign;
- return *this;
- }
- ~C() {
- ++dtor;
- }
- static size_t InstanceCount() {
- return def_ctor + copy_ctor + move_ctor - dtor;
- }
- static void Reset() {
- def_ctor = 0;
- copy_ctor = 0;
- move_ctor = 0;
- copy_assign = 0;
- move_assign = 0;
- dtor = 0;
- }
- inline static size_t def_ctor = 0;
- inline static size_t copy_ctor = 0;
- inline static size_t move_ctor = 0;
- inline static size_t copy_assign = 0;
- inline static size_t move_assign = 0;
- inline static size_t dtor = 0;
- };
- void TestInitialization() {
- C::Reset();
- {
- Optional<C> o;
- assert(!o.HasValue());
- assert(C::InstanceCount() == 0);
- }
- assert(C::InstanceCount() == 0);
- C::Reset();
- {
- C c;
- Optional<C> o(c);
- assert(o.HasValue());
- assert(C::def_ctor == 1
- && C::copy_ctor == 1);
- assert(C::InstanceCount() == 2);
- }
- assert(C::InstanceCount() == 0);
- C::Reset();
- {
- C c;
- Optional<C> o(std::move(c));
- assert(o.HasValue());
- assert(C::def_ctor == 1
- && C::move_ctor == 1
- && C::copy_ctor == 0
- && C::copy_assign == 0
- && C::move_assign == 0);
- assert(C::InstanceCount() == 2);
- }
- assert(C::InstanceCount() == 0);
- C::Reset();
- {
- C c;
- Optional<C> o1(c);
- const Optional<C> o2(o1);
- assert(o1.HasValue());
- assert(o2.HasValue());
- assert(C::def_ctor == 1
- && C::move_ctor == 0
- && C::copy_ctor == 2
- && C::copy_assign == 0
- && C::move_assign == 0);
- assert(C::InstanceCount() == 3);
- }
- assert(C::InstanceCount() == 0);
- C::Reset();
- {
- C c;
- Optional<C> o1(c);
- const Optional<C> o2(std::move(o1));
- assert(C::def_ctor == 1
- && C::copy_ctor == 1
- && C::move_ctor == 1
- && C::copy_assign == 0
- && C::move_assign == 0);
- assert(C::InstanceCount() == 3);
- }
- assert(C::InstanceCount() == 0);
- }
- void TestAssignment() {
- Optional<C> o1;
- Optional<C> o2;
- {
- C::Reset();
- C c;
- o1 = c;
- assert(C::def_ctor == 1
- && C::copy_ctor == 1
- && C::dtor == 0);
- }
- {
- C::Reset();
- o2 = o1;
- assert(C::copy_ctor == 1
- && C::copy_assign == 0
- && C::dtor == 0);
- }
- {
- C::Reset();
- o2 = o1;
- assert(C::copy_ctor == 0
- && C::copy_assign == 1
- && C::dtor == 0);
- }
- {
- C::Reset();
- Optional<C> empty;
- o1 = empty;
- assert(C::copy_ctor == 0
- && C::dtor == 1);
- assert(!o1.HasValue());
- }
- }
- void TestMoveAssignment() {
- {
- Optional<C> o1;
- C::Reset();
- C c;
- o1 = std::move(c);
- assert(C::def_ctor == 1
- && C::move_ctor == 1
- && C::dtor == 0);
- }
- {
- Optional<C> o1;
- Optional<C> o2{C{}};
- C::Reset();
- o1 = std::move(o2);
- assert(C::move_ctor == 1
- && C::move_assign == 0
- && C::dtor == 0);
- }
- {
- Optional<C> o1{C{}};
- Optional<C> o2{C{}};
- C::Reset();
- o2 = std::move(o1);
- assert(C::copy_ctor == 0
- && C::move_assign == 1
- && C::dtor == 0);
- }
- {
- Optional<C> o1{C{}};
- C::Reset();
- Optional<C> empty;
- o1 = std::move(empty);
- assert(C::copy_ctor == 0
- && C::move_ctor == 0
- && C::move_assign == 0
- && C::dtor == 1);
- assert(!o1.HasValue());
- }
- }
- void TestValueAccess() {
- using namespace std::literals;
- {
- Optional<std::string> o;
- o = "hello"s;
- assert(o.HasValue());
- assert(o.Value() == "hello"s);
- assert(&*o == &o.Value());
- assert(o->length() == 5);
- }
- {
- try {
- Optional<int> o;
- [[maybe_unused]] int v = o.Value();
- assert(false);
- } catch (const BadOptionalAccess& /*e*/) {
- } catch (...) {
- assert(false);
- }
- }
- }
- void TestReset() {
- C::Reset();
- {
- Optional<C> o{C()};
- assert(o.HasValue());
- o.Reset();
- assert(!o.HasValue());
- }
- }
- int main() {
- try {
- TestInitialization();
- TestAssignment();
- TestMoveAssignment();
- TestValueAccess();
- TestReset();
- } catch (...) {
- assert(false);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment