292 lines
6.5 KiB
Plaintext

#pragma once
#if !defined(BAD_APPLE_OS_VECTOR_INCLUDED)
#define BAD_APPLE_OS_VECTOR_INCLUDED
#include <cstddef>
#include <new>
#include <stdexcept>
#include <utility>
namespace std
{
template<typename T> // TODO: allocator
class vector
{
public:
using value_type = T;
using size_type = std::size_t;
using difference_type = std::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;
public:
constexpr vector() noexcept = default;
constexpr vector(const vector& other) noexcept
{
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))
{
}
constexpr explicit vector(size_type count, const value_type& value = value_type())
{
resize(count, value);
}
constexpr ~vector() noexcept
{
delete _elements;
}
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(std::move(value));
++_size;
}
template<typename... TArgs>
constexpr reference emplace_back(TArgs&&... args)
{
reserve(size() + 1);
::new (&_elements[size()]) T(std::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;
}
private:
void updateCapacity(size_type newCapacity)
{
if (capacity() == newCapacity) {
return;
}
T* newElements = static_cast<T*>(malloc(newCapacity * sizeof(T)));
for (size_type idx = 0; idx < size(); ++idx)
{
::new (&newElements[idx]) T(move(_elements[idx]));
_elements[idx].~T();
}
free(_elements);
_elements = newElements;
_capacity = newCapacity;
}
};
}
#endif // !defined(BAD_APPLE_OS_VECTOR_INCLUDED)