kutuzzzov

Урок 6 вставки и удаление в произвольной позиции

Dec 14th, 2022
712
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 38.41 KB | None | 0 0
  1. #include <cassert>
  2. #include <cstddef>
  3. #include <iterator>
  4. #include <string>
  5. #include <utility>
  6. #include <algorithm>
  7.  
  8. template <typename Type>
  9. class SingleLinkedList {
  10.     // Узел списка
  11.     struct Node {
  12.         Node() = default;
  13.         Node(const Type& val, Node* next)
  14.             : value(val)
  15.             , next_node(next) {
  16.         }
  17.         Type value{};
  18.         Node* next_node = nullptr;
  19.     };
  20.  
  21.     // Шаблон класса Базовый Итератор.
  22.     // Определяет поведение итератора на элементы односвязного списка
  23.     // ValueType - совпадает с Type (для Iterator) либо с const Type (для ConstIterator)
  24.     template <typename ValueType>
  25.     class BasicIterator {
  26.         // Класс списка объявляется дружественным, чтобы из методов списка
  27.         // был доступ к приватной области итератора
  28.         friend class SingleLinkedList;
  29.  
  30.         // Конвертирующий конструктор итератора из указателя на узел списка
  31.         explicit BasicIterator(Node* node) {
  32.             node_ = node;
  33.         }
  34.  
  35.     public:
  36.         // Объявленные ниже типы сообщают стандартной библиотеке о свойствах этого итератора
  37.  
  38.         // Категория итератора - forward iterator
  39.         // (итератор, который поддерживает операции инкремента и многократное разыменование)
  40.         using iterator_category = std::forward_iterator_tag;
  41.         // Тип элементов, по которым перемещается итератор
  42.         using value_type = Type;
  43.         // Тип, используемый для хранения смещения между итераторами
  44.         using difference_type = std::ptrdiff_t;
  45.         // Тип указателя на итерируемое значение
  46.         using pointer = ValueType*;
  47.         // Тип ссылки на итерируемое значение
  48.         using reference = ValueType&;
  49.  
  50.         BasicIterator() = default;
  51.  
  52.         // Конвертирующий конструктор/конструктор копирования
  53.         // При ValueType, совпадающем с Type, играет роль копирующего конструктора
  54.         // При ValueType, совпадающем с const Type, играет роль конвертирующего конструктора
  55.         BasicIterator(const BasicIterator<Type>& other) noexcept {
  56.             node_ = other.node_;
  57.         }
  58.  
  59.         // Чтобы компилятор не выдавал предупреждение об отсутствии оператора = при наличии
  60.         // пользовательского конструктора копирования, явно объявим оператор = и
  61.         // попросим компилятор сгенерировать его за нас.
  62.         BasicIterator& operator=(const BasicIterator& rhs) = default;
  63.  
  64.         // Оператор сравнения итераторов (в роли второго аргумента выступает константный итератор)
  65.         // Два итератора равны, если они ссылаются на один и тот же элемент списка, либо на end()
  66.         [[nodiscard]] bool operator==(const BasicIterator<const Type>& rhs) const noexcept {
  67.             return this->node_ == rhs.node_;
  68.         }
  69.  
  70.         // Оператор проверки итераторов на неравенство
  71.         // Противоположен !=
  72.         [[nodiscard]] bool operator!=(const BasicIterator<const Type>& rhs) const noexcept {
  73.             return this->node_ != rhs.node_;
  74.         }
  75.  
  76.         // Оператор сравнения итераторов (в роли второго аргумента итератор)
  77.         // Два итератора равны, если они ссылаются на один и тот же элемент списка, либо на end()
  78.         [[nodiscard]] bool operator==(const BasicIterator<Type>& rhs) const noexcept {
  79.             return this->node_ == rhs.node_;
  80.         }
  81.  
  82.         // Оператор проверки итераторов на неравенство
  83.         // Противоположен !=
  84.         [[nodiscard]] bool operator!=(const BasicIterator<Type>& rhs) const noexcept {
  85.             return this->node_ != rhs.node_;
  86.         }
  87.  
  88.         // Оператор прединкремента. После его вызова итератор указывает на следующий элемент списка
  89.         // Возвращает ссылку на самого себя
  90.         // Инкремент итератора, не указывающего на существующий элемент списка, приводит к неопределённому поведению
  91.         BasicIterator& operator++() noexcept {
  92.             assert(node_ != nullptr);
  93.             node_ = node_->next_node;
  94.             return *this;
  95.         }
  96.        
  97.         // Оператор постинкремента. После его вызова итератор указывает на следующий элемент списка.
  98.         // Возвращает прежнее значение итератора
  99.         // Инкремент итератора, не указывающего на существующий элемент списка,
  100.         // приводит к неопределённому поведению
  101.         BasicIterator operator++(int) noexcept {
  102.             assert(node_ != nullptr);
  103.             auto old_value(*this);
  104.             node_ = node_->next_node;
  105.             return old_value;
  106.         }
  107.  
  108.         // Операция разыменования. Возвращает ссылку на текущий элемент
  109.         // Вызов этого оператора у итератора, не указывающего на существующий элемент списка,
  110.         // приводит к неопределённому поведению
  111.         [[nodiscard]] reference operator*() const noexcept {
  112.             assert(node_ != nullptr);
  113.             return node_->value;
  114.         }
  115.  
  116.         // Операция доступа к члену класса. Возвращает указатель на текущий элемент списка.
  117.         // Вызов этого оператора у итератора, не указывающего на существующий элемент списка,
  118.         // приводит к неопределённому поведению
  119.         [[nodiscard]] pointer operator->() const noexcept {
  120.             assert(node_ != nullptr);
  121.             return &node_->value;
  122.         }
  123.  
  124.     private:
  125.         Node* node_ = nullptr;
  126.     };
  127.  
  128. public:
  129.     SingleLinkedList() {
  130.     }
  131.  
  132.     // Возвращает количество элементов в списке за время O(1)
  133.     [[nodiscard]] size_t GetSize() const noexcept {
  134.         return size_;
  135.     }
  136.  
  137.     // Сообщает, пустой ли список за время O(1)
  138.     [[nodiscard]] bool IsEmpty() const noexcept {
  139.         return !(size_ != 0);
  140.     }
  141.  
  142.     // Вставляет элемент value в начало списка за время O(1)
  143.     void PushFront(const Type& value) {
  144.         head_.next_node = new Node(value, head_.next_node);
  145.         ++size_;
  146.     }
  147.  
  148.     // Очищает список за время O(N)
  149.     void Clear() noexcept {
  150.         while (head_.next_node != nullptr) {
  151.             Node* new_head = head_.next_node->next_node;
  152.             delete head_.next_node;
  153.             head_.next_node = new_head;
  154.         }
  155.         size_ = 0;
  156.     }
  157.  
  158.     ~SingleLinkedList() {
  159.         Clear();
  160.     }
  161.  
  162.     using value_type = Type;
  163.     using reference = value_type&;
  164.     using const_reference = const value_type&;
  165.  
  166.     // Итератор, допускающий изменение элементов списка
  167.     using Iterator = BasicIterator<Type>;
  168.     // Константный итератор, предоставляющий доступ для чтения к элементам списка
  169.     using ConstIterator = BasicIterator<const Type>;
  170.  
  171.     // Возвращает итератор, ссылающийся на первый элемент
  172.     // Если список пустой, возвращённый итератор будет равен end()
  173.     [[nodiscard]] Iterator begin() noexcept {
  174.         return Iterator{ head_.next_node };
  175.     }
  176.  
  177.     // Возвращает итератор, указывающий на позицию, следующую за последним элементом односвязного списка
  178.     // Разыменовывать этот итератор нельзя - попытка разыменования приведёт к неопределённому поведению
  179.     [[nodiscard]] Iterator end() noexcept {
  180.         return Iterator{ nullptr };
  181.     }
  182.  
  183.     // Возвращает константный итератор, ссылающийся на первый элемент
  184.     // Если список пустой, возвращённый итератор будет равен end()
  185.     // Результат вызова эквивалентен вызову метода cbegin()
  186.     [[nodiscard]] ConstIterator begin() const noexcept {
  187.         return cbegin();
  188.     }
  189.    
  190.     // Возвращает константный итератор, указывающий на позицию, следующую за последним элементом односвязного списка
  191.     // Разыменовывать этот итератор нельзя - попытка разыменования приведёт к неопределённому поведению
  192.     // Результат вызова эквивалентен вызову метода cend()
  193.     [[nodiscard]] ConstIterator end() const noexcept {
  194.         return ConstIterator{ nullptr };
  195.     }
  196.  
  197.     // Возвращает константный итератор, ссылающийся на первый элемент
  198.     // Если список пустой, возвращённый итератор будет равен cend()
  199.     [[nodiscard]] ConstIterator cbegin() const noexcept {
  200.         return ConstIterator{ head_.next_node };
  201.     }
  202.  
  203.     // Возвращает константный итератор, указывающий на позицию, следующую за последним элементом односвязного списка
  204.     // Разыменовывать этот итератор нельзя - попытка разыменования приведёт к неопределённому поведению
  205.     [[nodiscard]] ConstIterator cend() const noexcept {
  206.         return ConstIterator{ nullptr };
  207.     }
  208.  
  209.     SingleLinkedList(std::initializer_list<Type> values) {
  210.     // используем шаблонный метод реализации
  211.         Assign(values.begin(), values.end());
  212.     }
  213.  
  214.     SingleLinkedList(const SingleLinkedList& other) {
  215.     // используем шаблонный метод реализации
  216.         Assign(other.begin(), other.end());
  217.     }
  218.  
  219.     SingleLinkedList& operator=(const SingleLinkedList& rhs) {
  220.         if (this != &rhs) {
  221.             if (rhs.IsEmpty()) {
  222.                 Clear();
  223.             } else {
  224.                 auto rhs_copy(rhs);
  225.                 swap(rhs_copy);
  226.             }
  227.         }
  228.         return *this;
  229.     }
  230.  
  231.     // Обменивает содержимое списков за время O(1)
  232.     void swap(SingleLinkedList& other) noexcept {
  233.         std::swap(other.head_.next_node, head_.next_node);
  234.         std::swap(other.size_, size_);
  235.     }
  236.  
  237.     // Возвращает итератор, указывающий на позицию перед первым элементом односвязного списка.
  238.     // Разыменовывать этот итератор нельзя - попытка разыменования приведёт к неопределённому поведению
  239.     [[nodiscard]] Iterator before_begin() noexcept {
  240.         return Iterator{ &head_ };
  241.     }
  242.  
  243.     // Возвращает константный итератор, указывающий на позицию перед первым элементом односвязного списка.
  244.     // Разыменовывать этот итератор нельзя - попытка разыменования приведёт к неопределённому поведению
  245.     [[nodiscard]] ConstIterator cbefore_begin() const noexcept {
  246.         return ConstIterator{ const_cast<Node*>(&head_) };
  247.     }
  248.  
  249.     // Возвращает константный итератор, указывающий на позицию перед первым элементом односвязного списка.
  250.     // Разыменовывать этот итератор нельзя - попытка разыменования приведёт к неопределённому поведению
  251.     [[nodiscard]] ConstIterator before_begin() const noexcept {
  252.         return cbefore_begin();
  253.     }
  254.  
  255.     /*
  256.      * Вставляет элемент value после элемента, на который указывает pos.
  257.      * Возвращает итератор на вставленный элемент
  258.      * Если при создании элемента будет выброшено исключение, список останется в прежнем состоянии
  259.      */
  260.     Iterator InsertAfter(ConstIterator pos, const Type& value) {
  261.         assert(pos.node_ != nullptr);
  262.        
  263.         pos.node_->next_node = new Node(value, pos.node_->next_node);
  264.         ++size_;
  265.         return Iterator{ pos.node_->next_node };
  266.     }
  267.    
  268.     void PopFront() noexcept {
  269.         assert(!IsEmpty());
  270.        
  271.         Node* new_head = head_.next_node->next_node;
  272.         delete head_.next_node;
  273.         head_.next_node = new_head;
  274.         --size_;
  275.     }
  276.  
  277.     /*
  278.      * Удаляет элемент, следующий за pos.
  279.      * Возвращает итератор на элемент, следующий за удалённым
  280.      */
  281.     Iterator EraseAfter(ConstIterator pos) noexcept {
  282.         assert(!IsEmpty());
  283.        
  284.         Node* temp = pos.node_->next_node->next_node;
  285.         delete pos.node_->next_node;
  286.         pos.node_->next_node = temp;
  287.         --size_;
  288.  
  289.         return Iterator{ pos.node_->next_node };
  290.     }
  291.  
  292. private:
  293.     // Фиктивный узел, используется для вставки "перед первым элементом"
  294.     Node head_;
  295.     size_t size_ = 0;
  296.    
  297.     template <typename InputIterator>
  298.     void Assign(InputIterator from, InputIterator to) {
  299.         SingleLinkedList<Type> tmp;
  300.    
  301.         Node** node_ptr = &tmp.head_.next_node;
  302.         while (from != to) {
  303.             assert(*node_ptr == nullptr);
  304.        
  305.             *node_ptr = new Node(*from, nullptr);
  306.             ++tmp.size_;
  307.        
  308.             node_ptr = &((*node_ptr)->next_node);
  309.        
  310.             ++from;
  311.         }
  312.         swap(tmp);
  313.     }
  314. };
  315.  
  316. template <typename Type>
  317. void swap(SingleLinkedList<Type>& lhs, SingleLinkedList<Type>& rhs) noexcept {
  318.     lhs.swap(rhs);
  319. }
  320.  
  321. template <typename Type>
  322. bool operator==(const SingleLinkedList<Type>& lhs, const SingleLinkedList<Type>& rhs) {
  323.     std::equal(lhs.begin(), lhs.end(),
  324.                rhs.begin(), lhs.end());
  325.     return true;
  326. }
  327.  
  328. template <typename Type>
  329. bool operator!=(const SingleLinkedList<Type>& lhs, const SingleLinkedList<Type>& rhs) {
  330.     !std::equal(lhs.begin(), lhs.end(),
  331.                 rhs.begin(), lhs.end());
  332.     return true;
  333. }
  334.  
  335. template <typename Type>
  336. bool operator<(const SingleLinkedList<Type>& lhs, const SingleLinkedList<Type>& rhs) {
  337.     std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
  338.     return true;
  339. }
  340.  
  341. template <typename Type>
  342. bool operator<=(const SingleLinkedList<Type>& lhs, const SingleLinkedList<Type>& rhs) {
  343.     return rhs < lhs;
  344. }
  345.  
  346. template <typename Type>
  347. bool operator>(const SingleLinkedList<Type>& lhs, const SingleLinkedList<Type>& rhs) {
  348.     return  rhs < lhs;
  349. }
  350.  
  351. template <typename Type>
  352. bool operator>=(const SingleLinkedList<Type>& lhs, const SingleLinkedList<Type>& rhs) {
  353.     return rhs < lhs;
  354. }
  355.  
  356. // Эта функция тестирует работу SingleLinkedList
  357. void Test0() {
  358.     using namespace std;
  359.     {
  360.         const SingleLinkedList<int> empty_int_list;
  361.         assert(empty_int_list.GetSize() == 0u);
  362.         assert(empty_int_list.IsEmpty());
  363.     }
  364.  
  365.     {
  366.         const SingleLinkedList<string> empty_string_list;
  367.         assert(empty_string_list.GetSize() == 0u);
  368.         assert(empty_string_list.IsEmpty());
  369.     }
  370. }
  371.  
  372. void Test1() {
  373.     // Шпион, следящий за своим удалением
  374.     struct DeletionSpy {
  375.         DeletionSpy() = default;
  376.         explicit DeletionSpy(int& instance_counter) noexcept
  377.             : instance_counter_ptr_(&instance_counter)  //
  378.         {
  379.             OnAddInstance();
  380.         }
  381.         DeletionSpy(const DeletionSpy& other) noexcept
  382.             : instance_counter_ptr_(other.instance_counter_ptr_)  //
  383.         {
  384.             OnAddInstance();
  385.         }
  386.         DeletionSpy& operator=(const DeletionSpy& rhs) noexcept {
  387.             if (this != &rhs) {
  388.                 auto rhs_copy(rhs);
  389.                 std::swap(instance_counter_ptr_, rhs_copy.instance_counter_ptr_);
  390.             }
  391.             return *this;
  392.         }
  393.         ~DeletionSpy() {
  394.             OnDeleteInstance();
  395.         }
  396.  
  397.     private:
  398.         void OnAddInstance() noexcept {
  399.             if (instance_counter_ptr_) {
  400.                 ++(*instance_counter_ptr_);
  401.             }
  402.         }
  403.         void OnDeleteInstance() noexcept {
  404.             if (instance_counter_ptr_) {
  405.                 assert(*instance_counter_ptr_ != 0);
  406.                 --(*instance_counter_ptr_);
  407.             }
  408.         }
  409.  
  410.         int* instance_counter_ptr_ = nullptr;
  411.     };
  412.  
  413.     // Проверка вставки в начало
  414.     {
  415.         SingleLinkedList<int> l;
  416.         assert(l.IsEmpty());
  417.         assert(l.GetSize() == 0u);
  418.         l.PushFront(0);
  419.         l.PushFront(1);
  420.         assert(l.GetSize() == 2);
  421.         assert(!l.IsEmpty());
  422.  
  423.         l.Clear();
  424.         assert(l.GetSize() == 0);
  425.         assert(l.IsEmpty());
  426.     }
  427.  
  428.     // Проверка фактического удаления элементов
  429.     {
  430.         int item0_counter = 0;
  431.         int item1_counter = 0;
  432.         int item2_counter = 0;
  433.         {
  434.             SingleLinkedList<DeletionSpy> list;
  435.             list.PushFront(DeletionSpy{ item0_counter });
  436.             list.PushFront(DeletionSpy{ item1_counter });
  437.             list.PushFront(DeletionSpy{ item2_counter });
  438.  
  439.             assert(item0_counter == 1);
  440.             assert(item1_counter == 1);
  441.             assert(item2_counter == 1);
  442.             list.Clear();
  443.             assert(item0_counter == 0);
  444.             assert(item1_counter == 0);
  445.             assert(item2_counter == 0);
  446.  
  447.             list.PushFront(DeletionSpy{ item0_counter });
  448.             list.PushFront(DeletionSpy{ item1_counter });
  449.             list.PushFront(DeletionSpy{ item2_counter });
  450.             assert(item0_counter == 1);
  451.             assert(item1_counter == 1);
  452.             assert(item2_counter == 1);
  453.         }
  454.         assert(item0_counter == 0);
  455.         assert(item1_counter == 0);
  456.         assert(item2_counter == 0);
  457.     }
  458.  
  459.     // Вспомогательный класс, бросающий исключение после создания N-копии
  460.     struct ThrowOnCopy {
  461.         ThrowOnCopy() = default;
  462.         explicit ThrowOnCopy(int& copy_counter) noexcept
  463.             : countdown_ptr(&copy_counter) {
  464.         }
  465.         ThrowOnCopy(const ThrowOnCopy& other)
  466.             : countdown_ptr(other.countdown_ptr)  //
  467.         {
  468.             if (countdown_ptr) {
  469.                 if (*countdown_ptr == 0) {
  470.                     throw std::bad_alloc();
  471.                 }
  472.                 else {
  473.                     --(*countdown_ptr);
  474.                 }
  475.             }
  476.         }
  477.         // Присваивание элементов этого типа не требуется
  478.         ThrowOnCopy& operator=(const ThrowOnCopy& rhs) = delete;
  479.         // Адрес счётчика обратного отсчёта. Если не равен nullptr, то уменьшается при каждом копировании.
  480.         // Как только обнулится, конструктор копирования выбросит исключение
  481.         int* countdown_ptr = nullptr;
  482.     };
  483.  
  484.     {
  485.         bool exception_was_thrown = false;
  486.         // Последовательно уменьшаем счётчик копирований до нуля, пока не будет выброшено исключение
  487.         for (int max_copy_counter = 5; max_copy_counter >= 0; --max_copy_counter) {
  488.             // Создаём непустой список
  489.             SingleLinkedList<ThrowOnCopy> list;
  490.             list.PushFront(ThrowOnCopy{});
  491.             try {
  492.                 int copy_counter = max_copy_counter;
  493.                 list.PushFront(ThrowOnCopy(copy_counter));
  494.                 // Если метод не выбросил исключение, список должен перейти в новое состояние
  495.                 assert(list.GetSize() == 2);
  496.             }
  497.             catch (const std::bad_alloc&) {
  498.                 exception_was_thrown = true;
  499.                 // После выбрасывания исключения состояние списка должно остаться прежним
  500.                 assert(list.GetSize() == 1);
  501.                 break;
  502.             }
  503.         }
  504.         assert(exception_was_thrown);
  505.     }
  506. }
  507.  
  508. void Test2() {
  509.     // Итерирование по пустому списку
  510.     {
  511.         SingleLinkedList<int> list;
  512.         // Константная ссылка для доступа к константным версиям begin()/end()
  513.         const auto& const_list = list;
  514.  
  515.         // Итераторы begine и end у пустого диапазона равны друг другу
  516.         assert(list.begin() == list.end());
  517.         assert(const_list.begin() == const_list.end());
  518.         assert(list.cbegin() == list.cend());
  519.         assert(list.cbegin() == const_list.begin());
  520.         assert(list.cend() == const_list.end());
  521.     }
  522.  
  523.     // Итерирование по непустому списку
  524.     {
  525.         SingleLinkedList<int> list;
  526.         const auto& const_list = list;
  527.  
  528.         list.PushFront(1);
  529.         assert(list.GetSize() == 1u);
  530.         assert(!list.IsEmpty());
  531.         assert(const_list.begin() != const_list.end());
  532.         assert(const_list.cbegin() != const_list.cend());
  533.         assert(list.begin() != list.end());
  534.  
  535.         assert(const_list.begin() == const_list.cbegin());
  536.  
  537.         assert(*list.cbegin() == 1);
  538.         *list.begin() = -1;
  539.         assert(*list.cbegin() == -1);
  540.  
  541.         const auto old_begin = list.cbegin();
  542.         list.PushFront(2);
  543.         assert(list.GetSize() == 2);
  544.  
  545.         const auto new_begin = list.cbegin();
  546.         assert(new_begin != old_begin);
  547.         // Проверка прединкремента
  548.         {
  549.             auto new_begin_copy(new_begin);
  550.             assert((++(new_begin_copy)) == old_begin);
  551.         }
  552.         // Проверка постинкремента
  553.         {
  554.             auto new_begin_copy(new_begin);
  555.             assert(((new_begin_copy)++) == new_begin);
  556.             assert(new_begin_copy == old_begin);
  557.         }
  558.         // Итератор, указывающий на позицию после последнего элемента равен итератору end()
  559.         {
  560.             auto old_begin_copy(old_begin);
  561.             assert((++old_begin_copy) == list.end());
  562.         }
  563.     }
  564.     // Преобразование итераторов
  565.     {
  566.         SingleLinkedList<int> list;
  567.         list.PushFront(1);
  568.         // Конструирование ConstItrator из Iterator
  569.         SingleLinkedList<int>::ConstIterator const_it(list.begin());
  570.         assert(const_it == list.cbegin());
  571.         assert(*const_it == *list.cbegin());
  572.  
  573.         SingleLinkedList<int>::ConstIterator const_it1;
  574.         // Присваивание ConstIterator-у значения Iterator
  575.         const_it1 = list.begin();
  576.         assert(const_it1 == const_it);
  577.     }
  578.     // Проверка оператора ->
  579.     {
  580.         using namespace std;
  581.         SingleLinkedList<std::string> string_list;
  582.  
  583.         string_list.PushFront("one"s);
  584.         assert(string_list.cbegin()->length() == 3u);
  585.         string_list.begin()->push_back('!');
  586.         assert(*string_list.begin() == "one!"s);
  587.     }
  588. }
  589.  
  590. void Test3() {
  591.     // Проверка списков на равенство и неравенство
  592.     {
  593.         SingleLinkedList<int> list_1;
  594.         list_1.PushFront(1);
  595.         list_1.PushFront(2);
  596.  
  597.         SingleLinkedList<int> list_2;
  598.         list_2.PushFront(1);
  599.         list_2.PushFront(2);
  600.         list_2.PushFront(3);
  601.  
  602.         SingleLinkedList<int> list_1_copy;
  603.         list_1_copy.PushFront(1);
  604.         list_1_copy.PushFront(2);
  605.  
  606.         SingleLinkedList<int> empty_list;
  607.         SingleLinkedList<int> another_empty_list;
  608.  
  609.         // Список равен самому себе
  610.         assert(list_1 == list_1);
  611.         assert(empty_list == empty_list);
  612.  
  613.         // Списки с одинаковым содержимым равны, а с разным - не равны
  614.         assert(list_1 == list_1_copy);
  615.         assert(list_1 != list_2);
  616.         assert(list_2 != list_1);
  617.         assert(empty_list == another_empty_list);
  618.     }
  619.  
  620.     // Обмен содержимого списков
  621.     {
  622.         SingleLinkedList<int> first;
  623.         first.PushFront(1);
  624.         first.PushFront(2);
  625.  
  626.         SingleLinkedList<int> second;
  627.         second.PushFront(10);
  628.         second.PushFront(11);
  629.         second.PushFront(15);
  630.  
  631.         const auto old_first_begin = first.begin();
  632.         const auto old_second_begin = second.begin();
  633.         const auto old_first_size = first.GetSize();
  634.         const auto old_second_size = second.GetSize();
  635.  
  636.         first.swap(second);
  637.  
  638.         assert(second.begin() == old_first_begin);
  639.         assert(first.begin() == old_second_begin);
  640.         assert(second.GetSize() == old_first_size);
  641.         assert(first.GetSize() == old_second_size);
  642.  
  643.         // Обмен при помощи функции swap
  644.         {
  645.             using std::swap;
  646.  
  647.             // В отсутствие пользовательской перегрузки будет вызвана функция std::swap, которая
  648.             // выполнит обмен через создание временной копии
  649.             swap(first, second);
  650.  
  651.             // Убеждаемся, что используется не std::swap, а пользовательская перегрузка
  652.             // Если бы обмен был выполнен с созданием временной копии,
  653.             // то итератор first.begin() не будет равен ранее сохранённому значению,
  654.             // так как копия будет хранить свои узлы по иным адресам
  655.             assert(first.begin() == old_first_begin);
  656.             assert(second.begin() == old_second_begin);
  657.             assert(first.GetSize() == old_first_size);
  658.             assert(second.GetSize() == old_second_size);
  659.         }
  660.     }
  661.  
  662.     // Инициализация списка при помощи std::initializer_list
  663.     {
  664.         SingleLinkedList<int> list{ 1, 2, 3, 4, 5 };
  665.         assert(list.GetSize() == 5);
  666.         assert(!list.IsEmpty());
  667.         assert(std::equal(list.begin(), list.end(), std::begin({ 1, 2, 3, 4, 5 })));
  668.     }
  669.  
  670.     // Лексикографическое сравнение списков
  671.     {
  672.         using IntList = SingleLinkedList<int>;
  673.  
  674.         assert((IntList{ 1, 2, 3 } < IntList{ 1, 2, 3, 1 }));
  675.         assert((IntList{ 1, 2, 3 } <= IntList{ 1, 2, 3 }));
  676.         assert((IntList{ 1, 2, 4 } > IntList{ 1, 2, 3 }));
  677.         assert((IntList{ 1, 2, 3 } >= IntList{ 1, 2, 3 }));
  678.     }
  679.  
  680.     // Копирование списков
  681.     {
  682.         const SingleLinkedList<int> empty_list{};
  683.         // Копирование пустого списка
  684.         {
  685.             auto list_copy(empty_list);
  686.             assert(list_copy.IsEmpty());
  687.         }
  688.  
  689.         SingleLinkedList<int> non_empty_list{ 1, 2, 3, 4 };
  690.         // Копирование непустого списка
  691.         {
  692.             auto list_copy(non_empty_list);
  693.  
  694.             assert(non_empty_list.begin() != list_copy.begin());
  695.             assert(list_copy == non_empty_list);
  696.         }
  697.     }
  698.  
  699.     // Присваивание списков
  700.     {
  701.         const SingleLinkedList<int> source_list{ 1, 2, 3, 4 };
  702.  
  703.         SingleLinkedList<int> receiver{ 5, 4, 3, 2, 1 };
  704.         receiver = source_list;
  705.         assert(receiver.begin() != source_list.begin());
  706.         assert(receiver == source_list);
  707.     }
  708.  
  709.     // Вспомогательный класс, бросающий исключение после создания N-копии
  710.     struct ThrowOnCopy {
  711.         ThrowOnCopy() = default;
  712.         explicit ThrowOnCopy(int& copy_counter) noexcept
  713.             : countdown_ptr(&copy_counter) {
  714.         }
  715.         ThrowOnCopy(const ThrowOnCopy& other)
  716.             : countdown_ptr(other.countdown_ptr)  //
  717.         {
  718.             if (countdown_ptr) {
  719.                 if (*countdown_ptr == 0) {
  720.                     throw std::bad_alloc();
  721.                 }
  722.                 else {
  723.                     --(*countdown_ptr);
  724.                 }
  725.             }
  726.         }
  727.         // Присваивание элементов этого типа не требуется
  728.         ThrowOnCopy& operator=(const ThrowOnCopy& rhs) = delete;
  729.         // Адрес счётчика обратного отсчёта. Если не равен nullptr, то уменьшается при каждом копировании.
  730.         // Как только обнулится, конструктор копирования выбросит исключение
  731.         int* countdown_ptr = nullptr;
  732.     };
  733.  
  734.     // Безопасное присваивание списков
  735.     {
  736.         SingleLinkedList<ThrowOnCopy> src_list;
  737.         src_list.PushFront(ThrowOnCopy{});
  738.         src_list.PushFront(ThrowOnCopy{});
  739.         auto thrower = src_list.begin();
  740.         src_list.PushFront(ThrowOnCopy{});
  741.  
  742.         int copy_counter = 0;  // при первом же копировании будет выброшего исключение
  743.         thrower->countdown_ptr = &copy_counter;
  744.  
  745.         SingleLinkedList<ThrowOnCopy> dst_list;
  746.         dst_list.PushFront(ThrowOnCopy{});
  747.         int dst_counter = 10;
  748.         dst_list.begin()->countdown_ptr = &dst_counter;
  749.         dst_list.PushFront(ThrowOnCopy{});
  750.         try {
  751.             dst_list = src_list;
  752.             // Ожидается исключение при присваивании
  753.             assert(false);
  754.         }
  755.         catch (const std::bad_alloc&) {
  756.             // Проверяем, что состояние списка-приёмника не изменилось
  757.             // при выбрасывании исключений
  758.             assert(dst_list.GetSize() == 2);
  759.             auto it = dst_list.begin();
  760.             assert(it != dst_list.end());
  761.             assert(it->countdown_ptr == nullptr);
  762.             ++it;
  763.             assert(it != dst_list.end());
  764.             assert(it->countdown_ptr == &dst_counter);
  765.             assert(dst_counter == 10);
  766.         }
  767.         catch (...) {
  768.             // Других типов исключений не ожидается
  769.             assert(false);
  770.         }
  771.     }
  772. }
  773.  
  774. void Test4() {
  775.     struct DeletionSpy {
  776.         ~DeletionSpy() {
  777.             if (deletion_counter_ptr) {
  778.                 ++(*deletion_counter_ptr);
  779.             }
  780.         }
  781.         int* deletion_counter_ptr = nullptr;
  782.     };
  783.  
  784.     // Проверка PopFront
  785.     {
  786.         SingleLinkedList<int> numbers{ 3, 14, 15, 92, 6 };
  787.         numbers.PopFront();
  788.         assert((numbers == SingleLinkedList<int>{14, 15, 92, 6}));
  789.  
  790.         SingleLinkedList<DeletionSpy> list;
  791.         list.PushFront(DeletionSpy{});
  792.         int deletion_counter = 0;
  793.         list.begin()->deletion_counter_ptr = &deletion_counter;
  794.         assert(deletion_counter == 0);
  795.         list.PopFront();
  796.         assert(deletion_counter == 1);
  797.     }
  798.  
  799.     // Доступ к позиции, предшествующей begin
  800.     {
  801.         SingleLinkedList<int> empty_list;
  802.         const auto& const_empty_list = empty_list;
  803.         assert(empty_list.before_begin() == empty_list.cbefore_begin());
  804.         assert(++empty_list.before_begin() == empty_list.begin());
  805.         assert(++empty_list.cbefore_begin() == const_empty_list.begin());
  806.  
  807.         SingleLinkedList<int> numbers{ 1, 2, 3, 4 };
  808.         const auto& const_numbers = numbers;
  809.         assert(numbers.before_begin() == numbers.cbefore_begin());
  810.         assert(++numbers.before_begin() == numbers.begin());
  811.         assert(++numbers.cbefore_begin() == const_numbers.begin());
  812.     }
  813.  
  814.     // Вставка элемента после указанной позиции
  815.     {  // Вставка в пустой список
  816.         {
  817.             SingleLinkedList<int> lst;
  818.             const auto inserted_item_pos = lst.InsertAfter(lst.before_begin(), 123);
  819.             assert((lst == SingleLinkedList<int>{123}));
  820.             assert(inserted_item_pos == lst.begin());
  821.             assert(*inserted_item_pos == 123);
  822.         }
  823.  
  824.         // Вставка в непустой список
  825.         {
  826.             SingleLinkedList<int> lst{ 1, 2, 3 };
  827.             auto inserted_item_pos = lst.InsertAfter(lst.before_begin(), 123);
  828.  
  829.             assert(inserted_item_pos == lst.begin());
  830.             assert(inserted_item_pos != lst.end());
  831.             assert(*inserted_item_pos == 123);
  832.             assert((lst == SingleLinkedList<int>{123, 1, 2, 3}));
  833.  
  834.             inserted_item_pos = lst.InsertAfter(lst.begin(), 555);
  835.             assert(++SingleLinkedList<int>::Iterator(lst.begin()) == inserted_item_pos);
  836.             assert(*inserted_item_pos == 555);
  837.             assert((lst == SingleLinkedList<int>{123, 555, 1, 2, 3}));
  838.         };
  839.     }
  840.     // Вспомогательный класс, бросающий исключение после создания N-копии
  841.     struct ThrowOnCopy {
  842.         ThrowOnCopy() = default;
  843.         explicit ThrowOnCopy(int& copy_counter) noexcept
  844.             : countdown_ptr(&copy_counter) {
  845.         }
  846.         ThrowOnCopy(const ThrowOnCopy& other)
  847.             : countdown_ptr(other.countdown_ptr)  //
  848.         {
  849.             if (countdown_ptr) {
  850.                 if (*countdown_ptr == 0) {
  851.                     throw std::bad_alloc();
  852.                 }
  853.                 else {
  854.                     --(*countdown_ptr);
  855.                 }
  856.             }
  857.         }
  858.         // Присваивание элементов этого типа не требуется
  859.         ThrowOnCopy& operator=(const ThrowOnCopy& rhs) = delete;
  860.         // Адрес счётчика обратного отсчёта. Если не равен nullptr, то уменьшается при каждом копировании.
  861.         // Как только обнулится, конструктор копирования выбросит исключение
  862.         int* countdown_ptr = nullptr;
  863.     };
  864.  
  865.     // Проверка обеспечения строгой гарантии безопасности исключений
  866.     {
  867.         bool exception_was_thrown = false;
  868.         for (int max_copy_counter = 10; max_copy_counter >= 0; --max_copy_counter) {
  869.             SingleLinkedList<ThrowOnCopy> list{ ThrowOnCopy{}, ThrowOnCopy{}, ThrowOnCopy{} };
  870.             try {
  871.                 int copy_counter = max_copy_counter;
  872.                 list.InsertAfter(list.cbegin(), ThrowOnCopy(copy_counter));
  873.                 assert(list.GetSize() == 4u);
  874.             }
  875.             catch (const std::bad_alloc&) {
  876.                 exception_was_thrown = true;
  877.                 assert(list.GetSize() == 3u);
  878.                 break;
  879.             }
  880.         }
  881.         assert(exception_was_thrown);
  882.     }
  883.  
  884.     // Удаление элементов после указанной позиции
  885.     {
  886.         {
  887.             SingleLinkedList<int> lst{ 1, 2, 3, 4 };
  888.             const auto& const_lst = lst;
  889.             const auto item_after_erased = lst.EraseAfter(const_lst.cbefore_begin());
  890.             assert((lst == SingleLinkedList<int>{2, 3, 4}));
  891.             assert(item_after_erased == lst.begin());
  892.         }
  893.         {
  894.             SingleLinkedList<int> lst{ 1, 2, 3, 4 };
  895.             const auto item_after_erased = lst.EraseAfter(lst.cbegin());
  896.             assert((lst == SingleLinkedList<int>{1, 3, 4}));
  897.             assert(item_after_erased == (++lst.begin()));
  898.         }
  899.         {
  900.             SingleLinkedList<int> lst{ 1, 2, 3, 4 };
  901.             const auto item_after_erased = lst.EraseAfter(++(++lst.cbegin()));
  902.             assert((lst == SingleLinkedList<int>{1, 2, 3}));
  903.             assert(item_after_erased == lst.end());
  904.         }
  905.         {
  906.             SingleLinkedList<DeletionSpy> list{ DeletionSpy{}, DeletionSpy{}, DeletionSpy{} };
  907.             auto after_begin = ++list.begin();
  908.             int deletion_counter = 0;
  909.             after_begin->deletion_counter_ptr = &deletion_counter;
  910.             assert(deletion_counter == 0u);
  911.             list.EraseAfter(list.cbegin());
  912.             assert(deletion_counter == 1u);
  913.         }
  914.     }
  915. }
  916.  
  917. int main() {
  918.     Test0();
  919.     Test1();
  920.     Test2();
  921.     Test3();
  922.     Test4();
  923. }
Add Comment
Please, Sign In to add comment