Advertisement
kalabukdima

std::vector (BSU)

Jul 13th, 2020
1,329
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 10.23 KB | None | 0 0
  1. #pragma once
  2.  
  3. #include <memory>
  4. #include <iterator>
  5. #include <type_traits>
  6. #include <algorithm>
  7.  
  8. template<typename _InIter>
  9. using _RequireInputIter = typename std::enable_if<
  10.     std::is_convertible<
  11.         typename std::iterator_traits<_InIter>::iterator_category,
  12.         std::input_iterator_tag
  13.     >::value
  14. >::type;
  15.  
  16. template <class T, class A = std::allocator<T> >
  17. class vector {
  18.     public:
  19.         using allocator_type = A;
  20.         using value_type = T;
  21.         using reference = T&;
  22.         using const_reference = const T&;
  23.         using pointer = typename std::allocator_traits<A>::pointer;
  24.         using const_pointer = typename std::allocator_traits<A>::const_pointer;
  25.         using difference_type = typename std::allocator_traits<A>::difference_type;
  26.         using size_type = typename std::allocator_traits<A>::size_type;
  27.  
  28.         using iterator = T*;
  29.         using const_iterator = const T*;
  30.  
  31.         using reverse_iterator = std::reverse_iterator<iterator>;
  32.         using const_reverse_iterator = std::reverse_iterator<const_iterator>;
  33.  
  34.     public:
  35.         explicit vector(size_type n = 0, const T& init = T(),
  36.                         const allocator_type& alloc = allocator_type()) :
  37.             _capacity(n), _alloc(alloc)
  38.         {
  39.             _data = std::allocator_traits<A>::allocate(_alloc, _capacity);
  40.             for (_size = 0; _size < n; ++_size) {
  41.                 try {
  42.                     std::allocator_traits<A>::construct(_alloc, _data + _size, init);
  43.                 } catch (...) {
  44.                     clear();
  45.                     throw;
  46.                 }
  47.             }
  48.         }
  49.  
  50.         template <class InIter,
  51.                   typename = _RequireInputIter<InIter> >
  52.         vector(InIter begin, InIter end,
  53.                const allocator_type& alloc = allocator_type()) :
  54.             _capacity(std::distance(begin, end)), _alloc(alloc)
  55.         {
  56.             _data = std::allocator_traits<A>::allocate(_alloc, _capacity);
  57.             for (auto it = begin; it != end; ++it) {
  58.                 try {
  59.                     std::allocator_traits<A>::construct(_alloc, _data + _size, *it);
  60.                 } catch (...) {
  61.                     clear();
  62.                     throw;
  63.                 }
  64.                 ++_size;
  65.             }
  66.         }
  67.  
  68.         vector(std::initializer_list<value_type> ilist,
  69.                         const allocator_type& alloc = allocator_type()) :
  70.             vector(ilist.begin(), ilist.end(), alloc) {}
  71.  
  72.         vector(const vector& rhs, const A& alloc) : _capacity(rhs._size), _alloc(alloc)
  73.         {
  74.             _data = std::allocator_traits<A>::allocate(_alloc, _capacity);
  75.             for (_size = 0; _size < rhs.size(); ++_size) {
  76.                 try {
  77.                     std::allocator_traits<A>::construct(_alloc, _data + _size, rhs[_size]);
  78.                 } catch (...) {
  79.                     clear();
  80.                     throw;
  81.                 }
  82.             }
  83.         }
  84.  
  85.         vector(const vector& rhs) : vector(rhs, rhs._alloc) {}
  86.  
  87.         vector(vector&& rhs, const A& alloc) : _size(rhs._size),
  88.                 _capacity(rhs._capacity), _data(rhs._data), _alloc(alloc)
  89.         {
  90.             rhs._data = nullptr;
  91.             rhs._capacity = 0;
  92.             rhs._size = 0;
  93.         }
  94.  
  95.         vector(vector&& rhs) : _size(rhs._size), _capacity(rhs._capacity),
  96.                 _data(rhs._data), _alloc(std::move(rhs._alloc))
  97.         {
  98.             rhs._data = nullptr;
  99.             rhs._capacity = 0;
  100.             rhs._size = 0;
  101.         }
  102.  
  103.         vector& operator=(vector rhs)
  104.         {
  105.             using std::swap;
  106.             vector tmp(std::move(rhs));
  107.             swap(*this, tmp);
  108.             return *this;
  109.         }
  110.  
  111.         ~vector()
  112.         {
  113.             clear();
  114.         }
  115.  
  116.         void reserve(size_type n)
  117.         {
  118.             if (n > _capacity) {
  119.                 _force_reserve(n);
  120.             }
  121.         }
  122.  
  123.         void shrink_to_fit()
  124.         {
  125.             if (_size < _capacity)
  126.                 _force_reserve(_size);
  127.         }
  128.  
  129.         void resize(size_type n, const value_type& val = value_type())
  130.         {
  131.             if (n == _size) return;
  132.             if (n < _size) {
  133.                 for (size_type i = n; i != _size; ++i) {
  134.                     std::allocator_traits<A>::destroy(_alloc, _data + i);
  135.                 }
  136.                 _size = n;
  137.             }
  138.             else {
  139.                 reserve(n);
  140.                 for (; _size < n; ++_size) {
  141.                     std::allocator_traits<A>::construct(_alloc, _data + _size, val);
  142.                 }
  143.             }
  144.         }
  145.  
  146.         reference operator[](size_type i)
  147.         {
  148.             return _data[i];
  149.         }
  150.  
  151.         const_reference operator[](size_type i) const
  152.         {
  153.             return _data[i];
  154.         }
  155.  
  156.         reference at(size_type i)
  157.         {
  158.             if (i < 0 || i >= _size) {
  159.                 throw std::out_of_range("Trying to access element outside allowed range");
  160.             }
  161.             return _data[i];
  162.         }
  163.  
  164.         const_reference at(size_type i) const
  165.         {
  166.             if (i < 0 || i >= _size) {
  167.                 throw std::out_of_range("Trying to access element outside allowed range");
  168.             }
  169.             return _data[i];
  170.         }
  171.  
  172.         reference back()
  173.         {
  174.             return _data[_size - 1];
  175.         }
  176.  
  177.         const_reference back() const
  178.         {
  179.             return _data[_size - 1];
  180.         }
  181.  
  182.         reference front()
  183.         {
  184.             return _data[0];
  185.         }
  186.  
  187.         const_reference front() const
  188.         {
  189.             return _data[0];
  190.         }
  191.  
  192.  
  193.         template <class... Ts>
  194.         void assign(Ts&&... args)
  195.         {
  196.             using std::swap;
  197.             vector tmp(std::forward<Ts>(args)...);
  198.             swap(*this, tmp);
  199.         }
  200.  
  201.         void assign(std::initializer_list<T> ilist)
  202.         {
  203.             assign(ilist.begin(), ilist.end());
  204.         }
  205.  
  206.         void push_back(const T& element)
  207.         {
  208.             emplace_back(element);
  209.         }
  210.  
  211.         template <class... Ts>
  212.         void emplace_back(Ts&&... args)
  213.         {
  214.             _expand(1);
  215.             std::allocator_traits<A>::construct(_alloc, _data + _size, std::forward<Ts>(args)...);
  216.             ++_size;
  217.         }
  218.  
  219.         void pop_back() noexcept
  220.         {
  221.             std::allocator_traits<A>::destroy(_alloc, _data + _size - 1);
  222.             --_size;
  223.         }
  224.  
  225.         template <class U>
  226.         iterator insert(iterator pos, U&& rhs)
  227.         {
  228.             return emplace(pos, std::forward<U>(rhs));
  229.         }
  230.  
  231.         iterator insert(iterator pos, size_type n,
  232.                         const value_type& val)
  233.         {
  234.             const auto rel = pos - begin();
  235.             _expand(n);
  236.             pos = begin() + rel;
  237.  
  238.             for (auto i = end() - 1; i != pos - 1; --i) {
  239.                 *(i + n) = std::move_if_noexcept(*i);
  240.             }
  241.             _size += n;
  242.             for (auto i = pos; i != pos + n; ++i) {
  243.                 *i = val;
  244.             }
  245.             return pos;
  246.         }
  247.  
  248.         template <class InIter,
  249.                     typename = _RequireInputIter<InIter> >
  250.         iterator insert(iterator pos, InIter first, InIter last)
  251.         {
  252.             const auto rel = pos - begin();
  253.             const auto n = std::distance(first, last);
  254.             _expand(n);
  255.             pos = begin() + rel;
  256.  
  257.             for (auto i = end() - 1; i != pos - 1; --i) {
  258.                 *(i + n) = std::move_if_noexcept(*i);
  259.             }
  260.             _size += n;
  261.             for (auto i = pos, j = first; i != pos + n; ++i, ++j) {
  262.                 *i = *j;
  263.             }
  264.             return pos;
  265.         }
  266.  
  267.         iterator insert(iterator pos, std::initializer_list<T> ilist)
  268.         {
  269.             return insert(pos, ilist.begin(), ilist.end());
  270.         }
  271.  
  272.         template <class... Ts>
  273.         iterator emplace(iterator pos, Ts&&... args)
  274.         {
  275.             difference_type rel = pos - begin();
  276.             _expand(1);
  277.             pos = begin() + rel;
  278.             for (iterator i = end(); i != pos; --i) {
  279.                 *i = std::move_if_noexcept(*(i - 1));
  280.             }
  281.             ++_size;
  282.             std::allocator_traits<A>::construct(_alloc, pos, std::forward<Ts...>(args...));
  283.             return const_cast<iterator>(pos);
  284.         }
  285.  
  286.         iterator erase(iterator pos)
  287.         {
  288.             return erase(pos, pos + 1);
  289.         }
  290.  
  291.         iterator erase(iterator first, iterator last)
  292.         {
  293.             {
  294.                 auto i = first;
  295.                 for (auto j = last; j != end(); ++i, ++j) {
  296.                     using std::swap;
  297.                     *i = std::move(*j);
  298.                     //swap(*i, *j);
  299.                 }
  300.                 for (; i != end(); ++i) {
  301.                     std::allocator_traits<A>::destroy(_alloc, i);
  302.                 }
  303.             }
  304.             _size -= std::distance(first, last);
  305.             return first;
  306.         }
  307.  
  308.         void clear() noexcept
  309.         {
  310.             for (auto i = end() - 1; i + 1 != begin(); --i) {
  311.                 std::allocator_traits<A>::destroy(_alloc, i);
  312.             }
  313.             std::allocator_traits<A>::deallocate(_alloc, _data, _capacity);
  314.             _data = nullptr;
  315.             _size = _capacity = 0;
  316.         }
  317.  
  318.         void swap(vector& rhs) noexcept
  319.         {
  320.             using std::swap;
  321.             swap(_size, rhs._size);
  322.             swap(_capacity, rhs._capacity);
  323.             swap(_data, rhs._data);
  324.             swap(_alloc, rhs._alloc);
  325.         }
  326.  
  327.         iterator begin() noexcept
  328.         {
  329.             return _data;
  330.         }
  331.         const_iterator begin() const noexcept
  332.         {
  333.             return _data;
  334.         }
  335.         iterator end() noexcept
  336.         {
  337.             return _data + _size;
  338.         }
  339.         const_iterator end() const noexcept
  340.         {
  341.             return _data + _size;
  342.         }
  343.         const_iterator cbegin() const noexcept
  344.         {
  345.             return _data;
  346.         }
  347.         const_iterator cend() const noexcept
  348.         {
  349.             return _data + _size;
  350.         }
  351.         reverse_iterator rbegin() noexcept
  352.         {
  353.             return reverse_iterator(_data + _size);
  354.         }
  355.         reverse_iterator rend() noexcept
  356.         {
  357.             return reverse_iterator(_data);
  358.         }
  359.         const_reverse_iterator crbegin() const noexcept
  360.         {
  361.             return const_reverse_iterator(_data + _size);
  362.         }
  363.         const_reverse_iterator crend() const noexcept
  364.         {
  365.             return const_reverse_iterator(_data);
  366.         }
  367.  
  368.         value_type* data() noexcept
  369.         {
  370.             return _data;
  371.         }
  372.  
  373.         const value_type* data() const noexcept
  374.         {
  375.             return _data;
  376.         }
  377.  
  378.         constexpr size_type size() const noexcept
  379.         {
  380.             return _size;
  381.         }
  382.  
  383.         constexpr size_type capacity() const noexcept
  384.         {
  385.             return _capacity;
  386.         }
  387.  
  388.         constexpr bool empty() const noexcept
  389.         {
  390.             return !_size;
  391.         }
  392.  
  393.         friend bool operator==(const vector& lhs, const vector& rhs)
  394.         {
  395.             return lhs.size() == rhs.size() &&
  396.                     std::equal(lhs.begin(), lhs.end(), rhs.begin());
  397.         }
  398.         friend bool operator!=(const vector& lhs, const vector& rhs)
  399.         {
  400.             return !(lhs == rhs);
  401.         }
  402.         friend bool operator<(const vector& lhs, const vector& rhs)
  403.         {
  404.             return std::lexicographical_compare(lhs.begin(), lhs.end(),
  405.                                                 rhs.begin(), rhs.end());
  406.         }
  407.         friend bool operator<=(const vector& lhs, const vector& rhs)
  408.         {
  409.             return lhs == rhs || lhs < rhs;
  410.         }
  411.         friend bool operator>(const vector& lhs, const vector& rhs)
  412.         {
  413.             return !(lhs <= rhs);
  414.         }
  415.         friend bool operator>=(const vector& lhs, const vector& rhs)
  416.         {
  417.             return !(lhs < rhs);
  418.         }
  419.  
  420.     private:
  421.         void _force_reserve(size_type n)
  422.         {
  423.             pointer new_data;
  424.             new_data = std::allocator_traits<A>::allocate(_alloc, n);
  425.             for (size_type i = 0; i < _size; ++i) {
  426.                 try {
  427.                     std::allocator_traits<A>::construct(_alloc, new_data + i,
  428.                                      std::move_if_noexcept(_data[i]));
  429.                 } catch (...) {
  430.                     for (size_type j = 0; j < i; ++j)
  431.                         std::allocator_traits<A>::destroy(_alloc, new_data + j);
  432.                     std::allocator_traits<A>::deallocate(_alloc, new_data, n);
  433.                     trow;
  434.                 }
  435.             }
  436.             const auto old_size = _size;
  437.             clear();
  438.  
  439.             _size = old_size;
  440.             _data = new_data;
  441.             _capacity = n;
  442.         }
  443.  
  444.         bool _expand(size_type req_size)
  445.         {
  446.             if (req_size + _size > _capacity) {
  447.                 reserve((req_size + _size) * 2);
  448.                 return true;
  449.             }
  450.             return false;
  451.         }
  452.  
  453.     private:
  454.         size_type _size = 0;
  455.         size_type _capacity = 0;
  456.         pointer _data = nullptr;
  457.         allocator_type _alloc = allocator_type();
  458. };
  459.  
  460. template <class T>
  461. void swap(vector<T>& lhs, vector<T>& rhs) noexcept
  462. {
  463.     lhs.swap(rhs);
  464. }
  465.  
  466. // vim:ts=4:sts=4:sw=4:noexpandtab
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement