Update: Have implemented some of the suggestions:
See GitHub: https://github.com/BostonBrooks/MathsGame/tree/master/Object_Pools_Demo
I am implementing a game engine where I have a sorted list of inanimate objects so that the closer objects get drawn over the further away objects, and I want to use an object pool rather than call malloc() every time a new object is spawned. I do not wish to store pointers directly to objects because these may move around when I save and restore the session.
I have written code that does this in the form of a high-scores list. Here it is, go nuts.
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#define LEVEL1 3
#define LEVEL2 5
typedef struct {
int Prev;
int Next;
char Name[16];
int Score;
} Object;
Object* Pool[LEVEL1] = { 0 };
int Available_Head = -1;
int Available_Tail = -1;
int List_Head = -1;
int List_Tail = -1;
int Increase_Pool(void);
int New_Object(void);
void Delete_Object(int);
void List_Object(int);
void DeList_Object(int);
Object* Lookup_Object(int);
void Print_All(void);
void Print_None(void);
int main (void) {
char Name[16];
int Score;
while(1) {
Print_All();
printf("Enter Name: ");
scanf("%s", Name);
printf("Enter Score: ");
scanf("%d", &Score);
int object_int = New_Object();
printf("object_int %d\n", object_int);
Object* object_address = Lookup_Object(object_int);
strcpy(object_address->Name, Name);
object_address->Score = Score;
List_Object(object_int);
}
}
void DeList_Object (int object_int){
//Remove from list
Object* object_address = Lookup_Object(object_int);
if (List_Head == -1 && List_Tail == -1){
//List Empty
} else if (object_address->Prev == -1 && object_address->Next == -1) {
//Object not in list
} else if ( List_Head == object_int && List_Tail == object_int){
//Only object in list
List_Head = -1;
List_Tail = -1;
object_address->Prev = -1;
object_address->Next = -1;
} else if (List_Head == object_int) {
// Object at top of list
List_Head = object_address->Next;
object_address->Next = -1;
object_address->Prev = -1;
object_address = Lookup_Object(List_Head);
object_address->Prev = -1;
} else if (List_Tail == object_int) {
//Object at end of list
List_Tail = object_address->Prev;
object_address->Next = -1;
object_address->Prev = -1;
object_address = Lookup_Object(List_Tail);
object_address->Next = -1;
} else {
//Object in middle of list
Object* Next = Lookup_Object(object_address->Next);
Object* Prev = Lookup_Object(object_address->Prev);
Next->Prev = object_address->Prev;
Prev->Next = object_address->Next;
object_address->Prev = -1;
object_address->Next = -1;
}
}
void Delete_Object(int object_int){
// Remove from list
DeList_Object (object_int);
//Return to Pool
if (Available_Head == -1 && Available_Tail == -1){
Available_Head = object_int;
Available_Tail = object_int;
} else{
Object* object_address = Lookup_Object(object_int);
object_address->Next = Available_Head;
//Available_Head->Prev = object_int;
Available_Head = object_int;
}
}
int New_Object(void){
if (Available_Head == -1){
assert (Available_Tail == -1);
int success = Increase_Pool();
assert(success == 1);
}
int object_int = Available_Head;
Object* object_address = Lookup_Object(object_int);
Available_Head = object_address->Next;
object_address->Prev = -1;
object_address->Next = -1;
if (Available_Head != -1) {
Object* Head = Lookup_Object(Available_Head);
Head->Prev = -1;
} else {
Available_Tail = -1;
}
return object_int;
}
int Increase_Pool(void){
int i;
for (i = 0; i < LEVEL1 && Pool[i] != 0; i++){
}
if (i == LEVEL1) {
printf("out of memory\n");
return(0);
} else {
Pool[i] = calloc(LEVEL2, sizeof(Object));
}
int j = 0;
if (Available_Head == -1){
assert (Available_Tail == -1);
Available_Head = i * LEVEL2;
Available_Tail = i * LEVEL2;
Object* object = Lookup_Object(Available_Head);
object->Prev = -1;
object->Next = i * LEVEL2 + 1;
j++;
} else {
Object* Tail = Lookup_Object(Available_Tail);
Object* New = Lookup_Object(i * LEVEL2);
Tail->Next = i * LEVEL2;
New->Prev = Available_Tail;
New->Next = i * LEVEL2 + 1;
j++;
}
for (1; j < LEVEL2; j++){
//add elements of Pool[i] to the Available list
Object* object_address = Lookup_Object(i * LEVEL2 + j);
object_address->Prev = i * LEVEL2 + j - 1;
object_address->Next = i * LEVEL2 + j + 1;
}
Available_Tail = (i+1) * LEVEL2 - 1;
Object* tail_address = Lookup_Object(Available_Tail);
tail_address->Next = -1;
return(1);
}
Object* Lookup_Object(int i){
return (&(Pool[i / LEVEL2])[i % LEVEL2]);
}
void List_Object(int object_int){
//Remove from list
DeList_Object(object_int);
//Add to list
Object* object_address = Lookup_Object(object_int);
if (List_Head == -1){ //list empty
assert (List_Tail == -1);
List_Head = object_int;
List_Tail = object_int;
printf("### empty, %s, %d ##", object_address->Name, object_address->Score);
return;
}
Object* head_address = Lookup_Object(List_Head);
if (object_address->Score >= head_address->Score) {//add to start of list
object_address->Prev = -1;
object_address->Next = List_Head;
head_address->Prev = object_int;
List_Head = object_int;
printf("### head %s, %d ##", object_address->Name, object_address->Score);
return;
}
Object* tail_address = Lookup_Object(List_Tail);
if (object_address->Score <= tail_address->Score) {//add to end of list
object_address->Next = -1;
object_address->Prev = List_Tail;
tail_address->Next = object_int;
List_Tail = object_int;
printf("### tail %s, %d ##", object_address->Name, object_address->Score);
return;
}
int target_int = List_Head;
Object* target_address = Lookup_Object(target_int);
//add to middle of list
while(object_address->Score < target_address->Score){
target_int = target_address->Next;
target_address = Lookup_Object(target_int);
}
int target_prev_int = target_address->Prev;
Object* target_prev_address = Lookup_Object(target_prev_int);
target_prev_address->Next = object_int;
object_address->Prev = target_prev_int;
object_address->Next = target_int;
target_address->Prev = object_int;
printf("### middle %s, %d ##", object_address->Name, object_address-> Score);
}
void Print_All(void){
if (List_Head == -1){
assert(List_Tail == -1);
printf("\n List Empty\n\n");
return;
}
int object_int = List_Head;
Object* object_address;
printf("\nName Score\n");
while (object_int != -1){
object_address = Lookup_Object(object_int);
printf("%s %d\n", object_address->Name, object_address->Score);
assert(object_int != object_address->Next);
object_int = object_address->Next;
}
printf("\n");
return;
}
//Print_None prints a list of available objects in the pool.
void Print_None(void){
if (Available_Head == -1){
assert(Available_Tail == -1);
printf("\n List Empty\n\n");
return;
}
int object_int = Available_Head;
Object* object_address;
printf("\nPrevious Next\n");
while (object_int != -1){
object_address = Lookup_Object(object_int);
printf("%d %d\n", object_address->Prev, object_address->Next);
assert(object_int != object_address->Next);
object_int = object_address->Next;
}
printf("\n");
return;
}
for (1; j < LEVEL2; j++){
, why the lone1
versus omitting it likefor (; j < LEVEL2; j++){
? Never have seen that style before. \$\endgroup\$