aboutsummaryrefslogtreecommitdiffstats
path: root/src/gos/gos_x_heap.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gos/gos_x_heap.c')
-rw-r--r--src/gos/gos_x_heap.c195
1 files changed, 195 insertions, 0 deletions
diff --git a/src/gos/gos_x_heap.c b/src/gos/gos_x_heap.c
new file mode 100644
index 00000000..94b74d37
--- /dev/null
+++ b/src/gos/gos_x_heap.c
@@ -0,0 +1,195 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+#include "gfx.h"
+
+#if GOS_NEED_X_HEAP
+
+#include <string.h> // Prototype for memcpy()
+
+
+#if GFX_OS_HEAP_SIZE == 0
+ #include <stdlib.h> // Prototype for malloc(), realloc() and free()
+
+ void _gosHeapInit(void) {
+ }
+ void *gfxAlloc(size_t sz) {
+ return malloc(sz);
+ }
+
+ void *gfxRealloc(void *ptr, size_t oldsz, size_t newsz) {
+ (void) oldsz;
+ return realloc(ptr, newsz);
+ }
+
+ void gfxFree(void *ptr) {
+ free(ptr);
+ }
+
+#else
+
+ // Slot structure - user memory follows
+ typedef struct memslot {
+ struct memslot *next; // The next memslot
+ size_t sz; // Includes the size of this memslot.
+ } memslot;
+
+ // Free Slot - immediately follows the memslot structure
+ typedef struct freeslot {
+ memslot *nextfree; // The next free slot
+ } freeslot;
+
+ #define GetSlotSize(sz) ((((sz) + (sizeof(freeslot) - 1)) & ~(sizeof(freeslot) - 1)) + sizeof(memslot))
+ #define NextFree(pslot) ((freeslot *)Slot2Ptr(pslot))->nextfree
+ #define Ptr2Slot(p) ((memslot *)(p) - 1)
+ #define Slot2Ptr(pslot) ((pslot)+1)
+
+ static memslot * firstSlot;
+ static memslot * lastSlot;
+ static memslot * freeSlots;
+ static char heap[GFX_OS_HEAP_SIZE];
+
+ void _gosHeapInit(void) {
+ lastSlot = 0;
+ gfxAddHeapBlock(heap, GFX_OS_HEAP_SIZE);
+ }
+
+ void gfxAddHeapBlock(void *ptr, size_t sz) {
+ if (sz < sizeof(memslot)+sizeof(freeslot))
+ return;
+
+ if (lastSlot)
+ lastSlot->next = (memslot *)ptr;
+ else
+ firstSlot = lastSlot = freeSlots = (memslot *)ptr;
+
+ lastSlot->next = 0;
+ lastSlot->sz = sz;
+ NextFree(lastSlot) = 0;
+ }
+
+ void *gfxAlloc(size_t sz) {
+ register memslot *prev, *p, *new;
+
+ if (!sz) return 0;
+ sz = GetSlotSize(sz);
+ for (prev = 0, p = freeSlots; p != 0; prev = p, p = NextFree(p)) {
+ // Loop till we have a block big enough
+ if (p->sz < sz)
+ continue;
+ // Can we save some memory by splitting this block?
+ if (p->sz >= sz + sizeof(memslot)+sizeof(freeslot)) {
+ new = (memslot *)((char *)p + sz);
+ new->next = p->next;
+ p->next = new;
+ new->sz = p->sz - sz;
+ p->sz = sz;
+ if (lastSlot == p)
+ lastSlot = new;
+ NextFree(new) = NextFree(p);
+ NextFree(p) = new;
+ }
+ // Remove it from the free list
+ if (prev)
+ NextFree(prev) = NextFree(p);
+ else
+ freeSlots = NextFree(p);
+ // Return the result found
+ return Slot2Ptr(p);
+ }
+ // No slots large enough
+ return 0;
+ }
+
+ void *gfxRealloc(void *ptr, size_t oldsz, size_t sz) {
+ register memslot *prev, *p, *new;
+ (void) oldsz;
+
+ if (!ptr)
+ return gfxAlloc(sz);
+ if (!sz) {
+ gfxFree(ptr);
+ return 0;
+ }
+
+ p = Ptr2Slot(ptr);
+ sz = GetSlotSize(sz);
+
+ // If the next slot is free (and contiguous) merge it into this one
+ if ((char *)p + p->sz == (char *)p->next) {
+ for (prev = 0, new = freeSlots; new != 0; prev = new, new = NextFree(new)) {
+ if (new == p->next) {
+ p->next = new->next;
+ p->sz += new->sz;
+ if (prev)
+ NextFree(prev) = NextFree(new);
+ else
+ freeSlots = NextFree(new);
+ if (lastSlot == new)
+ lastSlot = p;
+ break;
+ }
+ }
+ }
+
+ // If this block is large enough we are nearly done
+ if (sz < p->sz) {
+ // Can we save some memory by splitting this block?
+ if (p->sz >= sz + sizeof(memslot)+sizeof(freeslot)) {
+ new = (memslot *)((char *)p + sz);
+ new->next = p->next;
+ p->next = new;
+ new->sz = p->sz - sz;
+ p->sz = sz;
+ if (lastSlot == p)
+ lastSlot = new;
+ NextFree(new) = freeSlots;
+ freeSlots = new;
+ }
+ return Slot2Ptr(p);
+ }
+
+ // We need to do this the hard way
+ if ((new = gfxAlloc(sz)))
+ return 0;
+ memcpy(new, ptr, p->sz - sizeof(memslot));
+ gfxFree(ptr);
+ return new;
+ }
+
+ void gfxFree(void *ptr) {
+ register memslot *prev, *p, *new;
+
+ if (!ptr)
+ return;
+
+ p = Ptr2Slot(ptr);
+
+ // If the next slot is free (and contiguous) merge it into this one
+ if ((char *)p + p->sz == (char *)p->next) {
+ for (prev = 0, new = freeSlots; new != 0; prev = new, new = NextFree(new)) {
+ if (new == p->next) {
+ p->next = new->next;
+ p->sz += new->sz;
+ if (prev)
+ NextFree(prev) = NextFree(new);
+ else
+ freeSlots = NextFree(new);
+ if (lastSlot == new)
+ lastSlot = p;
+ break;
+ }
+ }
+ }
+
+ // Add it into the free chain
+ NextFree(p) = freeSlots;
+ freeSlots = p;
+ }
+#endif
+
+#endif /* GOS_NEED_X_HEAP */