shushus

Спринт 14. Variadic Templates. Задание 3.

May 5th, 2023
383
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.91 KB | None | 0 0
  1. -----------------------------------------------------------------------
  2. optional.h
  3. -----------------------------------------------------------------------
  4. #include <stdexcept>
  5. #include <utility>
  6.  
  7. class BadOptionalAccess : public std::exception {
  8. public:
  9.     using exception::exception;
  10.  
  11.     virtual const char* what() const noexcept override {
  12.         return "Bad optional access";
  13.     }
  14. };
  15.  
  16. template <typename T>
  17. class Optional {
  18. public:
  19.    
  20.     Optional() = default;
  21.    
  22.     Optional(const T& item) {
  23.         buff_ = new (&data_[0]) T(item);
  24.        
  25.         is_initialized_ = true;
  26.     }
  27.        
  28.     Optional(T&& item) {
  29.         buff_ = new (&data_[0]) T(std::forward<T>(item));
  30.        
  31.         is_initialized_ = true;
  32.     }
  33.    
  34.     Optional(const Optional& other) {
  35.  
  36.         (!other.HasValue() && HasValue()) ? Reset() :
  37.         (other.HasValue() && !this->HasValue()) ? (void)(buff_ = new (&data_[0]) T(other.Value()), is_initialized_ = true) :
  38.         (other.HasValue() && HasValue()) ? (void)(*buff_ = other.Value(), is_initialized_ = true) : void();
  39.  
  40.     }
  41.    
  42.     Optional(Optional&& other) noexcept {
  43.        
  44.         (!other.HasValue() && this->HasValue()) ? Reset() :
  45.         (other.HasValue() && !HasValue()) ? (void)(buff_ = new (&data_[0]) T(std::forward<T>(other.Value())), is_initialized_ = true) :
  46.         (other.HasValue() && HasValue()) ? (void)(*buff_ = std::forward<T>(other.Value()), is_initialized_ = true) : void();
  47.        
  48.     }
  49.    
  50.     ~Optional() {
  51.         is_initialized_ ? buff_->~T() : void();
  52.     }
  53.    
  54.     bool HasValue() const {return is_initialized_;}  
  55.     T& Value() {if (!is_initialized_) {throw BadOptionalAccess();} else {return *buff_;}}
  56.     const T& Value() const {if (!is_initialized_) {throw BadOptionalAccess();} else {return *buff_;}}
  57.  
  58.     void Reset() {is_initialized_ ? (is_initialized_ = false, buff_->~T()) : void();}
  59.    
  60.     template <typename ... Args>
  61.     void Emplace(Args&& ...args);
  62.  
  63.     Optional& operator=(const T& item) {
  64.        
  65.         HasValue() ? (void)(*buff_ = item ) : (void)(buff_ = new (&data_[0]) T(item), is_initialized_ = true);
  66.  
  67.         return *this;
  68.     }
  69.                                            
  70.     Optional& operator=(T&& item) {
  71.        
  72.         HasValue() ? (void)(*buff_ = std::forward<T>(item))
  73.         : (void)(buff_ = new (&data_[0]) T(std::forward<T>(item)), is_initialized_ = true);
  74.  
  75.         return *this;
  76.     }
  77.                                            
  78.     Optional& operator=(const Optional& other) {
  79.        
  80.         (!other.HasValue() && HasValue()) ? Reset() :
  81.         (other.HasValue() && !HasValue()) ? (void)(buff_ = new (&data_[0]) T(other.Value()), is_initialized_ = true) :
  82.         (other.HasValue() && HasValue()) ? (void)(*buff_ = other.Value(), is_initialized_ = true) : void();
  83.        
  84.         return *this;
  85.     }
  86.    
  87.     Optional& operator=(Optional&& other) noexcept {
  88.        
  89.         (!other.HasValue() && HasValue()) ? Reset() :
  90.         (other.HasValue() && !HasValue()) ? (void)(buff_ = new (&data_[0]) T(std::forward<T>(other.Value())), is_initialized_ = true) :
  91.         (other.HasValue() && HasValue()) ? (void)(*buff_ = std::forward<T>(other.Value()), is_initialized_ = true) : void();
  92.  
  93.         return *this;
  94.     }
  95.  
  96.     T& operator*() {return Value();}
  97.     const T& operator*() const {return Value();}
  98.     T* operator->() {return &Value();}
  99.     const T* operator->() const {return &Value();}
  100.  
  101. private:
  102.     T* buff_ = nullptr;
  103.    
  104.     alignas(T) char data_[sizeof(T)]{};
  105.     bool is_initialized_ = false;
  106. };
  107.  
  108. template <typename T>
  109. template <typename ... Args>
  110. void Optional<T>::Emplace(Args&& ...args) {
  111.  
  112.     if (is_initialized_) {buff_->~T();}
  113.  
  114.     buff_ = new (&data_[0]) T(std::forward<Args>(args)...);
  115.     is_initialized_ = true;
  116. }
  117. -----------------------------------------------------------------------
  118. main.cpp
  119. -----------------------------------------------------------------------
  120. #include "optional.h"
  121.  
  122. #include <cassert>
  123. #include <memory>
  124.  
  125. struct C {
  126.     C() noexcept {++def_ctor;}
  127.     C(const C& /*other*/) noexcept {++copy_ctor; }
  128.     C(C&& /*other*/) noexcept {++move_ctor;}
  129.    
  130.     C& operator=(const C& other) noexcept {
  131.         if (this != &other) {
  132.             ++copy_assign;
  133.         }
  134.        
  135.         return *this;
  136.     }
  137.    
  138.     C& operator=(C&& /*other*/) noexcept {
  139.         ++move_assign;
  140.         return *this;
  141.     }
  142.    
  143.     ~C() {
  144.         ++dtor;
  145.     }
  146.  
  147.     static size_t InstanceCount() {
  148.         return def_ctor + copy_ctor + move_ctor - dtor;
  149.     }
  150.  
  151.     static void Reset() {
  152.         def_ctor = 0;
  153.         copy_ctor = 0;
  154.         move_ctor = 0;
  155.         copy_assign = 0;
  156.         move_assign = 0;
  157.         dtor = 0;
  158.     }
  159.  
  160.     inline static size_t def_ctor = 0;
  161.     inline static size_t copy_ctor = 0;
  162.     inline static size_t move_ctor = 0;
  163.     inline static size_t copy_assign = 0;
  164.     inline static size_t move_assign = 0;
  165.     inline static size_t dtor = 0;
  166. };
  167.  
  168. void TestInitialization() {
  169.     C::Reset();
  170.     {
  171.         Optional<C> o;
  172.         assert(!o.HasValue());
  173.         assert(C::InstanceCount() == 0);
  174.     }
  175.     assert(C::InstanceCount() == 0);
  176.  
  177.     C::Reset();
  178.     {
  179.         C c;
  180.         Optional<C> o(c);
  181.         assert(o.HasValue());
  182.         assert(C::def_ctor == 1
  183.                && C::copy_ctor == 1);
  184.        
  185.         assert(C::InstanceCount() == 2);
  186.     }
  187.     assert(C::InstanceCount() == 0);
  188.  
  189.     C::Reset();
  190.     {
  191.         C c;
  192.         Optional<C> o(std::move(c));
  193.         assert(o.HasValue());
  194.        
  195.         assert(C::def_ctor == 1
  196.                && C::move_ctor == 1
  197.                && C::copy_ctor == 0
  198.                && C::copy_assign == 0
  199.                && C::move_assign == 0);
  200.        
  201.         assert(C::InstanceCount() == 2);
  202.     }
  203.     assert(C::InstanceCount() == 0);
  204.  
  205.     C::Reset();
  206.     {
  207.         C c;
  208.         Optional<C> o1(c);
  209.         const Optional<C> o2(o1);
  210.         assert(o1.HasValue());
  211.         assert(o2.HasValue());
  212.        
  213.         assert(C::def_ctor == 1
  214.                && C::move_ctor == 0
  215.                && C::copy_ctor == 2
  216.                && C::copy_assign == 0
  217.                && C::move_assign == 0);
  218.        
  219.         assert(C::InstanceCount() == 3);
  220.     }
  221.     assert(C::InstanceCount() == 0);
  222.  
  223.     C::Reset();
  224.     {
  225.         C c;
  226.         Optional<C> o1(c);
  227.         const Optional<C> o2(std::move(o1));
  228.         assert(C::def_ctor == 1
  229.                && C::copy_ctor == 1
  230.                && C::move_ctor == 1
  231.                && C::copy_assign == 0
  232.                && C::move_assign == 0);
  233.        
  234.         assert(C::InstanceCount() == 3);
  235.     }
  236.     assert(C::InstanceCount() == 0);
  237. }
  238.  
  239. void TestAssignment() {
  240.     Optional<C> o1;
  241.     Optional<C> o2;
  242.    
  243.     {
  244.         C::Reset();
  245.         C c;
  246.         o1 = c;
  247.         assert(C::def_ctor == 1
  248.                && C::copy_ctor == 1
  249.                && C::dtor == 0);
  250.     }
  251.    
  252.     {
  253.         C::Reset();
  254.         o2 = o1;
  255.         assert(C::copy_ctor == 1
  256.                && C::copy_assign == 0
  257.                && C::dtor == 0);
  258.     }
  259.    
  260.     {
  261.         C::Reset();
  262.         o2 = o1;
  263.         assert(C::copy_ctor == 0
  264.                && C::copy_assign == 1
  265.                && C::dtor == 0);
  266.     }
  267.    
  268.     {
  269.         C::Reset();
  270.         Optional<C> empty;
  271.         o1 = empty;
  272.         assert(C::copy_ctor == 0
  273.                && C::dtor == 1);
  274.        
  275.         assert(!o1.HasValue());
  276.     }
  277. }
  278.  
  279. void TestMoveAssignment() {
  280.     {
  281.         Optional<C> o1;
  282.         C::Reset();
  283.         C c;
  284.         o1 = std::move(c);
  285.         assert(C::def_ctor == 1
  286.                && C::move_ctor == 1
  287.                && C::dtor == 0);
  288.     }
  289.    
  290.     {
  291.         Optional<C> o1;
  292.         Optional<C> o2{C{}};
  293.         C::Reset();
  294.         o1 = std::move(o2);
  295.         assert(C::move_ctor == 1
  296.                && C::move_assign == 0
  297.                && C::dtor == 0);
  298.     }
  299.    
  300.     {
  301.         Optional<C> o1{C{}};
  302.         Optional<C> o2{C{}};
  303.         C::Reset();
  304.         o2 = std::move(o1);
  305.         assert(C::copy_ctor == 0
  306.                && C::move_assign == 1
  307.                && C::dtor == 0);
  308.     }
  309.    
  310.     {
  311.         Optional<C> o1{C{}};
  312.         C::Reset();
  313.         Optional<C> empty;
  314.         o1 = std::move(empty);
  315.         assert(C::copy_ctor == 0
  316.                && C::move_ctor == 0
  317.                && C::move_assign == 0
  318.                && C::dtor == 1);
  319.        
  320.         assert(!o1.HasValue());
  321.     }
  322. }
  323.  
  324. void TestValueAccess() {
  325.     using namespace std::literals;
  326.    
  327.     {
  328.         Optional<std::string> o;
  329.         o = "hello"s;
  330.         assert(o.HasValue());
  331.         assert(o.Value() == "hello"s);
  332.         assert(&*o == &o.Value());
  333.         assert(o->length() == 5);
  334.     }
  335.    
  336.     {
  337.         try {
  338.             Optional<int> o;
  339.             [[maybe_unused]] int v = o.Value();
  340.             assert(false);
  341.            
  342.         } catch (const BadOptionalAccess& /*e*/) {
  343.            
  344.         } catch (...) {
  345.             assert(false);
  346.         }
  347.     }
  348.    
  349. }
  350.  
  351. void TestReset() {
  352.     C::Reset();
  353.     {
  354.         Optional<C> o{C()};
  355.         assert(o.HasValue());
  356.         o.Reset();
  357.         assert(!o.HasValue());
  358.     }
  359. }
  360.  
  361. void TestEmplace() {
  362.     struct S {
  363.        
  364.         S(int i, std::unique_ptr<int>&& p) : i(i)
  365.                                            , p(std::move(p)) {}
  366.         int i;
  367.         std::unique_ptr<int> p;
  368.     };
  369.  
  370.     Optional<S> o;
  371.     o.Emplace(1, std::make_unique<int>(2));
  372.    
  373.     assert(o.HasValue());
  374.     assert(o->i == 1);
  375.     assert(*(o->p) == 2);
  376.  
  377.     o.Emplace(3, std::make_unique<int>(4));
  378.    
  379.     assert(o.HasValue());
  380.     assert(o->i == 3);
  381.     assert(*(o->p) == 4);
  382. }
  383.  
  384. int main() {
  385.     try {
  386.         TestInitialization();
  387.         TestAssignment();
  388.         TestMoveAssignment();
  389.         TestValueAccess();
  390.         TestReset();
  391.         TestEmplace();
  392.     } catch (...) {
  393.         assert(false);
  394.     }
  395. }
Advertisement
Add Comment
Please, Sign In to add comment