mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Add srb2::Vector
This commit is contained in:
parent
28e4440bb0
commit
8e7de22df5
3 changed files with 423 additions and 0 deletions
|
|
@ -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
58
src/core/vector.cpp
Normal 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
363
src/core/vector.hpp
Normal 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
|
||||
Loading…
Add table
Reference in a new issue