// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*- // vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi #ifndef CTL_VECTOR_H_ #define CTL_VECTOR_H_ #include "allocator.h" #include "allocator_traits.h" #include "copy.h" #include "distance.h" #include "equal.h" #include "fill_n.h" #include "initializer_list.h" #include "iterator_traits.h" #include "lexicographical_compare.h" #include "max.h" #include "move_backward.h" #include "move_iterator.h" #include "out_of_range.h" #include "require_input_iterator.h" #include "reverse_iterator.h" #include "uninitialized_fill.h" #include "uninitialized_fill_n.h" #include "uninitialized_move_n.h" namespace ctl { template> class vector { public: using value_type = T; using allocator_type = Allocator; using size_type = size_t; using difference_type = ptrdiff_t; using reference = value_type&; using const_reference = const value_type&; using pointer = typename ctl::allocator_traits::pointer; using const_pointer = typename ctl::allocator_traits::const_pointer; using iterator = pointer; using const_iterator = const_pointer; using reverse_iterator = ctl::reverse_iterator; using const_reverse_iterator = ctl::reverse_iterator; public: vector() noexcept(noexcept(Allocator())) : alloc_(), data_(nullptr), size_(0), capacity_(0) { } explicit vector(const Allocator& alloc) noexcept : alloc_(alloc), data_(nullptr), size_(0), capacity_(0) { } vector(size_type count, const T& value, const Allocator& alloc = Allocator()) : alloc_(alloc), data_(nullptr), size_(0), capacity_(0) { assign(count, value); } explicit vector(size_type count, const Allocator& alloc = Allocator()) : alloc_(alloc), data_(nullptr), size_(0), capacity_(0) { resize(count); } template> vector(InputIt first, InputIt last, const Allocator& alloc = Allocator()) : alloc_(alloc), data_(nullptr), size_(0), capacity_(0) { assign(first, last); } vector(const vector& other) : alloc_(ctl::allocator_traits< Allocator>::select_on_container_copy_construction(other.alloc_)) , data_(nullptr) , size_(0) , capacity_(0) { assign(other.begin(), other.end()); } vector(const vector& other, const Allocator& alloc) : alloc_(alloc), data_(nullptr), size_(0), capacity_(0) { assign(other.begin(), other.end()); } vector(vector&& other) noexcept : alloc_(ctl::move(other.alloc_)) , data_(other.data_) , size_(other.size_) , capacity_(other.capacity_) { other.data_ = nullptr; other.size_ = 0; other.capacity_ = 0; } vector(vector&& other, const Allocator& alloc) : alloc_(alloc), data_(nullptr), size_(0), capacity_(0) { if (alloc_ == other.alloc_) { data_ = other.data_; size_ = other.size_; capacity_ = other.capacity_; other.data_ = nullptr; other.size_ = 0; other.capacity_ = 0; } else { assign(ctl::make_move_iterator(other.begin()), ctl::make_move_iterator(other.end())); } } vector(std::initializer_list init, const Allocator& alloc = Allocator()) : alloc_(alloc), data_(nullptr), size_(0), capacity_(0) { assign(init.begin(), init.end()); } ~vector() { clear(); ctl::allocator_traits::deallocate(alloc_, data_, capacity_); } vector& operator=(const vector& other) { if (this != &other) { if (ctl::allocator_traits< Allocator>::propagate_on_container_copy_assignment::value) alloc_ = other.alloc_; assign(other.begin(), other.end()); } return *this; } vector& operator=(vector&& other) noexcept( ctl::allocator_traits::is_always_equal::value) { if (this != &other) { clear(); ctl::allocator_traits::deallocate( alloc_, data_, capacity_); if (ctl::allocator_traits< Allocator>::propagate_on_container_move_assignment::value) alloc_ = ctl::move(other.alloc_); data_ = other.data_; size_ = other.size_; capacity_ = other.capacity_; other.data_ = nullptr; other.size_ = 0; other.capacity_ = 0; } return *this; } vector& operator=(std::initializer_list ilist) { assign(ilist.begin(), ilist.end()); return *this; } void assign(size_type count, const T& value) { clear(); if (count > capacity_) reallocate(count); ctl::uninitialized_fill_n(data_, count, value); size_ = count; } template> void assign(InputIt first, InputIt last) { clear(); for (; first != last; ++first) push_back(*first); } void assign(std::initializer_list ilist) { assign(ilist.begin(), ilist.end()); } reference at(size_type pos) { if (pos >= size_) throw ctl::out_of_range(); return data_[pos]; } const_reference at(size_type pos) const { if (pos >= size_) throw ctl::out_of_range(); return data_[pos]; } reference operator[](size_type pos) { if (pos >= size_) __builtin_trap(); return data_[pos]; } const_reference operator[](size_type pos) const { if (pos >= size_) __builtin_trap(); return data_[pos]; } reference front() { return data_[0]; } const_reference front() const { return data_[0]; } reference back() { return data_[size_ - 1]; } const_reference back() const { return data_[size_ - 1]; } T* data() noexcept { return data_; } const T* data() const noexcept { return data_; } iterator begin() noexcept { return data_; } const_iterator begin() const noexcept { return data_; } const_iterator cbegin() const noexcept { return data_; } iterator end() noexcept { return data_ + size_; } const_iterator end() const noexcept { return data_ + size_; } const_iterator cend() const noexcept { return data_ + size_; } reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); } reverse_iterator rend() noexcept { return reverse_iterator(begin()); } const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); } bool empty() const noexcept { return size_ == 0; } size_type size() const noexcept { return size_; } size_type max_size() const noexcept { return __PTRDIFF_MAX__; } size_type capacity() const noexcept { return capacity_; } void reserve(size_type new_cap) { if (new_cap > capacity_) reallocate(new_cap); } void shrink_to_fit() { if (size_ < capacity_) reallocate(size_); } void clear() noexcept { for (size_type i = 0; i < size_; ++i) ctl::allocator_traits::destroy(alloc_, data_ + i); size_ = 0; } iterator insert(const_iterator pos, const T& value) { return insert(pos, 1, value); } iterator insert(const_iterator pos, T&& value) { difference_type index = pos - begin(); if (size_ == capacity_) grow(); iterator it = begin() + index; ctl::move_backward(it, end(), end() + 1); *it = ctl::move(value); ++size_; return it; } iterator insert(const_iterator pos, size_type count, const T& value) { difference_type index = pos - begin(); if (size_ + count > capacity_) reallocate(ctl::max(size_ + count, capacity_ * 2)); iterator it = begin() + index; ctl::move_backward(it, end(), end() + count); ctl::fill_n(it, count, value); size_ += count; return it; } template> iterator insert(const_iterator pos, InputIt first, InputIt last) { difference_type count = ctl::distance(first, last); difference_type index = pos - begin(); if (size_ + count > capacity_) reallocate(ctl::max(size_ + count, capacity_ * 2)); iterator it = begin() + index; ctl::move_backward(it, end(), end() + count); ctl::copy(first, last, it); size_ += count; return it; } iterator insert(const_iterator pos, std::initializer_list ilist) { return insert(pos, ilist.begin(), ilist.end()); } template iterator emplace(const_iterator pos, Args&&... args) { difference_type index = pos - begin(); if (size_ == capacity_) grow(); iterator it = begin() + index; ctl::move_backward(it, end(), end() + 1); ctl::allocator_traits::construct( alloc_, it, ctl::forward(args)...); ++size_; return it; } iterator erase(const_iterator pos) { return erase(pos, pos + 1); } constexpr iterator erase(const_iterator first, const_iterator last) { difference_type index = first - begin(); difference_type count = last - first; iterator it = begin() + index; for (iterator move_it = it + count; move_it != end(); ++move_it, ++it) *it = ctl::move(*move_it); for (difference_type i = 0; i < count; ++i) ctl::allocator_traits::destroy(alloc_, end() - i - 1); size_ -= count; return begin() + index; } void push_back(const T& value) { if (size_ == capacity_) grow(); ctl::allocator_traits::construct( alloc_, data_ + size_, value); ++size_; } void push_back(T&& value) { if (size_ == capacity_) grow(); ctl::allocator_traits::construct( alloc_, data_ + size_, ctl::move(value)); ++size_; } template reference emplace_back(Args&&... args) { if (size_ == capacity_) grow(); ctl::allocator_traits::construct( alloc_, data_ + size_, ctl::forward(args)...); return data_[size_++]; } void pop_back() { if (!empty()) { ctl::allocator_traits::destroy(alloc_, data_ + size_ - 1); --size_; } } void resize(size_type count) { resize(count, T()); } void resize(size_type count, const value_type& value) { if (count > size_) { if (count > capacity_) reallocate(count); ctl::uninitialized_fill(data_ + size_, data_ + count, value); } else if (count < size_) { for (size_type i = count; i < size_; ++i) ctl::allocator_traits::destroy(alloc_, data_ + i); } size_ = count; } void swap(vector& other) noexcept( ctl::allocator_traits::is_always_equal::value) { using ctl::swap; swap(alloc_, other.alloc_); swap(data_, other.data_); swap(size_, other.size_); swap(capacity_, other.capacity_); } allocator_type get_allocator() const noexcept { return alloc_; } private: void grow() { size_type c2; c2 = capacity_; if (c2 < 4) c2 = 4; c2 += c2 >> 1; reallocate(c2); } void reallocate(size_type new_capacity) { pointer new_data = ctl::allocator_traits::allocate(alloc_, new_capacity); size_type new_size = size_ < new_capacity ? size_ : new_capacity; try { ctl::uninitialized_move_n(data_, new_size, new_data); } catch (...) { ctl::allocator_traits::deallocate( alloc_, new_data, new_capacity); throw; } for (size_type i = 0; i < size_; ++i) ctl::allocator_traits::destroy(alloc_, data_ + i); ctl::allocator_traits::deallocate(alloc_, data_, capacity_); data_ = new_data; size_ = new_size; capacity_ = new_capacity; } [[no_unique_address]] Allocator alloc_; pointer data_; size_type size_; size_type capacity_; }; template bool operator==(const vector& lhs, const vector& rhs) { return lhs.size() == rhs.size() && ctl::equal(lhs.begin(), lhs.end(), rhs.begin()); } template bool operator!=(const vector& lhs, const vector& rhs) { return !(lhs == rhs); } template bool operator<(const vector& lhs, const vector& rhs) { return ctl::lexicographical_compare( lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); } template bool operator<=(const vector& lhs, const vector& rhs) { return !(rhs < lhs); } template bool operator>(const vector& lhs, const vector& rhs) { return rhs < lhs; } template bool operator>=(const vector& lhs, const vector& rhs) { return !(lhs < rhs); } template void swap(vector& lhs, vector& rhs) noexcept(noexcept(lhs.swap(rhs))) { lhs.swap(rhs); } template::value_type>> vector(InputIt, InputIt, Alloc = Alloc()) -> vector::value_type, Alloc>; template vector(size_t, const typename ctl::allocator_traits::value_type&, Alloc = Alloc()) -> vector::value_type, Alloc>; } // namespace ctl #endif // CTL_VECTOR_H_