#pragma once #if !defined(BAD_APPLE_OS_VECTOR_INCLUDED) #define BAD_APPLE_OS_VECTOR_INCLUDED #include #include #include #include #include #include namespace std { template> class vector { public: using value_type = T; using size_type = size_t; using difference_type = ptrdiff_t; using reference = value_type&; using const_reference = const value_type&; using pointer = value_type*; using const_pointer = const value_type*; using iterator = pointer; using const_iterator = const_pointer; private: T* _elements = nullptr; size_type _size = 0; size_type _capacity = 0; Allocator _allocator = {}; public: constexpr vector() noexcept = default; constexpr vector(const vector& other) noexcept : _allocator(other._allocator) { resize(other.size()); for (size_type idx = 0; idx < size(); ++idx) { (*this)[idx] = other[idx]; } } constexpr vector(vector&& other) noexcept : _elements(exchange(other._elements, nullptr)), _size(exchange(other._size, 0)), _capacity(exchange(other._capacity, 0)), _allocator(exchange(other._allocator, {})) { } constexpr explicit vector(const Allocator& allocator) noexcept : _allocator(allocator) {} constexpr explicit vector(size_type count, const value_type& value = value_type(), const Allocator& allocator = {}) : _allocator(allocator) { resize(count, value); } constexpr ~vector() noexcept { for (size_type idx = 0; idx < size(); ++idx) { _elements[idx].~T(); } _allocator.deallocate(_elements, _capacity); } constexpr vector& operator=(const vector& other) { if (this == &other) { return *this; } resize(other.size()); for (size_type idx = 0; idx < size(); ++idx) { (*this)[idx] = other[idx]; } return *this; } constexpr vector& operator=(vector&& other) { if (this == &other) { return *this; } clear(); _elements = exchange(other._elements, nullptr); _size = exchange(other._size, 0); _capacity = exchange(other._capacity, 0); return *this; } [[nodiscard]] constexpr reference operator[](size_type pos) noexcept { return _elements[pos]; } [[nodiscard]] constexpr const_reference operator[](size_type pos) const noexcept { return _elements[pos]; } [[nodiscard]] constexpr reference at(size_type pos) { if (pos >= size()) { __ba_throw out_of_range(); } return _elements[pos]; } [[nodiscard]] constexpr const_reference at(size_type pos) const { if (pos >= size()) { __ba_throw out_of_range(); } return _elements[pos]; } [[nodiscard]] constexpr reference front() noexcept { return _elements[0]; } [[nodiscard]] constexpr const_reference front() const noexcept { return _elements[0]; } [[nodiscard]] constexpr reference back() noexcept { return _elements[size() - 1]; } [[nodiscard]] constexpr const_reference back() const noexcept { return _elements[size() - 1]; } [[nodiscard]] constexpr pointer data() noexcept { return _elements; } [[nodiscard]] constexpr const_pointer data() const noexcept { return _elements; } [[nodiscard]] constexpr iterator begin() noexcept { return _elements; } [[nodiscard]] constexpr const_iterator begin() const noexcept { return _elements; } [[nodiscard]] constexpr const_iterator cbegin() const noexcept { return _elements; } [[nodiscard]] constexpr iterator end() noexcept { return &_elements[size()]; } [[nodiscard]] constexpr const_iterator end() const noexcept { return &_elements[size()]; } [[nodiscard]] constexpr const_iterator cend() const noexcept { return &_elements[size()]; } [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0; } [[nodiscard]] constexpr size_type size() const noexcept { return _size; } [[nodiscard]] constexpr size_type max_size() const noexcept { return size_type(-1); } constexpr void reserve(size_type newCapacity) { if (newCapacity <= capacity()) { return; } updateCapacity(newCapacity); } [[nodiscard]] size_type capacity() const noexcept { return _capacity; } constexpr void shrink_to_fit() { updateCapacity(size()); } constexpr void clear() { resize(0); } constexpr void push_back(const value_type& value) { reserve(size() + 1); ::new (&_elements[size()]) T(value); ++_size; } constexpr void push_back(value_type&& value) { reserve(size() + 1); ::new (&_elements[size()]) T(move(value)); ++_size; } constexpr void pop_back() noexcept { resize(size() - 1); } template constexpr reference emplace_back(TArgs&&... args) { reserve(size() + 1); ::new (&_elements[size()]) T(forward(args)...); ++_size; } constexpr void resize(size_type newSize) { if (newSize == size()) { return; } reserve(newSize); if (newSize > size()) { for (size_type idx = size(); idx < newSize; ++idx) { ::new (&_elements[idx]) T(); } } else { for (size_type idx = newSize; idx < size(); ++idx) { _elements[idx].~T(); } } _size = newSize; } constexpr void resize(size_type newSize, const value_type& initValue) { if (newSize == size()) { return; } reserve(newSize); if (newSize > size()) { for (size_type idx = size(); idx < newSize; ++idx) { ::new (&_elements[idx]) T(initValue); } } else { for (size_type idx = newSize; idx < size(); ++idx) { _elements[idx].~T(); } } _size = newSize; } constexpr iterator erase(const_iterator first, const_iterator last) { // the spec wants the parameters to be const iterators... iterator realFirst = begin() + (first - begin()); iterator realLast = begin() + (last - begin()); const size_t newSize = size() - (last - first); for (auto it = realLast; it != end(); ++it) { *realFirst = move(*it); ++realFirst; } resize(newSize); return realFirst; } constexpr iterator erase(const_iterator pos) { return erase(pos, pos + 1); } private: void updateCapacity(size_type newCapacity) { if (capacity() == newCapacity) { return; } T* newElements = _allocator.allocate(newCapacity * sizeof(T)); if (newElements == nullptr) { __ba_throw bad_alloc(); } for (size_type idx = 0; idx < size(); ++idx) { ::new (&newElements[idx]) T(move(_elements[idx])); _elements[idx].~T(); } _allocator.deallocate(_elements, _capacity); _elements = newElements; _capacity = newCapacity; } }; template constexpr vector::size_type erase_if(vector& vec, Pred pred) { auto it = remove_if(vec.begin(), vec.end(), pred); auto removed = vec.end() - it; vec.erase(it, vec.end()); return removed; } } #endif // !defined(BAD_APPLE_OS_VECTOR_INCLUDED)