Skip to content

Instantly share code, notes, and snippets.

@Geequlim
Last active December 31, 2019 14:12
Show Gist options
  • Save Geequlim/7646e4cb67cc987b11368422008b89be to your computer and use it in GitHub Desktop.
Save Geequlim/7646e4cb67cc987b11368422008b89be to your computer and use it in GitHub Desktop.
#ifndef ECMASCRIPT_ALLOCATOR_H
#define ECMASCRIPT_ALLOCATOR_H
#include "core/os/memory.h"
template <class T>
class ECMAScriptNativeAllocator {
struct Node {
Node *previous = NULL;
Node *next = NULL;
_ALWAYS_INLINE_ void *get_value() {
return this + 1;
}
};
Node *cursor = NULL;
size_t cursor_pos = 0;
size_t cursor_max = 0;
size_t pool_size = 0;
T default_value;
Node empty_node;
_ALWAYS_INLINE_ Node *internal_allocate_element() {
void *ptr = memalloc(sizeof(Node) + sizeof(T));
Node *node = (Node *)ptr;
memcpy(node, &empty_node, sizeof(Node));
memcpy(node->get_value(), &default_value, sizeof(T));
return node;
}
_ALWAYS_INLINE_ void internal_free_element(Node *node) {
memfree(node);
}
_ALWAYS_INLINE_ Node *get_node(T *value) {
return ((Node *)value) - 1;
}
_ALWAYS_INLINE_ void move_to_end(Node *p_node) {
if (!cursor) {
cursor = p_node;
return;
}
if (!p_node || cursor->next == p_node)
return;
Node *previouse = p_node->previous;
Node *next = p_node->next;
if (previouse) {
previouse->next = next;
}
if (next) {
next->previous = previouse;
}
Node *cursor_next = cursor->next;
if (cursor_next) {
cursor_next->previous = p_node;
}
cursor->next = p_node;
p_node->next = cursor_next;
p_node->previous = cursor;
}
void expand() {
size_t count = pool_size - (cursor_max - cursor_pos);
for (int i = 0; i < count; ++i) {
move_to_end(internal_allocate_element());
++cursor_max;
}
}
void contract() {
size_t count = cursor_max - cursor_pos - pool_size;
for (size_t i = 0; i < count; ++i) {
Node *previous = cursor->previous;
Node *next = cursor->next;
if (previous) {
previous->next = next;
}
if (next) {
next->previous = previous;
}
internal_free_element(cursor);
cursor = next;
--cursor_max;
}
}
public:
ECMAScriptNativeAllocator(size_t p_pool_size = 64) {
pool_size = p_pool_size;
}
~ECMAScriptNativeAllocator() {
if (cursor) {
Node *n = cursor->next;
while (n) {
Node *nn = n->next;
internal_free_element(n);
n = nn;
}
n = cursor->previous;
while (n) {
Node *nn = n->previous;
internal_free_element(n);
n = nn;
}
internal_free_element(cursor);
}
}
T *allocate() {
if (cursor_pos >= cursor_max - 1 || !cursor) {
expand();
}
T *ptr = (T *)(cursor->get_value());
++cursor_pos;
cursor = cursor->next;
return ptr;
}
void free(T *p_value) {
Node *node = get_node(p_value);
move_to_end(node);
++cursor_max;
if (cursor_max - cursor_pos >= pool_size * 2) {
contract();
}
}
};
#endif // ECMASCRIPT_ALLOCATOR_H
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment