{"id":15049379,"url":"https://github.com/zelang-dev/c-raii","last_synced_at":"2025-10-29T05:42:20.964Z","repository":{"id":234360479,"uuid":"788738720","full_name":"zelang-dev/c-raii","owner":"zelang-dev","description":"An robust high-level Defer, RAII implementation for C89, automatic memory safety, smartly!","archived":false,"fork":false,"pushed_at":"2024-09-26T03:19:06.000Z","size":5766,"stargazers_count":4,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-09-30T01:21:44.203Z","etag":null,"topics":["c","c89","defer","memory-management","raii"],"latest_commit_sha":null,"homepage":"https://zelang-dev.github.io/c-raii/","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/zelang-dev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"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-04-19T01:42:12.000Z","updated_at":"2024-09-26T03:18:42.000Z","dependencies_parsed_at":"2024-05-28T21:45:58.623Z","dependency_job_id":"01b35149-0f9f-4e14-9c65-b05d07269117","html_url":"https://github.com/zelang-dev/c-raii","commit_stats":null,"previous_names":["zelang-dev/c-exception","zelang-dev/c-raii"],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zelang-dev%2Fc-raii","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zelang-dev%2Fc-raii/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zelang-dev%2Fc-raii/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zelang-dev%2Fc-raii/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zelang-dev","download_url":"https://codeload.github.com/zelang-dev/c-raii/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":219855784,"owners_count":16556131,"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":["c","c89","defer","memory-management","raii"],"created_at":"2024-09-24T21:20:01.968Z","updated_at":"2025-10-29T05:42:20.956Z","avatar_url":"https://github.com/zelang-dev.png","language":"C","funding_links":[],"categories":["Memory Management"],"sub_categories":["Advanced books"],"readme":"# c-raii\n\n[![Windows \u0026 Ubuntu \u0026 Apple macOS](https://github.com/zelang-dev/c-raii/actions/workflows/ci.yml/badge.svg)](https://github.com/zelang-dev/c-raii/actions/workflows/ci.yml)\n[![CentOS Stream 9](https://github.com/zelang-dev/c-raii/actions/workflows/ci_centos.yml/badge.svg)](https://github.com/zelang-dev/c-raii/actions/workflows/ci_centos.yml)\n[![armv7, aarch64, riscv64](https://github.com/zelang-dev/c-raii/actions/workflows/ci_cpu.yml/badge.svg)](https://github.com/zelang-dev/c-raii/actions/workflows/ci_cpu.yml)\n[![ppc64le - ucontext](https://github.com/zelang-dev/c-raii/actions/workflows/ci_cpu-ppc64le.yml/badge.svg)](https://github.com/zelang-dev/c-raii/actions/workflows/ci_cpu-ppc64le.yml)\n\nAn robust high-level **Defer**, _RAII_ implementation for `C89`, automatic memory safety _smartly_, with **ultra** simple `threading` capabilities.\n\n* [Synopsis](#synopsis)\n  * [There is _1 way_ to create an smart memory pointer.](#there-is-1-way-to-create-an-smart-memory-pointer)\n  * [The following _malloc/calloc_ wrapper functions are used to get an raw memory pointer.](#the-following-malloccalloc-wrapper-functions-are-used-to-get-an-raw-memory-pointer)\n  * [Thereafter, an smart pointer can be use with these _raii__* functions.](#thereafter-an-smart-pointer-can-be-use-with-these-raii_-functions)\n  * [Using `thread local storage` for an default smart pointer, the following functions always available.](#using-thread-local-storage-for-an-default-smart-pointer-the-following-functions-always-available)\n  * [Fully automatic memory safety, using `guard/unguarded/guarded` macro.](#fully-automatic-memory-safety-using-guardunguardedguarded-macro)\n* [Installation](#installation)\n* [Contributing](#contributing)\n* [License](#license)\n\nThis branch, version `2.x` of **c-raii**, has an expanded feature set. It differs greatly from [1.x](https://github.com/zelang-dev/c-raii/blob/1.x/) to be in line with the fact that most ordinary `C` _libraries_ in-use will need _refactoring_ aka **rewrite**, to be use effectually with _memory safety_ as first class.\n\nThe features now encompass most things you might find in higher level languages, specificity **ease of use**, _with the same old_ **C89**. Not new concepts, you'll find most implicit in every _program/application_, if not explicit, now available in additional header files:\n\n* dynamic data-structures [vector.h](https://github.com/zelang-dev/c-raii/blob/main/include/vector.h), [hashtable.h](https://github.com/zelang-dev/c-raii/blob/main/include/hashtable.h) and [map.h](https://github.com/zelang-dev/c-raii/blob/main/include/map.h).\n* parsers [url_http.h](https://github.com/zelang-dev/c-raii/blob/main/include/url_http.h) and [json.h](https://github.com/zelang-dev/c-raii/blob/main/include/json.h).\n* execution context and control flow constructs, _threads, coroutines, and channels_, [future.h](https://github.com/zelang-dev/c-raii/blob/main/include/future.h), [coro.h](https://github.com/zelang-dev/c-raii/blob/main/include/coro.h) and [channel.h](https://github.com/zelang-dev/c-raii/blob/main/include/channel.h).\n* string manipulation/handling [swar.h](https://github.com/zelang-dev/c-raii/blob/main/include/swar.h).\n* access/manipulate an individual integer bits, with string representation [bitset.h](https://github.com/zelang-dev/c-raii/blob/main/include/bitset.h).\n* runtime code [reflection.h](https://github.com/zelang-dev/c-raii/blob/main/include/reflection.h), behavior similar to [C++ Reflection - Back on Track](https://youtu.be/nBUgjFPkoto) **video**.\n\n\u003e See [tests](https://github.com/zelang-dev/c-raii/blob/main/tests) and [examples](https://github.com/zelang-dev/c-raii/blob/main/examples) **folder** for _usage_.\n\nThis library has come full circle from it's initial aim at being _decoupled_ from ~c-coroutine~ [c-asio](https://zelang-dev.github.io/c-asio) to _bridging_ it back with different startup strategy behavior. Must either **`#define USE_CORO`** or call **`coro_start(main_func, argc, argv, 0)`**. When active **C** become whatever _high level_ language you can imagine that offers _automatic memory management_, otherwise no coroutine support, program will **crash** calling any specific coroutine only functions.\n\n\u003e The one _essential_ thing that all languages must _control_ and _redefine_ doing the compiler creation process, _function_ **\"creation/signature/entrance/exit\"** _process_. The whole **\"signature/entrance/exit\"** process hereforth is under **C-RAII** control.\n\nThe threading model, _execution context_ provided here is nothing new, the concept has been around for **C** aka _C89_ for quite awhile. The behavior is the same, but called under different _terminology_:\n\n* [Effect handlers](https://en.wikipedia.org/wiki/Effect_system) model with various implementations listed in [effect-handlers-bench](https://github.com/effect-handlers/effect-handlers-bench).\n* Various high level languages have direct compiler support for [Async/Await](https://en.wikipedia.org/wiki/Async/await),\nbut don't have [work stealing](https://en.wikipedia.org/wiki/Work_stealing) in that _paradigm_.\n\nThe model here mimics [Go concurrency](https://en.wikipedia.org/wiki/Go_(programming_language)#Concurrency) aka [Green thread](https://en.wikipedia.org/wiki/Green_thread) in _execution_ with follows [Cilk](https://en.wikipedia.org/wiki/Cilk) behavior. There are also [Weave](https://github.com/mratsim/weave) and [Lace](https://github.com/trolando/lace) both compete with **Cilk** behavior. **Weave** using [Nim programming language](https://nim-lang.org/), in which it's origins is `C`, and still compiles down to. **Lace** is `C11` base. In fact **Go** initial origins started as `C`, it's just a _matter of time_ before a [turing-complete](https://en.wikipedia.org/wiki/Turing_completeness) _understanding_ take effect, build _self_ with _self_. **It's amazing how things always come full circle**.\n\n**_Everything that follows at this point is from version `1.x`, noteing ~c-coroutine~ [c-asio repo](https://zelang-dev.github.io/c-asio) will be restructured/refactored for the sole purpose of integrating [libuv](https://github.com/libuv/libuv), the coroutine part to be removed._**\n\n---\n\nThis library has been decoupled from ~c-coroutine~ [c-asio](https://zelang-dev.github.io/c-asio) to be independently developed.\n\nIn the effort to find uniform naming of terms, various other packages was discovered [Except](https://github.com/meaning-matters/Except), and [exceptions-and-raii-in-c](https://github.com/psevon/exceptions-and-raii-in-c). Choose to settle in on [A defer mechanism for C](https://gustedt.wordpress.com/2020/12/14/a-defer-mechanism-for-c/), an upcoming C standard compiler feature. It's exactly this library's working design and concepts addressed in [c-asio](https://github.com/zelang-dev/c-asio).\n\nThis library uses an custom version of [rpmalloc](https://github.com/mjansson/rpmalloc) for **malloc/heap** allocation, not **C11** compiler `thread local` dependant, nor **C++** focus, _removed_. The customization is merged with required [c-threads](https://github.com/zelang-dev/c-threads) for **C11** _thread like emulation_.\n\n* The behavior here is as in other _languages_ **Go's** [defer](https://go.dev/ref/spec#Defer_statements), **Zig's** [defer](https://ziglang.org/documentation/master/#defer), **Swift's** [defer](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/statements/#Defer-Statement), even **Rust** has [multi defer crates](https://crates.io/keywords/defer) there are other **borrow checker** issues - [A defer discussion](https://internals.rust-lang.org/t/a-defer-discussion/20387).\n\n\u003e As a side benefit, just including a single `#include \"raii.h\"` will make your **Linux** only application **Windows** compatible, see `work-steal.c` in [examples](https://github.com/zelang-dev/c-raii/tree/main/examples) folder, it's from [Complementary Concurrency Programs for course \"Linux Kernel Internals\"](https://github.com/sysprog21/concurrent-programs), _2 minor changes_, using macro `make_atomic`.\n\n\u003e All aspect of this library as been incorporated into an **c++11** like _threading model_ as outlined in [std::async](https://cplusplus.com/reference/future/async/), any thread launched with signature `thrd_async(fn, num_of_args, ...)` has function executed within `guard` block as further described below, all allocations is automatically cleaned up and `defer` statements **run**.\n\nThe C++ version from \u003chttps://cplusplus.com/reference/future/future/wait/\u003e\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003cth\u003eRAII C89\u003c/th\u003e\n\u003cth\u003eC++11\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n```c\n#include \"raii.h\"\n\n// a non-optimized way of checking for prime numbers:\nvoid *is_prime(args_t arg) {\n    int i, x = arg[0].integer;\n    for (i = 2; i \u003c x; ++i) if (x % i == 0) return $(false);\n    return $(true);\n}\n\nint main(int argc, char **argv) {\n    int prime = 194232491;\n    // call function asynchronously:\n    future fut = thrd_async(is_prime, 1, prime);\n\n    printf(\"checking...\\n\");\n    thrd_wait(fut, thrd_yield);\n\n    printf(\"\\n194232491 \");\n    if (thrd_get(fut).boolean) // guaranteed to be ready (and not block) after wait returns\n        printf(\"is prime.\\n\");\n    else\n        printf(\"is not prime.\\n\");\n\n    return 0;\n}\n```\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n```c++\n// future::wait\n#include \u003ciostream\u003e       // std::cout\n#include \u003cfuture\u003e         // std::async, std::future\n#include \u003cchrono\u003e         // std::chrono::milliseconds\n\n// a non-optimized way of checking for prime numbers:\nbool is_prime (int x) {\n  for (int i=2; i\u003cx; ++i) if (x%i==0) return false;\n  return true;\n}\n\nint main ()\n{\n  // call function asynchronously:\n  std::future\u003cbool\u003e fut = std::async (is_prime,194232491);\n\n  std::cout \u003c\u003c \"checking...\\n\";\n  fut.wait();\n\n  std::cout \u003c\u003c \"\\n194232491 \";\n  if (fut.get())      // guaranteed to be ready (and not block) after wait returns\n    std::cout \u003c\u003c \"is prime.\\n\";\n  else\n    std::cout \u003c\u003c \"is not prime.\\n\";\n\n  return 0;\n}\n```\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\nThe planned implementation from [defer reference implementation for C](https://gustedt.gitlabpages.inria.fr/defer/):\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003cth\u003eRAII C89\u003c/th\u003e\n\u003cth\u003ePlanned C11\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n```c\n// includes \"cthreads.h\" emulated C11 threads\n#include \"raii.h\"\n\nint main(int argc, char **argv)\nguard {\n    // Panic if p == NULL\n    // Automatically _defer(free, p)\n    void *p = _malloc(25);\n    void *q = _calloc(1, 25);\n\n    if (mtx_lock(\u0026mut)==thrd_error) break;\n    _defer(mtx_unlock, \u0026mut);\n\n    // all resources acquired\n} unguarded(0);\n```\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n```c\nguard {\n  void * const p = malloc(25);\n  if (!p) break;\n  defer free(p);\n\n  void * const q = malloc(25);\n  if (!q) break;\n  defer free(q);\n\n  if (mtx_lock(\u0026mut)==thrd_error) break;\n  defer mtx_unlock(\u0026mut);\n\n  // all resources acquired\n}\n```\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\nThere C Standard implementation states: **The important interfaces of this tool are:**\n\n* `guard` prefixes a guarded block\n* `defer` prefixes a defer clause\n* `break` ends a guarded block and executes all its defer clauses\n* `return` unwinds all guarded blocks of the current function and returns to the caller\n* `exit` unwinds all defer clauses of all active function calls of the thread and exits normally\n* `panic` starts global unwinding of all guarded blocks\n* `recover` inside a defer clause stops a panic and provides an error code\n\nThere example from [source](https://gitlab.inria.fr/gustedt/defer/-/blob/master/defer4.c?ref_type=heads) - **gitlab**, outlined in [C Standard WG14 meeting](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2542.pdf) - **pdf**\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003cth\u003eRAII C89\u003c/th\u003e\n\u003cth\u003ePlanned C11\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n```c\n#include \"raii.h\"\n\nchar number[20];\nvoid g_print(void *ptr) {\n    int i = raii_value(ptr)-\u003einteger;\n    printf(\"Defer in g = %d.\\n\", i);\n}\n\nvoid g(int i) {\n    if (i \u003e 3) {\n        puts(\"Panicking!\");\n        snprintf(number, 20, \"%ld\", i);\n        _panic(number);\n    }\n    guard {\n      _defer(g_print, \u0026i);\n      printf(\"Printing in g = %d.\\n\", i);\n      g(i + 1);\n    } guarded;\n}\n\nvoid f_print(void *na) {\n    puts(\"In defer in f\");\n    fflush(stdout);\n    if (_recovered(_get_message())) {\n        printf(\"Recovered in f = %s\\n\", _get_message());\n        fflush(stdout);\n    }\n}\n\nvoid f()\nguard {\n    _defer(f_print, NULL);\n    puts(\"Calling g.\");\n    g(0);\n    puts(\"Returned normally from g.\");\n} guarded;\n\nint main(int argc, char **argv) {\n    f();\n    puts(\"Returned normally from f.\");\n    return EXIT_SUCCESS;\n}\n```\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n```c\n#include \u003cstdio.h\u003e\n#include \u003cstddef.h\u003e\n#include \u003cthreads.h\u003e\n#include \"stddefer.h\"\n\nvoid g(int i) {\n  if (i \u003e 3) {\n    puts(\"Panicking!\");\n    panic(i);\n  }\n  guard {\n    defer {\n      printf(\"Defer in g = %d.\\n\", i);\n    }\n    printf(\"Printing in g = %d.\\n\", i);\n    g(i+1);\n  }\n}\n\nvoid f() {\n  guard {\n    defer {\n        puts(\"In defer in f\");\n        fflush(stdout);\n      int err = recover();\n      if (err != 0) {\n        printf(\"Recovered in f = %d\\n\", err);\n        fflush(stdout);\n      }\n    }\n    puts(\"Calling g.\");\n    g(0);\n    puts(\"Returned normally from g.\");\n  }\n}\n\nint main(int argc, char* argv[static argc+1]) {\n  f();\n  puts(\"Returned normally from f.\");\n  return EXIT_SUCCESS;\n}\n```\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n_Function_ `​f`​ containing a **​defer​** statement which contains a call to the **​recover**\nfunction. _Function_ `​f`​ invokes _function_ `​g`​ which recursively descends before _panicking_ when the\nvalue of `​i \u003e 3`​. Execution of `​f`​ produces the following **output**:\n\u003cpre\u003e\nCalling g.\nPrinting in g = 0.\nPrinting in g = 1.\nPrinting in g = 2.\nPrinting in g = 3.\nPanicking!\nDefer in g = 3.\nDefer in g = 2.\nDefer in g = 1.\nDefer in g = 0.\nIn defer in f\nRecovered in f = 4\nReturned normally from f.\n\u003c/pre\u003e\n\n## Synopsis\n\n**C++** has a concept called [unique_ptr)](https://en.cppreference.com/w/cpp/memory/unique_ptr) where **\"a smart pointer that owns and manages another object through a pointer and disposes of that object when the unique_ptr goes out of scope. \"**\n\nHere too the same process is in effect through an **new** _typedef_ `unique_t` aka `memory_t` _structure_.\n\n```c\n/* Calls fn (with args as arguments) in separate thread, returning without waiting\nfor the execution of fn to complete. The value returned by fn can be accessed\nby calling `thrd_get()`. */\nC_API future thrd_async(thrd_func_t fn, size_t num_of_args, ...);\n\n/* Same as `thrd_async`, allows passing custom `context` scope for internal `promise`\nfor auto cleanup within caller's `scope`. */\nC_API future thrd_async_ex(memory_t *scope, thrd_func_t fn, void_t args);\n\n/* Returns the value of `future` ~promise~, a thread's shared object, If not ready, this\nfunction blocks the calling thread and waits until it is ready. */\nC_API values_type thrd_get(future);\n\n/* This function blocks the calling thread and waits until `future` is ready,\nwill execute provided `yield` callback function continuously. */\nC_API void thrd_wait(future, wait_func yield);\n\n/* Check status of `future` object state, if `true` indicates thread execution has ended,\nany call thereafter to `thrd_get` is guaranteed non-blocking. */\nC_API bool thrd_is_done(future);\nC_API void thrd_delete(future);\nC_API uintptr_t thrd_self(void);\nC_API size_t thrd_cpu_count(void);\n\n/* Return/create an arbitrary `vector/array` set of `values`, only available within `thread/future` */\nC_API vectors_t thrd_data(size_t, ...);\n\n/* Return/create an single `vector/array` ~value~, only available within `thread/future` */\n#define $(val) thrd_data(1, (val))\n\n/* Return/create an pair `vector/array` ~values~, only available within `thread/future` */\n#define $$(val1, val2) thrd_data(2, (val1), (val2))\n\nC_API future_t thrd_scope(void);\nC_API future_t thrd_sync(future_t);\nC_API rid_t thrd_spawn(thrd_func_t fn, size_t num_of_args, ...);\nC_API values_type thrd_result(rid_t id);\n\n// C_API future_t thrd_for(for_func_t loop, intptr_t initial, intptr_t times);\n\nC_API void thrd_then(result_func_t callback, future_t iter, void_t result);\nC_API void thrd_destroy(future_t);\nC_API bool thrd_is_finish(future_t);\n\n/**\n* Creates an scoped `vector/array/container` for arbitrary arguments passing\n* into an single `parameter` function.\n* - Use standard `array access` for retrieval of an `union` storage type.\n*\n* - MUST CALL `args_destructor_set()` to have memory auto released\n*   within ~callers~ scoped `context`, will happen either at return/exist or panics.\n*\n* - OTHERWISE `memory leak` will be shown in DEBUG build.\n*\n* NOTE: `vector_for` does auto memory cleanup.\n*\n* @param count numbers of parameters, `0` will create empty `vector/array`.\n* @param arguments indexed in given order.\n*/\nC_API args_t args_for(size_t, ...);\nC_API args_t args_ex(size_t, va_list);\nC_API void args_destructor_set(args_t);\nC_API bool is_args(void_t);\n\n/**\n* Creates an scoped `vector/array/container` for arbitrary item types.\n* - Use standard `array access` for retrieval of an `union` storage type.\n*\n* - MUST CALL `array_deferred_set` to have memory auto released\n*   when given `scope` context return/exist or panics.\n*\n* - OTHERWISE `memory leak` will be shown in DEBUG build.\n*\n* @param count numbers of parameters, `0` will create empty `vector/array`.\n* @param arguments indexed in given order.\n*/\nC_API arrays_t array_of(memory_t *, size_t, ...);\nC_API void array_deferred_set(arrays_t, memory_t *);\nC_API void array_append(arrays_t, void_t);\nC_API void array_delete(arrays_t);\nC_API void array_remove(arrays_t, int);\nC_API bool is_array(void_t);\n#define $append(arr, value) array_append((arrays_t)arr, (void_t)value)\n#define $remove(arr, index) array_remove((arrays_t)arr, index)\n\n#define vectorize(vec) vectors_t vec = vector_variant()\n#define vector(vec, count, ...) vectors_t vec = vector_for(nil, count, __VA_ARGS__)\n\n#define $push_back(vec, value) vector_push_back((vectors_t)vec, (void_t)value)\n#define $insert(vec, index, value) vector_insert((vectors_t)vec, index, (void_t)value)\n#define $clear(vec) vector_clear((vectors_t)vec)\n#define $size(vec) vector_size((vectors_t)vec)\n#define $capacity(vec) vector_capacity((vectors_t)vec)\n#define $erase(vec, index) vector_erase((vectors_t)vec, index)\n\n/* The `foreach(item in vector/array)` macro, similar to `C#`,\nexecutes a statement or a block of statements for each element in\nan instance of `vectors_t/args_t/arrays_t` */\n#define foreach(...) foreach_xp(foreach_in, (__VA_ARGS__))\n#define foreach_back(...) foreach_xp(foreach_in_back, (__VA_ARGS__))\n```\n\n### There is _1 way_ to create an smart memory pointer\n\n```c\n/* Creates smart memory pointer, this object binds any additional requests to it's lifetime.\nfor use with `malloc_*` `calloc_*` wrapper functions to request/return raw memory. */\nC_API unique_t *unique_init(void);\n```\n\n\u003e This system use macros `RAII_MALLOC`, `RAII_FREE`, `RAII_REALLOC`, and `RAII_CALLOC`.\n\u003e If not **defined**, the default **malloc/calloc/realloc/free** are used when expanded.\n\u003e The expansion thereto points to custom replacement allocation routines **rpmalloc**.\n\n### The following _malloc/calloc_ wrapper functions are used to get an raw memory pointer\n\n```c\n/* Request/return raw memory of given `size`, using smart memory pointer's lifetime scope handle.\nDO NOT `free`, will be freed with given `func`, when scope smart pointer panics/returns/exits. */\nC_API void *malloc_full(memory_t *scope, size_t size, func_t func);\n\n/* Request/return raw memory of given `size`, using smart memory pointer's lifetime scope handle.\nDO NOT `free`, will be freed with given `func`, when scope smart pointer panics/returns/exits. */\nC_API void *calloc_full(memory_t *scope, int count, size_t size, func_t func);\n```\n\nNote the above functions will **panic/throw** if request fails, is `NULL`,\nand begin **unwinding**, executing _deferred_ statements.\n\n### Thereafter, an smart pointer can be use with these _raii__* functions\n\n```c\n/* Defer execution `LIFO` of given function with argument,\nto the given `scoped smart pointer` lifetime/destruction. */\nC_API size_t raii_deferred(memory_t *, func_t, void *);\n\n/* Same as `raii_deferred` but allows recover from an Error condition throw/panic,\nyou must call `raii_is_caught` inside function to mark Error condition handled. */\nC_API void raii_recover_by(memory_t *, func_t, void *);\n\n/* Compare `err` to scoped error condition, will mark exception handled, if `true`. */\nC_API bool raii_is_caught(memory_t *scope, const char *err);\n\n/* Get scoped error condition string. */\nC_API const char *raii_message_by(memory_t *scope);\n\n/* Begin `unwinding`, executing given scope smart pointer `raii_deferred` statements. */\nC_API void raii_deferred_free(memory_t *);\n\n/* Same as `raii_deferred_free`, but also destroy smart pointer. */\nC_API void raii_delete(memory_t *ptr);\n```\n\n### Using `thread local storage` for an default smart pointer, the following functions always available\n\n```c\n/* Return current `context` ~scope~ smart pointer, in use! */\nC_API memory_t *get_scope(void);\n\n/* Returns protected raw memory pointer of given `size`,\nDO NOT FREE, will `throw/panic` if memory request fails.\nThis uses current `context` smart pointer, being in `guard` blocks,\ninside `thread/future`, or active `coroutine` call. */\nC_API void *malloc_local(size_t size);\n\n/* Returns protected raw memory pointer of given `size`,\nDO NOT FREE, will `throw/panic` if memory request fails.\nThis uses current `context` smart pointer, being in `guard` blocks,\ninside `thread/future`, or active `coroutine` call. */\nC_API void *calloc_local(int count, size_t size);\n\n/* Defer execution `LIFO` of given function with argument,\nto current `thread` scope lifetime/destruction. */\nC_API size_t raii_defer(func_t, void *);\n\n/* Same as `raii_defer` but allows recover from an Error condition throw/panic,\nyou must call `raii_caught` inside function to mark Error condition handled. */\nC_API void raii_recover(func_t, void *);\n\n/* Compare `err` to current error condition, will mark exception handled, if `true`. */\nC_API bool raii_caught(const char *err);\n\n/* Get current error condition string. */\nC_API const char *raii_message(void);\n\n/* Begin `unwinding`, executing current `thread` scope `raii_defer` statements. */\nC_API void raii_deferred_clean(void);\n```\n\n### Fully automatic memory safety, using `guard/unguarded/guarded` macro\n\nThe full potently of **RAII** is encapsulated in the `guard` macro.\nUsing `try/catch/catch_any/catch_if/finally/finality` exception system macros separately will be unnecessary, however see [examples](https://github.com/zelang-dev/c-raii/tree/main/examples) folder for usage.\n\nBelow is the **recommended pattern** for complete cross platform usage.\nSystem uses _native_ [Windows SEH](https://learn.microsoft.com/en-us/cpp/cpp/try-except-statement), _multiple_ `catch()` blocks not possible.\n\n\u003e NOTE: Only in **debug builds** _uncaught exceptions_ **backtrace** info is auto displayed.\n\n```c++\n#include \"raii.h\"\n\nstatic void pfree(void *p) {\n    printf(\"freeing protected memory pointed by '%s'\\n\", (char *)p);\n    free(p);\n}\n\nint main(int argc, char **argv) {\n    try {\n        int a = 1;\n        int b = 0.00000;\n        char *p = 0;\n        p = malloc_full(raii_init(), 3, pfree);\n        strcpy(p, \"p\");\n\n        *(int *)0 = 0;\n        printf(\"never reached\\n\");\n        printf(\"%d\\n\", (a / b));\n        raise(SIGINT);\n    } catch_if {\n        if (caught(bad_alloc))\n            printf(\"catch: exception %s (%s:%d) caught\\n\", err.name, err.file, err.line);\n        else if (caught(division_by_zero))\n            printf(\"catch: exception %s (%s:%d) caught\\n\", err.name, err.file, err.line);\n        else if (caught(sig_fpe))\n            printf(\"catch: exception %s (%s:%d) caught\\n\", err.name, err.file, err.line);\n        else if (caught(sig_ill))\n            printf(\"catch: exception %s (%s:%d) caught\\n\", err.name, err.file, err.line);\n        else if (caught(sig_int))\n            printf(\"catch: exception %s (%s:%d) caught\\n\", err.name, err.file, err.line);\n        else if (caught(sig_segv))\n            printf(\"catch: exception %s (%s:%d) caught\\n\", err.name, err.file, err.line);\n    } finally {\n        if (err.is_caught) {\n            printf(\"finally: try failed, but succeeded to catch -\u003e %s (%s:%d)\\n\", err.name, err.file, err.line);\n        } else {\n            printf(\"finally: try failed to `catch()`\\n\");\n            ex_backtrace(err.backtrace);\n        }\n    }\n\n    return 0;\n}\n```\n\nThe Planned C11 implementation details still holds here, but `defer` not confined to `guard` block, actual function call.\n\n```c\n/* Creates an scoped guard section, it replaces `{`.\nUsage of: `_defer`, `_malloc`, `_calloc`, `_assign_ptr` macros\nare only valid between these sections.\n    - Use `_return(x);` macro, or `break;` to exit early.\n    - Use `_assign_ptr(var)` macro, to make assignment of block scoped smart pointer. */\n#define guard\n\n/* This ends an scoped guard section, it replaces `}`.\nOn exit will begin executing deferred functions,\nreturn given `result` when done, use `NONE` for no return. */\n#define unguarded(result)\n\n/* This ends an scoped guard section, it replaces `}`.\nOn exit will begin executing deferred functions. */\n#define guarded\n\n#define _malloc(size) malloc_local(size)\n#define _calloc(count, size) calloc_local(count, size)\n\n/* Defer execution `LIFO` of given function with argument,\nOnly valid between `guard` blocks or inside `thread/future` call.\n\nExecution begins when current `guard` scope exits or panic/throw. */\n#define _defer(func, ptr)\n\n/* Compare `err` to scoped error condition, will mark exception handled, if `true`.\nOnly valid between `guard` blocks or inside `thread/future` call. */\n#define _recovered(err)\n\n/* Get scoped error condition string.\nOnly valid between `guard` blocks or inside `thread/future` call. */\n#define _get_message()\n\n/* Stops the ordinary flow of control and begins panicking,\nthrows an exception of given message. */\n#define _panic(err)\n\n/* Makes a reference assignment of current scoped smart pointer. */\n#define _assign_ptr(scope)\n\n/* Exit `guarded` section, begin executing deferred functions,\nreturn given `value` when done, use `NONE` for no return. */\n#define _return(value)\n```\n\nThe idea way of using this library, is to make a **new** _field_ for `unique_t` into your current _typedef_ **object**,\nmainly one held throughout application, and setup your wrapper functions to above **raii_** functions.\n\nThere are also `2 global callback` functions that need to be setup for complete integration.\n\n```c\n// Currently an wrapper function that set ctx-\u003edata, scoped error, and protection state, working on removing need\ntypedef void (*ex_setup_func)(ex_context_t *ctx, const char *ex, const char *panic);\n// Your wrapper to raii_deferred_free(ctx-\u003edata)\ntypedef void (*ex_unwind_func)(void *);\n\nex_setup_func exception_setup_func;\nex_unwind_func exception_unwind_func;\n```\n\n## Installation\n\nAny **commit** with an **tag** is considered _stable_ for **release** at that _version_ point.\n\nIf there are no _binary_ available for your platform under **Releases** then build using **cmake**,\nwhich produces **static** libraries by default.\n\nYou will need the _binary_ stored under `built`, and `*.h` headers, or complete `include` _folder_ if **Windows**.\n\n### Linux\n\n```shell\nmkdir build\ncd build\ncmake .. -DCMAKE_BUILD_TYPE=Debug/Release -D BUILD_TESTS=OFF -D BUILD_EXAMPLES=OFF # use to not build tests and examples\ncmake --build .\n```\n\n### Windows\n\n```shell\nmkdir build\ncd build\ncmake .. -D BUILD_TESTS=OFF -D BUILD_EXAMPLES=OFF # use to not build tests and examples\ncmake --build . --config Debug/Release\n```\n\n### As cmake project dependency\n\n\u003e For **CMake** versions earlier than `3.14`, see \u003chttps://cmake.org/cmake/help/v3.14/module/FetchContent.html\u003e\n\nAdd to **CMakeLists.txt**\n\n```c\nfind_package(raii QUIET)\nif(NOT raii_FOUND)\n    FetchContent_Declare(raii\n        URL https://github.com/zelang-dev/c-raii/archive/refs/tags/2.3.1.zip\n        URL_MD5 c1867e16749033765d10d440ed99c919\n    )\n    FetchContent_MakeAvailable(raii)\nendif()\n\ntarget_include_directories(your_project PUBLIC $\u003cBUILD_INTERFACE:${RAII_INCLUDE_DIR} $\u003cINSTALL_INTERFACE:${RAII_INCLUDE_DIR})\ntarget_link_libraries(your_project PUBLIC raii)\n```\n\n## Contributing\n\nContributions are encouraged and welcome; I am always happy to get feedback or pull requests on Github :) Create [Github Issues](https://github.com/zelang-dev/c-raii/issues) for bugs and new features and comment on the ones you are interested in.\n\n## License\n\nThe MIT License (MIT). Please see [License File](LICENSE.md) for more information.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzelang-dev%2Fc-raii","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzelang-dev%2Fc-raii","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzelang-dev%2Fc-raii/lists"}