Commit c61e82af authored by Gauthier Quesnel's avatar Gauthier Quesnel
Browse files

core: add a small_vector container

parent 7f03786d
......@@ -588,10 +588,184 @@ struct time_domain<time>
/*****************************************************************************
*
* Small string
* Containers
*
****************************************************************************/
/**
* @brief A vector like class but without dynamic allocation.
* @tparam T Any type (trivial or not).
* @tparam length The capacity of the vector.
*/
template<typename T, i32 length>
class small_vector
{
static_assert(length > 1);
std::byte m_buffer[length * sizeof(T)];
i32 m_size;
public:
using iterator = T*;
using const_iterator = const T*;
using size_type = u8;
using reference = T&;
using const_reference = const T&;
constexpr small_vector() noexcept
{
m_size = 0;
}
constexpr small_vector(const small_vector& other) noexcept
: m_size(other.m_size)
{
std::copy_n(other.data(), other.m_size, data());
}
constexpr small_vector& operator=(const small_vector& other) noexcept
{
if (&other != this) {
m_size = other.m_size;
std::copy_n(other.data(), other.m_size, data());
}
return *this;
}
constexpr small_vector(small_vector&& other) noexcept = delete;
constexpr small_vector& operator=(small_vector&& other) noexcept = delete;
constexpr T* data() noexcept
{
return reinterpret_cast<T*>(&m_buffer[0]);
}
constexpr const T* data() const noexcept
{
return reinterpret_cast<const T*>(&m_buffer[0]);
}
constexpr reference operator[](const sz index) noexcept
{
irt_assert(index < static_cast<sz>(m_size));
return data()[index];
}
constexpr const_reference operator[](const sz index) const noexcept
{
irt_assert(index < static_cast<sz>(m_size));
return data()[index];
}
constexpr iterator begin() noexcept
{
return data();
}
constexpr const_iterator begin() const noexcept
{
return data();
}
constexpr iterator end() noexcept
{
return data() + m_size;
}
constexpr const_iterator end() const noexcept
{
return data() + m_size;
}
constexpr sz size() const noexcept
{
return static_cast<sz>(m_size);
}
constexpr i32 ssize() const noexcept
{
return m_size;
}
constexpr sz capacity() const noexcept
{
return static_cast<sz>(length);
}
constexpr bool empty() const noexcept
{
return m_size == 0;
}
constexpr bool full() const noexcept
{
return m_size >= length;
}
constexpr void clear() noexcept
{
if constexpr (!std::is_trivial_v<T>) {
for (i32 i = 0; i != m_size; ++i)
data()[i].~T();
}
m_size = 0;
}
constexpr bool can_alloc() noexcept
{
return m_size < length - 1;
}
constexpr bool can_alloc(i32 number) noexcept
{
return length - m_size >= number;
}
template<typename... Args>
constexpr reference alloc(Args&&... args) noexcept
{
assert(can_alloc(1) && "check alloc() with full() before using use.");
new (&(data()[m_size])) T(std::forward<Args>(args)...);
++m_size;
return data()[m_size - 1];
}
constexpr void pop_back() noexcept
{
if (m_size) {
if constexpr (std::is_trivial_v<T>)
data()[m_size - 1].~T();
--m_size;
}
}
constexpr void swap_pop_back(sz index) noexcept
{
irt_assert(index < m_size);
if (index == m_size - 1) {
pop_back();
} else {
if constexpr (std::is_trivial_v<T>) {
data()[index] = data()[m_size - 1];
pop_back();
} else {
using std::swap;
swap(data()[index], data()[m_size - 1]);
pop_back();
}
}
}
};
template<size_t length = 8>
class small_string
{
......@@ -1208,6 +1382,28 @@ public:
return node->value;
}
reference operator[](sz index) noexcept
{
sz i = 0;
for (auto it = begin(), et = end(); it != et; ++it, ++i)
if (i == index)
return *it;
irt_unreachable();
}
const_reference operator[](sz index) const noexcept
{
sz i = 0;
for (auto it = begin(), et = end(); it != et; ++it, ++i)
if (i == index)
return *it;
irt_unreachable();
}
template<typename... Args>
iterator emplace_front(allocator_type& allocator, Args&&... args) noexcept
{
......
......@@ -502,6 +502,90 @@ main()
irt::time_domain<irt::time>::negative_infinity);
};
"small-vector<T>"_test = [] {
irt::small_vector<int, 8> v;
expect(v.empty());
expect(v.capacity() == 8);
v.alloc(0);
v.alloc(1);
v.alloc(2);
v.alloc(3);
v.alloc(4);
v.alloc(5);
v.alloc(6);
v.alloc(7);
expect(v.size() == 8);
expect(v.full());
expect(!v.empty());
expect(v[0] == 0);
expect(v[1] == 1);
expect(v[2] == 2);
expect(v[3] == 3);
expect(v[4] == 4);
expect(v[5] == 5);
expect(v[6] == 6);
expect(v[7] == 7);
v.swap_pop_back(0);
expect(v.size() == 7);
expect(!v.full());
expect(!v.empty());
expect(v[0] == 7);
expect(v[1] == 1);
expect(v[2] == 2);
expect(v[3] == 3);
expect(v[4] == 4);
expect(v[5] == 5);
expect(v[6] == 6);
v.swap_pop_back(6);
expect(v.size() == 6);
expect(!v.full());
expect(!v.empty());
expect(v[0] == 7);
expect(v[1] == 1);
expect(v[2] == 2);
expect(v[3] == 3);
expect(v[4] == 4);
expect(v[5] == 5);
irt::small_vector<int, 8> v2;
v2 = v;
v2[0] *= 2;
expect(v2[0] == 14);
expect(v2[1] == 1);
expect(v2[2] == 2);
expect(v2[3] == 3);
expect(v2[4] == 4);
expect(v2[5] == 5);
};
"small-vector-no-trivial"_test = [] {
struct toto
{
int i;
toto(int i_)
: i(i_)
{}
~toto()
{
i = 0;
}
};
irt::small_vector<toto, 4> v;
v.alloc(10);
v.clear();
expect(v.data()[0].i == 0);
irt::small_vector<toto, 4> v2 = v;
v2.alloc(10);
expect(v.data()[0].i == 0);
expect(v2.data()[0].i == 10);
};
"small_string"_test = [] {
irt::small_string<8> f1;
expect(f1.capacity() == 8_ul);
......@@ -1057,7 +1141,9 @@ main()
}
{
std::string string_error{ "0 0 0 0\n1\n0 5 6 qss1_integrator A B C\n" };
std::string string_error{
"0 0 0 0\n1\n0 5 6 qss1_integrator A B C\n"
};
std::istringstream is{ string_error };
irt::simulation sim;
irt::external_source srcs;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment