shushus

Спринт 8. Move-семантика для вектора.

Mar 6th, 2023 (edited)
900
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 16.03 KB | None | 0 0
  1. -----------------------------------------------------------------------
  2. array_ptr.h
  3. -----------------------------------------------------------------------
  4. #pragma once
  5.  
  6. #include <stdexcept>
  7. #include <algorithm>
  8. #include <cassert>
  9. #include <cstdlib>
  10.  
  11. template <typename Type>
  12. class ArrayPtr {
  13. public:
  14.  
  15.     ArrayPtr() = default;
  16.  
  17.     explicit ArrayPtr(size_t size) {
  18.         if (size) {
  19.             simple_vector_ = new Type[size]();
  20.         } else {
  21.             simple_vector_= nullptr;
  22.         }
  23.     }
  24.  
  25.     ArrayPtr(const ArrayPtr&) = delete;
  26.    
  27.     ArrayPtr& operator=(const ArrayPtr&) = delete;
  28.    
  29.     ArrayPtr(ArrayPtr&& other) {
  30.         std::swap(simple_vector_, other.simple_vector_);
  31.         other.simple_vector_ = nullptr;
  32.     }
  33.    
  34.     ArrayPtr& operator=(ArrayPtr&& other) {
  35.         if (this != &other) {
  36.             std::swap(simple_vector_, other.simple_vector_);
  37.         }
  38.         return *this;
  39.     }
  40.  
  41.     ~ArrayPtr() {
  42.         if(simple_vector_){
  43.             delete[] simple_vector_;
  44.         }
  45.     }
  46.    
  47.     [[nodiscard]] Type* Release() noexcept {
  48.         Type* helper = simple_vector_;
  49.         simple_vector_= nullptr;
  50.         return helper;
  51.     }
  52.    
  53.     Type* Get() const noexcept {
  54.         return simple_vector_;
  55.     }
  56.  
  57.     Type& operator[](size_t index) noexcept {
  58.         return simple_vector_[index];
  59.     }
  60.  
  61.     const Type& operator[](size_t index) const noexcept {
  62.         return simple_vector_[index];
  63.     }
  64.  
  65.     explicit operator bool() const {
  66.         return simple_vector_;
  67.     }
  68.  
  69.     void swap(ArrayPtr& other) noexcept {
  70.         std::swap(simple_vector_, other.simple_vector_);
  71.     }
  72.  
  73. private:
  74.     Type* simple_vector_ = nullptr;
  75. };
  76. -----------------------------------------------------------------------
  77. simple_vector.h
  78. -----------------------------------------------------------------------
  79. #pragma once
  80.  
  81. #include <initializer_list>
  82. #include <algorithm>
  83. #include <stdexcept>
  84. #include <utility>
  85. #include <cassert>
  86. #include <iterator>
  87. #include "array_ptr.h"
  88.  
  89. class ReserveProxyObj {
  90. public:    
  91.     explicit ReserveProxyObj (size_t capacity_to_reserve) : capacity_(capacity_to_reserve) {}
  92.     size_t Reserve_capacity() {
  93.         return capacity_;
  94.     }  
  95. private:    
  96.     size_t capacity_;
  97. };
  98.  
  99. ReserveProxyObj Reserve(size_t capacity_to_reserve) {
  100.     return ReserveProxyObj(capacity_to_reserve);
  101. }
  102.  
  103. template <typename Type>
  104. class SimpleVector {
  105. public:
  106.     using Iterator = Type*;
  107.     using ConstIterator = const Type*;
  108.  
  109.     SimpleVector() noexcept = default;
  110.  
  111.     explicit SimpleVector(size_t size) : SimpleVector(size, std::move(Type{})) {}
  112.  
  113.     SimpleVector(size_t size, const Type& value) : simple_vector_(size), size_(size), capacity_(size) {
  114.         std::fill(begin(), end(), value);
  115.     }
  116.  
  117.     SimpleVector(std::initializer_list<Type> init) : simple_vector_(init.size()), size_(init.size()), capacity_(init.size()){
  118.         std::copy(std::make_move_iterator(init.begin()), std::make_move_iterator(init.end()), begin());
  119.     }
  120.    
  121.     SimpleVector(ReserveProxyObj capacity_to_reserve) {
  122.         Reserve(capacity_to_reserve.Reserve_capacity());
  123.     }
  124.  
  125.     size_t GetSize() const noexcept {
  126.         return size_;
  127.     }
  128.  
  129.     size_t GetCapacity() const noexcept {
  130.         return capacity_;
  131.     }
  132.  
  133.     bool IsEmpty() const noexcept {
  134.         return !size_;
  135.     }
  136.  
  137.     Type& operator[](size_t index) noexcept {
  138.         assert(index < size_);
  139.         return simple_vector_[index];
  140.     }
  141.  
  142.     const Type& operator[](size_t index) const noexcept {
  143.         assert(index < size_);
  144.         return simple_vector_[index];
  145.     }
  146.  
  147.     Type& At(size_t index) {
  148.         if (index < size_) {
  149.             return simple_vector_[index];
  150.         } else {
  151.             throw std::out_of_range("Non-existent vector element.");
  152.         }
  153.     }
  154.  
  155.     const Type& At(size_t index) const {
  156.         if (index < size_) {
  157.             return simple_vector_[index];
  158.         } else {
  159.             throw std::out_of_range("Non-existent vector element.");
  160.         }
  161.     }
  162.  
  163.     void Clear() noexcept {
  164.         size_ = 0;
  165.     }
  166.  
  167.     void Resize(size_t new_size) {
  168.         if (size_ >= new_size) {
  169.             size_ = new_size;
  170.             return;
  171.         } else if (size_< new_size && capacity_ > new_size) {
  172.             for (auto iter = begin() + new_size; iter != end(); --iter) {
  173.                 *iter = std::move(Type{});
  174.             }
  175.             size_ = new_size;
  176.             return;
  177.         } else {
  178.             ArrayPtr<Type> helper(new_size);
  179.             std::move(begin(), end(), &helper[0]);
  180.             simple_vector_.swap(helper);
  181.             size_ = new_size;
  182.             capacity_ = new_size*2;
  183.         }
  184.     }
  185.  
  186.     Iterator begin() noexcept {
  187.         return Iterator(&simple_vector_[0]);
  188.     }
  189.  
  190.     Iterator end() noexcept {
  191.         return Iterator(&simple_vector_[size_]);
  192.     }
  193.  
  194.     ConstIterator begin() const noexcept {
  195.         return cbegin();
  196.     }
  197.  
  198.     ConstIterator end() const noexcept {
  199.         return cend();
  200.     }
  201.  
  202.     ConstIterator cbegin() const noexcept {
  203.         return ConstIterator(&simple_vector_[0]);
  204.     }
  205.  
  206.     ConstIterator cend() const noexcept {
  207.         return ConstIterator(&simple_vector_[size_]);
  208.     }
  209.    
  210.     SimpleVector(const SimpleVector& other) {
  211.         ArrayPtr<Type> helper(other.size_);
  212.         size_ = other.size_;
  213.         capacity_= other.capacity_;
  214.         std::copy(other.begin(), other.end(), &helper[0]);
  215.         simple_vector_.swap(helper);
  216.     }
  217.    
  218.     SimpleVector(SimpleVector&& other) : simple_vector_(other.size_) {
  219.         size_ = std::move(other.size_);
  220.         capacity_ = std::move(other.capacity_);
  221.         simple_vector_.swap(other.simple_vector_);
  222.         other.Clear();
  223.     }
  224.  
  225.     SimpleVector& operator=(const SimpleVector& rhs) {
  226.         if (this != &rhs) {
  227.             SimpleVector helper(rhs);
  228.             swap(helper);
  229.         }
  230.         return *this;
  231.     }
  232.    
  233.     void PushBack(const Type& item) {
  234.         if (capacity_ > size_) {
  235.             simple_vector_[size_++] = item;
  236.             return;
  237.         }
  238.         if (capacity_) {
  239.             ArrayPtr<Type> helper(capacity_*=2);
  240.             std::copy(begin(), end(), &helper[0]);
  241.             simple_vector_.swap(helper);
  242.             simple_vector_[size_++] = item;
  243.         } else {
  244.             ArrayPtr<Type> helper(++capacity_);
  245.             std::copy(begin(), end(), &helper[0]);
  246.             simple_vector_.swap(helper);
  247.             simple_vector_[size_++] = item;
  248.             return;
  249.         }
  250.     }
  251.  
  252.     void PushBack(Type&& item) {
  253.         if (capacity_ > size_) {
  254.             simple_vector_[size_++] = std::move(item);
  255.             return;
  256.         }
  257.         if (capacity_) {
  258.             ArrayPtr<Type> helper(capacity_*=2);
  259.             std::move(begin(), end(), &helper[0]);
  260.             simple_vector_.swap(helper);
  261.             simple_vector_[size_++] = std::move(item);
  262.         } else {
  263.             ArrayPtr<Type> helper(++capacity_);
  264.             std::move(begin(), end(), &helper[0]);
  265.             simple_vector_.swap(helper);
  266.             simple_vector_[size_++] = std::move(item);
  267.             return;
  268.         }
  269.     }
  270.  
  271.     Iterator Insert(ConstIterator pos, const Type& value) {
  272.         if (begin() <= pos && end() >= pos) {
  273.             auto index = std::distance(cbegin(), pos);
  274.             if (size_== capacity_) {
  275.                 if(size_) {
  276.                     ArrayPtr<Type> helper(size_*=2);
  277.                     std::copy(begin(), end(), &helper[0]);
  278.                     simple_vector_.swap(helper);
  279.                     size_ = size_;
  280.                     capacity_ = size_*2;
  281.                 } else {
  282.                     ArrayPtr<Type> helper(++capacity_);
  283.                     std::copy(begin(), end(), &helper[0]);
  284.                     simple_vector_.swap(helper);
  285.                     capacity_ =1;
  286.                 }
  287.             }
  288.             for (size_t i = size_; i > (size_t)index; --i) {
  289.                 simple_vector_[i] = simple_vector_[i-1];
  290.             }
  291.             ++size_;
  292.             simple_vector_[index] = value;
  293.             return const_cast<Iterator>(index +begin());
  294.         } else {
  295.             throw std::out_of_range("Non-existent vector pos.");
  296.         }
  297.     }
  298.    
  299.     Iterator Insert(ConstIterator pos, Type&& value) {
  300.         if (begin() <= pos && end() >= pos) {
  301.             if (!capacity_) {
  302.                 ArrayPtr<Type> helper(++capacity_);
  303.                 std::move(begin(), end(), &helper[0]);
  304.                 simple_vector_.swap(helper);
  305.                 simple_vector_[size_++] = std::move(value);
  306.                 return begin();
  307.             } else if (capacity_ < size_ || capacity_ == size_) {
  308.                 auto index = std::distance(begin(), const_cast<Iterator>(pos));
  309.                 ArrayPtr<Type> helper(capacity_*=2);
  310.                 std::move(begin(), end(), &helper[0]);
  311.                 std::copy_backward(std::make_move_iterator(const_cast<Iterator>(pos)), std::make_move_iterator(begin()+size_), (&helper[1 + size_]));
  312.                 helper[index] = std::move(value);
  313.                 ++size_;
  314.                 simple_vector_.swap(helper);
  315.                 return Iterator(&simple_vector_[index]);
  316.             } else {
  317.                 std::copy_backward(std::make_move_iterator(const_cast<Iterator>(pos)), std::make_move_iterator(end()), (&simple_vector_[++size_+1]));
  318.                 *const_cast<Iterator>(pos) = std::move(value);
  319.                 return const_cast<Iterator>(pos);
  320.             }
  321.         } else {
  322.             throw std::out_of_range("Non-existent vector pos.");
  323.         }
  324.     }
  325.    
  326.     void PopBack() noexcept {
  327.         if (size_) {
  328.             --size_;
  329.         }
  330.     }
  331.  
  332.     Iterator Erase(ConstIterator pos) {
  333.         if (begin() <= pos && end() >= pos) {
  334.             auto index = std::distance(cbegin(), pos);
  335.             std::move(&simple_vector_[index + 1], end(), const_cast<Iterator>(pos));
  336.             --size_;
  337.             return const_cast<Iterator>(pos);
  338.         } else {
  339.             throw std::out_of_range("Non-existent vector pos.");
  340.         }
  341.     }
  342.  
  343.     void swap(SimpleVector& other) noexcept {
  344.         simple_vector_.swap(other.simple_vector_);
  345.         std::swap(size_, other.size_);
  346.         std::swap(capacity_, other.capacity_);
  347.     }
  348.    
  349.     void Reserve(size_t new_capacity){
  350.         if (new_capacity > capacity_) {
  351.             ArrayPtr<Type> helper(new_capacity);
  352.             std::copy(begin(), end(), &helper[0]);
  353.             simple_vector_.swap(helper);
  354.             capacity_ = new_capacity;
  355.         } else {
  356.             return;
  357.         }
  358.     }
  359.    
  360. private:
  361.     ArrayPtr<Type> simple_vector_;
  362.     size_t size_ = 0;
  363.     size_t capacity_ = 0;
  364. };
  365.  
  366. template <typename Type>
  367. inline bool operator==(const SimpleVector<Type>& lhs, const SimpleVector<Type>& rhs) {
  368.     return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
  369. }
  370.  
  371. template <typename Type>
  372. inline bool operator!=(const SimpleVector<Type>& lhs, const SimpleVector<Type>& rhs) {
  373.     return !(lhs == rhs);
  374. }
  375.  
  376. template <typename Type>
  377. inline bool operator<(const SimpleVector<Type>& lhs, const SimpleVector<Type>& rhs) {
  378.     return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
  379. }
  380.  
  381. template <typename Type>
  382. inline bool operator<=(const SimpleVector<Type>& lhs, const SimpleVector<Type>& rhs) {
  383.     return lhs < rhs || lhs == rhs;
  384. }
  385.  
  386. template <typename Type>
  387. inline bool operator>(const SimpleVector<Type>& lhs, const SimpleVector<Type>& rhs) {
  388.     return rhs < lhs;
  389. }
  390.  
  391. template <typename Type>
  392. inline bool operator>=(const SimpleVector<Type>& lhs, const SimpleVector<Type>& rhs) {
  393.     return !(lhs < rhs);
  394. }
  395. -----------------------------------------------------------------------
  396. main.cpp
  397. -----------------------------------------------------------------------
  398. #include "simple_vector.h"
  399.  
  400. #include <cassert>
  401. #include <iostream>
  402. #include <numeric>
  403.  
  404. using namespace std;
  405.  
  406. class X {
  407. public:
  408.     X()
  409.         : X(5) {
  410.     }
  411.     X(size_t num)
  412.         : x_(num) {
  413.     }
  414.     X(const X& other) = delete;
  415.     X& operator=(const X& other) = delete;
  416.     X(X&& other) {
  417.         x_ = exchange(other.x_, 0);
  418.     }
  419.     X& operator=(X&& other) {
  420.         x_ = exchange(other.x_, 0);
  421.         return *this;
  422.     }
  423.     size_t GetX() const {
  424.         return x_;
  425.     }
  426.  
  427. private:
  428.     size_t x_;
  429. };
  430.  
  431. SimpleVector<int> GenerateVector(size_t size) {
  432.     SimpleVector<int> v(size);
  433.     iota(v.begin(), v.end(), 1);
  434.     return v;
  435. }
  436.  
  437. void TestTemporaryObjConstructor() {
  438.     const size_t size = 1000000;
  439.     cout << "Test with temporary object, copy elision" << endl;
  440.     SimpleVector<int> moved_vector(GenerateVector(size));
  441.     assert(moved_vector.GetSize() == size);
  442.     cout << "Done!" << endl << endl;
  443. }
  444.  
  445. void TestTemporaryObjOperator() {
  446.     const size_t size = 1000000;
  447.     cout << "Test with temporary object, operator=" << endl;
  448.     SimpleVector<int> moved_vector;
  449.     assert(moved_vector.GetSize() == 0);
  450.     moved_vector = GenerateVector(size);
  451.     assert(moved_vector.GetSize() == size);
  452.     cout << "Done!" << endl << endl;
  453. }
  454.  
  455. void TestNamedMoveConstructor() {
  456.     const size_t size = 1000000;
  457.     cout << "Test with named object, move constructor" << endl;
  458.     SimpleVector<int> vector_to_move(GenerateVector(size));
  459.     assert(vector_to_move.GetSize() == size);
  460.  
  461.     SimpleVector<int> moved_vector(move(vector_to_move));
  462.     assert(moved_vector.GetSize() == size);
  463.     assert(vector_to_move.GetSize() == 0);
  464.     cout << "Done!" << endl << endl;
  465. }
  466.  
  467. void TestNamedMoveOperator() {
  468.     const size_t size = 1000000;
  469.     cout << "Test with named object, operator=" << endl;
  470.     SimpleVector<int> vector_to_move(GenerateVector(size));
  471.     assert(vector_to_move.GetSize() == size);
  472.  
  473.     SimpleVector<int> moved_vector = move(vector_to_move);
  474.     assert(moved_vector.GetSize() == size);
  475.     assert(vector_to_move.GetSize() == 0);
  476.     cout << "Done!" << endl << endl;
  477. }
  478.  
  479. void TestNoncopiableMoveConstructor() {
  480.     const size_t size = 5;
  481.     cout << "Test noncopiable object, move constructor" << endl;
  482.     SimpleVector<X> vector_to_move;
  483.     for (size_t i = 0; i < size; ++i) {
  484.         vector_to_move.PushBack(X(i));
  485.     }
  486.  
  487.     SimpleVector<X> moved_vector = move(vector_to_move);
  488.     assert(moved_vector.GetSize() == size);
  489.     assert(vector_to_move.GetSize() == 0);
  490.  
  491.     for (size_t i = 0; i < size; ++i) {
  492.         assert(moved_vector[i].GetX() == i);
  493.     }
  494.     cout << "Done!" << endl << endl;
  495. }
  496.  
  497. void TestNoncopiablePushBack() {
  498.     const size_t size = 5;
  499.     cout << "Test noncopiable push back" << endl;
  500.     SimpleVector<X> v;
  501.     for (size_t i = 0; i < size; ++i) {
  502.         v.PushBack(X(i));
  503.     }
  504.  
  505.     assert(v.GetSize() == size);
  506.  
  507.     for (size_t i = 0; i < size; ++i) {
  508.         assert(v[i].GetX() == i);
  509.     }
  510.     cout << "Done!" << endl << endl;
  511. }
  512.  
  513. void TestNoncopiableInsert() {
  514.     const size_t size = 5;
  515.     cout << "Test noncopiable insert" << endl;
  516.     SimpleVector<X> v;
  517.     for (size_t i = 0; i < size; ++i) {
  518.         v.PushBack(X(i));
  519.     }
  520.  
  521.     v.Insert(v.begin(), X(size + 1));
  522.     assert(v.GetSize() == size + 1);
  523.     assert(v.begin()->GetX() == size + 1);
  524.  
  525.     v.Insert(v.end(), X(size + 2));
  526.     assert(v.GetSize() == size + 2);
  527.     assert((v.end() - 1)->GetX() == size + 2);
  528.  
  529.     v.Insert(v.begin() + 3, X(size + 3));
  530.     assert(v.GetSize() == size + 3);
  531.     assert((v.begin() + 3)->GetX() == size + 3);
  532.     cout << "Done!" << endl << endl;
  533. }
  534.  
  535. void TestNoncopiableErase() {
  536.     const size_t size = 3;
  537.     cout << "Test noncopiable erase" << endl;
  538.     SimpleVector<X> v;
  539.     for (size_t i = 0; i < size; ++i) {
  540.         v.PushBack(X(i));
  541.     }
  542.  
  543.     auto it = v.Erase(v.begin());
  544.     assert(it->GetX() == 1);
  545.     cout << "Done!" << endl << endl;
  546. }
  547.  
  548. int main() {
  549.     TestTemporaryObjConstructor();
  550.     TestTemporaryObjOperator();
  551.     TestNamedMoveConstructor();
  552.     TestNamedMoveOperator();
  553.     TestNoncopiableMoveConstructor();
  554.     TestNoncopiablePushBack();
  555.     TestNoncopiableInsert();
  556.     TestNoncopiableErase();
  557.     return 0;
  558. }
Advertisement
Add Comment
Please, Sign In to add comment