shushus

Спринт 7. Сравнение, копирование и присваивание.

Jan 12th, 2023
378
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 10.43 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) : value(val), next_node(next) {}
  14.         Type value;
  15.         Node* next_node = nullptr;
  16.     };
  17.  
  18.     template <typename ValueType>
  19.     class BasicIterator {
  20.    
  21.         friend class SingleLinkedList;
  22.  
  23.         explicit BasicIterator(Node* node) {
  24.             node_ = node;
  25.         }
  26.  
  27.     public:
  28.         using iterator_category = std::forward_iterator_tag;
  29.         using value_type = Type;
  30.         using difference_type = std::ptrdiff_t;
  31.         using pointer = ValueType*;
  32.         using reference = ValueType&;
  33.  
  34.         BasicIterator() = default;
  35.  
  36.         BasicIterator(const BasicIterator<Type>& other) noexcept {
  37.             node_ = other.node_;
  38.         }
  39.  
  40.         BasicIterator& operator=(const BasicIterator& rhs) = default;
  41.  
  42.         [[nodiscard]] bool operator==(const BasicIterator<const Type>& rhs) const noexcept {
  43.             return node_ == rhs.node_;
  44.         }
  45.  
  46.         [[nodiscard]] bool operator!=(const BasicIterator<const Type>& rhs) const noexcept {
  47.             return node_ != rhs.node_;
  48.         }
  49.  
  50.         [[nodiscard]] bool operator==(const BasicIterator<Type>& rhs) const noexcept {
  51.             return node_ == rhs.node_;
  52.         }
  53.  
  54.         [[nodiscard]] bool operator!=(const BasicIterator<Type>& rhs) const noexcept {
  55.             return node_ != rhs.node_;
  56.         }
  57.  
  58.         BasicIterator& operator++() noexcept {
  59.             node_ = node_->next_node;
  60.             return *this;
  61.         }
  62.  
  63.         BasicIterator operator++(int) noexcept {
  64.             auto old_value(*this);
  65.             ++(*this);
  66.             return old_value;
  67.         }
  68.  
  69.         [[nodiscard]] reference operator*() const noexcept {
  70.             return node_->value;
  71.         }
  72.  
  73.         [[nodiscard]] pointer operator->() const noexcept {
  74.             if(node_){
  75.                 return &node_->value;
  76.             }else{
  77.                 return nullptr;
  78.             }
  79.         }
  80.  
  81.     private:
  82.         Node* node_ = nullptr;
  83.     };
  84.  
  85. public:
  86.     SingleLinkedList() {}
  87.    
  88.     template <typename TypeIt>
  89.     void Init(TypeIt begin, TypeIt end) {
  90.         Node* node = &head_;
  91.         for (TypeIt i= begin;i!=end; ++i) {
  92.             ++size_;
  93.             node->next_node = new Node(*i, nullptr);
  94.             node = node->next_node;
  95.         }
  96.     }
  97.    
  98.     SingleLinkedList(std::initializer_list<Type> values) {
  99.         SingleLinkedList helper;
  100.         helper.Init(values.begin(), values.end());
  101.         swap(helper);
  102.     }
  103.  
  104.     SingleLinkedList(const SingleLinkedList& other) {
  105.         SingleLinkedList helper;
  106.         helper.Init(other.begin(), other.end());
  107.         swap(helper);
  108.     }
  109.    
  110.        
  111.     SingleLinkedList& operator=(const SingleLinkedList& rhs) {
  112.         if(this!= &rhs){
  113.             SingleLinkedList helper(rhs);
  114.             swap(helper);
  115.         }
  116.         return *this;
  117.     }
  118.    
  119.     using value_type = Type;
  120.     using reference = value_type&;
  121.     using const_reference = const value_type&;
  122.  
  123.     using Iterator = BasicIterator<Type>;
  124.     using ConstIterator = BasicIterator<const Type>;
  125.  
  126.     [[nodiscard]] Iterator begin() noexcept {
  127.         return Iterator{head_.next_node};
  128.     }
  129.  
  130.     [[nodiscard]] Iterator end() noexcept {
  131.         return Iterator{nullptr};
  132.     }
  133.  
  134.     [[nodiscard]] ConstIterator begin() const noexcept {
  135.         return ConstIterator{head_.next_node};
  136.     }
  137.  
  138.     [[nodiscard]] ConstIterator end() const noexcept {
  139.         return ConstIterator{nullptr};
  140.     }
  141.  
  142.     [[nodiscard]] ConstIterator cbegin() const noexcept {
  143.         return ConstIterator{head_.next_node};
  144.     }
  145.  
  146.     [[nodiscard]] ConstIterator cend() const noexcept {
  147.         return ConstIterator{nullptr};
  148.     }
  149.  
  150.     [[nodiscard]] size_t GetSize() const noexcept {
  151.         return size_;
  152.     }
  153.  
  154.     [[nodiscard]] bool IsEmpty() const noexcept {
  155.         if (!size_) {
  156.         return true;
  157.         }
  158.         return false;
  159.     }
  160.    
  161.     void PushFront(const Type& value) {
  162.         head_.next_node = new Node(value, head_.next_node);
  163.         ++size_;
  164.     }
  165.  
  166.     void Clear() noexcept {
  167.         while (head_.next_node) {
  168.             Node* new_head = head_.next_node->next_node;
  169.             delete head_.next_node;
  170.             head_.next_node = new_head;
  171.         }
  172.         size_ = 0;
  173.     }
  174.  
  175.     void swap(SingleLinkedList& other) noexcept {
  176.         std::swap(head_.next_node, other.head_.next_node);
  177.         std::swap(size_, other.size_);
  178.     }
  179.    
  180.     ~SingleLinkedList() {
  181.         Clear();
  182.     }
  183.  
  184. private:
  185.     Node head_;
  186.     size_t size_ = 0;
  187. };
  188.  
  189. template <typename Type>
  190. void swap(SingleLinkedList<Type>& lhs, SingleLinkedList<Type>& rhs) noexcept {
  191.     lhs.swap(rhs);
  192. }
  193.  
  194. template <typename Type>
  195. bool operator==(const SingleLinkedList<Type>& lhs, const SingleLinkedList<Type>& rhs) {
  196.     return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
  197. }
  198.  
  199. template <typename Type>
  200. bool operator!=(const SingleLinkedList<Type>& lhs, const SingleLinkedList<Type>& rhs) {
  201.     return !(lhs==rhs);
  202. }
  203.  
  204. template <typename Type>
  205. bool operator<(const SingleLinkedList<Type>& lhs, const SingleLinkedList<Type>& rhs) {
  206.     return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
  207. }
  208.  
  209. template <typename Type>
  210. bool operator<=(const SingleLinkedList<Type>& lhs, const SingleLinkedList<Type>& rhs) {
  211.     return !(rhs < lhs);
  212. }
  213.  
  214. template <typename Type>
  215. bool operator>(const SingleLinkedList<Type>& lhs, const SingleLinkedList<Type>& rhs) {
  216.     return rhs <lhs;
  217. }
  218.  
  219. template <typename Type>
  220. bool operator>=(const SingleLinkedList<Type>& lhs, const SingleLinkedList<Type>& rhs) {
  221.    return !(lhs <rhs);
  222. }
  223.  
  224. void Test3() {
  225.     {
  226.         SingleLinkedList<int> list_1;
  227.         list_1.PushFront(1);
  228.         list_1.PushFront(2);
  229.  
  230.         SingleLinkedList<int> list_2;
  231.         list_2.PushFront(1);
  232.         list_2.PushFront(2);
  233.         list_2.PushFront(3);
  234.  
  235.         SingleLinkedList<int> list_1_copy;
  236.         list_1_copy.PushFront(1);
  237.         list_1_copy.PushFront(2);
  238.  
  239.         SingleLinkedList<int> empty_list;
  240.         SingleLinkedList<int> another_empty_list;
  241.  
  242.         assert(list_1 == list_1);
  243.         assert(empty_list == empty_list);
  244.  
  245.         assert(list_1 == list_1_copy);
  246.         assert(list_1 != list_2);
  247.         assert(list_2 != list_1);
  248.         assert(empty_list == another_empty_list);
  249.     }
  250.  
  251.     {
  252.         SingleLinkedList<int> first;
  253.         first.PushFront(1);
  254.         first.PushFront(2);
  255.  
  256.         SingleLinkedList<int> second;
  257.         second.PushFront(10);
  258.         second.PushFront(11);
  259.         second.PushFront(15);
  260.  
  261.         const auto old_first_begin = first.begin();
  262.         const auto old_second_begin = second.begin();
  263.         const auto old_first_size = first.GetSize();
  264.         const auto old_second_size = second.GetSize();
  265.  
  266.         first.swap(second);
  267.  
  268.         assert(second.begin() == old_first_begin);
  269.         assert(first.begin() == old_second_begin);
  270.         assert(second.GetSize() == old_first_size);
  271.         assert(first.GetSize() == old_second_size);
  272.  
  273.         {
  274.             using std::swap;
  275.  
  276.             swap(first, second);
  277.  
  278.             assert(first.begin() == old_first_begin);
  279.             assert(second.begin() == old_second_begin);
  280.             assert(first.GetSize() == old_first_size);
  281.             assert(second.GetSize() == old_second_size);
  282.         }
  283.     }
  284.  
  285.     {
  286.         SingleLinkedList<int> list{1, 2, 3, 4, 5};
  287.         assert(list.GetSize() == 5);
  288.         assert(!list.IsEmpty());
  289.         assert(std::equal(list.begin(), list.end(), std::begin({1, 2, 3, 4, 5})));
  290.     }
  291.  
  292.     {
  293.         using IntList = SingleLinkedList<int>;
  294.  
  295.         assert((IntList{1, 2, 3} < IntList{1, 2, 3, 1}));
  296.         assert((IntList{1, 2, 3} <= IntList{1, 2, 3}));
  297.         assert((IntList{1, 2, 4} > IntList{1, 2, 3}));
  298.         assert((IntList{1, 2, 3} >= IntList{1, 2, 3}));
  299.     }
  300.  
  301.     {
  302.         const SingleLinkedList<int> empty_list{};
  303.         {
  304.             auto list_copy(empty_list);
  305.             assert(list_copy.IsEmpty());
  306.         }
  307.  
  308.         SingleLinkedList<int> non_empty_list{1, 2, 3, 4};
  309.         {
  310.             auto list_copy(non_empty_list);
  311.  
  312.             assert(non_empty_list.begin() != list_copy.begin());
  313.             assert(list_copy == non_empty_list);
  314.         }
  315.     }
  316.  
  317.     {
  318.         const SingleLinkedList<int> source_list{1, 2, 3, 4};
  319.  
  320.         SingleLinkedList<int> receiver{5, 4, 3, 2, 1};
  321.         receiver = source_list;
  322.         assert(receiver.begin() != source_list.begin());
  323.         assert(receiver == source_list);
  324.     }
  325.  
  326.     struct ThrowOnCopy {
  327.         ThrowOnCopy() = default;
  328.         explicit ThrowOnCopy(int& copy_counter) noexcept
  329.             : countdown_ptr(&copy_counter) {
  330.         }
  331.         ThrowOnCopy(const ThrowOnCopy& other)
  332.             : countdown_ptr(other.countdown_ptr)  //
  333.         {
  334.             if (countdown_ptr) {
  335.                 if (*countdown_ptr == 0) {
  336.                     throw std::bad_alloc();
  337.                 } else {
  338.                     --(*countdown_ptr);
  339.                 }
  340.             }
  341.         }
  342.  
  343.         ThrowOnCopy& operator=(const ThrowOnCopy& rhs) = delete;
  344.         int* countdown_ptr = nullptr;
  345.     };
  346.  
  347.     {
  348.         SingleLinkedList<ThrowOnCopy> src_list;
  349.         src_list.PushFront(ThrowOnCopy{});
  350.         src_list.PushFront(ThrowOnCopy{});
  351.         auto thrower = src_list.begin();
  352.         src_list.PushFront(ThrowOnCopy{});
  353.  
  354.         int copy_counter = 0;
  355.         thrower->countdown_ptr = &copy_counter;
  356.  
  357.         SingleLinkedList<ThrowOnCopy> dst_list;
  358.         dst_list.PushFront(ThrowOnCopy{});
  359.         int dst_counter = 10;
  360.         dst_list.begin()->countdown_ptr = &dst_counter;
  361.         dst_list.PushFront(ThrowOnCopy{});
  362.  
  363.         try {
  364.             dst_list = src_list;
  365.             assert(false);
  366.         } catch (const std::bad_alloc&) {
  367.             assert(dst_list.GetSize() == 2);
  368.             auto it = dst_list.begin();
  369.             assert(it != dst_list.end());
  370.             assert(it->countdown_ptr == nullptr);
  371.             ++it;
  372.             assert(it != dst_list.end());
  373.             assert(it->countdown_ptr == &dst_counter);
  374.             assert(dst_counter == 10);
  375.         } catch (...) {
  376.             assert(false);
  377.         }
  378.     }
  379. }
  380.  
  381. int main() {
  382.     Test3();
  383. }
Advertisement
Add Comment
Please, Sign In to add comment