{"id":34250432,"url":"https://github.com/skeletoss/ccc","last_synced_at":"2026-04-13T01:23:55.655Z","repository":{"id":221243764,"uuid":"744806091","full_name":"SkeletOSS/ccc","owner":"SkeletOSS","description":"Various containers written for C programmers who need complete control over their memory.","archived":false,"fork":false,"pushed_at":"2025-12-10T18:57:07.000Z","size":20440,"stargazers_count":14,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-12-11T05:35:50.234Z","etag":null,"topics":["buffer","containers","data-structures","double-ended-priority-queue","double-ended-queue","doubly-linked-list","handles","hash-table-c","hashmap","multimap","ordered-map","priority-queues","realtime-maps","ring-buffer","simd","singly-linked-list","splay-tree","wavl-tree"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SkeletOSS.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-01-18T03:20:25.000Z","updated_at":"2025-12-10T18:57:11.000Z","dependencies_parsed_at":"2024-02-06T23:23:28.535Z","dependency_job_id":"cfcf1cc8-1cc2-465a-95f0-a3dc2c0271e1","html_url":"https://github.com/SkeletOSS/ccc","commit_stats":null,"previous_names":["agl-alexglopez/tree-lib","agl-alexglopez/cc","agl-alexglopez/c-container-library","agl-alexglopez/ccc","skeletoss/ccc"],"tags_count":105,"template":false,"template_full_name":null,"purl":"pkg:github/SkeletOSS/ccc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SkeletOSS%2Fccc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SkeletOSS%2Fccc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SkeletOSS%2Fccc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SkeletOSS%2Fccc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SkeletOSS","download_url":"https://codeload.github.com/SkeletOSS/ccc/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SkeletOSS%2Fccc/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27761875,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-16T02:00:10.477Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["buffer","containers","data-structures","double-ended-priority-queue","double-ended-queue","doubly-linked-list","handles","hash-table-c","hashmap","multimap","ordered-map","priority-queues","realtime-maps","ring-buffer","simd","singly-linked-list","splay-tree","wavl-tree"],"created_at":"2025-12-16T09:21:19.609Z","updated_at":"2026-04-04T22:02:58.140Z","avatar_url":"https://github.com/SkeletOSS.png","language":"C","readme":"# C Container Collection (CCC)\n\nThe C Container Collection offers a variety of containers for C programmers who want fine-grained control of memory in their programs. All containers offer both allocating and non-allocating interfaces. For the motivations of why such a library is helpful in C read on.\n\n## Installation\n\nThe following are required for install:\n\n- GCC or Clang supporting `C23`.\n    - The oldest compilers I am aware of that build a release package are Clang 19.1.1 and GCC 14.2. Older compilers may work as well.\n    - To build the samples, tests, and utilities that are not included in the release package newer compilers are needed. At the time of writing Clang 22.1.0 and GCC 15.2 cover the newer C features used such as `defer`. These newer compilers are only needed for developers looking to contribute to the collection.\n- CMake \u003e= 3.23.\n- Read [INSTALL.md](INSTALL.md) for easy installation. Freestanding environments are also supported!\n\nCurrently, this library supports a `FetchContent` or manual installation via CMake. The [INSTALL.md](INSTALL.md) file is included in all [Releases](https://github.com/skeletoss/ccc/releases).\n\n## Quick Start\n\n- Read the [DOCS](https://skeletoss.github.io/ccc).\n- Read [types.h](https://skeletoss.github.io/ccc/types_8h.html) to understand the `CCC_Allocator_interface` interface.\n- Read the [header](https://skeletoss.github.io/ccc/files.html) for the desired container to understand its functionality.\n- Read about generic [traits.h](https://skeletoss.github.io/ccc/traits_8h.html) shared across containers to make code more succinct.\n- Read [CONTRIBUTING.md](CONTRIBUTING.md) and the [coverage report](https://skeletoss.github.io/ccc/coverage/) if interested in the project structure, tools, and todos.\n\n## Containers\n\n\u003cdetails\u003e\n\u003csummary\u003eadaptive_map.h (dropdown)\u003c/summary\u003e\nA pointer stable ordered map that stores unique keys, implemented with a self-optimizing tree structure.\n\n```c\n#include \u003cassert.h\u003e\n#include \u003cstring.h\u003e\n#define ADAPTIVE_MAP_USING_NAMESPACE_CCC\n#define TRAITS_USING_NAMESPACE_CCC\n#include \"ccc/adaptive_map.h\"\n#include \"ccc/traits.h\"\n\nstruct Name {\n    Adaptive_map_node e;\n    char const *name;\n};\n\nCCC_Order\nkey_val_cmp(CCC_Key_comparator_arguments cmp) {\n    char const *const key = *(char **)cmp.key_left;\n    struct Name const *const right = cmp.type_right;\n    int const res = strcmp(key, right-\u003ename);\n    if (res == 0) {\n        return CCC_ORDER_EQUAL;\n    }\n    if (res \u003c 0) {\n        return CCC_ORDER_LESSER;\n    }\n    return CCC_ORDER_GREATER;\n}\n\nint\nmain(void) {\n    struct Name nodes[5];\n    Adaptive_map om = adaptive_map_default(\n        struct Name,\n        e,\n        name,\n        (CCC_Key_comparator){.compare = key_val_cmp}\n    );\n    char const *const sorted_names[5]\n        = {\"Ferris\", \"Glenda\", \"Rocky\", \"Tux\", \"Ziggy\"};\n    size_t const size = sizeof(sorted_names) / sizeof(sorted_names[0]);\n    size_t j = 7 % size;\n    for (size_t i = 0; i \u003c size; ++i, j = (j + 7) % size) {\n        nodes[count(\u0026om).count].name = sorted_names[j];\n        CCC_Entry e = insert_or_assign(\n            \u0026om,\n            \u0026nodes[count(\u0026om).count].e\n            \u0026(CCC_Allocator){}\n        );\n        assert(!insert_error(\u0026e) \u0026\u0026 !occupied(\u0026e));\n    }\n    j = 0;\n    for (struct Name const *n = begin(\u0026om); n != end(\u0026om);\n         n = next(\u0026om, \u0026n-\u003ee)) {\n        assert(n-\u003ename == sorted_names[j]);\n        assert(strcmp(n-\u003ename, sorted_names[j]) == 0);\n        ++j;\n    }\n    assert(count(\u0026om).count == size);\n    CCC_Entry e = try_insert(\n        \u0026om,\n        \u0026(struct Name){.name = \"Ferris\"}.e,\n        \u0026(CCC_Allocator){}\n    );\n    assert(count(\u0026om).count == size);\n    assert(occupied(\u0026e));\n    return 0;\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003earray_adaptive_map.h (dropdown)\u003c/summary\u003e\nAn ordered map implemented in array with an index based self-optimizing tree. Offers handle stability. Handles remain valid until an element is removed from a table regardless of other insertions, other deletions, or resizing of the array.\n\n```c\n#include \u003cassert.h\u003e\n#include \u003cstdbool.h\u003e\n#define ARRAY_ADAPTIVE_MAP_USING_NAMESPACE_CCC\n#define TRAITS_USING_NAMESPACE_CCC\n#define TYPES_USING_NAMESPACE_CCC\n#include \"ccc/array_adaptive_map.h\"\n#include \"ccc/traits.h\"\n\nstruct Key_val {\n    int key;\n    int val;\n};\n\nstatic CCC_Order\nkey_val_cmp(CCC_Key_comparator_arguments const cmp) {\n    struct Key_val const *const right = cmp.type_right;\n    int const key_left = *((int *)cmp.key_left);\n    return (key_left \u003e right-\u003ekey) - (key_left \u003c right-\u003ekey);\n}\n\nint\nmain(void) {\n    /* stack array of 25 elements with one slot for sentinel, intrusive field\n       named elem, key field named key, no allocation permission, key comparison\n       function, no context data. */\n    Array_adaptive_map s = array_adaptive_map_with_storage(\n        key,\n        (CCC_Key_comparator){.compare = key_val_cmp},\n        (struct Key_val[26]){}\n    );\n    int const num_nodes = 25;\n    /* 0, 5, 10, 15, 20, 25, 30, 35,... 120 */\n    for (int i = 0, id = 0; i \u003c num_nodes; ++i, id += 5) {\n        (void)insert_or_assign(\n            \u0026s, \u0026(struct Key_val){.key = id, .val = i}.elem, \u0026(CCC_Allocator){}\n        );\n    }\n    /* This should be the following Range [6,44). 6 should raise to\n       next value not less than 6, 10 and 44 should be the first\n       value greater than 44, 45. */\n    int range_keys[8] = {10, 15, 20, 25, 30, 35, 40, 45};\n    Handle_range r = equal_range(\u0026s, \u0026(int){6}, \u0026(int){44});\n    int index = 0;\n    for (Handle_index i = range_begin(\u0026r); i != range_end(\u0026r);\n         i = next(\u0026s, i)) {\n        struct Key_val const *const kv = array_adaptive_map_at(\u0026s, i);\n        assert(kv-\u003ekey == range_keys[index]);\n        ++index;\n    }\n    /* This should be the following Range [119,84). 119 should be\n       dropped to first value not greater than 119 and last should\n       be dropped to first value less than 84. */\n    int range_reverse_keys[8] = {115, 110, 105, 100, 95, 90, 85, 80};\n    Handle_range_reverse rr = equal_range_reverse(\u0026s, \u0026(int){119}, \u0026(int){84});\n    index = 0;\n    for (Handle_index i = range_reverse_begin(\u0026rr); i != range_reverse_end(\u0026rr);\n         i = reverse_next(\u0026s, i)) {\n        struct Key_val const *const kv = array_adaptive_map_at(\u0026s, i);\n        assert(kv-\u003ekey == range_reverse_keys[index]);\n        ++index;\n    }\n    return 0;\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003earray_tree_map.h (dropdown)\u003c/summary\u003e\nAn ordered map with strict runtime bounds implemented in an array with indices tracking the tree structure. Offers handle stability. Handles remain valid until an element is removed from a table regardless of other insertions, other deletions, or resizing of the array.\n\n```c\n#include \u003cassert.h\u003e\n#include \u003cstdbool.h\u003e\n#define ARRAY_TREE_MAP_USING_NAMESPACE_CCC\n#define TRAITS_USING_NAMESPACE_CCC\n#define TYPES_USING_NAMESPACE_CCC\n#include \"ccc/array_tree_map.h\"\n#include \"ccc/traits.h\"\n\nstruct Key_val {\n    int key;\n    int val;\n};\n\nstatic CCC_Order\nkey_val_cmp(CCC_Key_comparator_arguments const cmp) {\n    struct Key_val const *const right = cmp.type_right;\n    int const key_left = *((int *)cmp.key_left);\n    return (key_left \u003e right-\u003ekey) - (key_left \u003c right-\u003ekey);\n}\n\nint\nmain(void) {\n    /* stack array, user defined type, key field named key, no allocation\n       permission, key comparison function, no context data. */\n    Array_tree_map s = array_tree_map_with_storage(\n        key,\n        (CCC_Key_comparator){.compare = key_val_cmp},\n        (struct Kay_val[64]){}\n    );\n    int const num_nodes = 25;\n    /* 0, 5, 10, 15, 20, 25, 30, 35,... 120 */\n    for (int i = 0, id = 0; i \u003c num_nodes; ++i, id += 5) {\n        (void)insert_or_assign(\n            \u0026s,\n            \u0026(struct Key_val){.key = id, .val = i}.elem,\n            \u0026(CCC_Allocator){}\n        );\n    }\n    /* This should be the following Range [6,44). 6 should raise to\n       next value not less than 6, 10 and 44 should be the first\n       value greater than 44, 45. */\n    int range_keys[8] = {10, 15, 20, 25, 30, 35, 40, 45};\n    Handle_range r = equal_range(\u0026s, \u0026(int){6}, \u0026(int){44});\n    int index = 0;\n    for (Handle_index i = range_begin(\u0026r); i != range_end(\u0026r);\n         i = next(\u0026s, \u0026i-\u003eelem)) {\n        struct Key_val const *const kv = array_tree_map_at(\u0026s, i);\n        assert(kv-\u003ekey == range_keys[index]);\n        ++index;\n    }\n    /* This should be the following Range [119,84). 119 should be\n       dropped to first value not greater than 119 and last should\n       be dropped to first value less than 84. */\n    int range_reverse_keys[8] = {115, 110, 105, 100, 95, 90, 85, 80};\n    Handle_range_reverse rr = equal_range_reverse(\u0026s, \u0026(int){119}, \u0026(int){84});\n    index = 0;\n    for (Handle_index i = range_reverse_begin(\u0026rr); i != range_reverse_end(\u0026rr);\n         i = reverse_next(\u0026s, \u0026i-\u003eelem)) {\n        struct Key_val const *const kv = array_tree_map_at(\u0026s, i);\n        assert(kv-\u003ekey == range_reverse_keys[index]);\n        ++index;\n    }\n    return 0;\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003edoubly_linked_list.h (dropdown)\u003c/summary\u003e\nA dynamic container for efficient insertion and removal at any position.\n\n```c\n#include \u003cassert.h\u003e\n#define DOUBLY_LINKED_LIST_USING_NAMESPACE_CCC\n#define TRAITS_USING_NAMESPACE_CCC\n#include \"ccc/doubly_linked_list.h\"\n#include \"ccc/traits.h\"\n\nstruct Int_node {\n    int i;\n    Doubly_linked_list_node e;\n};\n\nstatic CCC_Order\nint_cmp(CCC_Comparator_arguments const cmp) {\n    struct Int_node const *const left = cmp.type_left;\n    struct Int_node const *const right = cmp.type_right;\n    return (left-\u003ei \u003e right-\u003ei) - (left-\u003ei \u003c right-\u003ei);\n}\n\nint\nmain(void) {\n    Doubly_linked_list l = doubly_linked_list_default(l, struct Int_node, e);\n    struct Int_node elems[3] = {{.i = 3}, {.i = 2}, {.i = 1}};\n    (void)push_back(\u0026l, \u0026elems[0].e, \u0026(CCC_Allocator){});\n    (void)push_front(\u0026l, \u0026elems[1].e, \u0026(CCC_Allocator){});\n    (void)push_back(\u0026l, \u0026elems[2].e, \u0026(CCC_Allocator){});\n    (void)pop_back(\u0026l, \u0026(CCC_Allocator){});\n    struct Int_node *e = back(\u0026l);\n    assert(e-\u003ei == 3);\n    return 0;\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eflat_bitset.h (dropdown)\u003c/summary\u003e\nA fixed or dynamic contiguous array of bits for set operations.\n\n```c\n#include \u003cassert.h\u003e\n#include \u003cstdbool.h\u003e\n#include \u003cstddef.h\u003e\n\n#define FLAT_BITSET_USING_NAMESPACE_CCC\n#include \"ccc/flat_bitset.h\"\n#include \"ccc/types.h\"\n\n#define DIGITS 9L\n#define ROWS DIGITS\n#define COLS DIGITS\n#define BOX_SIZE 3L\n\n/* clang-format off */\nstatic int const valid_board[9][9] =\n{{5,3,0, 0,7,0, 0,0,0}\n,{6,0,0, 1,9,5, 0,0,0}\n,{0,9,8, 0,0,0, 0,6,0}\n\n,{8,0,0, 0,6,0, 0,0,3}\n,{4,0,0, 8,0,3, 0,0,1}\n,{7,0,0, 0,2,0, 0,0,6}\n\n,{0,6,0, 0,0,0, 2,8,0}\n,{0,0,0, 4,1,9, 0,0,5}\n,{0,0,0, 0,8,0, 0,7,9}};\n\nstatic int const invalid_board[9][9] =\n{{8,3,0, 0,7,0, 0,0,0} /* 8 in first box top left. */\n,{6,0,0, 1,9,5, 0,0,0}\n,{0,9,8, 0,0,0, 0,6,0} /* 8 in first box bottom right. */\n\n,{8,0,0, 0,6,0, 0,0,3} /* 8 also overlaps with 8 in top left by row. */\n,{4,0,0, 8,0,3, 0,0,1}\n,{7,0,0, 0,2,0, 0,0,6}\n\n,{0,6,0, 0,0,0, 2,8,0}\n,{0,0,0, 4,1,9, 0,0,5}\n,{0,0,0, 0,8,0, 0,7,9}};\n/* clang-format on */\n\n/* Returns if the box is valid (CCC_TRUE if valid CCC_FALSE if not). */\nstatic CCC_Tribool\nvalidate_sudoku_box(int const board[9][9], Flat_bitset *const row_check,\n                    Flat_bitset *const col_check, size_t const row_start,\n                    size_t const col_start) {\n    Flat_bitset box_check\n        = flat_bitset_with_storage(DIGITS, flat_bitset_storage_for(DIGITS));\n    CCC_Tribool was_on = CCC_FALSE;\n    for (size_t r = row_start; r \u003c row_start + BOX_SIZE; ++r) {\n        for (size_t c = col_start; c \u003c col_start + BOX_SIZE; ++c) {\n            if (!board[r][c]) {\n                continue;\n            }\n            /* Need the zero based digit. */\n            size_t const digit = board[r][c] - 1;\n            was_on = flat_bitset_set(\u0026box_check, digit, CCC_TRUE);\n            if (was_on) {\n                return CCC_FALSE;\n            }\n            was_on = flat_bitset_set(row_check, (r * DIGITS) + digit, CCC_TRUE);\n            if (was_on) {\n                return CCC_FALSE;\n            }\n            was_on = flat_bitset_set(col_check, (c * DIGITS) + digit, CCC_TRUE);\n            if (was_on) {\n                return CCC_FALSE;\n            }\n        }\n    }\n    return CCC_TRUE;\n}\n\n/* A small problem like this is a perfect use case for a stack based bit set.\n   All sizes are known at compile time meaning we get memory management for\n   free and the optimal space and time complexity for this problem. */\n\nstatic CCC_Tribool\nis_valid_sudoku(int const board[9][9]) {\n    Flat_bitset row_check = flat_bitset_with_storage(\n        ROWS * DIGITS, flat_bitset_storage_for(ROWS * DIGITS));\n    Flat_bitset col_check = flat_bitset_with_storage(\n        COLS * DIGITS, flat_bitset_storage_for(COLS * DIGITS));\n    for (size_t row = 0; row \u003c ROWS; row += BOX_SIZE) {\n        for (size_t col = 0; col \u003c COLS; col += BOX_SIZE) {\n            if (!validate_sudoku_box(board, \u0026row_check, \u0026col_check, row, col)) {\n                return CCC_FALSE;\n            }\n        }\n    }\n    return CCC_TRUE;\n}\n\nint\nmain(void) {\n    CCC_Tribool result = is_valid_sudoku(valid_board);\n    assert(result == CCC_TRUE);\n    result = is_valid_sudoku(invalid_board);\n    assert(result == CCC_FALSE);\n    return 0;\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eflat_buffer.h (dropdown)\u003c/summary\u003e\nA fixed or dynamic contiguous array of a single user defined type.\n\n```c\n#include \u003cassert.h\u003e\n#define FLAT_BUFFER_USING_NAMESPACE_CCC\n#define TRAITS_USING_NAMESPACE_CCC\n#include \"ccc/flat_buffer.h\"\n#include \"ccc/traits.h\"\n\nenum : size_t {\n    HCAP = 12,\n};\n\nstatic inline int\nmaxint(int const a, int const b) {\n    return a \u003e b ? a : b;\n}\n\n/* Trapping rainwater Leetcode problem with iterators */\nint\nmain(void) {\n    Flat_buffer const heights = flat_buffer_with_storage(\n        HCAP, (int[HCAP]){0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1});\n    int const correct_trapped = 6;\n    int trapped = 0;\n    int lpeak = *flat_buffer_front_as(\u0026heights, int);\n    int rpeak = *flat_buffer_back_as(\u0026heights, int);\n    /* Easy way to have a \"skip first\" iterator because the iterator is\n       returned from each iterator function. */\n    int const *l = next(\u0026heights, begin(\u0026heights));\n    int const *r = reverse_next(\u0026heights, reverse_begin(\u0026heights));\n    while (l \u003c= r) {\n        if (lpeak \u003c rpeak) {\n            lpeak = maxint(lpeak, *l);\n            trapped += (lpeak - *l);\n            l = next(\u0026heights, l);\n        } else {\n            rpeak = maxint(rpeak, *r);\n            trapped += (rpeak - *r);\n            r = reverse_next(\u0026heights, r);\n        }\n    }\n    assert(trapped == correct_trapped);\n    return 0;\n}\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eflat_doubled_ended_queue.h (dropdown)\u003c/summary\u003e\nA dynamic or fixed size double ended queue offering contiguously stored elements. When fixed size, its behavior is that of a ring buffer.\n\n```c\n#include \u003cassert.h\u003e\n#define FLAT_DOUBLE_ENDED_QUEUE_USING_NAMESPACE_CCC\n#define TRAITS_USING_NAMESPACE_CCC\n#include \"ccc/flat_double_ended_queue.h\"\n#include \"ccc/traits.h\"\n\nint\nmain(void) {\n    Flat_doubled_ended_queue q\n        = flat_doubled_ended_queue_with_storage(2, (int[2]){});\n    (void)push_back(\u0026q, \u0026(int){3}, \u0026(CCC_Allocator){});\n    (void)push_front(\u0026q, \u0026(int){2}, \u0026(CCC_Allocator){});\n    (void)push_back(\u0026q, \u0026(int){1}, \u0026(CCC_Allocator){}); /* Overwrite 2. */\n    int *i = front(\u0026q);\n    assert(*i == 3);\n    i = back(\u0026q);\n    assert(*i == 1);\n    (void)pop_back(\u0026q);\n    i = back(\u0026q);\n    assert(*i == 3);\n    i = front(\u0026q);\n    assert(*i == 3);\n    return 0;\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eflat_hash_map.h (dropdown)\u003c/summary\u003e\nAmortized O(1) access to elements stored in a flat array by key. Not pointer stable.\n\n```c\n#include \u003cassert.h\u003e\n#include \u003cstdbool.h\u003e\n#include \u003cstdint.h\u003e\n#define FLAT_HASH_MAP_USING_NAMESPACE_CCC\n#define TRAITS_USING_NAMESPACE_CCC\n#include \"ccc/flat_hash_map.h\"\n#include \"ccc/traits.h\"\n\nstruct Key_val {\n    int key;\n    int val;\n};\n\nstatic uint64_t\nflat_hash_map_int_to_u64(CCC_Key_arguments const k) {\n    int const key_int = *((int *)k.key);\n    uint64_t x = key_int;\n    x = (x ^ (x \u003e\u003e 30)) * UINT64_C(0xbf58476d1ce4e5b9);\n    x = (x ^ (x \u003e\u003e 27)) * UINT64_C(0x94d049bb133111eb);\n    x = x ^ (x \u003e\u003e 31);\n    return x;\n}\n\nstatic CCC_Order\nflat_hash_map_id_order(CCC_Key_comparator_arguments const cmp) {\n    struct Key_val const *const right = cmp.type_right;\n    int const left = *((int *)cmp.key_left;\n    return (left \u003e right-\u003ekey) - (left \u003c right-\u003ekey);\n}\n\nenum : size_t {\n    STANDARD_FIXED_CAP = 1024,\n};\n\n/* Longest Consecutive Sequence Leetcode Problem */\nint\nmain(void) {\n    Flat_hash_map fh = flat_hash_map_with_storage(\n        key,\n        ((CCC_Hasher){\n            .hash = flat_hash_map_int_to_u64,\n            .compare = flat_hash_map_id_order,\n        }),\n        (struct Key_val[STANDARD_FIXED_CAP]){}\n    );\n    /* Longest sequence is 1,2,3,4,5,6,7,8,9,10 of length 10. */\n    int const nums[] = {\n        99, 54, 1, 4, 9,  2, 3,   4,  8,  271, 32, 45, 86, 44, 7,  777, 6,  20,\n        19, 5,  9, 1, 10, 4, 101, 15, 16, 17,  18, 19, 20, 10, 21, 22,  23,\n    };\n    static_assert(sizeof(nums) / sizeof(nums[0]) \u003c STANDARD_FIXED_CAP / 2);\n    int const correct_max_run = 10;\n    size_t const nums_size = sizeof(nums) / sizeof(nums[0]);\n    int max_run = 0;\n    for (size_t i = 0; i \u003c nums_size; ++i) {\n        int const n = nums[i];\n        CCC_Entry const *const seen_n = flat_hash_map_try_insert_wrap(\n            \u0026fh, \u0026(struct Key_val){.key = n, .val = 1}, \u0026(CCC_Allocator){}\n        );\n        /* We have already connected this run as much as possible. */\n        if (occupied(seen_n)) {\n            continue;\n        }\n\n        /* There may or may not be runs already existing to left and right. */\n        struct Key_val const *const connect_left\n            = get_key_value(\u0026fh, \u0026(int){n - 1});\n        struct Key_val const *const connect_right\n            = get_key_value(\u0026fh, \u0026(int){n + 1});\n        int const left_run = connect_left ? connect_left-\u003eval : 0;\n        int const right_run = connect_right ? connect_right-\u003eval : 0;\n        int const full_run = left_run + 1 + right_run;\n\n        /* Track solution to problem. */\n        max_run = full_run \u003e max_run ? full_run : max_run;\n\n        /* Update the boundaries of the full run range. */\n        ((struct Key_val *)unwrap(seen_n))-\u003eval = full_run;\n        CCC_Entry const *const run_min = flat_hash_map_insert_or_assign_wrap(\n            \u0026fh,\n            \u0026(struct Key_val){.key = n - left_run, .val = full_run},\n            \u0026(CCC_Allocator){}\n        );\n        CCC_Entry const *const run_max = flat_hash_map_insert_or_assign_wrap(\n            \u0026fh,\n            \u0026(struct Key_val){.key = n + right_run, .val = full_run},\n            \u0026(CCC_Allocator){}\n        );\n\n        /* Validate for testing purposes. */\n        assert(occupied(run_min));\n        assert(occupied(run_max));\n        assert(!insert_error(run_min));\n        assert(!insert_error(run_max));\n    }\n    assert(max_run == correct_max_run);\n    return 0;\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eflat_priority_queue.h (dropdown)\u003c/summary\u003e\n\n```c\n#include \u003cassert.h\u003e\n#define FLAT_PRIORITY_QUEUE_USING_NAMESPACE_CCC\n#define TRAITS_USING_NAMESPACE_CCC\n#include \"ccc/flat_priority_queue.h\"\n#include \"ccc/traits.h\"\n\nstatic CCC_Order\nint_cmp(CCC_Comparator_arguments const ints) {\n    int const left = *(int *)ints.type_left;\n    int const right = *(int *)ints.type_right;\n    return (left \u003e right) - (left \u003c right);\n}\n\n/* In place O(N) heapify. */\nint\nmain(void) {\n    int heap[20] = {12, 61, -39, 76, 48, -93, -77, -81, 35, 21,\n                    -3, 90, 20,  27, 97, -22, -20, -19, 70, 76};\n    enum : size_t {\n        HCAP = sizeof(heap) / sizeof(*heap),\n    };\n    Flat_priority_queue priority_queue = flat_priority_queue_heapify(\n        int,\n        CCC_ORDER_LESSER,\n        (CCC_Comparator){.compare = int_cmp},\n        HCAP,\n        HCAP,\n        heap\n    );\n    int const prev = INT_MIN;\n    while (!is_empty(\u0026priority_queue))\n        int const *const cur = front(\u0026priority_queue);\n        assert(prev \u003c= *cur);\n        prev = *cur;\n        pop(\u0026priority_queue, \u0026(int){});\n    }\n    return 0;\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003epriority_queue.h (dropdown)\u003c/summary\u003e\nA pointer stable priority queue offering O(1) push and efficient decrease, increase, erase, and extract operations.\n\n```c\n#include \u003cassert.h\u003e\n#include \u003cstdbool.h\u003e\n#define PRIORITY_QUEUE_USING_NAMESPACE_CCC\n#define TRAITS_USING_NAMESPACE_CCC\n#define TYPES_USING_NAMESPACE_CCC\n#include \"ccc/priority_queue.h\"\n#include \"ccc/traits.h\"\n\nstruct Val {\n    Priority_queue_node elem;\n    int val;\n};\n\nstatic CCC_Order\nval_cmp(CCC_Comparator_arguments const cmp) {\n    struct Val const *const left = cmp.type_left;\n    struct Val const *const right = cmp.type_right;\n    return (left-\u003eval \u003e right-\u003eval) - (left-\u003eval \u003c right-\u003eval);\n}\n\nint\nmain(void) {\n    struct Val elems[5]\n        = {{.val = 3}, {.val = 3}, {.val = 7}, {.val = -1}, {.val = 5}};\n    Priority_queue priority_queue = priority_queue_default(\n        struct Val,\n        elem,\n        CCC_ORDER_LESSER,\n        (CCC_Comparator){.compare = val_cmp}\n    );\n    for (size_t i = 0; i \u003c (sizeof(elems) / sizeof(elems[0])); ++i) {\n        struct Val const *const v\n            = push(\u0026priority_queue, \u0026elems[i].elem, \u0026(CCC_Allocator){});\n        assert(v \u0026\u0026 v-\u003eval == elems[i].val);\n    }\n    bool const decreased = priority_queue_decrease_with(\n        \u0026priority_queue, \u0026elems[4].elem, { elems[4].val = -99; }\n    );\n    assert(decreased);\n    struct Val const *const v = front(\u0026priority_queue);\n    assert(v-\u003eval == -99);\n    return 0;\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003esingly_linked_list.h (dropdown)\u003c/summary\u003e\nA low overhead push-to-front container. When contiguity is not possible and the access pattern resembles a stack this is more-efficient than a doubly-linked list.\n\n```c\n#include \u003cassert.h\u003e\n#define SINGLY_LINKED_LIST_USING_NAMESPACE_CCC\n#define TRAITS_USING_NAMESPACE_CCC\n#include \"ccc/singly_linked_list.h\"\n#include \"ccc/traits.h\"\n\nstruct Int_node {\n    int i;\n    Singly_linked_list_node e;\n};\n\nstatic CCC_Order\nint_cmp(CCC_Comparator_arguments const cmp) {\n    struct Int_node const *const left = cmp.type_left;\n    struct Int_node const *const right = cmp.type_right;\n    return (left-\u003ei \u003e right-\u003ei) - (left-\u003ei \u003c right-\u003ei);\n}\n\nint\nmain(void) {\n    /* singly linked list l, list elem field e, no allocation permission,\n       comparing integers, no context data. */\n    Singly_linked_list l = singly_linked_list_default(struct Int_node, e);\n    struct Int_node elems[3] = {{.i = 3}, {.i = 2}, {.i = 1}};\n    (void)push_front(\u0026l, \u0026elems[0].e, \u0026(CCC_Allocator){});\n    (void)push_front(\u0026l, \u0026elems[1].e, \u0026(CCC_Allocator){});\n    (void)push_front(\u0026l, \u0026elems[2].e, \u0026(CCC_Allocator){});\n    struct Int_node const *i = front(\u0026l);\n    assert(i-\u003ei == 1);\n    pop_front(\u0026l, \u0026(CCC_Allocator){});\n    i = front(\u0026l);\n    assert(i-\u003ei == 2);\n    return 0;\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003etree_map.h (dropdown)\u003c/summary\u003e\nA pointer stable ordered map meeting strict O(lg N) runtime bounds for realtime applications.\n\n```c\n#include \u003cassert.h\u003e\n#define TREE_MAP_USING_NAMESPACE_CCC\n#define TRAITS_USING_NAMESPACE_CCC\n#define TYPES_USING_NAMESPACE_CCC\n#include \"ccc/traits.h\"\n#include \"ccc/tree_map.h\"\n\nstruct Key_val {\n    Tree_map_node elem;\n    int key;\n    int val;\n};\n\nstatic CCC_Order\nkey_val_cmp(CCC_Key_comparator_arguments const cmp) {\n    struct Key_val const *const right = cmp.type_right;\n    int const key_left = *((int *)cmp.key_left);\n    return (key_left \u003e right-\u003ekey) - (key_left \u003c right-\u003ekey);\n}\n\nint\nmain(void) {\n    struct Key_val elems[25];\n    Tree_map s = tree_map_default(\n        struct Key_val,\n        elem,\n        key,\n        (CCC_Key_comparator){.compare = key_val_cmp}\n    );\n    int const num_nodes = 25;\n    /* 0, 5, 10, 15, 20, 25, 30, 35,... 120 */\n    for (int i = 0, id = 0; i \u003c num_nodes; ++i, id += 5) {\n        elems[i].key = id;\n        elems[i].val = i;\n        (void)insert_or_assign(\u0026s, \u0026elems[i].elem, \u0026(CCC_Allocator){});\n    }\n    /* This should be the following Range [6,44). 6 should raise to\n       next value not less than 6, 10 and 44 should be the first\n       value greater than 44, 45. */\n    int range_keys[8] = {10, 15, 20, 25, 30, 35, 40, 45};\n    Range r = equal_range(\u0026s, \u0026(int){6}, \u0026(int){44});\n    int index = 0;\n    for (struct Key_val *i = range_begin(\u0026r); i != range_end(\u0026r);\n         i = next(\u0026s, \u0026i-\u003eelem)) {\n        assert(i-\u003ekey == range_keys[index]);\n        ++index;\n    }\n    /* This should be the following Range [119,84). 119 should be\n       dropped to first value not greater than 119 and last should\n       be dropped to first value less than 84. */\n    int range_reverse_keys[8] = {115, 110, 105, 100, 95, 90, 85, 80};\n    Range_reverse rr = equal_range_reverse(\u0026s, \u0026(int){119}, \u0026(int){84});\n    index = 0;\n    for (struct Key_val *i = range_reverse_begin(\u0026rr);\n         i != range_reverse_end(\u0026rr); i = reverse_next(\u0026s, \u0026i-\u003eelem)) {\n        assert(i-\u003ekey == range_reverse_keys[index]);\n        ++index;\n    }\n    return 0;\n}\n```\n\n\u003c/details\u003e\n\n## Features\n\n- [Intrusive and non-intrusive containers](#intrusive-and-non-intrusive-containers).\n- [Allocator passing](#allocator-passing).\n- [Compile time initialization](#compile-time-initialization).\n- [Metadata is trivially copyable](#metadata-is-trivially-copyable).\n- [No `container_of` macro required of the user to get to their type after a function call](#no-container-of-macros).\n- [Rust's Entry API for associative containers with C and C++ influences](#rusts-entry-interface).\n    - Opt-in macros for more succinct insertion and in place modifications (see \"closures\" in the [and_modify_wth](https://skeletoss.github.io/ccc/flat__hash__map_8h.html) interface for associative containers).\n- [Container Traits implemented with C `_Generic` capabilities](#traits).\n\n### Intrusive and Non-Intrusive Containers\n\nCurrently, many associative containers ask the user to store an element in their type. This means wrapping an element in a struct such as this type found in `samples/graph.c` for the priority queue.\n\n```c\nstruct Cost {\n    CCC_Priority_queue_node node;\n    int cost;\n    char name;\n    char from;\n};\n```\n\nThe interface may then ask for a handle to this type for certain operations. For example, a priority queue has the following interface for pushing an element.\n\n```c\nvoid *CCC_priority_queue_push(\n    CCC_Priority_queue *priority_queue,\n    CCC_Priority_queue_node *elem,\n    CCC_Allocator const *allocator\n);\n```\n\nNon-Intrusive containers exist when a flat container can operate without such help from the user. The `Flat_priority_queue` is a good example of this. When initializing we give it the following information.\n\n```c\nCCC_Flat_priority_queue flat_priority_queue\n    = CCC_flat_priority_queue_with_storage(\n        CCC_ORDER_LESSER,\n        (CCC_Comparator){.compare = int_cmp},\n        (int[40]){}\n    );\n```\n\nHere a small min priority queue of integers with a maximum capacity of 40 has been allocated on the stack with no allocation permission and no context data needed. As long as the flat priority queue knows the type upon initialization no intrusive elements are needed. We could have also initialized this container as empty.\n\n```c\nCCC_Flat_priority_queue flat_priority_queue\n    = CCC_flat_priority_queue_default(\n        int,\n        CCC_ORDER_LESSER,\n        (CCC_Comparator){.compare = int_cmp},\n    );\n```\n\nThe interface then looks like this.\n\n```c\nvoid *CCC_flat_priority_queue_push(\n    CCC_Flat_priority_queue *flat_priority_queue,\n    void const *element,\n    void *temp,\n    CCC_Allocator const *allocator\n);\n```\n\nThe element `element` here is just a generic reference to whatever type the user stores in the container and `temp` is a swap slot provided by the user.\n\n### Allocator Passing\n\nThe C Container Collection does not call malloc, realloc, or free directly. Instead, containers that may need to allocate memory accept an allocator argument at every call site where allocation could occur. This makes allocation visible in code rather than hidden inside container operations.\n\nAn allocator is a small struct bundling a function pointer and optional context.\n\n```c\ntypedef struct {\n    CCC_Allocator_interface *allocate;\n    void *context;\n} CCC_Allocator;\n```\n\nThe `CCC_Allocator_interface` function type implements a unified interface for allocation, reallocation, and deallocation. See `types.h` for the full contract. A standard library backed allocator might look like this:\n\n```c\nvoid *\nstd_allocate(CCC_Allocator_arguments const arguments)\n{\n    if (!arguments.input \u0026\u0026 !arguments.bytes) {\n        return NULL;\n    }\n    if (!arguments.input) {\n        return malloc(arguments.bytes);\n    }\n    if (!arguments.bytes) {\n        free(arguments.input);\n        return NULL;\n    }\n    return realloc(arguments.input, arguments.bytes);\n}\n\nstatic CCC_Allocator const std_allocator = {.allocate = std_allocate};\n```\n\nContainer code always accepts the allocator by `const *`, so sharing an allocator instance across threads is safe if the allocator provided is thread safe.\n\nAny function that may need to allocate accepts a `CCC_Allocator const *` as its last argument:\n\n```c\nCCC_flat_priority_queue_push(\u0026pq, \u0026(int){1}, \u0026(int){}, \u0026std_allocator);\nCCC_flat_priority_queue_push(\n    \u0026pq,\n    \u0026(int){2},\n    \u0026(int){},\n    \u0026(CCC_Allocator){.allocate = arena_allocate, .context = \u0026arena}\n);\n```\n\nFunctions that never allocate do not accept an allocator argument. The presence or absence of the allocator argument in a function signature is the signal of whether that function may allocate.\n\nTo explicitly prevent allocation pass an empty allocator.\n\n```c\nCCC_flat_priority_queue_push(\u0026pq, \u0026(int){1}, \u0026(int){}, \u0026(CCC_Allocator){});\n```\n\nAn empty `CCC_Allocator` has `NULL` internal fields. The container checks for this and returns an appropriate error rather than attempting allocation. Never pass `NULL` to any function in the C Container Collection.\n\nPassing allocators makes auditing CCC code easy.\n\n\u003e [!IMPORTANT]\n\u003e A non-empty allocator allocator argument signals allocation may occur.\n\u003e An empty allocator argument signals allocation is forbidden.\n\u003e A `NULL` argument at any C Container Collection function call site is always a programmer error.\n\n### Compile Time Initialization\n\nBecause the user may choose the source of memory for a container, initialization at compile time is possible for all intrusive and non-intrusive containers.\n\nThis is especially helpful for the containers that use buffer, arrays, and flat memory layouts when their capacity will be fixed for their lifetime. These containers can be prepared at compile time.\n\n```c\nstruct Key_val {\n    int key;\n    int val;\n};\nstatic CCC_Array_adaptive_map adaptive_map\n    = CCC_array_adaptive_map_with_storage(\n        key,\n        (CCC_Key_comparator){.compare = compare_int_key},\n        (struct Key_val[1024]){}\n    );\nstatic CCC_Array_tree_map tree_map\n    = CCC_array_tree_map_with_storage(\n        key,\n        (CCC_Key_comparator){.compare = compare_int_key},\n        (struct Key_val[1024]){}\n    );\nstatic CCC_Flat_hash_map hash_map\n    = CCC_flat_hash_map_with_storage(\n        key,\n        ((CCC_Hasher){.hash = hash_int, .compare = compare_int_key}),\n        (struct Key_val[1024]){}\n    );\nstatic CCC_Flat_priority_queue priority_queue\n    = CCC_flat_priority_queue_with_storage(\n        CCC_ORDER_LESSER,\n        (CCC_Comparator){.compare = compare_int},\n        (int[1024]){}\n    );\nstatic CCC_Flat_double_ended_queue ring_buffer\n    = CCC_flat_double_ended_queue_with_storage(\n        0,\n        (int[1024]){}\n    );\nstatic CCC_Flat_buffer buffer\n    = CCC_flat_buffer_with_storage(\n        0,\n        (int[1024]){}\n    );\nstatic CCC_Flat_bitset bitset\n    = CCC_flat_bitset_with_storage(\n        1024,\n        (CCC_Bit[1024]){}\n    );\n```\n\nBecause the above containers are of fixed size, the empty `\u0026(CCC_Allocator){}` will be passed to any functions requesting an allocator. If containers are going to grow dynamically at runtime, they can still be initialized at compile time.\n\n```c\nstatic CCC_Flat_hash_map hash_map = CCC_flat_hash_map_default(\n    struct Key_val,\n    key,\n    ((CCC_Hasher){.hash = hash_int, .compare = compare_int_key})\n);\n```\n\nThen, a non empty `\u0026std_allocator` or `\u0026(CCC_Allocator){.allocate = arena_allocate, .context = \u0026arena}` will be passed to functions that accept an allocator.\n\n### Metadata is Trivially Copyable\n\nFor all containers, the metadata structure that is passed to interface functions is separate from the underlying storage and has no self-referential pointers. The metadata only stores configuration and references to externally managed storage. Therefore, the metadata structure can be safely copied and returned by value.\n\n```c\nstatic CCC_Doubly_linked_list\nconstruct_empty(void) {\n    CCC_Doubly_linked_list this = CCC_doubly_linked_list_default(struct Val, e);\n    return this;\n}\n\nint\nmain(void) {\n    CCC_Doubly_linked_list list = construct_empty();\n    doubly_linked_list_push_front(\u0026list, \u0026(struct Val){.val = 1}.e);\n    assert(is_empty(\u0026list) == false);\n    assert(validate(\u0026list));\n    return 0;\n}\n```\n\nFor other C container libraries the metadata structure may contain sentinel fields to which the metadata structure or external allocations point, making the above example exhibit undefined behavior. In the C Container Collection, fields within a metadata structure are never referenced from either the metadata structure itself or the allocations it manages. Therefore, returning the metadata structure for a container is well defined. This means users can organize their code how they wish, given their own standards of encapsulation and readability. However, keep in mind that C performs shallow copies by default. Therefore, copying a container metadata structure does not duplicate underlying nodes, buffers, or arrays to which it points. Instead, the new metadata instance will refer to the same underlying storage as the original container.\n\n\n### No Container of Macros\n\nTraditionally, intrusive containers provide the following macro.\n\n```c\n/** list_entry - get the struct for this entry\n@pointer the \u0026struct list_node pointer.\n@type the type of the struct this is embedded in.\n@member\tthe name of the list_node within the struct. */\n#define list_entry(pointer, type, member) container_of(pointer, type, member)\n\n/* A provided function by the container. */\nstruct List_node *list_front(list *l);\n```\n\nThen, the user code looks like this.\n\n```c\nstruct Id {\n    int id;\n    struct List_node id_node;\n};\n\nint\nmain(void) {\n    static struct List id_list = list_initialize(id_list);\n    /* ...fill list... */\n    struct Id *front = list_entry(list_front(\u0026id_list), struct Id, id_node);\n}\n```\n\nHere, it may seem manageable to use such a macro, but it is required at every location in the code where the user type is needed. The opportunity for bugs in entering the type or field name grows the more the macro is used. It is better to take care of this step for the user and present a cleaner interface.\n\nHere is the same list example in the C Container Collection.\n\n```c\nstruct Id {\n    int id;\n    CCC_Doubly_linked_list_node id_node;\n};\n\nint\nmain(void) {\n    static CCC_Doubly_linked_list id_list\n    = CCC_doubly_linked_list_default(struct Id, id_node);\n    /* ...fill list... */\n    struct Id *front = CCC_doubly_linked_list_front(\u0026id_list);\n    struct Id *new_id = generate_id();\n    struct Id *new_front = CCC_doubly_linked_list_push_front(\n        \u0026id_list, \u0026new_id-\u003eid_node, \u0026std_allocator\n    );\n}\n```\n\nInternally the containers will remember the offsets of the provided elements within the user struct wrapping the intruder. Then, the contract of the interface is simpler: provide a handle to the container and receive your type in return. The user takes on less complexity overall by providing a slightly more detailed initialization. If the container does not require intrusive elements than this is not a concern to begin with. However, this ensures consistency across return values to access user types for intrusive and non-intrusive containers: a reference to the user type is always returned.\n\n### Rust's Entry Interface\n\nRust has solid interfaces for associative containers, largely due to the Entry Interface. In the C Container Collection the core of all associative containers is inspired by the Entry Interface (these versions are found in `ccc/traits.h` but specific names, behaviors, and parameters can be read in each container's header).\n\n- `CCC_Entry(container_pointer, key_pointer...)` - Obtains an entry, a view into an Occupied or Vacant user type stored in the container.\n- `CCC_and_modify(entry_pointer, mod_fn)` - Modify an occupied entry with a callback.\n- `CCC_and_context_modify(entry_pointer, mod_fn, context_arguments)` - Modify an Occupied entry with a callback that requires context data.\n- `CCC_or_insert(entry_pointer, or_insert_arguments)` - Insert a default key value if Vacant or return the Occupied entry.\n- `CCC_insert_entry(entry_pointer, insert_entry_arguments)` - Invariantly insert a new key value, overwriting an Occupied entry if needed.\n- `CCC_remove_entry(entry_pointer)` - Remove an Occupied entry from the container or do nothing.\n\nOther Rust Interface functions like `get_key_value`, `insert`, and `remove` are included and can provide information about previous values stored in the container.\n\nEach container offers it's own C version of \"closures\" for the `and_modify_with`. Here is an example from the `samples/words.c` program.\n\n- `and_modify_with(map_entry_pointer, closure_parameter, closure_over_closure_parameter...)` - Run code in `closure_over_closure_parameter` on the user named pointer type for that closure.\n\n```c\ntypedef struct {\n    String_offset ofs;\n    int cnt;\n} Word;\n/* Increment a found Word or insert a default count of 1. */\nCCC_Handle_index const h = array_adaptive_map_or_insert_with(\n    array_adaptive_map_and_modify_with(\n        handle_wrap(\u0026hom, \u0026key_ofs), Word * w, { w-\u003ecnt++; }\n    ),\n    \u0026std_allocator,\n    (Word){.ofs = ofs, .cnt = 1}\n);\n```\n\nThis is possible because of the details discussed in the previous section. Containers can always provide the user type stored in the container directly. However, there are other options to achieve the same result.\n\nSome C++ associative container interfaces have also been adapted to the Entry Interface.\n\n- `CCC_try_insert(container_pointer, try_insert_arguments...)` - Inserts a new element if none was present and reports if a previous entry existed.\n- `CCC_insert_or_assign(container_pointer, insert_or_assign_arguments...)` - Inserts a new element invariantly and reports if a previous entry existed.\n\nMany other containers fall back to C++ style interfaces when it makes sense to do so.\n\n#### Lazy Evaluation\n\nMany of the above functions come with an optional macro variant. For example, the `or_insert` function for associative containers will come with an `or_insert_with` variant. The word \"with\" in this context means a direct r-value.\n\nHere is an example for generating a maze with Prim's algorithm in the `samples/maze.c` sample.\n\nThe functional version.\n\n```c\nstruct Point const next = {\n    .r = c-\u003ecell.r + dir_offsets[i].r,\n    .c = c-\u003ecell.c + dir_offsets[i].c,\n};\nstruct Prim_cell new = (struct Prim_cell){\n    .cell = next,\n    .cost = rand_range(0, 100),\n};\nstruct Prim_cell *const cell = or_insert(\n    flat_hash_map_entry_wrap(\u0026cost_map, \u0026next, \u0026std_allocator), \u0026new\n);\n```\n\nThe lazily evaluated macro version.\n\n```c\nstruct Point const next = {\n    .r = c-\u003ecell.r + dir_offsets[i].r,\n    .c = c-\u003ecell.c + dir_offsets[i].c,\n};\nstruct Prim_cell const *const cell = flat_hash_map_or_insert_with(\n    flat_hash_map_entry_wrap(\u0026cost_map, \u0026next, \u0026std_allocator),\n    (struct Prim_cell){ .cell = next, .cost = rand_range(0, 100)}\n);\n```\n\nThe second example is slightly more convenient and efficient. The compound literal is provided to be directly assigned to a Vacant memory location allowing the compiler to decide how the copy should be performed; it is only constructed if there is no entry present. This also means the random generation function is only called if a Vacant entry requires the insertion of a new value. So, expensive function calls can be lazily evaluated only when needed.\n\nThe lazy evaluation of the `_with` family of functions offer an expressive way to write C code when needed. See each container's header for more.\n\n### Traits\n\nTraits, found in `ccc/traits.h`, offer a more succinct way to use shared functionality across containers. Instead of calling `CCC_flat_hash_map_entry` when trying to obtain an entry from a flat hash map, one can simply call `entry`. Traits utilize `_Generic` in C to choose the correct container function based on parameters provided.\n\nTraits cost nothing at runtime but may slightly increase compilation memory use.\n\n```c\n#define TRAITS_USING_NAMESPACE_CCC\ntypedef struct {\n    str_ofs ofs;\n    int cnt;\n} Word;\n/* ... Elsewhere generate offset ofs as key. */\nWord default = {.ofs = ofs, .cnt = 1};\nCCC_Handle_index const h = or_insert(\n    and_modify(array_tree_map_handle_wrap(\u0026map, \u0026ofs), increment),\n    \u0026default,\n    \u0026std_allocator\n);\n```\n\nOr the following.\n\n```c\n#define TRAITS_USING_NAMESPACE_CCC\ntypedef struct {\n    str_ofs ofs;\n    int cnt;\n} Word;\n/* ... Elsewhere generate offset ofs as key. */\nWord default = {.ofs = ofs, .cnt = 1};\nArray_adaptive_map_handle *h = array_tree_map_handle_wrap(\u0026map, \u0026ofs);\nh = and_modify(h, increment);\nWord *w = array_adaptive_map_at(\u0026map, or_insert(h, \u0026default, \u0026std_allocator));\n```\n\nTraits are completely opt-in by including the `traits.h` header.\n\n### Constructors\n\nAnother concern for the programmer related to allocation may be constructors and destructors, a C++ shaped peg for a C shaped hole. In general, this library has some limited support for destruction but does not provide an interface for direct constructors as C++ would define them; though this may change.\n\nConsider a constructor. If the container is allowed to allocate, and the user wants to insert a new element, they may see an interface like this (pseudocode as all containers are slightly different).\n\n```c\nvoid *insert_or_assign(Container *c, Container_node *e, Allocator const *);\n```\n\nBecause the user has wrapped the intrusive container element in their type, the entire user type will be written to the new allocation. All interfaces can also confirm when insertion succeeds if global state needs to be set in this case. So, if some action beyond setting values needs to be performed, there are multiple opportunities to do so.\n\n### Destructors\n\nFor destructors, the argument is similar but the container does offer more help. If an action other than freeing the memory of a user type is needed upon removal, there are options in an interface to obtain the element to be removed. Associative containers offer functions that can obtain entries (similar to Rust's Entry API). This reference can then be examined and complex destructor actions can occur before removal. Other containers like lists or priority queues offer references to an element of interest such as front, back, max, min, etc. These can all allow destructor-like actions before removal. One exception is the following interfaces.\n\nThe clear function works for pointer stable containers and flat containers.\n\n```c\nResult clear(Container *c, Destructor const *destuctor);\n```\n\nThe clear and free function works for flat containers.\n\n```c\nResult clear_and_free(\n    Container *c,\n    Destructor const *destructor,\n    Allocator const *allocator\n);\n```\n\nThe above functions free the resources of the container. Because there is no way to access each element before it is freed when this function is called, a destructor callback can be passed to operate on each element before the allocator is called.\n\n## Samples\n\nFor examples of what code that uses these ideas looks like, read and use the sample programs in the `samples/`. I try to only add non-trivial samples that do something mildly interesting to give a good idea of how to take advantage of this flexible memory philosophy.\n\nThe samples are not included in the release. To build them, clone the repository. Usage instructions should be available with the `-h` flag to any program or at the top of the file.\n\nClang.\n\n```zsh\nmake all-clang-release\n./build/bin/[SAMPLE] [SAMPLE CLI ARGS]\n```\n\nGCC.\n\n```zsh\nmake all-gcc-release\n./build/bin/[SAMPLE] [SAMPLE CLI ARGS]\n```\n\n## Tests\n\nThe tests also include various use cases that may be of interest. Tests are not included in the release. Clone the repository.\n\nClang.\n\n```zsh\nmake all-clang-release\nmake test\n```\n\nGCC.\n\n```zsh\nmake all-gcc-release\nmake test\n```\n\n## Quality Control\n\nThe C Container Collection is extensively tested and analyzed both statically and at runtime. See the `tests/` repository which is always seeking valuable additions. Also, visit `CONTRIBUTING.md` to see the extensive tooling that is constantly run locally and over CI via actions in the `.github/workflows` folder. Tools include `clang-format`, `clang-tidy`, `pre-commit`, `GCC's -fanalyzer`, and GCC's extensive address and undefined behavior sanitizers. Builds for both Linux `x86` and MacOS `ARM` run on every commit in pull requests, with additional portable implementation variants built. I aim to deliver a high quality library and welcome any suggestions for tools to further improve code quality.\n\nIf you are interested in contributing, tests that increase code coverage are a good way to start. View the [coverage report here](https://skeletoss.github.io/ccc/coverage).\n\n## Miscellaneous Why?\n- Why explicit allocator passing? The C Container Collection does not  call `malloc`, `realloc`, or `free` directly. Passing allocators at call sites makes allocation visible and auditable rather than hidden inside container operations. It also decouples the container from any specific memory strategy. This is particularly valuable in kernel and embedded contexts where allocation in certain code paths is forbidden. The overall idea is taken from Zig, which I think got this approach right in terms of useful patterns. See the [Allocator Passing](#allocator-passing) section for more.\n- Why are non-allocating containers needed? They are quite common in Operating Systems development. Kernel code may manage a process or thread that is part of many OS subsystems: the CPU scheduler, the virtual memory paging system, the child and parent process spawn and wait mechanisms. All of these systems require that the process use or be a part of some data structures. It is easiest to separate participation in these data structures from memory allocation. The process holds handles to intrusive elements to participate in these data structures because the thread/task/process will live until it has finished executing meaning its lifetime is greater than or equal to the longest lifetime data structure of which it is a part. Embedded developers also often seem interested in non-allocating containers when an entire program's memory use is known before execution begins. However, this library explores if non-allocating containers can have more general applications for creative C programming.\n- Why is initialization so ugly? Yes, this is a valid concern. Upfront complexity helps eliminate the need for a `container_of` macro for the user see the [no container_of macros](#no-container-of-macros) section for more. Later code becomes much cleaner and simpler.\n- Why callbacks? Freedom for more varied comparisons and allocations. Learn to love context data. Also you have the chance to craft the optimal function for your application; for example writing a perfectly tailored hash function for your data set.\n- Why not header only? Readability, maintainability, and update ability, for changing implementations in the source files. If the user wants to explore the implementation everything should be easily understandable. This can also be helpful if the user wants to fork and change a data structure to fit their needs. Smaller object size and easier modular compilation is also nice.\n- Why not opaque pointers and true implementation hiding? This is not possible in C if the user is in charge of memory. The container types must be complete if the user wishes to store them on the stack or data segment. I try to present a clean interface.\n- Why `Array_` and `Flat_` maps? Mostly experimenting. A flat hash map offers the ability to pack user data and fingerprint meta data in separate contiguous arrays within the same allocation. The handle variants of containers offer the same benefit along with handle stability. Many also follow the example of Zig with its Struct of Arrays approach to many data structures. Struct of Array (SOA) style data structures focus on space optimizations due to perfect alignment of user types, container metadata, and any supplementary data in separate arrays but within the same allocation.\n- Why `C23`? Several C23 features are foundational to this library: typed enums for precise constant types, `static_assert` in more contexts for compile time validation, improved compound literal semantics for compile time initialization, and `typeof` for macro type safety. Clang 19.1.1 and GCC 14.2 cover the features needed for release packages.\n\n## Related\n\nIf these containers do not fit your needs, here are some other data structure libraries I have found for C. If your project is at the application layer, where type safety and ergonomics are the primary concerns, these libraries are excellent choices and may be simpler to integrate than the C Container Collection. This collection is designed for projects where explicit memory control, allocation auditability, and separations between data structure and data memory management may be required.\n\n- [STC - Smart Template Containers](https://github.com/stclib/STC)\n- [C Template Library (CTL)](https://github.com/glouw/ctl)\n- [CC: Convenient Containers](https://github.com/JacksonAllan/CC)\n\n## Citations\n\nA few containers are based off of important work by other data structure developers and researchers. Here are the data structures that inspired some containers in this collection. Full citations and notices of changes can be read in the respective implementations in `source/` directory.\n\n- Rust's hashbrown hash table was the basis for the `flat_hash_map.h` container.\n    - https://github.com/rust-lang/hashbrown\n- Phil Vachon's implementation of a WAVL tree was the inspiration for the `tree_map.h` containers.\n    - https://github.com/pvachon/wavl_tree\n- Research by Daniel Sleator in implementations of Splay Trees helped shape the `adaptive_map.h` containers.\n    - https://www.link.cs.cmu.edu/splay/\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskeletoss%2Fccc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fskeletoss%2Fccc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskeletoss%2Fccc/lists"}