1
1
Fork 0
mirror of https://github.com/QB64-Phoenix-Edition/QB64pe.git synced 2024-09-20 05:34:47 +00:00

Move list API to separate cpp file

Fixes: #147
This commit is contained in:
Matthew Kilgore 2024-02-12 00:47:39 -05:00
parent 0da86b61a5
commit a891a6b255
4 changed files with 190 additions and 168 deletions

View file

@ -30,6 +30,7 @@
#include "http.h" #include "http.h"
#include "image.h" #include "image.h"
#include "keyhandler.h" #include "keyhandler.h"
#include "qblist.h"
#include "mem.h" #include "mem.h"
#include "mutex.h" #include "mutex.h"
#include "qbs.h" #include "qbs.h"
@ -426,174 +427,6 @@ int64 display_frame_order_next = 1;
int64 last_rendered_hardware_display_frame_order = 0; int64 last_rendered_hardware_display_frame_order = 0;
int64 last_hardware_display_frame_order = 0; int64 last_hardware_display_frame_order = 0;
// List Interface
// Purpose: Unify and optimize the way QB64 references lists of objects (such as handles)
// Notes: Does not use index 0
struct list {
ptrszint user_structure_size;
ptrszint internal_structure_size;
uint8 *structure; // block of structures of user-specified size
ptrszint structures;
ptrszint structures_last;
ptrszint *structure_freed; // quickly re-reference available structures after they have been removed
ptrszint *structure_freed_cleanup; // the previous *structure_freed memory block
ptrszint structures_freed;
ptrszint structures_freed_last;
ptrszint structure_base[64]; // every time the 'structure' block is full a new and larger block is allocated
// because the list doubles each time, 64 entries will never be exceeded
ptrszint structure_bases;
ptrszint *index; // pointers to the structures referred to by each index value
ptrszint *index_cleanup;
ptrszint indexes;
ptrszint indexes_last;
struct libqb_mutex *lock_add;
struct libqb_mutex *lock_remove;
};
// fwd refs
void *list_get(list *L, ptrszint i);
list *list_new(ptrszint structure_size) {
list *L;
L = (list *)calloc(1, sizeof(list));
L->structure = (uint8 *)malloc(sizeof(uint8 *));
L->structure_base[1] = (ptrszint)L->structure;
L->structure_bases = 1;
L->structure_freed = (ptrszint *)malloc(sizeof(ptrszint *));
L->index = (ptrszint *)malloc(sizeof(ptrszint *));
L->user_structure_size = structure_size;
L->internal_structure_size = structure_size + sizeof(ptrszint);
return L;
}
list *list_new_threadsafe(ptrszint structure_size) {
list *L = list_new(structure_size);
L->lock_add = libqb_mutex_new();
L->lock_remove = libqb_mutex_new();
return L;
}
ptrszint list_add(list *L) {
if (L->lock_add)
libqb_mutex_lock(L->lock_add);
ptrszint i;
if (L->structures_freed) { // retrieve index from freed list if possible
if (L->lock_remove)
libqb_mutex_lock(L->lock_remove);
i = L->structure_freed[L->structures_freed--];
uint8 *structure;
structure = (uint8 *)L->index[i];
memset(structure, 0, L->user_structure_size);
*(ptrszint *)(structure + L->user_structure_size) = i;
if (L->lock_remove)
libqb_mutex_unlock(L->lock_remove);
} else {
// create new buffer?
if ((L->structures + 1) > L->structures_last) {
ptrszint new_structures_last;
new_structures_last = (L->structures_last * 2) + 1;
// note: L->structure is only modified by list_add
L->structure = (uint8 *)calloc(1, L->internal_structure_size * (new_structures_last + 1));
if (L->structure == NULL) {
gui_alert("list_add: failed to allocate new buffer, structure size: %lld", (int64_t)L->internal_structure_size);
}
L->structures_last = new_structures_last;
L->structures = 0;
L->structure_base[++L->structure_bases] = (ptrszint)L->structure;
}
i = ++L->indexes;
*(ptrszint *)(L->structure + (L->internal_structure_size * (++L->structures)) + L->user_structure_size) = i;
// allocate new index
if (L->indexes > L->indexes_last) {
if (L->index_cleanup != NULL)
free(L->index_cleanup);
L->index_cleanup = L->index;
int32 new_indexes_last = (L->indexes_last * 2) + 1;
ptrszint *temp = (ptrszint *)malloc(sizeof(ptrszint) * (new_indexes_last + 1));
memcpy(temp, L->index, sizeof(ptrszint) * (L->indexes_last + 1));
L->index = temp;
L->index[i] = (ptrszint)(L->structure + (L->internal_structure_size * L->structures));
L->indexes_last = new_indexes_last;
} else {
L->index[i] = (ptrszint)(L->structure + (L->internal_structure_size * L->structures));
}
}
if (L->lock_add)
libqb_mutex_unlock(L->lock_add);
return i;
} // list_add
ptrszint list_remove(list *L, ptrszint i) { // returns -1 on success, 0 on failure
if (L->lock_remove)
libqb_mutex_lock(L->lock_remove);
if ((i < 1) || (i > L->indexes)) {
if (L->lock_remove)
libqb_mutex_unlock(L->lock_remove);
return 0;
}
uint8 *structure;
structure = (uint8 *)(L->index[i]);
if (!*(ptrszint *)(structure + L->user_structure_size)) {
if (L->lock_remove)
libqb_mutex_unlock(L->lock_remove);
return 0;
}
// expand buffer?
if ((L->structures_freed + 1) > L->structures_freed_last) {
ptrszint new_structures_freed_last;
new_structures_freed_last = (L->structures_freed_last * 2) + 1;
ptrszint *temp = (ptrszint *)malloc(sizeof(ptrszint) * (new_structures_freed_last + 1));
memcpy(temp, L->structure_freed, sizeof(ptrszint) * (L->structures_freed + 1));
if (L->structure_freed_cleanup != NULL)
free(L->structure_freed_cleanup);
L->structure_freed_cleanup = L->structure_freed;
L->structure_freed = temp;
L->structures_freed_last = new_structures_freed_last;
}
L->structure_freed[L->structures_freed + 1] = i;
*(ptrszint *)(structure + L->user_structure_size) = 0;
L->structures_freed++;
if (L->lock_remove)
libqb_mutex_unlock(L->lock_remove);
return -1;
};
void list_destroy(list *L) {
ptrszint i;
for (i = 1; i <= L->structure_bases; i++) {
free((void *)L->structure_base[i]);
}
free(L->structure_base);
free(L->structure_freed);
free(L);
}
void *list_get(list *L, ptrszint i) { // Returns a pointer to an index's structure
if ((i < 1) || (i > L->indexes)) {
return NULL;
}
uint8 *structure;
structure = (uint8 *)(L->index[i]);
if (!*(ptrszint *)(structure + L->user_structure_size))
return NULL;
return (void *)structure;
}
ptrszint list_get_index(list *L, void *structure) { // Retrieves the index value of a structure
ptrszint i = *(ptrszint *)(((uint8 *)structure) + L->user_structure_size);
return i;
}
enum class special_handle_type { enum class special_handle_type {
Invalid, Invalid,
Stream, Stream,

View file

@ -7,6 +7,7 @@ libqb-objs-y += $(PATH_LIBQB)/src/filesystem.o
libqb-objs-y += $(PATH_LIBQB)/src/datetime.o libqb-objs-y += $(PATH_LIBQB)/src/datetime.o
libqb-objs-y += $(PATH_LIBQB)/src/error_handle.o libqb-objs-y += $(PATH_LIBQB)/src/error_handle.o
libqb-objs-y += $(PATH_LIBQB)/src/gfs.o libqb-objs-y += $(PATH_LIBQB)/src/gfs.o
libqb-objs-y += $(PATH_LIBQB)/src/qblist.o
libqb-objs-y += $(PATH_LIBQB)/src/mem.o libqb-objs-y += $(PATH_LIBQB)/src/mem.o
libqb-objs-y += $(PATH_LIBQB)/src/rounding.o libqb-objs-y += $(PATH_LIBQB)/src/rounding.o
libqb-objs-y += $(PATH_LIBQB)/src/qbs.o libqb-objs-y += $(PATH_LIBQB)/src/qbs.o

View file

@ -0,0 +1,39 @@
#pragma once
#include <stdint.h>
#include "mutex.h"
// List Interface
// Purpose: Unify and optimize the way QB64 references lists of objects (such as handles)
// Notes: Does not use index 0
struct list {
intptr_t user_structure_size;
intptr_t internal_structure_size;
uint8_t *structure; // block of structures of user-specified size
intptr_t structures;
intptr_t structures_last;
intptr_t *structure_freed; // quickly re-reference available structures after they have been removed
intptr_t *structure_freed_cleanup; // the previous *structure_freed memory block
intptr_t structures_freed;
intptr_t structures_freed_last;
intptr_t structure_base[64]; // every time the 'structure' block is full a new and larger block is allocated
// because the list doubles each time, 64 entries will never be exceeded
intptr_t structure_bases;
intptr_t *index; // pointers to the structures referred to by each index value
intptr_t *index_cleanup;
intptr_t indexes;
intptr_t indexes_last;
struct libqb_mutex *lock_add;
struct libqb_mutex *lock_remove;
};
list *list_new(intptr_t structure_size);
list *list_new_threadsafe(intptr_t structure_size);
void list_destroy(list *L);
intptr_t list_add(list *L);
intptr_t list_remove(list *L, intptr_t i); // returns -1 on success, 0 on failure
//
void *list_get(list *L, intptr_t i); // Returns a pointer to an index's structure
//
intptr_t list_get_index(list *L, void *structure); // Retrieves the index value of a structure

View file

@ -0,0 +1,149 @@
#include "libqb-common.h"
#include <stdlib.h>
#include <string.h>
#include "gui.h"
#include "qblist.h"
list *list_new(intptr_t structure_size) {
list *L;
L = (list *)calloc(1, sizeof(list));
L->structure = (uint8_t *)malloc(sizeof(uint8_t *));
L->structure_base[1] = (intptr_t)L->structure;
L->structure_bases = 1;
L->structure_freed = (intptr_t *)malloc(sizeof(intptr_t *));
L->index = (intptr_t *)malloc(sizeof(intptr_t *));
L->user_structure_size = structure_size;
L->internal_structure_size = structure_size + sizeof(intptr_t);
return L;
}
list *list_new_threadsafe(intptr_t structure_size) {
list *L = list_new(structure_size);
L->lock_add = libqb_mutex_new();
L->lock_remove = libqb_mutex_new();
return L;
}
intptr_t list_add(list *L) {
if (L->lock_add)
libqb_mutex_lock(L->lock_add);
intptr_t i;
if (L->structures_freed) { // retrieve index from freed list if possible
if (L->lock_remove)
libqb_mutex_lock(L->lock_remove);
i = L->structure_freed[L->structures_freed--];
uint8_t *structure;
structure = (uint8_t *)L->index[i];
memset(structure, 0, L->user_structure_size);
*(intptr_t *)(structure + L->user_structure_size) = i;
if (L->lock_remove)
libqb_mutex_unlock(L->lock_remove);
} else {
// create new buffer?
if ((L->structures + 1) > L->structures_last) {
intptr_t new_structures_last;
new_structures_last = (L->structures_last * 2) + 1;
// note: L->structure is only modified by list_add
L->structure = (uint8_t *)calloc(1, L->internal_structure_size * (new_structures_last + 1));
if (L->structure == NULL) {
gui_alert("list_add: failed to allocate new buffer, structure size: %lld", (int64_t)L->internal_structure_size);
}
L->structures_last = new_structures_last;
L->structures = 0;
L->structure_base[++L->structure_bases] = (intptr_t)L->structure;
}
i = ++L->indexes;
*(intptr_t *)(L->structure + (L->internal_structure_size * (++L->structures)) + L->user_structure_size) = i;
// allocate new index
if (L->indexes > L->indexes_last) {
if (L->index_cleanup != NULL)
free(L->index_cleanup);
L->index_cleanup = L->index;
int32_t new_indexes_last = (L->indexes_last * 2) + 1;
intptr_t *temp = (intptr_t *)malloc(sizeof(intptr_t) * (new_indexes_last + 1));
memcpy(temp, L->index, sizeof(intptr_t) * (L->indexes_last + 1));
L->index = temp;
L->index[i] = (intptr_t)(L->structure + (L->internal_structure_size * L->structures));
L->indexes_last = new_indexes_last;
} else {
L->index[i] = (intptr_t)(L->structure + (L->internal_structure_size * L->structures));
}
}
if (L->lock_add)
libqb_mutex_unlock(L->lock_add);
return i;
} // list_add
intptr_t list_remove(list *L, intptr_t i) { // returns -1 on success, 0 on failure
if (L->lock_remove)
libqb_mutex_lock(L->lock_remove);
if ((i < 1) || (i > L->indexes)) {
if (L->lock_remove)
libqb_mutex_unlock(L->lock_remove);
return 0;
}
uint8_t *structure;
structure = (uint8_t *)(L->index[i]);
if (!*(intptr_t *)(structure + L->user_structure_size)) {
if (L->lock_remove)
libqb_mutex_unlock(L->lock_remove);
return 0;
}
// expand buffer?
if ((L->structures_freed + 1) > L->structures_freed_last) {
intptr_t new_structures_freed_last;
new_structures_freed_last = (L->structures_freed_last * 2) + 1;
intptr_t *temp = (intptr_t *)malloc(sizeof(intptr_t) * (new_structures_freed_last + 1));
memcpy(temp, L->structure_freed, sizeof(intptr_t) * (L->structures_freed + 1));
if (L->structure_freed_cleanup != NULL)
free(L->structure_freed_cleanup);
L->structure_freed_cleanup = L->structure_freed;
L->structure_freed = temp;
L->structures_freed_last = new_structures_freed_last;
}
L->structure_freed[L->structures_freed + 1] = i;
*(intptr_t *)(structure + L->user_structure_size) = 0;
L->structures_freed++;
if (L->lock_remove)
libqb_mutex_unlock(L->lock_remove);
return -1;
};
void list_destroy(list *L) {
intptr_t i;
for (i = 1; i <= L->structure_bases; i++) {
free((void *)L->structure_base[i]);
}
free(L->structure_base);
free(L->structure_freed);
free(L);
}
void *list_get(list *L, intptr_t i) { // Returns a pointer to an index's structure
if ((i < 1) || (i > L->indexes)) {
return NULL;
}
uint8_t *structure;
structure = (uint8_t *)(L->index[i]);
if (!*(intptr_t *)(structure + L->user_structure_size))
return NULL;
return (void *)structure;
}
intptr_t list_get_index(list *L, void *structure) { // Retrieves the index value of a structure
intptr_t i = *(intptr_t *)(((uint8_t *)structure) + L->user_structure_size);
return i;
}