167 lines
3.1 KiB
C
167 lines
3.1 KiB
C
|
#pragma once
|
||
|
#include "log/Log.h"
|
||
|
#include "std/ensure.h"
|
||
|
#include "std/stdlib.h"
|
||
|
#include "std/string.h"
|
||
|
#include "utils/new.h"
|
||
|
|
||
|
#define __noinline __attribute__((noinline))
|
||
|
|
||
|
template <typename T> struct Dynamic
|
||
|
{
|
||
|
Dynamic()
|
||
|
{
|
||
|
set_expand_rate(16);
|
||
|
ensure(expand_fixed());
|
||
|
}
|
||
|
|
||
|
Dynamic(size_t capacity)
|
||
|
{
|
||
|
set_expand_rate(16);
|
||
|
ensure(expand_fixed());
|
||
|
}
|
||
|
|
||
|
Dynamic(const Dynamic<T>& other)
|
||
|
{
|
||
|
set_expand_rate(other.m_expand_rate);
|
||
|
ensure_capacity(other.capacity());
|
||
|
m_size = other.size();
|
||
|
memcpy(m_buf, other.data(), m_capacity * sizeof(T));
|
||
|
}
|
||
|
|
||
|
Dynamic(Dynamic<T>&& other)
|
||
|
{
|
||
|
set_expand_rate(other.m_expand_rate);
|
||
|
m_buf = other.release_data();
|
||
|
m_capacity = other.capacity();
|
||
|
m_size = other.size();
|
||
|
}
|
||
|
|
||
|
Dynamic<T>& operator=(const Dynamic<T>& other)
|
||
|
{
|
||
|
if (this == &other) return *this;
|
||
|
|
||
|
if (m_buf)
|
||
|
{
|
||
|
while (m_size) pop(); // destroy all objects
|
||
|
kfree(m_buf);
|
||
|
}
|
||
|
|
||
|
set_expand_rate(other.m_expand_rate);
|
||
|
ensure_capacity(other.capacity());
|
||
|
m_size = other.size();
|
||
|
memcpy(m_buf, other.data(), m_capacity * sizeof(T));
|
||
|
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
~Dynamic()
|
||
|
{
|
||
|
if (m_buf)
|
||
|
{
|
||
|
while (m_size) pop(); // destroy all objects
|
||
|
kfree(m_buf);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
T& at(size_t index)
|
||
|
{
|
||
|
ensure(index < m_size);
|
||
|
return m_buf[index];
|
||
|
}
|
||
|
|
||
|
const T& at(size_t index) const
|
||
|
{
|
||
|
ensure(index < m_size);
|
||
|
return m_buf[index];
|
||
|
}
|
||
|
|
||
|
T& operator[](size_t index)
|
||
|
{
|
||
|
return at(index);
|
||
|
}
|
||
|
|
||
|
const T& operator[](size_t index) const
|
||
|
{
|
||
|
return at(index);
|
||
|
}
|
||
|
|
||
|
bool expand_capacity(size_t capacity)
|
||
|
{
|
||
|
return expand(capacity);
|
||
|
}
|
||
|
|
||
|
void ensure_capacity(size_t capacity)
|
||
|
{
|
||
|
ensure(expand(capacity));
|
||
|
}
|
||
|
|
||
|
void set_expand_rate(size_t rate)
|
||
|
{
|
||
|
if (!rate) return;
|
||
|
m_expand_rate = rate;
|
||
|
}
|
||
|
|
||
|
__noinline bool push(const T& item)
|
||
|
{
|
||
|
if (m_size == m_capacity)
|
||
|
if (!expand_fixed()) return false;
|
||
|
m_size++;
|
||
|
T* loc = ptr_at(m_size - 1);
|
||
|
new (loc) T(item);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void pop()
|
||
|
{
|
||
|
at(m_size - 1).~T();
|
||
|
m_size--;
|
||
|
}
|
||
|
|
||
|
size_t capacity() const
|
||
|
{
|
||
|
return m_capacity;
|
||
|
}
|
||
|
|
||
|
size_t size() const
|
||
|
{
|
||
|
return m_size;
|
||
|
}
|
||
|
|
||
|
const T* data() const
|
||
|
{
|
||
|
return m_buf;
|
||
|
}
|
||
|
|
||
|
T* release_data()
|
||
|
{
|
||
|
T* result = m_buf;
|
||
|
m_buf = nullptr;
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
T* m_buf = nullptr;
|
||
|
size_t m_capacity = 0;
|
||
|
size_t m_size = 0;
|
||
|
size_t m_expand_rate = 16;
|
||
|
|
||
|
bool expand(size_t new_capacity)
|
||
|
{
|
||
|
m_buf = (T*)krealloc(m_buf, new_capacity * sizeof(T));
|
||
|
if (!m_buf) return false;
|
||
|
m_capacity = new_capacity;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool expand_fixed()
|
||
|
{
|
||
|
ensure(m_expand_rate != 0);
|
||
|
return expand(m_capacity + m_expand_rate);
|
||
|
}
|
||
|
|
||
|
T* ptr_at(size_t index)
|
||
|
{
|
||
|
return (T*)((char*)m_buf + index * sizeof(T));
|
||
|
}
|
||
|
};
|