Add srb2::Vector

This commit is contained in:
Eidolon 2024-12-13 10:44:19 -06:00
parent 28e4440bb0
commit 8e7de22df5
3 changed files with 423 additions and 0 deletions

View file

@ -5,4 +5,6 @@ target_sources(SRB2SDL2 PRIVATE
static_vec.hpp
thread_pool.cpp
thread_pool.h
vector.cpp
vector.hpp
)

58
src/core/vector.cpp Normal file
View file

@ -0,0 +1,58 @@
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2025 by Ronald "Eidolon" Kinard
// Copyright (C) 2025 by Kart Krew
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
#include "vector.hpp"
#include <algorithm>
#include <cstddef>
#include <memory>
namespace srb2
{
AbstractVector::GrowResult AbstractVector::_realloc_mem(void* data, size_t size, size_t old_cap, size_t elem_size, Move move, size_t cap) noexcept
{
GrowResult ret;
std::allocator<uint8_t> allocator;
if (old_cap == 0)
{
cap = std::max<size_t>(cap, 1);
ret.data = allocator.allocate(cap * elem_size + sizeof(std::max_align_t));
ret.cap = cap;
return ret;
}
cap = std::max<size_t>(cap, old_cap * 2);
ret.data = allocator.allocate(cap * elem_size + sizeof(std::max_align_t));
(move)(ret.data, data, size);
allocator.deallocate(reinterpret_cast<uint8_t*>(data), old_cap * elem_size + sizeof(std::max_align_t));
ret.cap = cap;
return ret;
}
void AbstractVector::_free_mem(void* data, size_t cap, size_t elem_size) noexcept
{
std::allocator<uint8_t> allocator;
allocator.deallocate(reinterpret_cast<uint8_t*>(data), cap * elem_size + sizeof(std::max_align_t));
}
template class Vector<bool>;
template class Vector<std::byte>;
template class Vector<uint8_t>;
template class Vector<uint16_t>;
template class Vector<uint32_t>;
template class Vector<uint64_t>;
template class Vector<int8_t>;
template class Vector<int16_t>;
template class Vector<int32_t>;
template class Vector<int64_t>;
} // namespace srb2

363
src/core/vector.hpp Normal file
View file

@ -0,0 +1,363 @@
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2025 by Ronald "Eidolon" Kinard
// Copyright (C) 2025 by Kart Krew
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
#ifndef SRB2_CORE_VEC_HPP
#define SRB2_CORE_VEC_HPP
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <initializer_list>
#include <iterator>
#include <type_traits>
#include <utility>
namespace srb2
{
class AbstractVector
{
protected:
size_t size_;
size_t capacity_;
size_t elem_size_;
void* data_;
using Move = void(*)(void* dst, void* src, size_t size);
template <typename T>
static void _move(void* dst, void* src, size_t size) noexcept
{
T* d = (T*)dst;
T* s = (T*)src;
for (size_t i = 0; i < size; i++)
{
new (&d[i]) T(std::move(s[i]));
}
}
struct GrowResult
{
void* data;
size_t cap;
};
static GrowResult _realloc_mem(void* data, size_t size, size_t old_cap, size_t elem_size, Move move, size_t cap) noexcept;
static void _free_mem(void* data, size_t cap, size_t elem_size) noexcept;
template <typename T>
void _reserve_mem(size_t c) noexcept
{
if (c > capacity_)
{
GrowResult r = _realloc_mem(data_, size_, capacity_, elem_size_, _move<T>, c);
data_ = r.data;
capacity_ = r.cap;
}
}
constexpr AbstractVector() : size_(0), capacity_(0), elem_size_(0), data_(nullptr) {}
};
template <typename T>
class Vector : AbstractVector
{
public:
// iter traits
using value_type = T;
using size_type = size_t;
using difference_type = ptrdiff_t;
using reference = T&;
using const_reference = const T&;
using pointer = T*;
using const_pointer = const T*;
using iterator = T*;
using const_iterator = const T*;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
Vector() : AbstractVector()
{
elem_size_ = sizeof(T);
}
Vector(const Vector& rhs) : Vector()
{
*this = rhs;
}
Vector(Vector&& rhs) noexcept : AbstractVector()
{
elem_size_ = sizeof(T);
*this = std::move(rhs);
}
~Vector()
{
if (data_)
{
for (size_type i = 0; i < size_; i++)
{
((T*)(data_))[(size_ - i - 1)].~T();
}
_free_mem(data_, capacity_, elem_size_);
}
data_ = nullptr;
}
explicit Vector(size_type capacity) : AbstractVector()
{
elem_size_ = sizeof(T);
_reserve_mem<T>(capacity);
}
Vector(std::initializer_list<T> l) : AbstractVector()
{
elem_size_ = sizeof(T);
if (l.size() == 0)
{
return;
}
_reserve_mem<T>(l.size());
for (auto itr = l.begin(); itr != l.end(); itr++)
{
emplace_back(*itr);
}
}
template <
typename It,
typename std::enable_if_t<
std::is_constructible_v<
T,
typename std::iterator_traits<It>::reference
>,
int
> = 0
>
Vector(It begin, It end) : AbstractVector()
{
elem_size_ = sizeof(T);
for (auto itr = begin; itr != end; ++itr)
{
push_back(*itr);
}
}
Vector& operator=(const Vector& rhs)
{
for (auto itr = rhs.begin(); itr != rhs.end(); itr++)
{
push_back(*itr);
}
return *this;
}
Vector& operator=(Vector&& rhs) noexcept
{
std::swap(size_, rhs.size_);
std::swap(capacity_, rhs.capacity_);
std::swap(data_, rhs.data_);
return *this;
}
constexpr size_type size() const noexcept { return size_; }
constexpr size_type capacity() const noexcept { return capacity_; }
constexpr bool empty() const noexcept { return size_ == 0; }
constexpr T* data() noexcept { return (T*) data_; }
constexpr const T* data() const noexcept { return (const T*) data_; }
constexpr T* begin() noexcept { return data(); }
constexpr const T* begin() const noexcept { return data(); }
constexpr T* end() noexcept { return data() + size(); }
constexpr const T* end() const noexcept { return data() + size(); }
constexpr const T* cbegin() const noexcept { return data(); }
constexpr const T* cend() const noexcept { return end(); }
constexpr auto rbegin() noexcept { return std::reverse_iterator(end()); }
constexpr auto rbegin() const noexcept { return std::reverse_iterator(end()); }
constexpr auto rend() noexcept { return std::reverse_iterator(begin()); }
constexpr auto rend() const noexcept { return std::reverse_iterator(begin()); }
constexpr auto crbegin() const noexcept { return rbegin(); }
constexpr auto crend() const noexcept { return rend(); }
T& front() noexcept { return data()[0]; }
const T& front() const noexcept { return data()[0]; }
T& back() noexcept { return data()[size() - 1]; }
const T& back() const noexcept { return data()[size() - 1]; }
void push_back(const T& t)
{
reserve(size() + 1);
new (&data()[size()]) T(t);
size_++;
}
void push_back(T&& t)
{
reserve(size() + 1);
new (&data()[size()]) T(std::move(t));
size_++;
}
void pop_back()
{
T* end = &data()[size() - 1];
end->~T();
size_--;
}
void clear() { for (auto& x : *this) x.~T(); size_ = 0; }
void reserve(size_type c)
{
_reserve_mem<T>(c);
}
void resize(size_type s)
{
resize(s, T());
}
void resize(size_type s, const T& value)
{
if (s <= size())
{
auto itr_begin = rbegin();
auto itr_end = std::prev(rend(), s);
size_t count_destroyed = 0;
for (auto itr = itr_begin; itr != itr_end; itr++)
{
itr->~T();
count_destroyed++;
}
size_ = s;
}
else
{
reserve(s);
size_type oldsize = size();
size_ = s;
for (auto itr = std::next(begin(), oldsize); itr != end(); itr++)
{
try
{
new (itr) T(value);
}
catch (...)
{
size_ = oldsize;
std::rethrow_exception(std::current_exception());
}
}
}
}
const T& at(size_type i) const { if (i >= size()) throw std::out_of_range("index out of range"); return data()[i]; }
T& at(size_type i) { if (i >= size()) throw std::out_of_range("index out of range"); return data()[i]; }
T& operator[](size_type i) { return data()[i]; }
const T& operator[](size_type i) const { return data()[i]; }
iterator erase(const_iterator first) { return erase(first, first + 1); }
iterator erase(const_iterator first, const_iterator last)
{
iterator firstm = const_cast<iterator>(first);
iterator lastm = const_cast<iterator>(last);
if (first == last) return firstm;
auto diff = last - first;
if (last != end()) std::move(lastm, end(), firstm);
resize(size_ - diff);
return firstm;
}
iterator insert(const_iterator pos, const T& value)
{
return insert(pos, (size_type)1, std::forward<const T&>(value));
}
iterator insert(const_iterator pos, T&& value)
{
size_type oldsize = size();
difference_type offs = pos - data();
push_back(std::move(value));
std::rotate(data() + offs, data() + oldsize, data() + size());
return data() + offs;
}
iterator insert(const_iterator pos, size_type count, const T& value)
{
size_type oldsize = size();
difference_type offs = pos - data();
reserve(oldsize + count);
T* d = data();
for (uint32_t i = 0; i < count; i++)
{
// must be copy-initialized;
// value is currently uninitialized
new ((T*)(&d[oldsize + i])) T(value);
}
size_ = oldsize + count;
std::rotate(d + offs, d + oldsize, d + (oldsize + count));
return data() + offs;
}
template <
class InputIt,
typename std::enable_if_t<
std::is_constructible<
T,
typename std::iterator_traits<InputIt>::reference
>::value,
int
> = 0
>
iterator insert(const_iterator pos, InputIt first, InputIt last)
{
size_type oldsize = size();
difference_type offs = pos - data();
size_type count = 0;
while (first != last)
{
push_back(*first);
++first;
++count;
}
std::rotate(data() + offs, data() + oldsize, data() + (oldsize + count));
return data() + offs;
}
template <typename... A>
iterator emplace(const_iterator position, A&&... args)
{
return insert(position, T(std::forward<A>(args)...));
}
template <typename... A>
T& emplace_back(A&&... args)
{
reserve(size() + 1);
new (&data()[size()]) T(std::forward<A>(args)...);
size_++;
return (*this)[size_ - 1];
}
};
extern template class Vector<bool>;
extern template class Vector<std::byte>;
extern template class Vector<uint8_t>;
extern template class Vector<uint16_t>;
extern template class Vector<uint32_t>;
extern template class Vector<uint64_t>;
extern template class Vector<int8_t>;
extern template class Vector<int16_t>;
extern template class Vector<int32_t>;
extern template class Vector<int64_t>;
} // namespace srb2
#endif // SRB2_CORE_VEC_HPP