{"id":13846368,"url":"https://github.com/cher-nov/Gena","last_synced_at":"2025-07-12T07:32:35.837Z","repository":{"id":92944520,"uuid":"84583785","full_name":"cher-nov/Gena","owner":"cher-nov","description":"Generic pseudo-templated containers for C. Written entirely in C89 with design inspired by the C++ STL. /// DOCS ARE SLIGHTLY OUTDATED, PROJECT IS STABLE AND STILL BEING DEVELOPED","archived":false,"fork":false,"pushed_at":"2022-06-20T09:38:18.000Z","size":227,"stargazers_count":85,"open_issues_count":12,"forks_count":6,"subscribers_count":8,"default_branch":"master","last_synced_at":"2024-02-17T10:37:23.446Z","etag":null,"topics":["aesthetic","c","containers","gena","generics","library","stl","templates"],"latest_commit_sha":null,"homepage":"https://habr.com/ru/post/324210/","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"wtfpl","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cher-nov.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"COPYING","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2017-03-10T17:20:18.000Z","updated_at":"2024-01-04T07:56:42.000Z","dependencies_parsed_at":"2023-04-12T05:46:08.725Z","dependency_job_id":null,"html_url":"https://github.com/cher-nov/Gena","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cher-nov%2FGena","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cher-nov%2FGena/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cher-nov%2FGena/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cher-nov%2FGena/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cher-nov","download_url":"https://codeload.github.com/cher-nov/Gena/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225807261,"owners_count":17527221,"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":["aesthetic","c","containers","gena","generics","library","stl","templates"],"created_at":"2024-08-04T18:00:31.177Z","updated_at":"2024-11-21T21:30:25.996Z","avatar_url":"https://github.com/cher-nov.png","language":"C","funding_links":[],"categories":["Other projects"],"sub_categories":[],"readme":"# genvector – Generalized Vector\n\nAn implementation of *vector* – dynamic linear array – in pure C89.\nThis one is competently generalized with macros (*pseudo-templated*), so you can create vector of **any** datatype supported in C – i.e. primitive types, structs and unions. Just preliminarily instantiate it for needed types and you're on.\nInterface is based mostly on the design of `std::vector` from C++11.\n\n## Table of contents\n\n* [Features in a nutshell](#features-in-a-nutshell)\n* [Example (C99)](#example-c99)\n* [Design notes](#design-notes)\n* [Usage](#usage)\n  - [Static approach](#static-approach)\n  - [Modular approach](#modular-approach)\n    * [Typesets](#typesets)\n* [Functions](#functions)\n  - [Functions to manage `gvec_h`, and specialized versions of them](#functions-to-manage-gvec_h-and-specialized-versions-of-them)\n  - [Specialized-only functions](#specialized-only-functions)\n  - [General-purpose functions](#general-purpose-functions)\n* [Library adjustment using optional defines](#library-adjustment-using-optional-defines)\n  - [Before header inclusion](#before-header-inclusion)\n  - [At compile-time](#at-compile-time)\n\n## Features in a nutshell\n\n1. Access vector elements just like plain C arrays: `vec[k]`.\n2. Support of multidimensional vectors (aka vector of vectors of...). Accessing them is Cpp-like too: `vec[i][j]`, `vec[x][y][z]`, and so on.\n3. It's possible to copy one vector into another, even if they contain values of different types.\n4. It's easy to instantiate necessary vector types once in a separate module, instead of doing this every time you needed a vector.\n5. You can choose how to pass values into a vector and how to return them from it: by value or by pointer.\n6. No code reduplication: only functions that take or return values of user type are specialized.\n\n## Example (C99)\n\n```c\n#include \u003cstdlib.h\u003e\n#include \u003cstdio.h\u003e\n\n#include \"genvector/genvector.h\"\n\ntypedef struct {\n  char Name[32];\n  int Age;\n} person_s;\n\n#define C_PERSON(name, age) ( (person_s){ .Name=name, .Age=age } )\n\nGVEC_INSTANTIATE_EX( person_s, society, GENA_USE_SAMPLE, GENA_USE_ENTITY, GENA_ASSIGN_NAIVE );\n\nint main() {\n  gvec_society_h family = gvec_society_new(0);\n  if (family == NULL) { return EXIT_FAILURE; }\n\n  gvec_society_push( \u0026family, C_PERSON(\"Alice\", 30) );\n  gvec_society_push( \u0026family, C_PERSON(\"Bob\", 32) );\n  gvec_society_push( \u0026family, C_PERSON(\"Kate\", 10) );\n\n  printf( \"%zu\\n\", gvec_count( family ) );\n  while ( gvec_count( family ) \u003e 0 ) {\n    person_s member = *gvec_society_pop( family );\n    printf( \"name %s, age %d\\n\", member.Name, member.Age );\n  }\n\n  gvec_free( family );\n  return EXIT_SUCCESS;\n}\n```\n\n## Design notes\n\n1. All indices and positions are zero-based.\n2. Functions validate their input arguments using only standard C89 `assert()` from *assert.h*.\n3. Non-specialized functions always return a defined result.\n4. If an error occurrs, the vector remains valid and unchanged.\n5. A vector storage never gets reduced, unless `gvec_shrink()` is called.\n6. So-called *\"vector of void\"* type, `gvec_h`, is just a vector of untyped memory chunks.\n\n## Usage\n\nBy default, library provides only the next set of methods:\n\n1. Specialized functions.\n2. General-purpose functions.\n3. Instantiation macros.\n\nTo create a type *\"vector of T\"* and specialize management functions for it, you should *instantiate* it using instantiation macros.\nThese are two and a half approaches in instantiation: *static* and *modular*, supplied with *typesets*.\nLet's examine them more closely.\n\n### Static approach\n\nThis approach is good when vector is used only in one translation unit (*module*). It is easier and set by default.\nJust include library header into module source and instantiate vector for types you need, using `GVEC_INSTANTIATE()`:\n```c\nGVEC_INSTANTIATE( tpTypeInfo, tpSurname, tpUseBy );\n```\n* *tpTypeInfo* – type for which vector should be instantiated\n* *tpSurname* – unique vector name that will be placed into names of specialized functions, for example: `gvec_mystruct_new()`\n* *tpUseBy* – specifies how values should be passed to specialized functions and returned from them\n\nPossible values both for *tpUseBy* are:\n* `GENA_USE_SAMPLE` – pass/return by value\n* `GENA_USE_ENTITY` – pass/return by reference\n\nIt is also a good practice to place library header inclusion and vector types instantiation in a separate header.\n\n### Modular approach\n\nThe main disadvantage about static approach is that vector type and it's corresponding specialized functions will be instantiated every time you use `GVEC_INSTANTIATE()`. This is bad if same vector type is used in different modules – it will be instantiated for all of them, increasing output code size.\nTo prevent this problem, a modular approach should be used. Its idea is derived from the recommendation about separate header in the static approach: let's instantiate necessary vector types in a separate wrapper module, and use it instead of library itself every time you need a vector.\nFor the next code template let's assume that wrapper module is called *gvec_wrapper*.\n\n***gvec_wrapper.h***\n```c\n#include \"genvector.h\"\n\nGVEC_H_DECLARE( tpTypeInfo, tpSurname, tpUseBy );\n```\n\n***gvec_wrapper.c***\n```c\n#include \"gvec_wrapper.h\"\n\nGVEC_C_DEFINE( tpTypeInfo, tpSurname, tpUseBy );\n```\n\nThe arguments for `GVEC_H_DECLARE()` and `GVEC_C_DEFINE()` are the same as for `GVEC_INSTANTIATE()`.\n\n#### Typesets\n\nAs you might have noticed, arguments for every pair of `GVEC_H_DECLARE()` and `GVEC_C_DEFINE()` are always the same. It's a sort of code duplication that may be considered undesirable.\nTo prevent this, *typesets* were introduced. Let's consider them using the modified version of the previous code template:\n\n***gvec_wrapper.h***\n```c\n#include \"genvector.h\"\n\n#define ZZ_GVEC_TYPESET_SOMETHING \\\n  (tpTypeInfo, tpSurname, tpUseBy)\n\nGENA_APPLY_TYPESET( GVEC_H_DECLARE, ZZ_GVEC_TYPESET_SOMETHING );\n```\n\n***gvec_wrapper.c***\n```c\n#include \"gvec_wrapper.h\"\n\nGENA_APPLY_TYPESET( GVEC_C_DEFINE, ZZ_GVEC_TYPESET_SOMETHING );\n```\n\n## Functions\n\n**Please note:** `gena_bool` type is fully compatible with `bool` from *stdbool.h* in C99 and later, so it's preferred not to use `gena_bool` if possible.\n\nNotation:\n* `NAME`: value of `tpSurname`\n* `PASSVAL`: `const tpTypeInfo` if `tpUseBy` is `GENA_USE_SAMPLE`, and `const tpTypeInfo*` otherwise\n* `RETVAL`: `tpTypeInfo` if `tpUseBy` is `GENA_USE_SAMPLE`, and `tpTypeInfo*` otherwise\n\n### Specialized functions to manage instantiated vector types\n\n```c\ngvec_NAME_h gvec_NAME_new( size_t min_count )\n```\nCreate a vector.\n\n* *min_count* – a minimum count of elements that can be stored without storage relocation\n\n*Return value:* a handle to the new vector, or `NULL` on error\n\n```c\ngena_bool gvec_NAME_reset( gvec_NAME_h* phandle, size_t count, const PASSVAL value )\n```\nResize a vector to specified count of elements and assign a value to them all.\n\n* *phandle* – a pointer to the handle to a vector\n* *count* – a new count of elements in a vector\n* *value* – a value to be assigned to elements\n\n*Return value:* `GENA_TRUE` if operation was performed successfully, `GENA_FALSE` otherwise\n\n```c\ngena_bool gvec_NAME_resize( gvec_NAME_h* phandle, size_t new_count, const PASSVAL value )\n```\nResize a vector.\n*It's recommended to use `gvec_resize()` for reducing the size, and `gvec_NAME_resize()` for increasing.*\n\n* *phandle* – a pointer to the handle to a vector\n* *new_count* – a new count of elements in a vector\n* *value* – a value to be assigned to new elements\n\n*Return value:* `GENA_TRUE` if operation was performed successfully, `GENA_FALSE` otherwise\n\n```c\ngena_bool gvec_NAME_reserve( gvec_NAME_h* phandle, size_t min_count )\n```\nReserve a space in a vector storage, at least for specified count of elements.\n\n* *phandle* – a pointer to the handle to a vector\n* *min_count* – a minimum count of elements that vector should accept without any relocation of its storage\n\n*Return value:* `GENA_TRUE` if operation was performed successfully, `GENA_FALSE` otherwise\n\n```c\ngena_bool gvec_shrink( gvec_NAME_h* phandle )\n```\nFree memory that isn't used by a vector now.\n\n* *phandle* – a pointer to the handle to a vector\n\n*Return value:* `GENA_TRUE` if operation was performed successfully, `GENA_FALSE` otherwise\n\n```c\ngena_bool gvec_NAME_insert( gvec_NAME_h* phandle, size_t position, size_t count, const PASSVAL value )\n```\nInsert elements into a vector.\n\n* *phandle* – a pointer to the handle to a vector\n* *position* – a position of the first element to be inserted\n* *count* – a count of elements to be inserted\n* *value* – a value to be assigned to elements\n\n*Return value:* `GENA_TRUE` if operation was performed successfully, `GENA_FALSE` otherwise\n\n```c\ngena_bool gvec_NAME_push( gvec_NAME_h* phandle, const PASSVAL value )\n```\nAdd an element to the end of a vector.\n\n* *phandle* – a pointer to the handle to a vector\n* *value* – a value to be assigned to the element\n\n*Return value:* `GENA_TRUE` if operation was performed successfully, `GENA_FALSE` otherwise\n\n```c\nRETVAL gvec_NAME_pop( gvec_h handle )\n```\nDrop the last element from a vector, and return it.\n\n* *handle* – a handle to a vector\n\n*Return value:*\n* `tpUseBy` is `GENA_USE_SAMPLE`: a value of the element (**undefined** if vector is empty)\n* `tpUseBy` is `GENA_USE_ENTITY`: a pointer to the element, or `NULL` if vector is empty\n\n### General-purpose functions to manage any vector type\n\n```c\ngvec_h gvec_assign( gvec_h* phandle, gvec_h source )\n```\nCopy-assign one vector to another. Sizes of the elements in both arrays must coincide. On error, the destination vector remains untouched.\n\n* *phandle* – a pointer to the handle to a destination vector\n* *source* – a handle to a source vector\n\n*Return value:* a handle to the destination vector, or `NULL` on error\n\n```c\ngvec_h gvec_copy( gvec_h handle )\n```\nDuplicate a vector.\n\n* *handle* – a handle to a source vector\n\n*Return value:* a handle to the vector duplicate, or `NULL` on error\n\n```c\nvoid gvec_free( gvec_h handle )\n```\nFree a vector.\n\n* *handle* – a handle to a vector (if `NULL`, nothing will occur)\n\n```c\nvoid gvec_clear( gvec_h handle )\n```\nClear all elements from a vector.\n\n* *handle* – a handle to a vector\n\n```c\nvoid gvec_reduce( gvec_h handle, size_t new_count )\n```\nReduce a vector to the specified count of elements.\n\n* *handle* – a handle to a vector\n* *new_count* – a new count of elements in a vector (should not exceed the current count)\n\n```c\ngena_bool gvec_remove( gvec_h handle, size_t position, size_t count )\n```\nRemove elements from a vector.\n\n* *handle* – a handle to a vector\n* *position* – a position of the first element to be removed\n* *count* – a count of elements to be removed\n\n*Return value:* `GENA_TRUE` if operation was performed successfully, `GENA_FALSE` otherwise\n\n```c\ngena_bool gvec_drop( gvec_h handle )\n```\nDrop the last element from a vector.\n\n* *handle* – a handle to a vector\n\n*Return value:* `GENA_TRUE` if operation was performed successfully, `GENA_FALSE` otherwise\n\n```c\nsize_t gvec_count( gvec_h handle )\n```\nGet count of elements in a vector.\n\n* *handle* – a handle to a vector\n\n*Return value:* the count of elements\n\n```c\nsize_t gvec_size( gvec_h handle )\n```\nGet size of a vector storage.\n\n* *handle* – a handle to a vector\n\n*Return value:* the current size\n\n```c\ngena_bool gvec_empty( gvec_h handle )\n```\nReturns if a vector specified is empty.\n\n* *handle* – a handle to a vector\n\n*Return value:* boolean\n\n## Library adjustment using optional defines\n\n* `GVEC_GROWTH_FACTOR` (1.5 by default)\nGrowth factor of vectors storages.\n\n* `GVEC_CALCULATE_SIZE_MATH`\nUse math function for size calculation, instead of loop-based.\n\n* `GVEC_INSERT_NO_REALLOC`\nDon't perform storage relocation using `realloc()` on elements insertion.\nThis prevents excess memory copying when inserting elements not at the end of a vector.\n\nIt's also recommended to compile with `NDEBUG` defined, to disable assertion checks.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcher-nov%2FGena","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcher-nov%2FGena","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcher-nov%2FGena/lists"}