-
Notifications
You must be signed in to change notification settings - Fork 56
lst
#include <lst.h>
The CTL lst
, analogous to the STL std::list
, is a container specializing in element pointer validity. Implemented as a doubly linked list, a lst
may be used in place of a vec
when all elements are consistently accessed and modified in batch operations (eg. with foreach
) or on the head and tail. While slower to iterate than the <vec.h> template, pointers to list elements remain valid as the list grows and shrinks in size, and when the list is sorted.
Similar to Example 1 of the vec
tutorial, occurrences of vec
have been swapped for lst
. The same structure holds, except that
per element access is not possible.
Like the vec
example, #define P
indicates no further freeing is required per lst
element.
#include <stdio.h>
#define P
#define T int
#include <lst.h>
int compare(int* a, int* b)
{
return *b < *a;
}
int main(void)
{
lst_int a = lst_int_init();
for(int i = 0; i < 32; i++)
lst_int_push_back(&a, rand() % 1024);
lst_int_sort(&a, compare);
int sum = 0;
int index = 0;
foreach(lst_int, &a, it)
{
printf("%2d: %4d\n", index, *it.ref);
sum += *it.ref;
index += 1;
}
printf("%d\n", sum);
lst_int_free(&a);
}
gcc main.c -I ctl
Game engines specializing in large scale medieval combat benefit from using a lst
when batch operations are consistently modifying elements in the middle of the list. For example, "dead" entities can be removed from the lst
with a single foreach
statement, where each removal is an O(1)
operation:
#include <stdio.h>
#include <str.h>
typedef struct
{
float x;
float y;
}
point;
typedef struct
{
str name;
point p;
float health;
float attack;
float defense;
}
entity;
void
entity_free(entity* e)
{
str_free(&e->name);
}
entity
entity_copy(entity* e)
{
entity other = *e;
other.name = str_copy(&e->name);
return other;
}
#define T entity
#include <lst.h>
int is_dead(entity* e)
{
return e->health < 2.0f;
}
int main(void)
{
lst_entity a = lst_entity_init();
for(int i = 0; i < 64; i++)
{
point p = {
32.0f * rand() / RAND_MAX,
32.0f * rand() / RAND_MAX,
};
entity e = {
str_init("blue slime"),
p,
rand() % 10,
rand() % 10,
rand() % 10,
};
lst_entity_push_back(&a, e);
}
size_t before = a.size;
lst_entity_remove_if(&a, is_dead);
foreach(lst_entity, &a, it)
{
entity* e = it.ref;
printf("%s : {%5.2f %5.2f} %5.2f %5.2f %5.2f\n",
str_c_str(&e->name), e->p.x, e->p.y, e->health, e->attack, e->defense);
}
printf("size before: %lu\n", before);
printf("size after: %lu\n", a.size);
lst_entity_free(&a);
}
gcc main.c -I ctl
Declarations for entity_free
and entity_copy
can replace their definitions, and the definitions can be placed elsewhere, preferably after main, or in another file, to ease template instantiation readability:
void
entity_free(entity*);
entity
entity_copy(entity*);
#define T entity
#include <lst.h>
int main(void)
{
...
}
void
entity_free(entity* e)
{
str_free(&e->name);
}
entity
entity_copy(entity* e)
{
entity other = *e;
other.name = str_copy(&e->name);
return other;
}