Advertisement
ulfben

Container 2020 day 2 (refactoring)

Nov 20th, 2020 (edited)
843
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.74 KB | None | 0 0
  1. #pragma once
  2. #include <algorithm>
  3. #include <numeric>
  4. #include <cassert>
  5. #include <stdexcept>
  6. namespace API
  7. {
  8.     template<typename T>
  9.     class Container
  10.     {
  11.     public:
  12.         using pointer = T*;
  13.         using const_pointer = const T*;
  14.         using iterator = T*; //aliases for generic code
  15.         using const_iterator = const T*;
  16.         using value_type = T;
  17.         using size_type = size_t;
  18.         using reference = T&;
  19.         using const_reference = const T&;          
  20.  
  21.         Container() = default;
  22.         ~Container() { delete[] _data;  } //WARNING: may invoke double-delete, if we've manually called destructors on our Ts.
  23.         explicit Container(size_type count) : _data(new T[count]), _count(count), _capacity(count){
  24.             //STL behavior is to fill with defaulted-Ts.
  25.                 //std::fill(begin(), end(), T());  
  26.             //I'm ignoring this to let me delegate to this constructor efficiently.            
  27.         };
  28.  
  29.         //range construction
  30.         Container(const_iterator begin, const_iterator end) : Container(static_cast<size_type>(std::distance(begin, end))) {
  31.             assert(begin <= end && "Container(iter, iter): begin & end iterators are reversed");
  32.             std::copy(begin, end, begin());
  33.         }
  34.        
  35.         //copy ctor, delegating to range
  36.         explicit Container(const Container& that) : Container(that.begin(), that.end()){}
  37.        
  38.         //list construction, delegating to range.
  39.         Container(std::initializer_list<T> list) : Container(std::begin(list), std::end(list)) {}
  40.  
  41.         Container(Container&& that) noexcept {         
  42.             _count = std::exchange(that._count, 0);
  43.             _capacity = std::exchange(that._capacity, 0);          
  44.             _data = std::exchange(that._data, nullptr);        
  45.         }
  46.  
  47.         //by value assignment idiom. deals with both copy- and move assignment
  48.         Container& operator=(Container that) noexcept {
  49.             swap(that); //we take all in that, and give that all of us. that is destroyed at the return of this function.
  50.             return *this;
  51.         }
  52.  
  53.         void swap(Container& that) noexcept {
  54.             using std::swap;
  55.             swap(_data, that._data);
  56.             swap(_count, that._count);
  57.             swap(_capacity, that._capacity);
  58.         }
  59.  
  60.         //ADL overload. See Arthur O'Dwyer: https://youtu.be/7Qgd9B1KuMQ?t=2597
  61.         friend void swap(Container<T>& a, Container<T>& b) noexcept {
  62.             a.swap(b);
  63.         }          
  64.        
  65.         void clear() noexcept {
  66.             //TODO: could be erase(begin(), end()).
  67.             while (!empty()) {
  68.                 pop_back();
  69.             }
  70.         }
  71.  
  72.         void pop_back() noexcept {
  73.             assert(!empty() && "pop_back() on empty container is undefined!");
  74.             back().~T(); //WARNING: will lead do double delete when we call delete[] on _data
  75.             --_count;
  76.         }
  77.  
  78.         void reserve(size_type newCapacity) {
  79.             if (newCapacity <= _capacity) { return;  } //never decrease the allocation
  80.             pointer newBuffer = new T[newCapacity];
  81.             std::move(begin(), end(), newBuffer);
  82.             delete[] _data;
  83.             _data = newBuffer;
  84.             _capacity = newCapacity;
  85.         }
  86.        
  87.         void push_back(const T& value) {
  88.             if (_capacity == 0) {
  89.                 reserve(2);
  90.             }
  91.             else if (_count == _capacity) {
  92.                 reserve(2 * _capacity);
  93.             }
  94.             _data[_count] = value;
  95.             _count++;
  96.         }
  97.  
  98.         reference at(size_type index) {
  99.             if (index >= size()) {
  100.                 throw std::out_of_range("Container at() index is out of range!");
  101.             }
  102.             return _data[index];
  103.         }
  104.         const_reference at(size_type index) const {
  105.             if (index >= size()) {
  106.                 throw std::out_of_range("Container at() index is out of range!");
  107.             }
  108.             return _data[index];
  109.         }
  110.  
  111.         reference operator[](size_type index) noexcept{
  112.             assert(index < size() && "Container operator[] index is out of range!");
  113.             return _data[index];
  114.         }
  115.         const_reference operator[](size_type index) const noexcept {
  116.             assert(index < size() && "Container operator[] index is out of range!");
  117.             return _data[index];
  118.         }
  119.  
  120.         reference front() noexcept {
  121.             assert(!empty() && "front() on empty container is UB");
  122.             return _data[0];
  123.         }
  124.         const_reference front() const noexcept {
  125.             assert(!empty() && "front() on empty container is UB");
  126.             return _data[0];
  127.         }
  128.  
  129.         const_reference back() const noexcept {
  130.             assert(!empty() && "back() on empty container is UB");
  131.             return _data[size() - 1];
  132.         }
  133.         reference back() noexcept {
  134.             assert(!empty() && "back() on empty container is UB");
  135.             return _data[size() - 1];
  136.         }
  137.        
  138.         [[nodiscard]] constexpr bool empty() const noexcept {
  139.             return size() == 0;
  140.         }
  141.  
  142.         size_type capacity() const noexcept {
  143.             return _capacity;
  144.         }
  145.         size_type size() const noexcept {
  146.             return _count;
  147.         }
  148.  
  149.         //TODO: make free functions of these
  150.         const_iterator begin() const noexcept { return _data; }    
  151.         const_iterator cbegin() const noexcept { return _data; }
  152.         iterator begin() noexcept { return _data; }
  153.  
  154.         const_iterator end() const noexcept { return _data + _count; }
  155.         const_iterator cend() const noexcept { return _data + _count; }    
  156.         iterator end() noexcept { return _data + _count; }
  157.  
  158.     private:
  159.         T* _data = nullptr;
  160.         size_type _count = 0;
  161.         size_type _capacity = 0;
  162.     };
  163.    
  164.     template<typename T>
  165.     bool operator==(const Container<T>& lhs, const Container<T>& rhs) noexcept {
  166.         if (std::size(lhs) != std::size(rhs)) { return false; }
  167.         return std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs));
  168.     }
  169.     template<typename T>
  170.     bool operator<(const Container<T>& lhs, const Container<T>& rhs) noexcept {
  171.         return std::lexicographical_compare(lhs.begin(), lhs.end(),
  172.             rhs.begin(), rhs.end());
  173.     }
  174.  
  175.     template<typename T>
  176.     bool operator!=(const Container<T>& lhs, const Container<T>& rhs) noexcept {
  177.         return not(lhs == rhs);
  178.     }
  179.     template<typename T>
  180.     bool operator>(const Container<T>& lhs, const Container<T>& rhs) noexcept {
  181.         return rhs < lhs;
  182.     }
  183.     template<typename T>
  184.     bool operator<=(const Container<T>& lhs, const Container<T>& rhs) noexcept {
  185.         !(lhs > rhs);
  186.     }
  187.     template<typename T>
  188.     bool operator>=(const Container<T>& lhs, const Container<T>& rhs) noexcept {
  189.         !(lhs < rhs);
  190.     }
  191. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement