Last active
December 31, 2019 14:12
-
-
Save Geequlim/7646e4cb67cc987b11368422008b89be to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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