Correct the name of 'modules' folder to 'libraries'
This commit is contained in:
16
src/libraries/kutil/assert.cpp
Normal file
16
src/libraries/kutil/assert.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#include "assert.h"
|
||||
|
||||
namespace kutil {
|
||||
|
||||
assert_callback __kernel_assert_p = nullptr;
|
||||
|
||||
assert_callback
|
||||
assert_set_callback(assert_callback f)
|
||||
{
|
||||
assert_callback old = __kernel_assert_p;
|
||||
__kernel_assert_p = f;
|
||||
return old;
|
||||
}
|
||||
|
||||
|
||||
} // namespace kutil
|
||||
18
src/libraries/kutil/assert.h
Normal file
18
src/libraries/kutil/assert.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
namespace kutil {
|
||||
|
||||
using assert_callback =
|
||||
void (*) (const char *file, unsigned line, const char *message);
|
||||
|
||||
/// Set the global kernel assert callback
|
||||
/// \args f The new callback
|
||||
/// \returns The old callback
|
||||
assert_callback assert_set_callback(assert_callback f);
|
||||
|
||||
extern assert_callback __kernel_assert_p;
|
||||
|
||||
} // namespace kutil
|
||||
|
||||
|
||||
#define kassert(stmt, message) do { if(!(stmt)) { ::kutil::__kernel_assert_p(__FILE__, __LINE__, (message)); }} while(0);
|
||||
14
src/libraries/kutil/coord.h
Normal file
14
src/libraries/kutil/coord.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
namespace kutil {
|
||||
|
||||
template <typename T>
|
||||
struct coord
|
||||
{
|
||||
T x, y;
|
||||
coord() : x(T{}), y(T{}) {}
|
||||
coord(T x, T y) : x(x), y(y) {}
|
||||
T size() const { return x * y; }
|
||||
};
|
||||
|
||||
} // namespace kutil
|
||||
90
src/libraries/kutil/enum_bitfields.h
Normal file
90
src/libraries/kutil/enum_bitfields.h
Normal file
@@ -0,0 +1,90 @@
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
template<typename E>
|
||||
struct is_enum_bitfield { static constexpr bool value = false; };
|
||||
|
||||
#define IS_BITFIELD(name) \
|
||||
template<> struct ::is_enum_bitfield<name> {static constexpr bool value=true;}
|
||||
|
||||
template <typename E, typename F>
|
||||
typename std::enable_if<is_enum_bitfield<E>::value,E>::type
|
||||
operator & (E lhs, F rhs)
|
||||
{
|
||||
return static_cast<E> (
|
||||
static_cast<typename std::underlying_type<E>::type>(lhs) &
|
||||
static_cast<typename std::underlying_type<E>::type>(rhs));
|
||||
}
|
||||
|
||||
template <typename E, typename F>
|
||||
typename std::enable_if<is_enum_bitfield<E>::value,E>::type
|
||||
operator | (E lhs, F rhs)
|
||||
{
|
||||
return static_cast<E> (
|
||||
static_cast<typename std::underlying_type<E>::type>(lhs) |
|
||||
static_cast<typename std::underlying_type<E>::type>(rhs));
|
||||
}
|
||||
|
||||
template <typename E, typename F>
|
||||
typename std::enable_if<is_enum_bitfield<E>::value,E>::type
|
||||
operator ^ (E lhs, F rhs)
|
||||
{
|
||||
return static_cast<E> (
|
||||
static_cast<typename std::underlying_type<E>::type>(lhs) ^
|
||||
static_cast<typename std::underlying_type<E>::type>(rhs));
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
typename std::enable_if<is_enum_bitfield<E>::value,E>::type
|
||||
operator ~ (E rhs)
|
||||
{
|
||||
return static_cast<E>(~static_cast<typename std::underlying_type<E>::type>(rhs));
|
||||
}
|
||||
|
||||
template <typename E, typename F>
|
||||
typename std::enable_if<is_enum_bitfield<E>::value,E>::type&
|
||||
operator |= (E &lhs, F rhs)
|
||||
{
|
||||
lhs = static_cast<E>(
|
||||
static_cast<typename std::underlying_type<E>::type>(lhs) |
|
||||
static_cast<typename std::underlying_type<E>::type>(rhs));
|
||||
|
||||
return lhs;
|
||||
}
|
||||
|
||||
template <typename E, typename F>
|
||||
typename std::enable_if<is_enum_bitfield<E>::value,E>::type&
|
||||
operator &= (E &lhs, F rhs)
|
||||
{
|
||||
lhs = static_cast<E>(
|
||||
static_cast<typename std::underlying_type<E>::type>(lhs) &
|
||||
static_cast<typename std::underlying_type<E>::type>(rhs));
|
||||
|
||||
return lhs;
|
||||
}
|
||||
|
||||
template <typename E, typename F>
|
||||
typename std::enable_if<is_enum_bitfield<E>::value,E>::type&
|
||||
operator ^= (E &lhs, F rhs)
|
||||
{
|
||||
lhs = static_cast<E>(
|
||||
static_cast<typename std::underlying_type<E>::type>(lhs) ^
|
||||
static_cast<typename std::underlying_type<E>::type>(rhs));
|
||||
|
||||
return lhs;
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
typename std::enable_if<is_enum_bitfield<E>::value,bool>::type
|
||||
operator ! (E rhs)
|
||||
{
|
||||
return static_cast<typename std::underlying_type<E>::type>(rhs) == 0;
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
typename std::enable_if<is_enum_bitfield<E>::value,bool>::type
|
||||
bitfield_has(E set, E flag)
|
||||
{
|
||||
return (set & flag) == flag;
|
||||
}
|
||||
38
src/libraries/kutil/guid.h
Normal file
38
src/libraries/kutil/guid.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
/// \file guid.h
|
||||
/// Definition of the guid type and related functions
|
||||
#include <stdint.h>
|
||||
#include "kutil/misc.h"
|
||||
|
||||
namespace kutil {
|
||||
|
||||
|
||||
/// A GUID
|
||||
struct guid
|
||||
{
|
||||
uint64_t a, b;
|
||||
};
|
||||
|
||||
/// Make a GUID by writing it naturally-ordered in code:
|
||||
/// AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE becomes:
|
||||
/// make_guid(0xAAAAAAAA, 0xBBBB, 0xCCCC, 0xDDDD, 0xEEEEEEEEEEEE);
|
||||
/// \returns The guid object
|
||||
inline constexpr guid make_guid(uint32_t a, uint16_t b, uint16_t c, uint16_t d, uint64_t e)
|
||||
{
|
||||
const uint64_t h =
|
||||
static_cast<uint64_t>(c) << 48 |
|
||||
static_cast<uint64_t>(b) << 32 |
|
||||
a;
|
||||
|
||||
const uint64_t l =
|
||||
static_cast<uint64_t>(byteswap(e & 0xffffffff)) << 32 |
|
||||
(byteswap(e >> 32) & 0xffff0000) |
|
||||
((d << 8) & 0xff00) | ((d >> 8) & 0xff);
|
||||
|
||||
return {h, l};
|
||||
}
|
||||
|
||||
} // namespace kutil
|
||||
|
||||
|
||||
inline bool operator==(const kutil::guid &a, const kutil::guid &b) { return a.a == b.a && a.b == b.b; }
|
||||
28
src/libraries/kutil/memory.cpp
Normal file
28
src/libraries/kutil/memory.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
#include "memory.h"
|
||||
|
||||
void * operator new (size_t, void *p) noexcept { return p; }
|
||||
void * operator new (size_t n) { return kutil::malloc(n); }
|
||||
void * operator new[] (size_t n) { return kutil::malloc(n); }
|
||||
void operator delete (void *p) noexcept { return kutil::free(p); }
|
||||
void operator delete[] (void *p) noexcept { return kutil::free(p); }
|
||||
|
||||
namespace kutil {
|
||||
|
||||
void *
|
||||
memset(void *s, uint8_t v, size_t n)
|
||||
{
|
||||
uint8_t *p = reinterpret_cast<uint8_t *>(s);
|
||||
for (size_t i = 0; i < n; ++i) p[i] = v;
|
||||
return s;
|
||||
}
|
||||
|
||||
void *
|
||||
memcpy(void *dest, void *src, size_t n)
|
||||
{
|
||||
uint8_t *s = reinterpret_cast<uint8_t *>(src);
|
||||
uint8_t *d = reinterpret_cast<uint8_t *>(dest);
|
||||
for (size_t i = 0; i < n; ++i) d[i] = s[i];
|
||||
return d;
|
||||
}
|
||||
|
||||
} // namespace kutil
|
||||
69
src/libraries/kutil/memory.h
Normal file
69
src/libraries/kutil/memory.h
Normal file
@@ -0,0 +1,69 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
using addr_t = uint64_t;
|
||||
|
||||
void * operator new (size_t, void *p) noexcept;
|
||||
|
||||
|
||||
namespace kutil {
|
||||
|
||||
/// Allocate memory. Note: this needs to be implemented
|
||||
/// by the kernel, or other program using this library.
|
||||
/// \arg n The number of bytes to allocate
|
||||
/// \returns The allocated memory
|
||||
void * malloc(size_t n);
|
||||
|
||||
/// Free memory allocated by malloc(). Note: this needs
|
||||
/// to be implemented by the kernel, or other program
|
||||
/// using this library.
|
||||
/// \arg p A pointer previously returned by malloc()
|
||||
void free(void *p);
|
||||
|
||||
/// Fill memory with the given value.
|
||||
/// \arg p The beginning of the memory area to fill
|
||||
/// \arg v The byte value to fill memory with
|
||||
/// \arg n The size in bytes of the memory area
|
||||
/// \returns A pointer to the filled memory
|
||||
void * memset(void *p, uint8_t v, size_t n);
|
||||
|
||||
/// Copy an area of memory to another
|
||||
/// \dest The memory to copy to
|
||||
/// \src The memory to copy from
|
||||
/// \n The number of bytes to copy
|
||||
/// \returns A pointer to the destination memory
|
||||
void * memcpy(void *dest, void *src, size_t n);
|
||||
|
||||
/// Read a value of type T from a location in memory
|
||||
/// \arg p The location in memory to read
|
||||
/// \returns The value at the given location cast to T
|
||||
template <typename T>
|
||||
inline T read_from(const void *p)
|
||||
{
|
||||
return *reinterpret_cast<const T *>(p);
|
||||
}
|
||||
|
||||
/// Get a pointer that's offset from another pointer
|
||||
/// \arg p The base pointer
|
||||
/// \arg n The offset in bytes
|
||||
/// \returns The offset pointer
|
||||
template <typename T>
|
||||
inline T * offset_pointer(T *p, ptrdiff_t n)
|
||||
{
|
||||
return reinterpret_cast<T *>(reinterpret_cast<addr_t>(p) + n);
|
||||
}
|
||||
|
||||
/// Return a pointer with the given bits masked out
|
||||
/// \arg p The original pointer
|
||||
/// \arg mask A bitmask of bits to clear from p
|
||||
/// \returns The masked pointer
|
||||
template <typename T>
|
||||
inline T* mask_pointer(T *p, addr_t mask)
|
||||
{
|
||||
return reinterpret_cast<T *>(reinterpret_cast<addr_t>(p) & ~mask);
|
||||
}
|
||||
|
||||
} // namespace kutil
|
||||
168
src/libraries/kutil/memory_manager.cpp
Normal file
168
src/libraries/kutil/memory_manager.cpp
Normal file
@@ -0,0 +1,168 @@
|
||||
#include <stdint.h>
|
||||
#include "assert.h"
|
||||
#include "memory.h"
|
||||
#include "memory_manager.h"
|
||||
|
||||
namespace kutil {
|
||||
|
||||
|
||||
struct memory_manager::mem_header
|
||||
{
|
||||
mem_header(mem_header *prev, mem_header *next, uint8_t size) :
|
||||
m_prev(prev), m_next(next)
|
||||
{
|
||||
set_size(size);
|
||||
}
|
||||
|
||||
inline void set_size(uint8_t size)
|
||||
{
|
||||
m_prev = reinterpret_cast<mem_header *>(
|
||||
reinterpret_cast<addr_t>(prev()) | (size & 0x3f));
|
||||
}
|
||||
|
||||
inline void set_used(bool used)
|
||||
{
|
||||
m_next = reinterpret_cast<mem_header *>(
|
||||
reinterpret_cast<addr_t>(next()) | (used ? 1 : 0));
|
||||
}
|
||||
|
||||
inline void set_next(mem_header *next)
|
||||
{
|
||||
bool u = used();
|
||||
m_next = next;
|
||||
set_used(u);
|
||||
}
|
||||
|
||||
inline void set_prev(mem_header *prev)
|
||||
{
|
||||
uint8_t s = size();
|
||||
m_prev = prev;
|
||||
set_size(s);
|
||||
}
|
||||
|
||||
void remove()
|
||||
{
|
||||
if (next()) next()->set_prev(prev());
|
||||
if (prev()) prev()->set_next(next());
|
||||
set_prev(nullptr);
|
||||
set_next(nullptr);
|
||||
}
|
||||
|
||||
inline mem_header * next() { return kutil::mask_pointer(m_next, 0x3f); }
|
||||
inline mem_header * prev() { return kutil::mask_pointer(m_prev, 0x3f); }
|
||||
|
||||
inline mem_header * buddy() const {
|
||||
return reinterpret_cast<mem_header *>(
|
||||
reinterpret_cast<addr_t>(this) ^ (1 << size()));
|
||||
}
|
||||
|
||||
inline bool eldest() const { return this < buddy(); }
|
||||
|
||||
inline uint8_t size() const { return reinterpret_cast<addr_t>(m_prev) & 0x3f; }
|
||||
inline bool used() const { return reinterpret_cast<addr_t>(m_next) & 0x1; }
|
||||
|
||||
private:
|
||||
mem_header *m_prev;
|
||||
mem_header *m_next;
|
||||
};
|
||||
|
||||
|
||||
memory_manager::memory_manager() :
|
||||
m_start(nullptr),
|
||||
m_length(0),
|
||||
m_grow(nullptr)
|
||||
{
|
||||
kutil::memset(m_free, 0, sizeof(m_free));
|
||||
}
|
||||
|
||||
memory_manager::memory_manager(void *start, grow_callback grow_cb) :
|
||||
m_start(start),
|
||||
m_length(0),
|
||||
m_grow(grow_cb)
|
||||
{
|
||||
kutil::memset(m_free, 0, sizeof(m_free));
|
||||
grow_memory();
|
||||
}
|
||||
|
||||
void *
|
||||
memory_manager::allocate(size_t length)
|
||||
{
|
||||
size_t total = length + sizeof(mem_header);
|
||||
unsigned size = min_size;
|
||||
while (total > (1 << size)) size++;
|
||||
kassert(size <= max_size, "Tried to allocate a block bigger than max_size");
|
||||
|
||||
mem_header *header = pop_free(size);
|
||||
header->set_used(true);
|
||||
return header + 1;
|
||||
}
|
||||
|
||||
void
|
||||
memory_manager::free(void *p)
|
||||
{
|
||||
mem_header *header = reinterpret_cast<mem_header *>(p);
|
||||
header -= 1; // p points after the header
|
||||
header->set_used(false);
|
||||
|
||||
while (true) {
|
||||
mem_header *buddy = header->buddy();
|
||||
if (buddy->used() || buddy->size() != header->size()) break;
|
||||
buddy->remove();
|
||||
header = header->eldest() ? header : buddy;
|
||||
header->set_size(header->size() + 1);
|
||||
}
|
||||
|
||||
uint8_t size = header->size();
|
||||
header->set_next(get_free(size));
|
||||
get_free(size) = header;
|
||||
if (header->next())
|
||||
header->next()->set_prev(header);
|
||||
}
|
||||
|
||||
void
|
||||
memory_manager::grow_memory()
|
||||
{
|
||||
size_t length = (1 << max_size);
|
||||
|
||||
void *next = kutil::offset_pointer(m_start, m_length);
|
||||
kassert(m_grow, "Tried to grow heap without a growth callback");
|
||||
m_grow(next, length);
|
||||
|
||||
mem_header *block = new (next) mem_header(nullptr, get_free(max_size), max_size);
|
||||
get_free(max_size) = block;
|
||||
if (block->next())
|
||||
block->next()->set_prev(block);
|
||||
m_length += length;
|
||||
}
|
||||
|
||||
void
|
||||
memory_manager::ensure_block(unsigned size)
|
||||
{
|
||||
if (get_free(size) != nullptr) return;
|
||||
else if (size == max_size) {
|
||||
grow_memory();
|
||||
return;
|
||||
}
|
||||
|
||||
mem_header *orig = pop_free(size + 1);
|
||||
|
||||
mem_header *next = kutil::offset_pointer(orig, 1 << size);
|
||||
new (next) mem_header(orig, nullptr, size);
|
||||
|
||||
orig->set_next(next);
|
||||
orig->set_size(size);
|
||||
get_free(size) = orig;
|
||||
}
|
||||
|
||||
memory_manager::mem_header *
|
||||
memory_manager::pop_free(unsigned size)
|
||||
{
|
||||
ensure_block(size);
|
||||
mem_header *block = get_free(size);
|
||||
get_free(size) = block->next();
|
||||
|
||||
block->remove();
|
||||
return block;
|
||||
}
|
||||
|
||||
} // namespace kutil
|
||||
69
src/libraries/kutil/memory_manager.h
Normal file
69
src/libraries/kutil/memory_manager.h
Normal file
@@ -0,0 +1,69 @@
|
||||
#pragma once
|
||||
/// \file memory_manager.h
|
||||
/// A buddy allocator and related definitions.
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace kutil {
|
||||
|
||||
|
||||
/// Manager for allocation of virtual memory.
|
||||
class memory_manager
|
||||
{
|
||||
public:
|
||||
using grow_callback = void (*)(void *start, size_t length);
|
||||
|
||||
/// Default constructor. Creates an invalid manager.
|
||||
memory_manager();
|
||||
|
||||
/// Constructor.
|
||||
/// \arg start Pointer to the start of the heap to be managed
|
||||
/// \arg grow_cb Function pointer to grow the heap size
|
||||
memory_manager(void *start, grow_callback grow_cb);
|
||||
|
||||
/// Allocate memory from the area managed.
|
||||
/// \arg length The amount of memory to allocate, in bytes
|
||||
/// \returns A pointer to the allocated memory, or nullptr if
|
||||
/// allocation failed.
|
||||
void * allocate(size_t length);
|
||||
|
||||
/// Free a previous allocation.
|
||||
/// \arg p A pointer previously retuned by allocate()
|
||||
void free(void *p);
|
||||
|
||||
/// Minimum block size is (2^min_size). Must be at least 6.
|
||||
static const unsigned min_size = 6;
|
||||
|
||||
/// Maximum block size is (2^max_size). Must be less than 64.
|
||||
static const unsigned max_size = 16;
|
||||
|
||||
protected:
|
||||
class mem_header;
|
||||
|
||||
/// Expand the size of memory
|
||||
void grow_memory();
|
||||
|
||||
/// Ensure there is a block of a given size, recursively splitting
|
||||
/// \arg size Size category of the block we want
|
||||
void ensure_block(unsigned size);
|
||||
|
||||
/// Helper accessor for the list of blocks of a given size
|
||||
/// \arg size Size category of the block we want
|
||||
/// \returns A mutable reference to the head of the list
|
||||
mem_header *& get_free(unsigned size) { return m_free[size - min_size]; }
|
||||
|
||||
/// Helper to get a block of the given size, growing if necessary
|
||||
/// \arg size Size category of the block we want
|
||||
/// \returns A detached block of the given size
|
||||
mem_header * pop_free(unsigned size);
|
||||
|
||||
mem_header *m_free[max_size - min_size];
|
||||
void *m_start;
|
||||
size_t m_length;
|
||||
|
||||
grow_callback m_grow;
|
||||
|
||||
memory_manager(const memory_manager &) = delete;
|
||||
};
|
||||
|
||||
} // namespace kutil
|
||||
12
src/libraries/kutil/misc.h
Normal file
12
src/libraries/kutil/misc.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
namespace kutil {
|
||||
|
||||
constexpr uint32_t
|
||||
byteswap(uint32_t x)
|
||||
{
|
||||
return ((x >> 24) & 0x000000ff) | ((x >> 8) & 0x0000ff00)
|
||||
| ((x << 8) & 0x00ff0000) | ((x << 24) & 0xff000000);
|
||||
}
|
||||
|
||||
}
|
||||
164
src/libraries/kutil/vector.h
Normal file
164
src/libraries/kutil/vector.h
Normal file
@@ -0,0 +1,164 @@
|
||||
#pragma once
|
||||
/// \file vector.h
|
||||
/// Definition of a simple dynamic vector collection for use in kernel space
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include "kutil/memory.h"
|
||||
|
||||
namespace kutil {
|
||||
|
||||
/// A dynamic array.
|
||||
template <typename T>
|
||||
class vector
|
||||
{
|
||||
public:
|
||||
/// Default constructor. Creates an empty vector with no capacity.
|
||||
vector() :
|
||||
m_size(0),
|
||||
m_capacity(0),
|
||||
m_elements(nullptr)
|
||||
{}
|
||||
|
||||
/// Constructor. Creates an empty array with capacity.
|
||||
/// \arg capacity Initial capacity to allocate
|
||||
vector(size_t capacity) :
|
||||
m_size(0),
|
||||
m_capacity(0),
|
||||
m_elements(nullptr)
|
||||
{
|
||||
set_capacity(capacity);
|
||||
}
|
||||
|
||||
/// Copy constructor. Allocates a copy of the other's array.
|
||||
vector(const vector& other) :
|
||||
m_size(0),
|
||||
m_capacity(0),
|
||||
m_elements(nullptr)
|
||||
{
|
||||
set_capacity(other.m_capacity);
|
||||
kutil::memcpy(m_elements, other.m_elements, other.m_size * sizeof(T));
|
||||
m_size = other.m_size;
|
||||
}
|
||||
|
||||
/// Move constructor. Takes ownership of the other's array.
|
||||
vector(vector&& other) :
|
||||
m_size(other.m_size),
|
||||
m_capacity(other.m_capacity),
|
||||
m_elements(other.m_elements)
|
||||
{
|
||||
other.m_size = 0;
|
||||
other.m_capacity = 0;
|
||||
other.m_elements = nullptr;
|
||||
}
|
||||
|
||||
/// Destructor. Destroys any remaining items in the array.
|
||||
~vector()
|
||||
{
|
||||
while (m_size) remove();
|
||||
delete [] m_elements;
|
||||
}
|
||||
|
||||
/// Get the size of the array.
|
||||
/// \returns The number of elements in the array
|
||||
inline size_t count() const { return m_size; }
|
||||
|
||||
/// Access an element in the array.
|
||||
inline T & operator[] (size_t i) { return m_elements[i]; }
|
||||
|
||||
/// Access an element in the array.
|
||||
inline const T & operator[] (size_t i) const { return m_elements[i]; }
|
||||
|
||||
/// Get a pointer to the beginning for iteration.
|
||||
/// \returns A pointer to the beginning of the array
|
||||
T * begin() { return m_elements; }
|
||||
|
||||
/// Get a pointer to the beginning for iteration.
|
||||
/// \returns A pointer to the beginning of the array
|
||||
const T * begin() const { return m_elements; }
|
||||
|
||||
/// Get a pointer to the end for iteration.
|
||||
/// \returns A pointer to the end of the array
|
||||
T * end() { return m_elements + m_size; }
|
||||
|
||||
/// Get a pointer to the end for iteration.
|
||||
/// \returns A pointer to the end of the array
|
||||
const T * end() const { return m_elements + m_size; }
|
||||
|
||||
/// Add an item onto the array by copying it.
|
||||
/// \arg item The item to add
|
||||
/// \returns A reference to the added item
|
||||
T & append(const T& item)
|
||||
{
|
||||
ensure_capacity(m_size + 1);
|
||||
m_elements[m_size] = item;
|
||||
return m_elements[m_size++];
|
||||
}
|
||||
|
||||
/// Construct an item in place onto the end of the array.
|
||||
/// \returns A reference to the added item
|
||||
template <typename... Args>
|
||||
T & emplace(Args&&... args)
|
||||
{
|
||||
ensure_capacity(m_size + 1);
|
||||
new (&m_elements[m_size]) T(std::forward<Args>(args)...);
|
||||
return m_elements[m_size++];
|
||||
}
|
||||
|
||||
/// Remove an item from the end of the array.
|
||||
void remove()
|
||||
{
|
||||
m_size -= 1;
|
||||
m_elements[m_size].~T();
|
||||
}
|
||||
|
||||
/// Set the size of the array. Any new items are default
|
||||
/// constructed. The array is realloced if needed.
|
||||
/// \arg size The new size
|
||||
void set_size(size_t size)
|
||||
{
|
||||
ensure_capacity(size);
|
||||
for (size_t i = m_size; i < size; ++i)
|
||||
new (&m_elements[i]) T;
|
||||
m_size = size;
|
||||
}
|
||||
|
||||
/// Ensure the array will fit an item.
|
||||
/// \arg size Size of the array
|
||||
void ensure_capacity(size_t size)
|
||||
{
|
||||
if (m_capacity >= size) return;
|
||||
|
||||
size_t capacity = m_capacity;
|
||||
while (capacity < size) {
|
||||
if (capacity == 0) capacity = 4;
|
||||
else capacity *= 2;
|
||||
}
|
||||
set_capacity(capacity);
|
||||
}
|
||||
|
||||
/// Reallocate the array. Copy over any old elements that will
|
||||
/// fit into the new array. The rest are destroyed.
|
||||
/// \arg capacity Number of elements to allocate
|
||||
void set_capacity(size_t capacity)
|
||||
{
|
||||
T *new_array = reinterpret_cast<T *>(malloc(capacity * sizeof(T)));
|
||||
size_t size = std::min(capacity, m_size);
|
||||
|
||||
kutil::memcpy(new_array, m_elements, size * sizeof(T));
|
||||
|
||||
while (size < m_size) remove();
|
||||
m_size = size;
|
||||
m_capacity = capacity;
|
||||
|
||||
delete [] m_elements;
|
||||
m_elements = new_array;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t m_size;
|
||||
size_t m_capacity;
|
||||
T *m_elements;
|
||||
};
|
||||
|
||||
} // namespace kutil
|
||||
14
src/libraries/kutil/wscript
Normal file
14
src/libraries/kutil/wscript
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
def configure(ctx):
|
||||
pass
|
||||
|
||||
def build(bld):
|
||||
sources = bld.path.ant_glob("**/*.cpp")
|
||||
|
||||
bld.stlib(
|
||||
source = sources,
|
||||
name = 'kutil',
|
||||
target = 'kutil',
|
||||
)
|
||||
|
||||
# vim: ft=python et
|
||||
Reference in New Issue
Block a user