{"id":21235719,"url":"https://github.com/comba92/stc","last_synced_at":"2025-03-15T02:44:34.250Z","repository":{"id":252412326,"uuid":"840342098","full_name":"Comba92/stc","owner":"Comba92","description":"Basic generic C library with a better memory management.","archived":false,"fork":false,"pushed_at":"2024-10-19T13:14:45.000Z","size":70,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-21T18:48:44.862Z","etag":null,"topics":["c-library","dynamic-array","memory-management"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Comba92.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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-08-09T13:42:38.000Z","updated_at":"2024-10-19T13:14:48.000Z","dependencies_parsed_at":"2024-08-09T16:29:19.075Z","dependency_job_id":"c195d041-3b6f-4b57-98df-a67a7bd9b40e","html_url":"https://github.com/Comba92/stc","commit_stats":null,"previous_names":["comba92/stc"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Comba92%2Fstc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Comba92%2Fstc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Comba92%2Fstc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Comba92%2Fstc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Comba92","download_url":"https://codeload.github.com/Comba92/stc/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243676714,"owners_count":20329432,"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-library","dynamic-array","memory-management"],"created_at":"2024-11-21T00:02:37.766Z","updated_at":"2025-03-15T02:44:34.234Z","avatar_url":"https://github.com/Comba92.png","language":"C","readme":"# STC (Standard Comba Library)\nStc is a simple header-only C library with quality of life features.\nIt aims to simplify and enhance basic language features which the C language lacks, such as dynamic arrays, better strings, and hashmaps.\n\nIt is subdivided in modules, but they are mostly interconnected with each other.\nTest files should offer a simple example of how to use the library.\n\n## stc_mem\nAn implementation for a growable Arena allocator and a growable Pool allocator.\nAn Arena is a region-based allocator, which works by allocating a big chunk of memory, and allocating data contiguously.\nThe arena doesn't keep track of the allocated data, so it isn't possible to free pointers. However, the arena can be freed all at once. This behaviour is extremely useful, as very often we need 'scratch' objects which we use for a short amount of time, and we can release when we're done.\n\nArena also simplifies the problem of 'lifetimes', which is hard to deal with using a variable size allocator such as malloc. As we have to always pass the arena when we alloc, we make allocations 'explicit', so we know data depending on the arena will live until the arena lives too.\n\nAn example:\n```c\n  Arena a1 = {0};\n  Arena a2 = {0};\n  MyType* bigArrayOfStructs = arena_alloc(\u0026a1, 10000 * sizeof(MyType));\n  MyOtherType* bigStruct = arena_alloc(\u0026a1, sizeof(MyOtherType));\n\n  MyType* anotherArrayOfStructs = arena_alloc(\u0026a2, 5000 * sizeof(MyType));\n\n  // ... do some stuff with the data...\n\n  // We're done with anotherArrayOfStructs\n  arena_free(\u0026a2);\n  \n  // We're done with the other data\n  arena_free(\u0026a1);\n```\n\nIf the region is full, a new region will be allocated and will point to the old one. This way, no reallocations occurs, and all the pointers won't be invalidated. The arena can thus grow indefinetely, and the user doesn't have to deal with complex allocations. It is only sufficient to free the arena at the end of its usage.\n\nThe Pool allocator on the other hand, reserves a big chunk of static sized blocks, useful if we need a big number of the same objects, and we also need to be able to free them independently.\nThe Pool keeps track of allocations with a free list. \n(Fun fact, the pool stores its data in an Arena!)\n\n```c\n  // We tell the pool how big the chunks should be\n  Pool p = pool_new(sizeof(MyType));\n  MyType* myTypes[100];\n\n  for(int i=0; i\u003c100; ++i) {\n    myTypes[i] = pool_alloc(\u0026p);\n  }\n\n  // wee can free some objects \n  pool_free(\u0026p, myTypes[0]);\n  pool_free(\u0026p, myTypes[1]);\n  pool_free(\u0026p, myTypes[2]);\n\n  // do some stuff with the data...\n\n  // we destroy the pool\n  pool_reset(\u0026p);\n```\n\nThe pool grows in size if it is filled, in a similiar way to the Arena.\n\n## stc_list\nAn implementation for a generic dynamic array, using a simple struct with data, length, and capacity.\nIt mainly consists of macros, but they are fairly simple, so not very dangerous.\nIf you want to make a generic list, you first have to 'define' it, giving its name and type, as so:\n\n```c \n  list_define(int, ListOfInts);\n```\n\nA big enough chunk of memory is allocated at first. When we fill the array, we simply reallocate it to double its size. The macro takes care of assignin the new address to the old variable!\nBe warned that with reallocation, the array will change address, so if you have other references to it, they will all become dangling. It is usually wise to always have only a single reference to a dynamic array.\n\n```c \n  ListOfInts list = {0};\n\n  for (int i=0; i\u003c100; ++i) list_push(list, i);\n\n  list_free(list);\n```\n\nMore generic macros are implemented, such as foreach, concat, filter, and map.\nAn arena allocated list is also avaible, with its respective macros.\n\n## stc_str\nImplementation of a string view and owned string.\nA String View (str) is a simple fat pointer, or slice, of a static C string (char*).\nBasically, it points to the static string, and has a length.\nIt isn't NULL terminated, so it won't work with libc string functions, especially such as printf.\n\nA str can be converted to a C string with cstr(), which is malloc-allocated, or zstr(), which is allocated in a scratch arena, freeable with zstrings_free().\n\nA big number of utilities and string management are avaible for the str type. The best thing is that they are memory safe!\nOperations on String Views NEVER allocate any new memory, with the exception of cstr() and zstr().\n\nAs a simple example:\n```c\n  str s = str_from(\"Hello World!\");\n  str hello = str_slice(s.data, 0, 5); // contains 'Hello'\n  str world = str_skip_until_char(s, ' '); // contains 'World!'\n\n  str trimmed = str_trim(str_from(\"    help...    \")); // contains \"help...\"\n  str_cmp(hello, world); // will output -1, and it is a memory safe strcmp!\n\n  char* cstring = cstr(s);\n  printf(\"%s %s\", cstring, zstr(s));  // this will print a NULL terminated C string, which works with printf\n\n  // C strings have to be freed, Zstrings are freed all at once\n  free(cstring);\n  zstrings_free();\n```\n\nThe moment we need to edit a String View, we need an Owned String.\nAn Owned String (String) is an arena allocated string, which permits modfications.\nA String is always allocated, and every string operation always allocates a new string, so the problem of dangling references is non existent, as long as the arena is alive.\nThe only exception is str_append(), which might reallocate.\n\nOwned Strings can be converted to Views with STR().\nString supports all the str operations, returning a view to the owned string.\nIt isn't NULL terminated, so like str, you need to convert it to a C string with zstring().\n\n```c\n  Arena a = {0};\n\n  str view = str_from(\"Hello World!\");\n\n  String owned = string_from(\u0026a, view);\n  String upper = str_to_upper(\u0026a, owned); // contains \"HELLO WORLD!\"\n\n  String concat = str_concat(\u0026a, owned, s, str_from(\"New data!\")); // new string is allocated, owned is untouched\n\n  str_append(\u0026a, \u0026owned, s, str_from(\"New data!\")); // append is the only operations which edits in-place, owned is modified and eventually reallocated\n\n  // format string, will contain 'Some numbers: 69, 420, and some data!'\n  String fmt = str_format(\u0026a, \"Some numbers: %d, %d, and %s\", 69, 420, \" some data!\");\n\n  // all strings are freed\n  arena_free(\u0026a);\n```\n\n## stc_matrix\nA simple generic implementation of a fixed size 2D array.\n\n## stc_map\nAn implementation for a generic dynamic dictionary, using an hashtable with linear probing for dealing with hash collisions.\nThe keys are always a string view.\nLike the lists, they first must be defined:\n\n```c\n  map_define(int, MapOfInts);\n```\n\n```c\n  MapOfInts map = {0};\n  map_init(50);\n\n  map_MapOfInts_insert(\u0026map, str_from(\"test\"), 5);\n  int value = map_MapOfInts_get(\u0026map, str_from(\"test\"));\n```\n\nThe map will be reallocated if it is filled.","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcomba92%2Fstc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcomba92%2Fstc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcomba92%2Fstc/lists"}