Lists - osvaldoandrade/ova-lib GitHub Wiki

Lists

Read this page when position is part of the contract. The list API is the right tool when the caller chooses the insertion index or when indexed reads matter after insertion.

Constructor and Shared Interface

The constructor is:

list *create_list(ListType type, int initial_capacity, comparator cmp);

Every list exposes the same method table:

Field Meaning
insert(self, item, index) inserts one item at an index
get(self, index) returns the stored pointer at an index or NULL
remove(self, index) removes one item at an index
size(self) returns the current element count
free(self) frees the list and internal storage

The method-table field insert_bulk(self, elements, count) appends all pointers from the array. It is called as list->insert_bulk(list, elements, count). If the list is NULL, the array is NULL, or count <= 0, it does nothing.

Choose the Variant

Variant Use it when... Order rule Read cost Middle insert or remove
ARRAY_LIST indexed reads matter caller-controlled direct by index shifts the tail
LINKED_LIST node insertion and removal matter more than direct indexing caller-controlled traversal to the index no array shift
SORTED_LIST the list must stay ordered after every insert comparator-controlled direct by index after insertion shifts the tail after comparator placement

ARRAY_LIST

ARRAY_LIST stores a void ** buffer and grows geometrically.

Use it when appending and indexed reads dominate the workload. Appending at size is the clean path. Inserting in the middle still works, but every element after the insertion point shifts.

get returns NULL when the index is out of range. Inserting with an invalid index leaves the list unchanged in the shipped tests.

LINKED_LIST

LINKED_LIST stores linked nodes and keeps the same public interface as ARRAY_LIST.

Use it when insertion or removal in the middle matters more than direct index lookup. There is still no constant-time random access. get must walk nodes to the requested index.

Out-of-range get returns NULL. Inserting with an invalid index leaves the list unchanged in the shipped tests.

SORTED_LIST

SORTED_LIST maintains order on every insertion. The comparator is therefore part of the contract and is required in practice.

The index argument passed to insert is ignored. Placement is decided by the comparator, not by the caller. That point matters because code that assumes insert(..., 0) means front insertion will be wrong for SORTED_LIST.

After insertion, get reads the ordered position. remove deletes by index and the remaining elements stay ordered.

Ownership and Cleanup

Lists store pointers. They do not copy or destroy the pointed-to payloads.

Destroy the list with list->free(list). Free the payloads in your own code if your program owns them.

Example

#include "list.h"

int main(void) {
    list *names = create_list(ARRAY_LIST, 2, NULL);
    char *a = "alpha";
    char *b = "beta";

    names->insert(names, a, 0);
    names->insert(names, b, 1);

    char *first = (char *)names->get(names, 0);
    names->free(names);
    return first && first[0] == 'a' ? 0 : 1;
}

When Not to Use a List

If the main operation is FIFO removal, move to Queues-and-Stacks.

If the main operation is “give me the top-priority item,” move to Heaps-and-Priority-Queues.

If the main operation is push and pop at both ends, move to Deque.