Advertisement
Guest User

Untitled

a guest
Sep 25th, 2023
102
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.54 KB | None | 0 0
  1. #include <iostream>
  2. #include <memory>
  3. #include <string>
  4.  
  5. struct ContainerTester {
  6.     static int instances;
  7.     int counter{};
  8.     int val;
  9.    
  10.     ContainerTester() : ContainerTester(-1) {};
  11.     ContainerTester(int val) : val(val)
  12.     {
  13.         ++counter;
  14.         ++instances;
  15.         //~ std::cout << "create " << val << std::endl;
  16.     }
  17.    
  18.     ContainerTester(ContainerTester const& rhs) : counter(rhs.counter), val(rhs.val)
  19.     {
  20.         //~ std::cout << "copy " << val << std::endl;
  21.         ++instances;
  22.     }
  23.    
  24.     ~ContainerTester() {
  25.         //~ std::cout << "destroy " << val << std::endl;
  26.         --counter;
  27.         --instances;
  28.         if (counter < 0) std::cout << "multiple destructor calls on same element" << std::endl;
  29.         if (instances < 0) std::cout <<"negative number of instances" << std::endl;
  30.     }
  31. };
  32.  
  33. int ContainerTester::instances{};
  34.  
  35. std::ostream& operator<<(std::ostream& o, const ContainerTester& c) {return o << c.val;}
  36.  
  37.  
  38.  
  39. template<typename T> class Deque {
  40. public:
  41.     Deque():
  42.         current_capacity(8)
  43.         ,push_back_position(current_capacity/2)
  44.         ,push_front_position(push_back_position - 1)
  45.     {arr = malloc.allocate(current_capacity);}
  46.  
  47.     size_t size() const {
  48.         return current_size;
  49.     }
  50.  
  51.     void push_back(const T &item);
  52.     void push_front(const T &item);
  53.     T pop_front();
  54.     T pop_back();
  55.  
  56.     //why returning by value? return by reference
  57.     T const& front() const {
  58.         //could hardly be expressed in a more complicated way :)
  59.         // and the - 1 has to be a + 1 anyway
  60.         //~ return *((arr + push_front_position) - 1);
  61.         return arr[push_front_position + 1];
  62.     }
  63.  
  64.     //why returning by value return by reference
  65.     T const& back() const {
  66.         //could hardly be expressed in a more complicated way :)
  67.         //~ return *((arr + push_back_position) - 1);
  68.         return arr[push_back_position - 1];
  69.     }
  70.    
  71.     //btw you may want T& front() and T& back() too, to hand out modifiable references
  72.  
  73.     //as for now, the output operator has to access private Deque members
  74.     friend std::ostream& operator<<(std::ostream&, Deque<auto> const&);
  75.  
  76. private:
  77.     T *arr = nullptr;
  78.     void reallocate();
  79.     size_t current_size = 0;
  80.    
  81.     size_t current_capacity;
  82.     // current_capacity is uninitialized here (has an arbitrary value)
  83.     // and you initialize push_*_position on behalf of this arbitrary value
  84.     //~ size_t push_back_position = (current_capacity / 2) + 1;
  85.     //~ size_t push_front_position = current_capacity / 2;
  86.    
  87.     size_t push_back_position;
  88.     size_t push_front_position;
  89.     static std::allocator<T> malloc;
  90. };
  91.  
  92. template<typename T> std::allocator<T> Deque<T>::malloc;
  93.  
  94.  
  95. template<typename T> void Deque<T>::reallocate() {
  96.  
  97.     T *new_arr = malloc.allocate(current_capacity * 2);
  98.  
  99. //the data has to be centered in new_arr, you put it at its beginning
  100.     std::uninitialized_copy(arr, arr + current_capacity, new_arr + current_capacity - current_size/2 - 1);
  101.    
  102.     //allocator::destroy has been removed in C++20
  103.     //~ for (size_t i = 0; i != current_capacity; ++i)
  104.         //~ malloc.destroy(arr + i);
  105.  
  106.     //deallocate calls operator delete, which calls the destructor
  107.     malloc.deallocate(arr, current_capacity);
  108.  
  109.     arr = new_arr;
  110.  
  111.     //~ current_capacity = current_capacity * 2;
  112.     current_capacity *= 2;
  113.  
  114.     //you reset the insert positions to the center of new_arr
  115.     //~ push_back_position = (current_capacity / 2) + 1;
  116.     //~ push_front_position = current_capacity / 2;
  117.  
  118.     //they have to be set off by half of the number of elements
  119.     push_back_position = current_capacity/2 + current_size/2;
  120.     push_front_position = current_capacity/2 - current_size/2 - 1;
  121. }
  122.  
  123.  
  124. template<typename T> void Deque<T>::push_back(const T &item) {
  125.     //if your Deque has a capacity of e.g. 8 and a size of 0, and you push_back 5 elements, then it has a size of 5, but push_back_position would be capacity + 1, which is obviously wrong
  126.     //~ if (current_size + 1 > current_capacity)
  127.     if (push_back_position > current_capacity)
  128.         reallocate();
  129.  
  130. // allocator::construct was removed in C++20
  131.     //~ malloc.construct(arr + push_back_position, item);
  132.  
  133.     //this in fact calls the assignment operator
  134.     //if you really want to call the copy constructor, you can use placement new
  135.     arr[push_back_position] = item;
  136.  
  137.     ++push_back_position;
  138.     ++current_size;
  139.  
  140.     //debug output
  141.     std::cout << "PB: " << *this << " @" << push_back_position << std::endl;
  142. }
  143.  
  144.  
  145. template<typename T> void Deque<T>::push_front(const T &item) {
  146.     // see ::push_back, similar problem
  147.     //~ if (current_size + 1 > current_capacity)
  148.  
  149.     if (push_front_position == 0)
  150.         reallocate();
  151.  
  152. // allocator::construct was removed in C++20
  153.     //~ malloc.construct(arr + push_front_position, item);
  154.  
  155.     //this in fact calls the assignment operator
  156.     //if you really want to call the copy constructor, you can use placement new
  157.     arr[push_front_position] = item;
  158.  
  159.     --push_front_position;
  160.     ++current_size;
  161.  
  162.     //debug output
  163.     std::cout << "PF: " << *this << " @" << push_front_position << std::endl;
  164. }
  165.  
  166. //outputs the Deque, useful for debugging
  167. std::ostream& operator<<(std::ostream& o, Deque<auto> const& d)
  168. {
  169.     for (auto i{d.push_front_position + 1}; i < d.push_back_position; ++i)
  170.         o << d.arr[i] << " ";
  171.     return o;
  172. }
  173.  
  174. //the correct signature of main is int main(int, char**)
  175. //~ int main() {
  176. int main(int, char**) {
  177.     Deque<ContainerTester> test;
  178.  
  179.     for (int i = 0; i < 5; ++i)
  180.         test.push_front(i);
  181.  
  182.     for (int i = 5; i <= 10; ++i)
  183.         test.push_back(i);
  184.  
  185. //added by me
  186.     for (int i = 11; i < 20; ++i)
  187.         test.push_front(i);
  188.  
  189.  
  190.     std::cout << test.front() << std::endl;
  191.     std::cout << test.back() << std::endl;
  192.  
  193.     std::cout << test << std::endl;
  194.  
  195.     return 0; //obsolete: if main returns without an explicit return, it's implicitly return 0;
  196. }
  197.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement