paul_list.h

Includes:
<stddef.h>
<assert.h>
<stdlib.h>
<string.h>

Introduction

Dynamic array (stretchy-buffer) macros for C/C++.

Discussion

Implementation is included when PAUL_LIST_IMPLEMENTATION or PAUL_IMPLEMENTATION is defined.

Updated:
Monday, September 29, 2025


Macro Definitions

list_append

Append a value to the end of the list.

list_car

Return a pointer to the first element of the list (the "car").

list_cdr

Return a pointer to the list starting at the second element (the "cdr").

list_clear

Clear all elements from the list and shrink its backing allocation.

list_count

Return the number of elements currently stored in the list.

list_free

Free the underlying buffer used by a dynamic list created with these macros.

list_insert

Insert a value at the specified index, shifting subsequent elements.

list_last

Return a pointer to the last element in the list.

list_pop

Remove the last element from the list (decrement count) and possibly shrink the backing storage.

list_push

Push a value to the front of the list (insert at index 0).

list_remove_at

Remove the element at the given index, shifting subsequent elements left.

list_reverse

Reverse the order of elements in the list in-place.

list_shift

Remove the first element of the list (shift).

list_shuffle

Randomly shuffle the elements of the list in-place using rand().


list_append


Append a value to the end of the list.

#define list_append(a, v)  
Parameters
a

The list variable (pointer-to-element-type). May be NULL; it will be grown as needed.

v

The value to append (assigned by value into the list element slot).

Discussion

This macro may reallocate the list to accommodate the new element. After growing, it stores the value at the next index and increments the list count.


list_car


Return a pointer to the first element of the list (the "car").

#define list_car(a)  
Parameters
a

The list variable (pointer-to-element-type).

Return Value

Pointer to the first element, or NULL if the list is NULL.


list_cdr


Return a pointer to the list starting at the second element (the "cdr").

#define list_cdr(a)  
Parameters
a

The list variable (pointer-to-element-type).

Return Value

Pointer to the second element of the list, or NULL if the list has fewer than two elements.


list_clear


Clear all elements from the list and shrink its backing allocation.

#define list_clear(a)  
Parameters
a

The list variable (pointer-to-element-type).


list_count


Return the number of elements currently stored in the list.

#define list_count(a)  
Parameters
a

The list variable (pointer-to-element-type). May be NULL.

Return Value

The number of elements in the list (0 if 'a' is NULL).


list_free


Free the underlying buffer used by a dynamic list created with these macros.

#define list_free(a)  
Parameters
a

The list pointer previously used with the list macros. May be NULL.

Discussion

If 'a' is non-NULL this macro frees the internal allocation backing the list. After calling this macro the caller must not use 'a' unless it is reinitialized. The macro evaluates to 0.


list_insert


Insert a value at the specified index, shifting subsequent elements.

#define list_insert(a, idx, v)  
Parameters
a

The list variable (pointer-to-element-type). May be NULL; it will be grown as needed.

idx

Zero-based index at which to insert the value. Must be <= current count.

v

The value to insert.

Discussion

This macro grows the list if necessary, shifts elements starting at 'idx' one slot to the right, stores 'v' at 'idx', and increments the stored element count.


list_last


Return a pointer to the last element in the list.

#define list_last(a)  
Parameters
a

The list variable (pointer-to-element-type).

Return Value

Pointer to the last element, or NULL if the list is NULL or empty.


list_pop


Remove the last element from the list (decrement count) and possibly shrink the backing storage.

#define list_pop(a)  
Parameters
a

The list variable (pointer-to-element-type).

Discussion

This macro only adjusts the stored element count; it does not return the popped value. It may shrink the backing allocation when the list becomes sparse.


list_push


Push a value to the front of the list (insert at index 0).

#define list_push(a, v)  
Parameters
a

The list variable (pointer-to-element-type).

v

The value to push.


list_remove_at


Remove the element at the given index, shifting subsequent elements left.

#define list_remove_at(a, idx)  
Parameters
a

The list variable (pointer-to-element-type).

idx

The zero-based index of the element to remove.

Discussion

The macro shifts elements after 'idx' down and adjusts the stored count. It will also attempt to shrink the backing allocation when appropriate.


list_reverse


Reverse the order of elements in the list in-place.

#define list_reverse(a) \ 
    do { \ 
    int len = list_count(a); \ 
    for (int i = 0; i < len / 2; i++) { \ 
    int j = (len - i) - 1; \ 
    typeof(a[i]) tmp = a[i]; \ 
    a[i] = a[j]; \ 
    a[j] = tmp; \ 
    } \ 
    } while(0) 
Parameters
a

The list variable (pointer-to-element-type).


list_shift


Remove the first element of the list (shift).

#define list_shift(a)  
Parameters
a

The list variable (pointer-to-element-type).


list_shuffle


Randomly shuffle the elements of the list in-place using rand().

#define list_shuffle(a) \ 
    do { \ 
    int i, j, n = list_count(a); \ 
    for (i = n - 1; i > 0; i--) { \ 
    j = rand() % (i + 1); \ 
    typeof(a[i]) tmp = a[j]; \ 
    a[j] = a[i]; \ 
    a[i] = tmp; \ 
    } \ 
    } while(0) 
Parameters
a

The list variable (pointer-to-element-type).

Discussion

Uses the Fisher–Yates shuffle algorithm. The caller is responsible for seeding the PRNG (e.g. srand()) if reproducible behaviour is required.