341 lines
8.0 KiB
Plaintext
341 lines
8.0 KiB
Plaintext
|
|
#pragma once
|
|
|
|
#if !defined(BAD_APPLE_OS_VECTOR_INCLUDED)
|
|
#define BAD_APPLE_OS_VECTOR_INCLUDED
|
|
|
|
#include <algorithm>
|
|
#include <cstddef>
|
|
#include <memory>
|
|
#include <new>
|
|
#include <stdexcept>
|
|
#include <utility>
|
|
|
|
namespace std
|
|
{
|
|
template<typename T, typename Allocator = allocator<T>>
|
|
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<typename... TArgs>
|
|
constexpr reference emplace_back(TArgs&&... args)
|
|
{
|
|
reserve(size() + 1);
|
|
::new (&_elements[size()]) T(forward<TArgs>(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<typename T, typename TAlloc, typename Pred>
|
|
constexpr vector<T, TAlloc>::size_type erase_if(vector<T, TAlloc>& 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)
|