Luna/kernel/include/utils/Dynamic.h

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));
}
};