Advertisement
chevengur

СПРИНТ № 8 | Эффективные линейные контейнеры | Урок 12: Улучшаем собственный вектор

Jul 1st, 2024 (edited)
687
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 13.51 KB | None | 0 0
  1. simple_vector.h
  2.  
  3. #pragma once
  4.  
  5. #include <cassert>
  6. #include <initializer_list>
  7. #include <vector>
  8. #include <exception>
  9. #include <algorithm>
  10. #include <iostream>
  11. #include "array_ptr.h"
  12.  
  13. class ReserveProxyObj {
  14. public:
  15.     ReserveProxyObj(size_t capacity_to_reserve)
  16.         : capacity_(capacity_to_reserve) {}
  17.  
  18.     size_t GetCapacity() const {
  19.         return capacity_;
  20.     }
  21.  
  22. private:
  23.     size_t capacity_;
  24. };
  25.  
  26. ReserveProxyObj Reserve(size_t capacity_to_reserve) {
  27.     return ReserveProxyObj(capacity_to_reserve);
  28. };
  29.  
  30. template <typename Type>
  31. class SimpleVector {
  32. public:
  33.     using Iterator = Type*;
  34.     using ConstIterator = const Type*;
  35.  
  36.     SimpleVector() noexcept = default;
  37.  
  38.     // Создаёт вектор из size элементов, инициализированных значением по умолчанию
  39.     explicit SimpleVector(size_t size) : size_(size), capacity_(size), ptr_(size) {
  40.         std::fill(begin(), end(), 0);
  41.     }
  42.  
  43.     // Создаёт вектор из size элементов, инициализированных значением value
  44.     SimpleVector(size_t size, const Type& value) : size_(size), capacity_(size), ptr_(size) {
  45.         std::fill(begin(), end(), value);
  46.     }
  47.  
  48.     // Создаёт вектор из std::initializer_list
  49.     SimpleVector(std::initializer_list<Type> init) : size_(init.size()), capacity_(init.size()), ptr_(init.size())
  50.     {
  51.         size_t b = 0;
  52.         for (const auto& i : init)
  53.         {
  54.             ptr_[b] = i;
  55.             ++b;
  56.         }
  57.     }
  58.  
  59.     SimpleVector(const SimpleVector& other): size_(other.size_), capacity_(other.capacity_), ptr_(other.size_){
  60.         std::copy(other.begin(), other.end(), begin());
  61.     }
  62.  
  63.     SimpleVector(ReserveProxyObj new_capacity)
  64.     {
  65.         Reserve(new_capacity.GetCapacity());
  66.     }
  67.  
  68.     SimpleVector& operator=(const SimpleVector& rhs) {
  69.         SimpleVector copy{ rhs };
  70.         swap(copy);
  71.         return *this;
  72.     }
  73.  
  74.     void Reserve(size_t new_capacity)
  75.     {
  76.         if(new_capacity > capacity_)
  77.         {
  78.             auto new_vec = ArrayPtr<Type>(new_capacity);
  79.             for (size_t i = 0; i < capacity_; ++i)
  80.             {
  81.                 new_vec[i] = ptr_[i];
  82.             }
  83.             ptr_.swap(new_vec);
  84.             capacity_ = new_capacity;
  85.         }
  86.     }
  87.  
  88.     ~SimpleVector() {}
  89.  
  90.     // Возвращает количество элементов в массиве
  91.     size_t GetSize() const noexcept {
  92.         return size_;
  93.     }
  94.  
  95.     // Возвращает вместимость массива
  96.     size_t GetCapacity() const noexcept {
  97.         return capacity_;
  98.     }
  99.  
  100.     // Сообщает, пустой ли массив
  101.     bool IsEmpty() const noexcept {
  102.         return size_ == 0;
  103.     }
  104.  
  105.     // Возвращает ссылку на элемент с индексом index
  106.     Type& operator[](size_t index) noexcept {
  107.         return ptr_[index];
  108.     }
  109.  
  110.     // Возвращает константную ссылку на элемент с индексом index
  111.     const Type& operator[](size_t index) const noexcept {
  112.  
  113.         return ptr_[index];
  114.     }
  115.  
  116.     // Возвращает константную ссылку на элемент с индексом index
  117.     // Выбрасывает исключение std::out_of_range, если index >= size
  118.     Type& At(size_t index) {
  119.         if (index >= size_)
  120.             throw std::out_of_range("out of range");
  121.         return ptr_[index];
  122.     }
  123.  
  124.     // Возвращает константную ссылку на элемент с индексом index
  125.     // Выбрасывает исключение std::out_of_range, если index >= size
  126.     const Type& At(size_t index) const {
  127.         if (index > size_)
  128.             throw std::out_of_range("out of range");
  129.         return ptr_[index];
  130.     }
  131.  
  132.     // Обнуляет размер массива, не изменяя его вместимость
  133.     void Clear() noexcept {
  134.         size_ = 0;
  135.     }
  136.  
  137.     // Изменяет размер массива.
  138.     // При увеличении размера новые элементы получают значение по умолчанию для типа Type
  139.     void Resize(size_t new_size) {
  140.         if (new_size > capacity_) {
  141.             auto new_array = ArrayPtr<Type>(new_size);
  142.             for (size_t i = 0; i < size_; ++i) {
  143.                 new_array[i] = ptr_[i];
  144.             }
  145.             ptr_.swap(new_array);
  146.             capacity_ = new_size;
  147.         }
  148.         for (size_t i = size_; i < new_size; ++i) {
  149.             ptr_[i] = Type();
  150.         }
  151.         size_ = new_size;
  152.     }
  153.  
  154.     // Возвращает итератор на начало массива
  155.     // Для пустого массива может быть равен (или не равен) nullptr
  156.     Iterator begin() noexcept {
  157.         return ptr_.Get();
  158.         // Напишите тело самостоятельно
  159.     }
  160.  
  161.     // Возвращает итератор на элемент, следующий за последним
  162.     // Для пустого массива может быть равен (или не равен) nullptr
  163.     Iterator end() noexcept {
  164.         return ptr_.Get() + size_;
  165.     }
  166.  
  167.     // Возвращает константный итератор на начало массива
  168.     // Для пустого массива может быть равен (или не равен) nullptr
  169.     ConstIterator begin() const noexcept {
  170.         return ptr_.Get();
  171.     }
  172.  
  173.     // Возвращает итератор на элемент, следующий за последним
  174.     // Для пустого массива может быть равен (или не равен) nullptr
  175.     ConstIterator end() const noexcept {
  176.         return ptr_.Get() + size_;
  177.     }
  178.  
  179.     // Возвращает константный итератор на начало массива
  180.     // Для пустого массива может быть равен (или не равен) nullptr
  181.     ConstIterator cbegin() const noexcept {
  182.         return ptr_.Get();
  183.     }
  184.  
  185.     // Возвращает итератор на элемент, следующий за последним
  186.     // Для пустого массива может быть равен (или не равен) nullptr
  187.     ConstIterator cend() const noexcept {
  188.         return ptr_.Get() + size_;
  189.     }
  190.  
  191.     // Добавляет элемент в конец вектора
  192.     // При нехватке места увеличивает вдвое вместимость вектора
  193.     void PushBack(const Type& item) {
  194.        if(size_ == capacity_)
  195.        {
  196.             auto new_capacity = (capacity_ == 0) ? 1 : capacity_ * 2;
  197.             auto new_vector = ArrayPtr<Type>(new_capacity);
  198.             for (size_t i = 0; i < size_; ++i)
  199.             {
  200.                 new_vector[i] = ptr_[i];
  201.             }
  202.             ptr_.swap(new_vector);
  203.             capacity_ = new_capacity;
  204.        }
  205.        ptr_[size_] = item;
  206.        ++size_;
  207.     }
  208.  
  209.     // Вставляет значение value в позицию pos.
  210.     // Возвращает итератор на вставленное значение
  211.     // Если перед вставкой значения вектор был заполнен полностью,
  212.     // вместимость вектора должна увеличиться вдвое, а для вектора вместимостью 0 стать равной 1
  213.     Iterator Insert(ConstIterator pos, const Type& value) {
  214.         size_t index = pos - begin();
  215.         if(index > capacity_)
  216.         {
  217.             std::out_of_range("exit of out_of_range");
  218.         }
  219.         if(size_ == capacity_)
  220.         {
  221.             auto new_capacity = (capacity_ == 0) ? 1 : capacity_ * 2;
  222.             auto new_vector = ArrayPtr<Type>(new_capacity);
  223.             std::copy(begin(), begin()+index, new_vector.Get());
  224.             new_vector[index] = value;
  225.             std::copy(begin()+index, end(), new_vector.Get()+index+1);
  226.             ptr_.swap(new_vector);
  227.             capacity_ = new_capacity;
  228.         }
  229.         else
  230.         {
  231.             std::copy_backward(begin()+index, end(), end());
  232.             ptr_[index] = value;
  233.         }
  234.         ++size_;
  235.         return Iterator(ptr_.Get() + index);
  236.     }
  237.  
  238.     // "Удаляет" последний элемент вектора. Вектор не должен быть пустым
  239.     void PopBack() noexcept {
  240.         if(size_) --size_;
  241.     }
  242.  
  243.     // Удаляет элемент вектора в указанной позиции
  244.     Iterator Erase(ConstIterator pos) {
  245.         auto index = pos-begin();
  246.        
  247.         if(size_)
  248.         {
  249.             auto new_vector = ArrayPtr<Type>(capacity_);
  250.             std::copy(begin(), begin()+index, new_vector.Get());
  251.            
  252.             std::copy(begin() + index+1, end(), new_vector.Get()+index);
  253.             --size_;
  254.             ptr_.swap(new_vector);
  255.         }
  256.         return Iterator(begin() + index);
  257.     }
  258.  
  259.     // Обменивает значение с другим вектором
  260.     void swap(SimpleVector& other) noexcept {
  261.         std::swap(size_, other.size_);
  262.         std::swap(capacity_, other.capacity_);
  263.         ptr_.swap(other.ptr_);
  264.     }
  265. private:
  266.     size_t size_ = 0;
  267.     size_t capacity_ = 0;
  268.     ArrayPtr<Type> ptr_;
  269. };
  270.  
  271. template <typename Type>
  272. inline bool operator==(const SimpleVector<Type>& lhs, const SimpleVector<Type>& rhs) {
  273.     return std::equal(lhs.begin(), lhs.end(), rhs.begin());
  274. }
  275.  
  276. template <typename Type>
  277. inline bool operator!=(const SimpleVector<Type>& lhs, const SimpleVector<Type>& rhs) {
  278.     return !(rhs==lhs);
  279. }
  280.  
  281. template <typename Type>
  282. inline bool operator<(const SimpleVector<Type>& lhs, const SimpleVector<Type>& rhs) {
  283.     return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
  284.    
  285. }
  286.  
  287. template <typename Type>
  288. inline bool operator<=(const SimpleVector<Type>& lhs, const SimpleVector<Type>& rhs) {
  289.     // Заглушка. Напишите тело самостоятельно
  290.     return (lhs<rhs) || (lhs==rhs);
  291. }
  292.  
  293. template <typename Type>
  294. inline bool operator>(const SimpleVector<Type>& lhs, const SimpleVector<Type>& rhs) {
  295.     return std::lexicographical_compare(rhs.begin(), rhs.end(), lhs.begin(), lhs.end());
  296. }
  297.  
  298. template <typename Type>
  299. inline bool operator>=(const SimpleVector<Type>& lhs, const SimpleVector<Type>& rhs) {
  300.     // Заглушка. Напишите тело самостоятельно
  301.     return (lhs>rhs) || (lhs==rhs);
  302. }
  303.  
  304. =======================================================================================================================================
  305.  
  306. array_ptr.h
  307.  
  308. #include <cassert>
  309. #include <cstdlib>
  310.  
  311. template <typename Type>
  312. class ArrayPtr {
  313. public:
  314.     ArrayPtr() = default;
  315.  
  316.     explicit ArrayPtr(size_t size) {
  317.         (size == 0) ? raw_ptr_ = nullptr : raw_ptr_ = new Type[size];
  318.     }
  319.  
  320.     explicit ArrayPtr(Type* raw_ptr) noexcept {
  321.         if (raw_ptr) raw_ptr_ = raw_ptr;
  322.     }
  323.  
  324.     ArrayPtr(const ArrayPtr&) = delete;
  325.  
  326.     ~ArrayPtr() {
  327.         delete[] raw_ptr_;
  328.     }
  329.  
  330.     ArrayPtr& operator=(const ArrayPtr&) = delete;
  331.  
  332.     [[nodiscard]] Type* Release() noexcept {
  333.         Type* currentarr = raw_ptr_;
  334.         raw_ptr_ = nullptr;
  335.         return currentarr;
  336.     }
  337.  
  338.     Type& operator[](size_t index) noexcept {
  339.         return raw_ptr_[index];
  340.     }
  341.  
  342.     const Type& operator[](size_t index) const noexcept {
  343.         return raw_ptr_[index];
  344.     }
  345.  
  346.     explicit operator bool() const {
  347.         return (raw_ptr_) ? true : false;
  348.     }
  349.  
  350.     Type* Get() const noexcept {
  351.         return raw_ptr_;
  352.     }
  353.  
  354.     void swap(ArrayPtr& other) noexcept {
  355.         Type* temp = other.raw_ptr_;
  356.         other.raw_ptr_ = raw_ptr_;
  357.         raw_ptr_ = temp;
  358.     }
  359.  
  360. private:
  361.     Type* raw_ptr_ = nullptr;
  362. };
  363.  
  364. =======================================================================================================================================
  365.  
  366. main.cpp
  367.  
  368. // В качестве заготовки используйте решение задания из предыдущего урока.
  369. #include "simple_vector.h"
  370.  
  371. #include <cassert>
  372. #include <iostream>
  373.  
  374. using namespace std;
  375.  
  376. void TestReserveConstructor() {
  377.     cout << "TestReserveConstructor"s << endl;
  378.     SimpleVector<int> v(Reserve(5));
  379.     assert(v.GetCapacity() == 5);
  380.     assert(v.IsEmpty());
  381.     cout << "Done!"s << endl;
  382. }
  383.  
  384. void TestReserveMethod() {
  385.     cout << "TestReserveMethod"s << endl;
  386.     SimpleVector<int> v;
  387.     // зарезервируем 5 мест в векторе
  388.     v.Reserve(5);
  389.     assert(v.GetCapacity() == 5);
  390.     assert(v.IsEmpty());
  391.  
  392.     // попытаемся уменьшить capacity до 1
  393.     v.Reserve(1);
  394.     // capacity должно остаться прежним
  395.     assert(v.GetCapacity() == 5);
  396.     // поместим 10 элементов в вектор
  397.     for (int i = 0; i < 10; ++i) {
  398.         v.PushBack(i);
  399.     }
  400.     assert(v.GetSize() == 10);
  401.     // увеличим capacity до 100
  402.     v.Reserve(100);
  403.     // проверим, что размер не поменялся
  404.     assert(v.GetSize() == 10);
  405.     assert(v.GetCapacity() == 100);
  406.     // проверим, что элементы на месте
  407.     for (int i = 0; i < 10; ++i) {
  408.         assert(v[i] == i);
  409.     }
  410.     cout << "Done!"s << endl;
  411. }
  412.  
  413. int main() {
  414.     TestReserveConstructor();
  415.     TestReserveMethod();
  416. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement