{"id":19607969,"url":"https://github.com/tidwall/bgen","last_synced_at":"2025-04-06T01:06:59.433Z","repository":{"id":260985551,"uuid":"882843627","full_name":"tidwall/bgen","owner":"tidwall","description":"B-tree generator for C","archived":false,"fork":false,"pushed_at":"2025-02-16T13:50:09.000Z","size":4159,"stargazers_count":130,"open_issues_count":0,"forks_count":11,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-03-30T00:06:07.558Z","etag":null,"topics":["b-tree","generator","generics","index","key-value","spatial","type-safe"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tidwall.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/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}},"created_at":"2024-11-03T22:27:49.000Z","updated_at":"2025-03-28T04:06:08.000Z","dependencies_parsed_at":"2025-01-07T02:46:24.216Z","dependency_job_id":"ced5e8fe-3c28-4f88-95dd-74735b18572c","html_url":"https://github.com/tidwall/bgen","commit_stats":null,"previous_names":["tidwall/bgen"],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tidwall%2Fbgen","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tidwall%2Fbgen/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tidwall%2Fbgen/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tidwall%2Fbgen/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tidwall","download_url":"https://codeload.github.com/tidwall/bgen/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247419860,"owners_count":20936012,"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","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":["b-tree","generator","generics","index","key-value","spatial","type-safe"],"created_at":"2024-11-11T10:13:20.316Z","updated_at":"2025-04-06T01:06:59.413Z","avatar_url":"https://github.com/tidwall.png","language":"C","readme":"# Bgen\n\n[![api reference](https://img.shields.io/badge/api-reference-blue.svg)](docs/API.md)\n\nBgen is a [B-tree](https://en.wikipedia.org/wiki/B-tree) generator for C.\nIt's small \u0026 fast and includes a variety of options for creating custom\nin-memory btree based collections.\n\n## Features\n\n- Compile-time generation using preprocessor templates\n- Type-safe generic data structure\n- Single-file header with no dependencies\n- [Namespaces](#namespaces)\n- Support for [custom allocators](#custom-allocators)\n- Callback and loop-based [iteration](#iterators)\n- [Copy-on-write](#copy-on-write) with O(1) cloning.\n- Loads of useful [toggles and options](#options)\n- Enable specialized btrees\n  - [Counted B-tree](#counted-b-tree)\n  - [Vector B-tree](#vector-b-tree)\n  - [Spatial B-tree](#spatial-b-tree)\n- Supports most C compilers (C99+). Clang, gcc, tcc, etc\n- Webassembly support with Emscripten (emcc)\n- Exhaustively [tested](tests/README.md) with 100% coverage\n- [Very fast](#performance) 🚀\n\n## Goals\n\n- Give C programs high performance in-memory btrees\n- Provide a template system for optimized code generation\n- Allow for sane customizations and options\n- Make it possible to use one btree library for a variety of collection types,\n  such as maps, sets, stacks, queues, lists, vectors, and spatial indexes. \n  See the [examples](examples).\n\nIt's a non-goal for bgen to provide disk-based functionality or a B+tree\nimplementation.\n\n## Using\n\nJust drop the \"bgen.h\" into your project and create your btree using the \nC preprocessor.\n\n## Example 1 (Insert items)\n\nInsert items into a simple btree that only stores ints.\n\n```c\n#include \u003cstdio.h\u003e\n\n#define BGEN_NAME bt            // The namespace for the btree structure.\n#define BGEN_TYPE int           // The data type for all items in the btree\n#define BGEN_LESS return a \u003c b; // A code fragment for comparing items\n#include \"../bgen.h\"            // Include \"bgen.h\" to generate the btree\n\nint main() {\n    // Create an empty btree instance.\n    struct bt *tree = 0;\n\n    // Insert some items into the btree\n    bt_insert(\u0026tree, 3, 0, 0);\n    bt_insert(\u0026tree, 8, 0, 0);\n    bt_insert(\u0026tree, 2, 0, 0);\n    bt_insert(\u0026tree, 5, 0, 0);\n\n    // Print items in tree\n    struct bt_iter *iter;\n    bt_iter_init(\u0026tree, \u0026iter, 0);\n    for (bt_iter_scan(iter); bt_iter_valid(iter); bt_iter_next(iter)) {\n        int item;\n        bt_iter_item(iter, \u0026item);\n        printf(\"%d \", item);\n    } \n    printf(\"\\n\");\n\n    // Delete an item\n    bt_delete(\u0026tree, 3, 0, 0);\n\n    // Print again\n    for (bt_iter_scan(iter); bt_iter_valid(iter); bt_iter_next(iter)) {\n        int item;\n        bt_iter_item(iter, \u0026item);\n        printf(\"%d \", item);\n    } \n    printf(\"\\n\");\n\n    bt_iter_release(iter);\n    bt_clear(\u0026tree, 0);\n    return 0;\n}\n// Output:\n// 2 3 5 8\n// 2 5 8\n```\n\n## Example 2 (Key-value map)\n\nCreate a key-value map where the key is a string and value is an int.\n\n```c\n#include \u003cstdio.h\u003e\n#include \u003cstdbool.h\u003e\n#include \u003cstring.h\u003e\n#include \u003cassert.h\u003e\n\nstruct pair {\n    const char *key;\n    int value;\n};\n\n#define BGEN_NAME map\n#define BGEN_TYPE struct pair\n#define BGEN_COMPARE return strcmp(a.key, b.key);\n#include \"../bgen.h\"\n\nvoid print_map(const char *comment, struct map **map) {\n    printf(\"%s\", comment);\n    struct map_iter *iter;\n    map_iter_init(map, \u0026iter, 0);\n    for (map_iter_scan(iter); map_iter_valid(iter); map_iter_next(iter)) {\n        struct pair pair;\n        map_iter_item(iter, \u0026pair);\n        printf(\"[%s] = %d; \", pair.key, pair.value);\n    }\n    map_iter_release(iter);\n    printf(\"\\n\");\n}\n\nint main() {\n    // Create a map of three (string, int) pairs\n    struct map *map = 0;\n    map_insert(\u0026map, (struct pair){\"GPU\", 15}, 0, 0);\n    map_insert(\u0026map, (struct pair){\"RAM\", 20}, 0, 0);\n    map_insert(\u0026map, (struct pair){\"CPU\", 10}, 0, 0);\n    print_map(\"1) Initial map:  \", \u0026map);\n\n    // Get an existing item\n    struct pair item;\n    assert(map_get(\u0026map, (struct pair){\"GPU\"}, \u0026item, 0) == map_FOUND);\n    printf(\"2) Get item:     [%s] = %d;\\n\", item.key, item.value);\n\n    // Update an existing item\n    assert(map_insert(\u0026map, (struct pair){\"CPU\", 25}, 0, 0) == map_REPLACED);\n    // Insert a new item\n    assert(map_insert(\u0026map, (struct pair){\"SSD\", 30}, 0, 0) == map_INSERTED); \n    print_map(\"3) Updated map:  \", \u0026map);\n    assert(map_insert(\u0026map, (struct pair){\"UPS\"}, 0, 0) == map_INSERTED); \n    print_map(\"4) Updated map:  \", \u0026map);\n\n    assert(map_delete(\u0026map, (struct pair){.key=\"GPU\"}, 0, 0) == map_DELETED);\n    print_map(\"5) After delete: \", \u0026map);\n\n    return 0;\n}\n\n// Output:\n// 1) Initial map:  [CPU] = 10; [GPU] = 15; [RAM] = 20;\n// 2) Get item:     [GPU] = 15;\n// 3) Updated map:  [CPU] = 25; [GPU] = 15; [RAM] = 20; [SSD] = 30;\n// 4) Updated map:  [CPU] = 25; [GPU] = 15; [RAM] = 20; [SSD] = 30; [UPS] = 0;\n// 5) After delete: [CPU] = 25; [RAM] = 20; [SSD] = 30; [UPS] = 0;\n```\n\n## Example 3 (Priority queue)\n\nCreate two [priority queues](https://en.wikipedia.org/wiki/Priority_queue).\nOne ordered by the maximum value and the other by the minimum value.\n\n```c\n#include \u003cstdio.h\u003e\n#include \u003cstdbool.h\u003e\n#include \u003cstring.h\u003e\n#include \u003cassert.h\u003e\n\n#define BGEN_NAME max_priority_queue\n#define BGEN_TYPE int\n#define BGEN_LESS return a \u003c b;\n#include \"../bgen.h\"\n\n#define BGEN_NAME min_priority_queue\n#define BGEN_TYPE int\n#define BGEN_LESS return b \u003c a;\n#include \"../bgen.h\"\n\nint main() {\n    int data[] = { 1, 8, 5, 6, 3, 4, 0, 9, 7, 2 };\n    int n = sizeof(data)/sizeof(int);\n    printf(\"data: \");\n    for (int i = 0; i \u003c n; i++) {\n        printf(\"%d \", data[i]);\n    }\n    printf(\"\\n\");\n\n    struct max_priority_queue *max_priority_queue = 0;\n\n    // Fill the priority queue.\n    for (int i = 0; i \u003c n; i++) {\n        max_priority_queue_insert(\u0026max_priority_queue, data[i], 0, 0);\n    }\n\n    printf(\"max_priority_queue: \");\n    while (max_priority_queue_count(\u0026max_priority_queue, 0) \u003e 0) {\n        int val;\n        max_priority_queue_pop_front(\u0026max_priority_queue, \u0026val, 0);\n        printf(\"%d \", val);\n    }\n    printf(\"\\n\");\n\n    struct min_priority_queue *min_priority_queue = 0;\n\n    // Fill the priority queue.\n    for (int i = 0; i \u003c n; i++) {\n        min_priority_queue_insert(\u0026min_priority_queue, data[i], 0, 0);\n    }\n\n    printf(\"min_priority_queue: \");\n    while (min_priority_queue_count(\u0026min_priority_queue, 0) \u003e 0) {\n        int val;\n        min_priority_queue_pop_front(\u0026min_priority_queue, \u0026val, 0);\n        printf(\"%d \", val);\n    }\n    printf(\"\\n\");\n\n\n    return 0;\n}\n\n// Output:\n// data: 1 8 5 6 3 4 0 9 7 2\n// max_priority_queue: 0 1 2 3 4 5 6 7 8 9\n// min_priority_queue: 9 8 7 6 5 4 3 2 1 0\n```\n\nCheck out the [examples](examples) directory for more examples, and\nthe [API reference](docs/API.md) for the full list of operations.\n\n## Options\n\nBgen provides a bunch of options for customizing your btree. All options are\nset using the C preprocessor.\n\n| Option                       | Description |\n| :--------------------------- | :---------- |\n| BGEN_NAME `\u003ckv\u003e`             | The [Namespace](#namespaces) |\n| BGEN_TYPE `\u003ctype\u003e`           | The btree item type |\n| BGEN_FANOUT `\u003cint\u003e`          | Set the [fanout](#fanout) (max number of children per node) |\n| BGEN_LESS `\u003ccode\u003e`           | Define a \"less\" [comparator](#comparators). Such as \"a\u003cb\" |\n| BGEN_COMPARE `\u003ccode\u003e`        | Define a \"compare\" [comparator](#comparators). Such as \"a\u003cb?-1:a\u003eb\" |\n| BGEN_MAYBELESSEQUAL `\u003ccode\u003e` | Define a [less-equal hint](#less-equal-hint) for complex compares (advanced) |\n| BGEN_MALLOC `\u003ccode\u003e`         | Define [custom malloc](#custom-allocators) function |\n| BGEN_FREE `\u003ccode\u003e`           | Define [custom free](#custom-allocators) function |\n| BGEN_BSEARCH                 | Enable [binary searching](#binary-search-or-linear-search) (otherwise [linear](#binary-search-or-linear-search)) |\n| BGEN_COW                     | Enable [copy-on-write](#copy-on-write) support |\n| BGEN_COUNTED                 | Enable [counted btree](#counted-b-tree) support |\n| BGEN_SPATIAL                 | Enable [spatial btree](#spatial-b-tree) support |\n| BGEN_NOORDER                 | Disable all ordering. (btree becomes a [dynamic array](#vector-b-tree)) |\n| BGEN_NOATOMICS               | Disable atomics for [copy-on-write](#copy-on-write) (single threaded only) |\n| BGEN_NOHINTS                 | Disable path hints ([path hints](#path-hints) are only available for [bsearch](#binary-search-or-linear-search)) |\n| BGEN_ITEMCOPY `\u003ccode\u003e`       | Define operation for [internally copying items](#item-copying-and-freeing) |\n| BGEN_ITEMFREE `\u003ccode\u003e`       | Define operation for [internally freeing items](#item-copying-and-freeing) |\n| BGEN_DIMS `\u003cint\u003e`            | Define the number of dimensions for [spatial btree](#spatial-b-tree) |\n| BGEN_ITEMRECT `\u003ccode\u003e`       | Define a rect filling operation for [spatial btree](#spatial-b-tree) |\n| BGEN_RTYPE `\u003ctype\u003e`          | Define a rect coordinate type [spatial btree](#spatial-b-tree) (default double) |\n| BGEN_HEADER                  | Generate header declaration only. See [Header and source](#header-and-source) |\n| BGEN_SOURCE                  | Generate source declaration only. See [Header and source](#header-and-source) |\n\n## Namespaces\n\nEach bgen btree will have its own namespace using the `BGEN_NAME` define.\n\nFor example, the following will create a btree using the `users` namespace.\n\n```c\n#define BGEN_NAME users\n#define BGEN_TYPE struct user\n#define BGEN_LESS return a.id \u003c b.id;\n#include \"bgen.h\"\n```\n\nThis will generate all the functions and types using the `users` prefix, such as:\n\n```c\nstruct users; // The btree type\nint users_get(struct users **root, struct user key, struct user *item, void *udata);\nint users_insert(struct users **root, struct user item, struct user *old, void *udata);\nint users_delete(struct users **root, struct user key, struct user *old, void *udata);\n```\n\nMany more functions will also be generated, see the [API](docs/API.md) for a complete list.\n\nIt's also possible to generate multiple btrees in the same source file.\n\n```c\n#define BGEN_NAME users\n#define BGEN_TYPE struct user\n#define BGEN_LESS return a.id \u003c b.id;\n#include \"bgen.h\"\n\n#define BGEN_NAME orders\n#define BGEN_TYPE struct order\n#define BGEN_LESS return a.id \u003c b.id;\n#include \"bgen.h\"\n\n#define BGEN_NAME events\n#define BGEN_TYPE struct event\n#define BGEN_LESS return a.id \u003c b.id;\n#include \"bgen.h\"\n```\n\nFor the remainder of this README, and unless otherwise specified, the prefix\n`bt` will be used as the namespace.\n\n## Comparators\n\nEvery btree requires one comparator, which is a code fragment that compares two\nitems, using BGEN_LESS or BGEN_COMPARE. \n\nBgen provides three variables to the code fragment `a`, `b`, and `udata`.\nThe `a` and `b` variables are the items that need to be compared, and `udata` is\noptional [user data](#the-udata-parameter) that may be provided to any bgen\noperation.\n\n```c\n#define BGEN_LESS    return a \u003c b;               /* return true or false */\n#define BGEN_COMPARE return a \u003c b ? -1 : a \u003e b;  /* return -1, 0, 1 */\n```\n\nIt's up to the developer to choose which of the two is most appropriate. \nBut in general, BGEN_LESS is a good choice for numeric comparisons and\nBGEN_COMPARE may be better suited for strings and more complex keys. \n\n## Binary search or Linear search\n\nBgen defaults to linear searching. This means that btree operations will \nperform internal searches by scanning the items one-by-one. This is often very\ncache-efficient, providing excellent performance for [small nodes](#fanout).\n\nOptionally the BGEN_BSEARCH may be used to enable binary searches instead of\nlinear. This may be better for large nodes or where comparing items may be slow.\n\nNote that bgen automatically enables [path hints](#path-hints) when the \nBGEN_BSEARCH option is provided.\n\n## Less-equal hint\n\nThe BGEN_MAYBELESSEQUAL is a code fragment option that may be provided as an\noptimization to speed up linear searches for complex comparisons.\nMore specifically for tuple-like items with composite keys, where the leading\nfield in the tuple is numeric and the other fields are indirect such as a\npointer to a string.\n\nBgen provides three variables to the code fragment `a`, `b`, and `udata`.\n\nFor example, let's say you have a btree index \"status_users\" btree that orders\non the composite key (status,name).\n\n```c\nstruct status_user {\n    int status;\n    char *name;\n    char *desc;\n};\n\nint user_compare(struct user a, struct user b) {\n    return a.status \u003c b.status ? -1 : a.status \u003e b.status ? 1 : \n           strcmp(a.name, b.name);\n}\n\n#define BGEN_NAME            status_users\n#define BGEN_TYPE            struct status_user\n#define BGEN_COMPARE         return user_compare(a, b);\n#define BGEN_MAYBELESSEQUAL  return a.status \u003c= b.status;\n#include \"bgen.h\"\n```\n\nWith the BGEN_MAYBELESSEQUAL option, the btree will perform a quick linear\nsearch on status and fallback to the slower user_compare function when needed.\n\nNote that BGEN_MAYBELESSEQUAL is only for linear searches cannot be used in \ncombination with BGEN_BSEARCH. \n\n## Copy-on-write\n\nBgen provides [copy-on-write](#copy-on-write) support when BGEN_COW is provided.\nIf enabled, the `bt_clone()` function can make an instant O(1) copy of the\nbtree.\nThis implementation uses atomic reference counters to monitor the shared state\nof each node and preforms just-in-time copies of nodes for mutable operations,\nsuch as `bt_insert()` and `bt_delete()`. \n\nThe `BGEN_NOATOMIC` option may be provided to disable atomics, instead using\nnormal integers as reference counters. This may be needed for single-threaded\nprograms, embedded environments, or webassembly.\n\nWith BGEN_COW; while all mutable operations will perform copy-on-write\ninternally, immutable operations such as `bt_get()` will not.\nIt is possible to force the btree to perform copy-on-write for otherwise\nimmutable operations by using the their `_mut()` alternatives. \nFor example, `bt_get() / bt_get_mut()` and \n`bt_iter_init() / bt_iter_init_mut()`. \n\n## Fanout\n\nThe fanout is the maximum number of children an internal btree node may have.\nBgen allows for setting the fanout using the BGEN_FANOUT option.\nThe default is 16.\n\nChoosing the best fanout is dependent on a number of factors such as item size,\nkey types, and system architecture. \nIn general, 8, 16, or 32 are typically pretty good choices.\n\n## Custom allocators\n\nThe BGEN_MALLOC and BGEN_FREE can be used to provide a custom allocator for \nall btree operations. By default, the built-in `malloc()` and `free()`\nfunctions from `\u003cstdlib.h\u003e` are used. \n\nBGEN_MALLOC provides the `size` and `udata` variables.  \nBGEN_FREE provides the `ptr`, the original `size`, and `udata` variables.\n\n```c\n#define BGEN_MALLOC return mymalloc(size);\n#define BGEN_FREE   myfree(ptr);\n```\n\nBgen is designed for graceful error handling when malloc fails.\nAll mutable btree operations such as `bt_insert()` may fail when attempting to\nallocate memory. It's generally a good idea to check for the `bt_NOMEM` \n[status code](#status-codes). \n\n## Item copying and freeing\n\nWhen the `bt_copy()`, `bt_clone()`, and `bt_clear()` functions are \nused, the btree will internally copy and free nodes. \nWith BGEN_ITEMFREE and BGEN_ITEMCOPY, it's possible to also have the btree copy \nand free items.\n\nThis may be needed when items have internal memory allocations, such as strings\nor other heap-based fields, that require isolation per btree instance and to\navoid memory corruptions such as double free errors.\n\nBGEN_ITEMCOPY provides the `item`, `copy`, and `udata` variables.\nBGEN_ITEMFREE provides the `item` and `udata` variables.\n\nFor example:\n\n```c\nstruct user {\n    int id;\n    char *name;\n};\n\nbool copy_user(struct user item, struct user *copy) {\n    copy-\u003ename = malloc(strlen(item.name)+1);\n    if (!copy-\u003ename) {\n        return false;\n    }\n    strcpy(copy-\u003ename, item.name);\n    copy-\u003eid = item-\u003eid;\n    return true;\n}\n\nvoid free_user(struct user item) {\n    free(item.name);\n}\n\n#define BGEN_NAME users\n#define BGEN_TYPE struct user\n#define BGEN_LESS a.id \u003c b.id\n#define BGEN_ITEMCOPY return copy_user(item, copy);\n#define BGEN_ITEMFREE free_user(item);\n#include \"bgen.h\"\n```\n\nNow when `users_clear()` is called all items will also be freed with \n`free_user()`, and when `users_clone()` or `users_copy()` are called items will\nautomatically be copied with `copy_user()`.\n\nThe BGEN_ITEMCOPY expects a return value of `true` or `false`, where `false`\nmeans that there was an error such as out of memory. \n\n## Path hints\n\nBgen uses path hints when BGEN_BSEARCH is provided.\nIt's an automatic search optimization which causes the btree to track the\nsearch path of every operation, using that path as a hint for the next\noperation.\n\nIt can lead to better performance for common access patterns, where subsequent \noperations work on items that are typically nearby each other in the btree.\n\nFor more information see the \n[original document](https://github.com/tidwall/btree/blob/master/PATH_HINT.md).\n\nThis implementation uses a thread-local variable to manage the hint.\nOther than providing BGEN_BSEARCH, there are no additional requirements to make\nthis feature work.\n\nTo disable path hints, provide the BGEN_NOHINTS option.\n\n## Iterators\n\nIteration comes in two flavors, callback and loop-based. \n\nCallback iteration requires a callback function that will be called for each\nitem in the iteration. \n\nFor example, let's say you have a `users` btree that orders users on\n(last,first).\n\n```c\nstruct user {\n    char *last;\n    char *first;\n    int age;\n};\n\nint user_compare(struct user a, struct user b) {\n    int cmp = strcmp(a.last, b.last);\n    if (cmp == 0) {\n        cmp = strcmp(a.first, b.first);\n    }\n    return cmp;\n}\n\nbool user_iter(struct user user, void *udata) {\n    printf(\"%s %s (age=%d)\\n\", user.first, user.last, user.age);\n    return true;\n}\n\n#define BGEN_NAME users\n#define BGEN_TYPE struct user\n#define BGEN_COMPARE { return user_compare(a, b); }\n#include \"../bgen.h\"\n```\n\nCallback iterators such as `bt_scan()` and `bt_seek()` are available.\n\n```c\nbt_scan(\u0026tree, user_iter, 0);\n```\n\nLoop iteration allows for keeping the iterator from leaving the current \nfunction. It takes a little more work to set up but is sometimes easier t\nmanage the context of operation.\n\n```c\nstruct users_iter *iter;\nusers_iter_init(\u0026users, \u0026iter, 0);\nusers_iter_scan(iter);\nwhile (users_iter_valid(iter)) {\n    users_iter_item(iter, \u0026user);\n    printf(\"%s %s (age=%d)\\n\", user.first, user.last, user.age);\n    users_iter_next(iter);\n}\nusers_iter_release(iter);\n```\n\nIt's usually not safe to modify the btree while iterating. \nIf you need to filter data then it's best to reset the iterator after\neach modification.\n\n```c\nstruct users_iter *iter;\nusers_iter_init(\u0026users, \u0026iter, 0);\nusers_iter_scan(iter);\nwhile (users_iter_valid(iter)) {\n    users_iter_item(iter, \u0026user);\n    if (user.age \u003e= 30 \u0026\u0026 user.age \u003c 40) {\n        users_delete(\u0026users, user, 0, 0);\n        users_iter_seek(iter, user);\n        continue;\n    } \n    users_iter_next(iter);\n}\nusers_iter_release(iter);\n```\n\nMake sure to call `bt_iter_release()` when you are done iterating;\n\n## Status codes \n\nMost btree operations, such as `bt_get()` and `bt_insert()` return status\ncodes that indicate the success of the operation. All status codes are prefixed\nwith the same namespace as specified with BGEN_NAME. \n\n| Status         | Description |\n| :------------- | :--- |\n| bt_INSERTED    | New item was inserted |\n| bt_REPLACED    | Item replaced an existing item |\n| bt_DELETED     | Item was successfully deleted |\n| bt_FOUND       | Item was successfully found |\n| bt_NOTFOUND    | Item was not found |\n| bt_OUTOFORDER  | Item cannot be inserted due to out of order |\n| bt_FINISHED    | Callback iterator returned all items |\n| bt_STOPPED     | Callback iterator was stopped early |\n| bt_COPIED      | Tree was copied: `bt_clone()`, `bt_copy()` |\n| bt_NOMEM       | Out of memory error |\n| bt_UNSUPPORTED | Operation not supported |\n\nIt's always a good idea to check the return value of mutable btree operations to \nensure it doesn't return an error.\n\n## The udata parameter\n\nAll bgen functions provide an optional `udata` parameter that may be used for\nuser-defined data. What this data is used for is up to the developer.\n\nAll operations, callbacks, and code fragments (such as BGEN_COMPARE and \nBGEN_LESS) provide a `udata` variable that is the same as what is passed to \noriginal btree function.\n\n## Counted B-tree\n\nA [counted btree](https://www.chiark.greenend.org.uk/~sgtatham/algorithms/cbtree.html) \nallows for random access and modifications with O(log n) complexity.\n\nAdding the BGEN_COUNTED option enables this feature.\n\nThis is pretty nice for programs that need to make changes using an index, \nrather than a key. It basically allows for functions like `bt_insert_at()`, \n`bt_delete_at()`, and `bt_get_at()` to modify and access items at any position.\n\nBut it's worth noting that the `bt_insert_at()` operation still requires that\nitems inserted at specific positions are in the correct order.\nThe `bt_OUTOFORDER` error will be returned otherwise.\n\n## Vector B-tree\n\nWhen the BGEN_COUNTED and BGEN_NOORDER options are both provided, bgen will\ngenerate a specialized btree that allows for both random access and storing\nitems in any order.\nThis effectively treats the btree like a dynamic array, aka a vector.\n\nThose familiar with vectors in other languages, such a Rust and C++, may know \nthat appending and accessing items is fast but modifying is slow.\n\nWith a bgen vector all operations have the same\n[time complexity](https://en.wikipedia.org/wiki/Time_complexity).\n\n| Operation  | Bgen     | Others       |\n| :--------  | :------- | :----------- |\n| push_back  | O(log n) | O(1)         |\n| pop_back   | O(log n) | O(1)         |\n| get_at     | O(log n) | O(1)         |\n| push_front | O(log n) | O(n)         |\n| pop_front  | O(log n) | O(n)         |\n| insert_at  | O(log n) | O(n)         |\n| delete_at  | O(log n) | O(n)         |\n\nHere's how to create a vector that stores ints.\n\n```c\n#define BGEN_NAME vector\n#define BGEN_TYPE int\n#define BGEN_COUNTED\n#define BGEN_NOORDER\n#include \"../bgen.h\"\n```\n\nNow `vector_insert_at()`, `vector_delete_at()`, and `vector_get_at()` can be\nused to modify and access items at any position, in any order. \n\nFor a more detailed example, check out the [examples](examples) directory.\n\n## Spatial B-tree\n\nA [spatial btree](docs/SPATIAL_BTREE.md) allows for working with\nmultidimensional data.\n\nAdding the BGEN_SPATIAL option enables this feature.\n\nAdditionally, the BGEN_ITEMRECT needs to be provided, which is responsible \nfor filling the 'min' and 'max' rectangle (bounding box) for each item.\nThis rectangle is used by the btree for efficient spatial searching.\n\n```c\nvoid point_rect(struct point point, double min[], double max[]) {\n    min[0] = point.x;\n    min[1] = point.y;\n    max[0] = point.x;\n    max[1] = point.y;\n}\n\n#define BGEN_NAME spatial\n#define BGEN_TYPE struct point\n#define BGEN_SPATIAL\n#define BGEN_ITEMRECT return point_rect(item, min, max);\n#define BGEN_COMPARE return point_compare(a, b);\n#include \"../bgen.h\"\n```\n\nBy default, a spatial btree is two dimensions and uses `double` as the rectangle\ncoordinate type.\n\nThese can be changed using BGEN_DIMS and BGEN_RTYPE.\n\n```c\n#define BGEN_DIMS  3         // use three dimensions instead of two\n#define BGEN_RTYPE uint32_t  // use uint32_t instead of double \n```\n\nOnce enabled you can use the `bt_intersects` and `bt_nearby` iterators to \nefficiently searching intersecting rectangles and the performing the nearest \nneighbors operation ([kNN](https://en.wikipedia.org/wiki/K-nearest_neighbors_algorithm)).\n\nSee the [spatial.c](examples/spatial.c) example from the [examples directory](examples).\n\n## Header and source\n\nBy default, bgen generates all the code as a static unit for the current source\nfile that includes \"bgen.h\".\n\nThis is great if all you need to access the btree from that one file.\nBut if you want other c source files to access those same btree functions too\nthen you'll use the `BGEN_HEADER` and `BGEN_SOURCE` options.\n\nFor example, here we'll create a \"users.h\" and \"users.c\" where one generates\nonly the header declarations and the other generates the code.\n\n```c\n// users.h\n#ifndef USERS_H\n#define USERS_H\n\nstruct user {\n    int id;\n    char *name;\n};\n\n#define BGEN_NAME users\n#define BGEN_TYPE struct user\n#define BGEN_HEADER\n#include \"../deps/bgen.h\"\n\n#endif\n```\n\n```c\n// users.c\n#include \"users.h\"\n\n#define BGEN_NAME users\n#define BGEN_TYPE struct user\n#define BGEN_LESS return a.id \u003c b.id;\n#define BGEN_SOURCE\n#include \"../deps/bgen.h\"\n```\n\n\n## Performance\n\nThe following benchmarks compare the performance of bgen to the very fast\n[frozenca/btree](https://github.com/frozenca/BTree) for C++ and the built-in\nRust B-tree.\n\nAlso compared is the bgen spatial btree vs a standard r-tree with data inserted\nin hilbert order.\n\n*See the [tidwall/bgen-bench](https://github.com/tidwall/bgen-bench) project\nfor more information*\n\n### Details \n\n- Linux, AMD Ryzen 9 5950X 16-Core processor\n- CC=clang-17 CFLAGS=-ljemalloc\n- Items are simple 4-byte ints. \n\nBenchmarking 1000000 items, 50 times, taking the average result\n\n## Bgen B-tree\n\n```\ninsert(seq)         1,000,000 ops in   0.042 secs     41.8 ns/op    23,933,327 op/sec\ninsert(rand)        1,000,000 ops in   0.087 secs     86.7 ns/op    11,539,702 op/sec\nget(seq)            1,000,000 ops in   0.030 secs     30.3 ns/op    32,989,495 op/sec\nget(rand)           1,000,000 ops in   0.078 secs     78.0 ns/op    12,814,152 op/sec\ndelete(seq)         1,000,000 ops in   0.018 secs     17.7 ns/op    56,342,904 op/sec\ndelete(rand)        1,000,000 ops in   0.096 secs     96.4 ns/op    10,369,073 op/sec\nreinsert(rand)      1,000,000 ops in   0.082 secs     82.4 ns/op    12,138,316 op/sec\npush_first          1,000,000 ops in   0.009 secs      8.6 ns/op   116,842,897 op/sec\npush_last           1,000,000 ops in   0.010 secs      9.8 ns/op   101,998,378 op/sec\npop_first           1,000,000 ops in   0.012 secs     12.3 ns/op    81,491,602 op/sec\npop_last            1,000,000 ops in   0.012 secs     12.1 ns/op    82,480,762 op/sec\nscan                1,000,000 ops in   0.002 secs      1.5 ns/op   665,448,960 op/sec\nscan_desc           1,000,000 ops in   0.002 secs      1.8 ns/op   561,393,712 op/sec\niter_scan           1,000,000 ops in   0.004 secs      3.6 ns/op   280,244,979 op/sec\niter_scan_desc      1,000,000 ops in   0.004 secs      4.0 ns/op   248,567,689 op/sec\n```\n\n## Rust B-tree\n\n```\ninsert(seq)         1,000,000 ops in   0.049 secs     48.6 ns/op    20,574,261 op/sec\ninsert(rand)        1,000,000 ops in   0.105 secs    105.4 ns/op     9,489,152 op/sec\nget(seq)            1,000,000 ops in   0.034 secs     33.7 ns/op    29,706,515 op/sec\nget(rand)           1,000,000 ops in   0.095 secs     94.6 ns/op    10,568,904 op/sec\ndelete(seq)         1,000,000 ops in   0.023 secs     22.6 ns/op    44,236,754 op/sec\ndelete(rand)        1,000,000 ops in   0.116 secs    115.8 ns/op     8,635,239 op/sec\nreinsert(rand)      1,000,000 ops in   0.097 secs     97.1 ns/op    10,299,834 op/sec\n```\n\n## C++ B-tree ([frozenca/btree](https://github.com/frozenca/BTree))\n\n```\ninsert(seq)         1,000,000 ops in   0.054 secs     54.2 ns/op    18,435,446 op/sec\ninsert(rand)        1,000,000 ops in   0.088 secs     88.0 ns/op    11,369,690 op/sec\nget(seq)            1,000,000 ops in   0.030 secs     29.5 ns/op    33,894,683 op/sec\nget(rand)           1,000,000 ops in   0.080 secs     79.5 ns/op    12,573,739 op/sec\ndelete(seq)         1,000,000 ops in   0.023 secs     23.2 ns/op    43,042,237 op/sec\ndelete(rand)        1,000,000 ops in   0.113 secs    113.4 ns/op     8,815,550 op/sec\nreinsert(rand)      1,000,000 ops in   0.101 secs    100.9 ns/op     9,909,315 op/sec\n```\n\n## Bgen Spatial B-tree\n\nRandom geospatial points in Hilbert curve order.\n\n```\ninsert(seq)         1,000,000 ops in   0.056 secs     55.6 ns/op    17,982,904 op/sec\ninsert(rand)        1,000,000 ops in   0.133 secs    132.9 ns/op     7,524,517 op/sec\nsearch-item(seq)    1,000,000 ops in   0.086 secs     85.8 ns/op    11,655,348 op/sec\nsearch-item(rand)   1,000,000 ops in   0.259 secs    258.5 ns/op     3,867,919 op/sec\nsearch-1%               1,000 ops in   0.002 secs   1580.6 ns/op       632,651 op/sec\nsearch-5%               1,000 ops in   0.017 secs  17456.8 ns/op        57,284 op/sec\nsearch-10%              1,000 ops in   0.053 secs  53262.3 ns/op        18,775 op/sec\n```\n\n## R-tree ([tidwall/rtree.c](https://github.com/tidwall/rtree.c))\n\nRandom geospatial points inserted in Hilbert order.\n\n```\ninsert(seq)         1,000,000 ops in   0.088 secs     87.7 ns/op    11,399,120 op/sec\ninsert(rand)        1,000,000 ops in   0.162 secs    162.1 ns/op     6,169,577 op/sec\nsearch-item(seq)    1,000,000 ops in   0.095 secs     94.9 ns/op    10,536,006 op/sec\nsearch-item(rand)   1,000,000 ops in   0.312 secs    312.1 ns/op     3,204,491 op/sec\nsearch-1%               1,000 ops in   0.002 secs   1953.0 ns/op       512,023 op/sec\nsearch-5%               1,000 ops in   0.017 secs  16968.3 ns/op        58,933 op/sec\nsearch-10%              1,000 ops in   0.054 secs  53888.1 ns/op        18,556 op/sec\n```\n\n## Contributing\n\nRead [CONTRIBUTING.md](.github/CONTRIBUTING.md), but in general please\ndo not open a PR without talking to me first.\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftidwall%2Fbgen","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftidwall%2Fbgen","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftidwall%2Fbgen/lists"}