{"id":13342939,"url":"https://github.com/Frityet/ManagedC","last_synced_at":"2025-03-12T03:30:41.956Z","repository":{"id":40235680,"uuid":"438728054","full_name":"Frityet/ManagedC","owner":"Frityet","description":"Reference counter for C","archived":true,"fork":false,"pushed_at":"2023-03-05T00:32:50.000Z","size":307,"stargazers_count":53,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-07T17:54:57.038Z","etag":null,"topics":["ansi-c","c","pointers","raii","reference-counting","xmake"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-2.1","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Frityet.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":"2021-12-15T18:10:47.000Z","updated_at":"2024-11-22T14:49:46.000Z","dependencies_parsed_at":"2024-10-24T05:19:50.918Z","dependency_job_id":"b88fb4e3-2f58-4477-8596-f3d643fda246","html_url":"https://github.com/Frityet/ManagedC","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Frityet%2FManagedC","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Frityet%2FManagedC/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Frityet%2FManagedC/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Frityet%2FManagedC/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Frityet","download_url":"https://codeload.github.com/Frityet/ManagedC/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243150684,"owners_count":20244443,"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":["ansi-c","c","pointers","raii","reference-counting","xmake"],"created_at":"2024-07-29T19:30:08.425Z","updated_at":"2025-03-12T03:30:41.660Z","avatar_url":"https://github.com/Frityet.png","language":"C","readme":"# ManagedC\n\nLibrary to add a reference counter to C. See [`tests/src/`](tests/src) for examples\n\n\u003e |ℹ️ Note ℹ️        |\n\u003e |-----------------|\n\u003e | If you have GCC extensions enabled, you get access to more features, i.e the `auto` macro for automatic releasing! |    \n\n\n# Installation\n\nUsing [xmake](https://xmake.io) you can easily use this library by adding `managedc` to your packages\n\nIf you do not use `xmake` then you can just copy the file [`managed.h`](src/managed.h) from [`src/`](src/). [`mstring.h`](src/managed/mstring.h) adds helper functions for string usage.\n\n# Usage\n\n## Allocation and deallocation\n\nTo get a \"managed\" type, you must allocate your type with \n```c\nstatic void *mc_nullable managed_allocate(size_t count, size_t typesize, void (*mc_nullable)(void *mc_nonnull) free, const void *mc_nullable data)\n````\nor\n```c\n#define mc_alloc(T, free) (T *)managed_allocate(1, sizeof(T), (managed_Free_f *)free, NULL)\n```\nor, for arrays\n```c\n#define mc_array(T, count, free) (T *)managed_allocate(count, sizeof(T), (managed_Free_f *)(free), NULL)\n```\n\nand you can release your reference using\n```c\nstatic void managed_release(const void *mc_nonnull ptr)\n```\nor\n```c\n#define mc_free(ptr) managed_release(ptr)\n```\n\nYou can specify a custom \"deconstructor\", which is a function that will run on each element of the array on deallocation\n\n```c\n#include \u003cstdio.h\u003e\n\n#include \"managed.h\"\n\n//We get a pointer to the value that we can free\n//It is a double pointer because we have an array \n//of pointers in main\nvoid free_int_ref(int **ref)\n{\n    //This function will be called for each item in the array\n    printf(\"Value: %d\\n\", **ref);\n    \n    //mc_free is used for deallocating \"managed\" types.\n    mc_free(ref);\n}\n\nint main(void)\n{\n    int **alloc_list = mc_array(int *, 5, \u0026free_int_ref); \n    \n    alloc_list[0] = mc_alloc(int, NULL);\n    *alloc_list[0] = 11;\n    \n    alloc_list[1] = mc_alloc(int, NULL);\n    *alloc_list[1] = 10;\n\n    alloc_list[2] = mc_alloc(int, NULL);\n    *alloc_list[2] = 9;\n    \n    alloc_list[3] = mc_alloc(int, NULL);\n    *alloc_list[3] = 8;\n    \n    alloc_list[4] = mc_alloc(int, NULL);\n    *alloc_list[4] = 7;\n    \n    mc_free(alloc_list);\n}\n```\n\n## Referencing\n\nFor the reference counter to work, assigning a reference through the regular `=` will result in no additional references being counted, which is useful for \"weak\" references. To make a strong reference to a \"managed\" pointer, use\n```c\nstatic void *managed_reference(const void *mc_nonnull ptr)\n```\nor the\n```c\n#define mc_ref(ptr) MC_EXPAND((mc_typeof(ptr)))managed_reference(ptr)\n```\nmacro.\n\nThe pointer will not be freed until all the references are not in use.\n\n```c\n#include \"managed.h\"\n\nint *func_that_allocs(void)\n{\n    int *mem = managed_alloc(sizeof(int), 128, NULL, NULL);\n\n    return mem;\n}\n\nint main(void)\n{\n    //You can pass in managed_release (not mc_free) as a param, and it will run on the value of the pointer, which must also be a managed pointer\n    int **refarray = mc_alloc(int *, managed_release);\n\n    {\n        int *array = func_that_allocs();\n        *array = 10;\n        refarray[0] = mc_reference(array); //Will not be deallocateed because we got a reference\n        mc_free(array);\n\t}\n\t\n\tmc_free(refarray);\n}\n```\n\n## Metadata\n\nManagedC keeps metadata about the pointer, meaning that you do not have to keep track of this data yourself.\nThe metadata is stored in this struct\n```c\nstruct managed_PointerInfo {\n    /**\n     * count: Number of used array elements.\n     * capacity: Number of allocated array elements. (Used for managed_Vector)\n     * typesize: Size of the type.\n     * reference_count: Number of references to this pointer.\n     */\n    size_t count, capacity, typesize, reference_count;\n\n    /**\n    * Function to call on 0 references.\n    */\n    managed_Free_f *mc_nullable free;\n\n    /**\n    * Pointer to the data, should be just in front of data.\n    */\n    void *mc_nonnull data;\n\n#if MC_MUTEX\n    /**\n    * Lock on the metadata, maps to an OS specific object.\n    */\n    mc_Mutex_t lock;\n#endif\n};\n```\nIt can be accessed by using\n```c\nconst struct managed_PointerInfo *mc_nullable managed_info_of(const void *mc_nonnull ptr)\n```\n\nAs `count` is the most common field you will probably access, you can call\n```c\n#define mc_countof(ptr) (managed_info_of(ptr)-\u003ecount)\n```\nto quickly get the count of elements in the allocations.\n\n### Extensions - GCC/Clang\n\nJust as the original use of `auto` in BCPL was to declare that a stack-allocated variable was to be deallocated once outside of the scope, `mc_auto` in this library declares that a **heap allocated variable allocated with `managed_allocate` will be freed once outside the scope**.\n\nFor example\n\n```c\n#include \"managed.h\"\n\nvoid func_that_allocs(void)\n{\n    mc_auto int *mem = mc_alloc(int, NULL);\n    //...usage\n   \n    //Automatically deallocated!\n}\n\nint main(void)\n{\n    func_that_allocs();\n    func_that_allocs();\n    func_that_allocs();\n    func_that_allocs();\n    func_that_allocs();\n    //no leaks!\n}\n```\n\n### Extensions - Clang\n\nIf you use clang, you can use `mc_defer` to make code run once out of scope. This requires `-fBlocks` and you may have to link with `libBlocksRuntime`.\n```c\nint main(void)\n{\n    FILE *fp = fopen(\"hi.txt\", \"rb\");\n    mc_defer { fclose(fp); };\n    //...usage\n    //Automatically closed!\n}\n```\n\n## Datastructures\n\nManagedC also comes with reference counted common data structures, with the list still growing\nYou can see them [here](src/managed/)\n\n### TODO\n- [x] Safer and better thread support   - [issue](https://github.com/Frityet/ManagedC/issues/1)\n- [X] Fix for reallocation              - [issue](https://github.com/Frityet/ManagedC/issues/3)\n- [X] A solution to circular references - [issue](https://github.com/Frityet/ManagedC/issues/2)\n- [X] Solution for MSVC/ISO-C           - [issue](https://github.com/Frityet/ManagedC/issues/4)\n- [X] Easier/standardized referencing   - [issue](https://github.com/Frityet/ManagedC/issues/5)\n- [X] Data structures                   - [issue](https://github.com/Frityet/ManagedC/issues/8)\n\n- [ ] Even more data structures!        - [issue](https://github.com/Frityet/ManagedC/issues/10)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FFrityet%2FManagedC","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FFrityet%2FManagedC","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FFrityet%2FManagedC/lists"}