Skip to content

GenericList

Description

The generic linked list. Not meant to be directly used by user code.

Usage example (Cross-references)

Usage examples (Cross-references)
        Allocator        *allocator;
        u64               __magic;
    } GenericList;
    
    ///
    /// TAGS: List, Generic, Cast
    ///
    #define GENERIC_LIST(list) ((GenericList *)(void *)(list))
    
    ///
    /// TAGS: List, Validate, API
    ///
    #define ValidateList(l) validate_list((const GenericList *)GENERIC_LIST(l))
    
    #endif // MISRA_STD_CONTAINER_LIST_TYPE_H
    #include <Misra/Std/Memory.h>
    
    void deinit_list(GenericList *list, u64 item_size) {
        if (!list || !item_size) {
            LOG_FATAL("invalid arguments.");
    
    
    bool insert_into_list(GenericList *list, const void *item_data, u64 item_size, u64 idx) {
        GenericListNode *new_node;
        GenericListNode *next_node;
    }
    
    void remove_range_list(GenericList *list, void *removed_data, u64 item_size, u64 start, u64 count) {
        if (!list || !item_size) {
            LOG_FATAL("invalid arguments.");
    
    
    bool list_sort(GenericList *list, u64 item_size, GenericCompare comp) {
        GenericListNode *node;
        void            *data;
    
    
    void swap_list(GenericList *list, u64 item_size, u64 idx1, u64 idx2) {
        if (!list || !item_size) {
            LOG_FATAL("invalid arguments.");
    
    
    void reverse_list(GenericList *list, u64 item_size) {
        if (!list || !item_size) {
            LOG_FATAL("invalid arguments.");
    
    
    bool push_arr_list(GenericList *list, u64 item_size, const void *arr, u64 count) {
        const u8 *cursor;
        u64       old_length;
    
    
    bool merge_list(GenericList *list1, u64 item_size, GenericList *list2) {
        GenericListNode *node;
        u64              old_length;
    
    
    void clear_list(GenericList *list, u64 item_size) {
        if (!list || !item_size) {
            LOG_FATAL("invalid arguments.");
    
    
    GenericListNode *node_at_list(GenericList *list, u64 item_size, u64 idx) {
        if (!list || !item_size) {
            LOG_FATAL("invalid arguments.");
    
    
    void *item_ptr_at_list(GenericList *list, u64 item_size, u64 idx) {
        if (!list || !item_size) {
            LOG_FATAL("invalid arguments.");
    }
    
    size find_idx_list(GenericList *list, const void *item_data, u64 item_size, GenericCompare comp) {
        if (!list || !item_data || !item_size || !comp) {
            LOG_FATAL("invalid arguments.");
    // consistency. Memoized via MAGIC_VALIDATED_BIT; every mutator that
    // touches head/tail/length flips the bit at the end of its work.
    static void validate_list_structural(const GenericList *l) {
        if (!l->allocator) {
            LOG_FATAL("List allocator pointer is NULL.");
    }
    
    void validate_list(const GenericList *l) {
        if (!l) {
            LOG_FATAL("List pointer is NULL.");
        }
        validate_list_structural(l);
        ((GenericList *)(void *)l)->__magic &= ~MAGIC_VALIDATED_BIT;
    }
    }
    
    GenericListNode *get_node_random_access(GenericList *list, GenericListNode *node, u64 nidx, i64 ridx) {
        if (!list || !node) {
            LOG_FATAL("Invalid arguments");
    }
    
    GenericListNode *get_node_for_list_iteration(GenericList *list, GenericListNode *node, u64 nidx, u64 target_idx) {
        if (!list) {
            LOG_FATAL("Invalid arguments");
    }
    
    bool list_insert_one_l(GenericList *list, const void *item_copy, void *source, u64 item_size, u64 idx) {
        return list_zero_source_on_success(list, source, item_size, insert_into_list(list, item_copy, item_size, idx));
    }
    }
    
    bool list_insert_one_r(GenericList *list, const void *item_copy, u64 item_size, u64 idx) {
        return insert_into_list(list, item_copy, item_size, idx);
    }
    }
    
    bool list_insert_range_l(GenericList *list, void *items, u64 item_size, u64 count) {
        if (!count) {
            return true;
    }
    
    bool list_insert_range_r(GenericList *list, const void *items, u64 item_size, u64 count) {
        if (!count) {
            return true;
    }
    
    bool list_merge_l(GenericList *dst, GenericList *src, u64 item_size) {
        if (!src->length) {
            return true;
    }
    
    bool list_merge_r(GenericList *dst, GenericList *src, u64 item_size) {
        if (!src->length) {
            return true;
    }
    
    static bool list_matches(GenericList *list, const int *expected, size count) {
        if (ListLen(list) != count) {
            return false;
    }
    
    static bool list_holds(GenericList *list, const int *expected, size count) {
        if (ListLen(list) != count) {
            return false;
    }
    
    static bool list_matches(GenericList *list, const int *expected, size count) {
        if (ListLen(list) != count) {
            return false;
    }
    
    static bool list_holds(GenericList *list, const int *expected, size count) {
        if (ListLen(list) != count) {
            return false;
    
    // Build [0, 10, 20, ... ] so value == index * 10 -> data identifies the node.
    static void fill_decades(GenericList *list, u64 count) {
        for (u64 i = 0; i < count; i++) {
            int v = (int)(i * 10);
        fill_decades(GENERIC_LIST(&list), 4);
    
        GenericList *g = GENERIC_LIST(&list);
    
        // First validate consumes the validated bit (real path), so subsequent
    
    // Build [0, 10, 20, ... ] so value == index * 10 -> data identifies the node.
    static void fill_decades(GenericList *list, u64 count) {
        for (u64 i = 0; i < count; i++) {
            int v = (int)(i * 10);
        GenericListNode node = {0};
        List(int) list       = ListInit(get_test_alloc());
        GenericList *g       = GENERIC_LIST(&list);
    
        // intentional bypass: ListHead/ListTail/ListLen are read-only; plant
        GenericListNode node  = {.next = NULL, .prev = NULL, .data = &value};
        List(int) list        = ListInit(get_test_alloc());
        GenericList *g        = GENERIC_LIST(&list);
    
        // intentional bypass: ListHead/ListTail/ListLen are read-only; plant
        GenericListNode node  = {.next = NULL, .prev = (GenericListNode *)1, .data = &value};
        List(int) list        = ListInit(get_test_alloc());
        GenericList *g        = GENERIC_LIST(&list);
    
        // intentional bypass: ListHead/ListTail/ListLen are read-only; plant a
        GenericListNode node  = {.next = (GenericListNode *)1, .prev = NULL, .data = &value};
        List(int) list        = ListInit(get_test_alloc());
        GenericList *g        = GENERIC_LIST(&list);
    
        // intentional bypass: ListHead/ListTail/ListLen are read-only; plant a
        FILL_EIGHT(&list);
    
        GenericList *g = GENERIC_LIST(&list);
        (void)get_node_for_list_iteration(g, NULL, 0, ListLen(&list));
        FILL_EIGHT(&list);
    
        GenericList     *g    = GENERIC_LIST(&list);
        GenericListNode *base = node_at_list(g, sizeof(int), 4);
        (void)get_node_random_access(g, base, 4, 4);
        fill_decades(GENERIC_LIST(&list), 4);
    
        GenericList *g = GENERIC_LIST(&list);
        // nidx == length (4) with ridx 0. Real aborts at the bound guard. The
        // node pointer is the head (valid) so only the guard distinguishes.
    }
    
    static bool list_matches(GenericList *list, const int *expected, size count) {
        if (ListLen(list) != count) {
            return false;
    #include "../../Util/TestRunner.h"
    
    static bool list_matches(GenericList *list, const int *expected, size count) {
        if (ListLen(list) != count) {
            return false;
    
    // Build [0, 10, 20, ... ] so value == index * 10 -> data identifies the node.
    static void fill_decades(GenericList *list, u64 count) {
        for (u64 i = 0; i < count; i++) {
            int v = (int)(i * 10);
    }
    
    static bool list_matches(GenericList *list, const int *expected, size count) {
        if (ListLen(list) != count) {
            return false;
        FILL_EIGHT(&list);
    
        GenericList     *g    = GENERIC_LIST(&list);
        GenericListNode *base = node_at_list(g, sizeof(int), 7);
        GenericListNode *got  = get_node_random_access(g, base, 7, -4);
        FILL_EIGHT(&list);
    
        GenericList     *g    = GENERIC_LIST(&list);
        GenericListNode *base = node_at_list(g, sizeof(int), 0);
        GenericListNode *got  = get_node_random_access(g, base, 0, 4);
        FILL_EIGHT(&list);
    
        GenericList *g      = GENERIC_LIST(&list);
        bool         result = true;
        for (u64 i = 0; i < 8; i++) {
        fill_decades(GENERIC_LIST(&list), 9); // indices 0..8, tail value 80
    
        GenericList     *g    = GENERIC_LIST(&list);
        GenericListNode *tail = node_at_list(g, sizeof(int), 8);
        GenericListNode *got  = get_node_random_access(g, tail, 8, 0);
Last updated on