{"id":13400221,"url":"https://github.com/P-p-H-d/mlib","last_synced_at":"2025-03-14T05:31:38.096Z","repository":{"id":40589218,"uuid":"82404078","full_name":"P-p-H-d/mlib","owner":"P-p-H-d","description":"Library of generic and type safe containers in pure C language (C99 or C11) for a wide collection of container (comparable to the C++ STL).","archived":false,"fork":false,"pushed_at":"2024-08-19T20:03:25.000Z","size":10154,"stargazers_count":861,"open_issues_count":3,"forks_count":77,"subscribers_count":28,"default_branch":"master","last_synced_at":"2024-08-20T23:54:07.888Z","etag":null,"topics":["algorithms","array","bitset","c","collections","data-structures","generic","hashmap","json","list","lock-free","memory-pool","priority-queue","queue","set","stack","string","tree","tuples","variant"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/P-p-H-d.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":"2017-02-18T17:35:25.000Z","updated_at":"2024-08-19T20:03:29.000Z","dependencies_parsed_at":"2023-10-28T12:23:29.480Z","dependency_job_id":"2ab4ec09-dfe2-41ae-b276-f278f1017baf","html_url":"https://github.com/P-p-H-d/mlib","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/P-p-H-d%2Fmlib","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/P-p-H-d%2Fmlib/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/P-p-H-d%2Fmlib/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/P-p-H-d%2Fmlib/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/P-p-H-d","download_url":"https://codeload.github.com/P-p-H-d/mlib/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243532517,"owners_count":20306151,"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":["algorithms","array","bitset","c","collections","data-structures","generic","hashmap","json","list","lock-free","memory-pool","priority-queue","queue","set","stack","string","tree","tuples","variant"],"created_at":"2024-07-30T19:00:49.687Z","updated_at":"2025-03-14T05:31:38.050Z","avatar_url":"https://github.com/P-p-H-d.png","language":"C","funding_links":[],"categories":["GPU computing","Data Structures","数据结构","C++"],"sub_categories":[],"readme":"M\\*LIB: Generic type-safe Container Library for C language\n==========================================================\n\n1. [Overview](#overview)\n2. [Components](#components)\n3. [Build \u0026 Installation](#build--installation)\n4. [How to use](#how-to-use)\n5. [Performance](#performance)\n6. [OPLIST](#oplist)\n7. [Memory Allocation](#memory-allocation)\n8. [Emplace construction](#Emplace-construction)\n9. [Errors \u0026 compilers](#errors--compilers)\n10. [External Reference](#external-reference)\n11. [API Documentation](#api-documentation)\n    1. [Generic methods](#generic-methods)\n    2. [List](#m-list)\n    3. [Array](#m-array)\n    4. [Deque](#m-deque)\n    5. [Dictionary](#m-dict)\n    6. [Tuple](#m-tuple)\n    7. [Variant](#m-variant)\n    8. [Red/Black Tree](#m-rbtree)\n    9. [B+ Tree](#m-bptree)\n    10. [Generic Tree](#m-tree)\n    11. [Priority queue](#m-prioqueue)\n    12. [Fixed buffer queue](#m-buffer)\n    13. [Atomic Shared Register](#m-snapshot)\n    14. [Shared pointers](#m-shared-ptr)\n    15. [Intrusive Shared Pointers](#m-i-shared)\n    16. [Intrusive list](#m-i-list)\n    17. [Concurrent adapter](#m-concurrent)\n    18. [Bitset](#m-bitset)\n    19. [String](#m-string)\n    20. [Core preprocessing](#m-core)\n    21. [Thread](#m-thread)\n    22. [Worker threads](#m-worker)\n    23. [Atomic](#m-atomic)\n    24. [Generic algorithms](#m-algo)\n    25. [Function objects](#m-funcobj)\n    26. [Exception handling](#m-try)\n    27. [Memory pool](#m-mempool)\n    28. [JSON Serialization](#m-serial-json)\n    29. [Binary Serialization](#m-serial-bin)\n    30. [Generic interface](#m-generic)\n    31. [Byte String](#m-bstring)\n12. [Global User Customization](#global-user-customization)\n13. [License](#license)\n\n## Overview\n\nM\\*LIB (M star lib) is a C library enabling to define and to use **generic and\ntype safe container** in C, aka handling generic\n[containers](https://en.wikipedia.org/wiki/Container_%28abstract_data_type%29) in pure C language.\nThe encapsulated objects can have their own constructor, destructor, operators\nor can be basic C type like the C type 'int': both are fully supported.\nThis makes it possible to construct fully\nrecursive container objects (`container-of[...]-container-of-type-T`)\nwhile keeping compile time type checking.\n\nThis is an equivalent of the [C++](https://en.wikipedia.org/wiki/C%2B%2B)\n[Standard Library](https://en.wikipedia.org/wiki/C%2B%2B_Standard_Library),\nproviding vector, deque, forward_list, set, map, multiset, multimap,\nunordered_set, unordered_map, stack, queue, shared_ptr, string, variant, option\nto standard ISO C99 / C11.\nThere is not a strict mapping as both the STL and M\\*LIB have their exclusive containers:\n\nSee [here](https://github.com/P-p-H-d/mlib/wiki/STL-to-M*LIB-mapping) for details.\nM\\*LIB provides also additional concurrent containers to design properly\nmulti-threaded programs: shared register, communication queue, ...\n\nM\\*LIB is portable to any systems that support [ISO C99](https://en.wikipedia.org/wiki/C99).\nSome optional features need at least [ISO C11](https://en.wikipedia.org/wiki/C11_(C_standard_revision)).\n\nM\\*LIB is **only** composed of a set of headers.\nThere is no C file, and as such, the installation is quite simple:\nyou just have to put the header in the search path of your compiler,\nand it will work.\nThere is no dependency (except some other headers of M\\*LIB and the LIBC).\n\nOne of M\\*LIB design key is to ensure safety. This is done by multiple means:\n\n* in debug mode, defensive programming is extensively used:\n  the contracts of the function are checked, ensuring\n  that the data are not corrupted. For example, strict\n  [Buffer overflow](https://en.wikipedia.org/wiki/Buffer_overflow) are checked in this mode\n  through [bound checking](https://en.wikipedia.org/wiki/Bounds_checking)\n  or the intrinsic properties of a Red-Black tree (for example) are verified.\n  Buffer overflow checks can still be kept in release mode if needed.\n* as few cast as possible are used within the library (casts are the evil of safety).\n  Still the library can be used with the greatest level of warnings by a C compiler without\n  any aliasing warning.\n* the genericity is not done directly by macro (which usually prevent type safety), but indirectly by making them\n  define inline functions with the proper prototypes: this enables\n  the user calls to have proper error and warning checks.\n* extensive testing: the library is tested on the main targets using Continuous Integration with a coverage of the test suite of more than 99%.\n  The test suite itself is run through the multiple sanitizers defined by GCC/CLANG (Address, undefined, leak, thread).\n  The test suite also includes a comparison of equivalent behaviors of M\\*LIB with the C++ STL using random testing or fuzzer testing.\n* static analysis: multiple static analyzer (like scan-build or GCC fanalyzer or CodeQL) are run on the generated code, and the results analyzed.\n\nOther key designs are:\n\n* do not rewrite the C library and just wrap around it (for example don't rewrite sort but stable sort),\n* do not make users pay the cost of what they don't need.\n\nDue to the unfortunate [weak](https://en.wikipedia.org/wiki/Strong_and_weak_typing#Pointers) nature of the C language for pointers,\n[type safe](https://en.wikipedia.org/wiki/Type_safety) means that at least a warning\nis generated by the compiler in case of wrong type passed as\ncontainer arguments to the functions.\n\nM\\*LIB is still quite-efficient:\nthere is no overhead in using this library rather than using\ndirect C low-level access as the compiler is able to **fully** optimize\nthe library usage\nand the library is carefully designed.\nIn [fact](https://github.com/P-p-H-d/mlib/wiki/performance), M\\*LIB\nis one of the fastest generic C/C++ library you can find.\n\nM\\*LIB uses internally the `malloc`, `realloc` and `free` functions to handle\nthe memory pool. This behavior can be overridden at different level.\nIts default policy is to abort the program if there is a memory error.\nHowever, this behavior can also be customized globally.\nM\\*LIB supports also the exception error model by providing its own implementation of the try / catch mechanism.\nThis mechanism is compatible with [RAII programming](https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization):\nwhen an exception is thrown, the destructors of the constructed objects are called (See [m-try](#m-try) for more details).\n\nM\\*LIB may use a lot of assertions in its implementation to ensure safety:\nit is highly recommended to properly define `NDEBUG` for released programs.\n\nM\\*LIB provides automatically several [serialization](https://en.wikipedia.org/wiki/Serialization) methods for each containers.\nYou can read or write your full and complex data structure into [JSON](https://en.wikipedia.org/wiki/JSON) format in a few lines.\n\nM\\*LIB is distributed under BSD-2 simplified license.\n\nIt is strongly advised not to read the source to know how to use the library\nas the code is quite complex and uses a lot of tricks\nbut rather read the examples.\n\nIn this documentation, \n* _shall_ will be used to indicate a user constraint that is\nmandatory to follow under penalty of undefined behavior.\n* _should_ will be used to indicate a recommendation to the user.\n\nAll pointers expected by the functions of the library shall expect non-null argument except if indicated.\n\n## Components\n\nThe following headers define containers that don't require the user structure to be modified:\n\n* [m-array.h](#m-array): header for creating dynamic array of generic type,\n* [m-list.h](#m-list): header for creating singly-linked list of generic type,\n* [m-deque.h](#m-deque): header for creating dynamic double-ended queue of generic type,\n* [m-dict.h](#m-dict): header for creating unordered associative array (through hashmap) or unordered set of generic type,\n* [m-rbtree.h](#m-rbtree): header for creating ordered set (through Red/Black binary sorted tree) of generic type,\n* [m-bptree.h](#m-bptree): header for creating ordered map/set/multimap/multiset (through sorted B+TREE) of generic type,\n* [m-tree.h](#m-tree): header for creating arbitrary tree of generic type,\n* [m-tuple.h](#m-tuple): header for creating arbitrary tuple of generic types,\n* [m-variant.h](#m-variant): header for creating arbitrary variant of generic type,\n* [m-prioqueue.h](#m-prioqueue): header for creating dynamic priority queue of generic type.\n\nThe available containers of M\\*LIB for thread synchronization are in the following headers:\n\n* [m-buffer.h](#m-buffer): header for creating fixed-size queue (or stack) of generic type (multiple producer / multiple consumer),\n* [m-snapshot](#m-snapshot): header for creating 'atomic buffer' (through triple buffer) for sharing synchronously big data (thread safe),\n* [m-shared-ptr.h](#m-shared-ptr): header for creating shared pointer of generic type,\n* m-c-mempool.h: WIP header for creating fast concurrent memory allocation.\n\nThe following containers are intrusive (You need to modify your structure to add fields needed by the container) and are defined in:\n\n* [m-i-list.h](#m-i-list): header for creating doubly-linked intrusive list of generic type,\n\nOther headers offering other functionality are:\n\n* [m-string.h](#m-string): header for creating dynamic string of characters (UTF-8 support),\n* [m-bstring.h](#m-bstring): header for creating dynamic string of BYTE,\n* [m-bitset.h](#m-bitset): header for creating dynamic bitset (or \"packed array of bool\"),\n* [m-algo.h](#m-algo): header for providing various generic algorithms to the previous containers,\n* [m-funcobj.h](#m-funcobj): header for creating function object (used by algorithm generation),\n* [m-try.h](#m-try): header for handling errors by throwing exceptions,\n* [m-mempool.h](#m-mempool): header for creating specialized \u0026 fast memory allocator,\n* [m-worker.h](#m-worker): header for providing an easy pool of workers on separated threads to handle work orders (used for parallel tasks),\n* [m-serial-json.h](#m-serial-json): header for importing / exporting the containers in [JSON format](https://en.wikipedia.org/wiki/JSON),\n* [m-serial-bin.h](#m-serial-bin): header for importing / exporting the containers in an adhoc fast binary format,\n* [m-generic.h](#m-generic): header for using a common interface for all registered types,\n* [m-genint.h](m-genint.h): internal header for generating unique integers in a concurrent context,\n* [m-core.h](#m-core): header for meta-programming with the C preprocessor (used by all other headers).\n\nFinally, headers for compatibility with non C11 compilers:\n\n* [m-atomic.h](#m-atomic): header for ensuring compatibility between C's `stdatomic.h` and C++'s atomic header (provide also its own implementation if nothing is available),\n* [m-thread.h](#m-thread): header for providing a very thin layer across multiple implementation of mutex/threads (C11/PTHREAD/WIN32).\n\nThe following headers are obsolete:\n* [m-shared.h](#m-shared): header for creating shared pointer of generic type,\n* [m-concurrent.h](#m-concurrent): header for transforming a container into a concurrent container (thread safe),\n* [m-i-shared.h](#m-i-shared): header for creating intrusive shared pointer of generic type (Thread Safe).\n\nEach containers define their iterators (if it is meaningful).\n\nAll containers try to expose the same common interface:\nif the method name is the same, then it does the same thing\nand is used in the same way.\nIn some rare case, the method is adapted to the container needs.\n\nEach header can be used separately from others: dependency between headers have been kept to the minimum.\n\n![Dependence between headers](https://raw.githubusercontent.com/P-p-H-d/mlib/master/doc/depend.png)\n\n## Build \u0026 Installation\n\nM\\*LIB is **only** composed of a set of headers, as such there is no build for the library.\nThe library doesn't depend on any other library than the LIBC.\n\nTo run the test suite, run:\n\n```bash\nmake check\n```\n\nYou can also override the compiler CC or its flags CFLAGS if needed:\n\n```bash\nmake check CC=\"gcc\" CFLAGS=\"-O3\"\n```\n\nTo generate the documentation, run:\n\n```bash\nmake doc\n```\n\nTo install the headers, run:\n\n```bash\nmake install PREFIX=/my/directory/where/to/install [DESTDIR=...]\n```\n\nOther targets exist. Mainly for development purpose.\n\n## How to use\n\nTo use these data structures, you first include the desired header,\ninstantiate the definition of the structure and its associated methods\nby using a macro `_DEF` for the needed container.\nThen you use the defined types and functions. Let's see a first simple example\nthat creates a list of unsigned int:\n\n```C\n#include \u003cstdio.h\u003e\n#include \"m-list.h\"\n\nLIST_DEF(list_uint, unsigned int) /* Define struct list_uint_t and its methods */\n\nint main(void) {\n   list_uint_t list ;             /* list_uint_t has been define above */\n   list_uint_init(list);          /* All type needs to be initialized */\n   list_uint_push_back(list, 42); /* Push 42 in the list */\n   list_uint_push_back(list, 17); /* Push 17 in the list */\n   list_uint_it_t it;             /* Define an iterator to scan each one */\n   for(list_uint_it(it, list)     /* Start iterator on first element */\n       ; !list_uint_end_p(it)     /* Until the end is not reached */\n       ; list_uint_next(it)) {    /* Set the iterator to the next element*/\n          printf(\"%d\\n\",          /* Get a reference to the underlying */\n            *list_uint_cref(it)); /* data and print it */\n   }\n   list_uint_clear(list);         /* Clear all the list (destroying the object list)*/\n}\n```\n\n\u003e [!NOTE] Do not forget to add `-std=c99` (or c11) to your compile command to request a C99 compatible build\n\u003e\n\nThis looks like a typical C program except the line with `LIST_DEF`\nthat doesn't have any semi-colon at the end. And in fact, except\nthis line, everything is typical C program and even macro free!\nThe only macro is in fact `LIST_DEF`: this macro expands to the\ngood type for the list of the defined type and to all the necessary\nfunctions needed to handle such type. It is heavily context dependent\nand can generate different code depending on it.\nYou can use it as many times as needed to defined as many lists as you want.\nThe first argument of the macro is the name to use, e.g. the prefix that\nis added to all generated functions and types.\nThe second argument of the macro is the type to embed within the container.\nIt can be any C type.\nThe third argument of the macro is optional and is the oplist to use.\nSee below for more information.\n\nYou could replace `LIST_DEF` by `ARRAY_DEF` to change\nthe kind of container (an array instead of a linked list)\nwithout changing the code below: the generated interface\nof a list or of an array is very similar.\nYet the performance remains the same as hand-written code\nfor both the list variant and the array variant.\n\nThis is equivalent to this C++ program using the STL:\n\n```C\n#include \u003ciostream\u003e\n#include \u003clist\u003e\n\ntypedef std::list\u003cunsigned int\u003e list_uint_t;\ntypedef std::list\u003cunsigned int\u003e::iterator list_uint_it_t;\n\nint main(void) {\n   list_uint_t list ;             /* list_uint_t has been define above */\n   list.push_back(42);            /* Push 42 in the list */\n   list.push_back(17);            /* Push 17 in the list */\n   for(list_uint_it_t it = list.begin()  /* Iterator is first element*/\n       ; it != list.end()         /* Until the end is not reached */\n       ; ++it) {                  /* Set the iterator to the next element*/\n       std::cout \u003c\u003c *it \u003c\u003c '\\n';  /* Print the underlying data */\n   }\n}\n```\n\nAs you can see, this is rather equivalent with the following remarks:\n\n* M\\*LIB requires an explicit definition of the instance of the list,\n* M\\*LIB code is more verbose in the method name,\n* M\\*LIB needs explicit construction and destruction (as plain old C requests),\n* M\\*LIB doesn't return a value to the underlying data but a pointer to this value:\n  - this was done for performance (it avoids copying all the data within the stack)\n  - and for generality reasons (some structure may not allow copying data).\n\nNote: M\\*LIB defines its own container as an array of a structure of size 1.\nThis has the following advantages:\n\n* you effectively reserve the data whenever you declare a variable,\n* you pass automatically the variable per reference for a function call,\n* you can not copy the variable by an affectation (you have to use the API instead).\n\nM\\*LIB offers also the possibility to condense further your code, so that it is more high level:\nby using the `M_EACH` \u0026 `M_LET` macros (if you are not afraid of using syntactic macros):\n\n```C\n#include \u003cstdio.h\u003e\n#include \"m-list.h\"\n\nLIST_DEF(list_uint, unsigned int)   /* Define struct list_uint_t and its methods */\n\nint main(void) {\n   M_LET(list, LIST_OPLIST(uint)) { /* Define \u0026 init list as list_uint_t */\n     list_uint_push_back(list, 42); /* Push 42 in the list */\n     list_uint_push_back(list, 17); /* Push 17 in the list */\n     for M_EACH(item, list, LIST_OPLIST(uint)) {\n       printf(\"%d\\n\", *item);       /* Print the item */\n     }\n   }                                /* Clear of list will be done now */\n}\n```\n\nHere is another example with a complete type (with proper initialization \u0026 clear function) by using the [GMP](https://gmplib.org/) library:\n\n```C\n#include \u003cstdio.h\u003e\n#include \u003cgmp.h\u003e\n#include \"m-array.h\"\nARRAY_DEF(array_mpz, mpz_t, (INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear)) )\nint main(void) {\n   array_mpz_t array ;             /* array_mpz_t has been define above */\n   array_mpz_init(array);          /* All type needs to be initialized */\n   mpz_t z;                        /* Define a mpz_t type */\n   mpz_init(z);                    /* Initialize the z variable */\n   mpz_set_ui (z, 42);\n   array_mpz_push_back(array, z);  /* Push 42 in the array */\n   mpz_set_ui (z, 17);\n   array_mpz_push_back(array, z); /* Push 17 in the array */\n   array_it_mpz_t it;              /* Define an iterator to scan each one */\n   for(array_mpz_it(it, array)     /* Start iterator on first element */\n       ; !array_mpz_end_p(it)      /* Until the end is not reached */\n       ; array_mpz_next(it)) {     /* Set the iterator to the next element*/\n          gmp_printf(\"%Zd\\n\",      /* Get a reference to the underlying */\n            *array_mpz_cref(it));  /* data and print it */\n   }\n   mpz_clear(z);                   /* Clear the z variable */\n   array_mpz_clear(array);         /* Clear all the array */\n}\n```\n\nAs the `mpz_t` type needs proper initialization, copy and destroy functions\nwe need to tell to the container how to handle such a type.\nThis is done by giving it the oplist associated to the type.\nAn oplist is an associative array where an operator is associated to its associated method.\nThis associative array only exists in the preprocessing step of the compilation,\nresulting in no runtime cost and strict aliasing check.\n\nIn the example, we tell to the container to use\nthe `mpz_init` function for the `INIT` operator of the type (aka constructor),\nthe `mpz_clear` function for the `CLEAR` operator of the type (aka destructor),\nthe `mpz_set` function for the `SET` operator of the type (aka copy),\nthe `mpz_init_set` function for the `INIT_SET` operator of the type (aka copy constructor).\nSee [OPLIST](#oplist) chapter for more detailed information.\n\nWe can also write the same example shorter:\n\n```C\n#include \u003cstdio.h\u003e\n#include \u003cgmp.h\u003e\n#include \"m-array.h\"\n\n// Register the oplist of a mpz_t.\n#define M_OPL_mpz_t() (INIT(mpz_init), INIT_SET(mpz_init_set), \\\n        SET(mpz_set), CLEAR(mpz_clear))\n// Define an instance of an array of mpz_t (both type and function)\nARRAY_DEF(array_mpz, mpz_t)\n// Register the oplist of the created instance of array of mpz_t\n#define M_OPL_array_mpz_t() ARRAY_OPLIST(array_mpz, M_OPL_mpz_t())\n\nint main(void) {\n  // Let's define `array` as an 'array_mpz_t' \u0026 initialize it.\n  M_LET(array, array_mpz_t)\n    // Let's define 'z1' and 'z2' to be 'mpz_t' \u0026 initialize it\n    M_LET (z1, z2, mpz_t) {\n     mpz_set_ui (z1, 42);\n     array_mpz_push_back(array, z1);  /* Push 42 in the array */\n     mpz_set_ui (z2, 17);\n     array_mpz_push_back(array, z2); /* Push 17 in the array */\n     // Let's iterate over all items of the container\n     for M_EACH(item, array, array_mpz_t) {\n          gmp_printf(\"%Zd\\n\", *item);\n     }\n  } // All variables are cleared with the proper method beyond this point.\n  return 0;\n}\n```\n\nOr even shorter when you're comfortable enough with the library:\n\n```C\n#include \u003cstdio.h\u003e\n#include \u003cgmp.h\u003e\n#include \"m-array.h\"\n\n// Register the oplist of a mpz_t. It is a classic oplist.\n#define M_OPL_mpz_t() M_OPEXTEND(M_CLASSIC_OPLIST(mpz),         \\\n        INIT_WITH(mpz_init_set_ui), EMPLACE_TYPE(unsigned int))\n// Define an instance of an array of mpz_t (both type and function)\nARRAY_DEF(array_mpz, mpz_t)\n// Register the oplist of the created instance of array of mpz_t\n#define M_OPL_array_mpz_t() ARRAY_OPLIST(array_mpz, M_OPL_mpz_t())\n\nint main(void) {\n    // Let's define `array` as an 'array_mpz_t' with mpz_t(17) and mpz_t(42)\n    M_LET((array,(17),(42)), array_mpz_t) {\n     // Let's iterate over all items of the container\n     for M_EACH(item, array, array_mpz_t) {\n          gmp_printf(\"%Zd\\n\", *item);\n     }\n  } // All variables are cleared with the proper method beyond this point.\n  return 0;\n}\n```\n\nThere are two ways a container can known which oplist is to be used for the type:\n\n* either the oplist is passed explicitly for each definition of container and for the `M_LET` and `M_EACH` macros,\n* or the oplist is registered globally by defining a new macro starting with the prefix `M_OPL_` and finishing with the name of type (don't forget the parenthesis and the suffix _t if needed). The macros performing the definition of container and the `M_LET` and `M_EACH` will test if such macro is defined. If it is defined, it will be used. Otherwise, default methods are used.\n\nHere we can see that we register the `mpz_t` type into the container with\nthe minimum information of its interface needed, and another one to initialize a `mpz_t` from an unsigned integer.\n\nWe can also see in this example so the container ARRAY provides also\na macro to define the oplist of the array itself. This is true for\nall containers and this enables to define proper recursive container like in this example which reads from a text file a definition of sections:\n\n```C\n#include \u003cstdio.h\u003e\n#include \"m-array.h\"\n#include \"m-tuple.h\"\n#include \"m-dict.h\"\n#include \"m-string.h\"\n\nTUPLE_DEF2(symbol, (offset, long), (value, long))\n#define M_OPL_symbol_t() TUPLE_OPLIST(symbol, M_BASIC_OPLIST, M_BASIC_OPLIST)\n\nARRAY_DEF(array_symbol, symbol_t)\n#define M_OPL_array_symbol_t() ARRAY_OPLIST(array_symbol, M_OPL_symbol_t())\n\nDICT_DEF2(sections, string_t, array_symbol_t)\n#define M_OPL_sections_t() DICT_OPLIST(sections, STRING_OPLIST, M_OPL_array_symbol_t())\n\nint main(int argc, const char *argv[])\n{\n  if (argc \u003c 2) abort();\n  FILE *f = fopen(argv[1], \"rt\");\n  if (!f) abort();\n  M_LET(sc, sections_t) {\n    sections_in_str(sc, f);\n    array_symbol_t *a = sections_get(sc, STRING_CTE(\".text\"));\n    if (a == NULL) {\n      printf(\"There is no .text section.\");\n    } else {\n      printf(\"Section .text is :\");\n      array_symbol_out_str(stdout, *a);\n      printf(\"\\n\");\n    }\n  }\n  return 0;\n}\n```\n\nThis example reads the data from a file\nand outputs the .text section if it finds it on the terminal.\n\nOther examples are available in the example folder.\n\nInternal fields of the structure are subject to change even for small revision\nof the library.\n\nThe final goal of the library is to be able to write code like this in pure C while keeping type safety and compile time name resolution:\n\n```C\nM_LET(list, list_uint_t) {\n  push(list, 42);\n  push(list, 17);\n  for each (item, list) {\n    M_PRINT(*item, \"\\n\");\n  }\n}\n```\n\nSee the [example](https://github.com/P-p-H-d/mlib/blob/master/example/ex11-generic01.c)\nand [M-GENERIC](#M-GENERIC) header for details.\n\n## Performance\n\nM\\*LIB performance is compared to the one of GNU C++ STL (v10.2) in the following graphs.\nEach graph is presented first in linear scale and then in logarithmic scale to better realize the differences.\nM\\*LIB is on par with the STL or even faster.\n\nAll used bench codes are available in this [repository](https://github.com/P-p-H-d/c-stl-comparison)\nThe results for several different libraries are also available [in a separate page](https://github.com/P-p-H-d/mlib/wiki/performance).\n\n#### Singly List\n\n![Singly List performance](https://raw.githubusercontent.com/P-p-H-d/mlib/master/doc/bench-list.png)\n![Singly List performance - Log Scale](https://raw.githubusercontent.com/P-p-H-d/mlib/master/doc/bench-list-log.png)\n\n#### Array\n\n![Array performance](https://raw.githubusercontent.com/P-p-H-d/mlib/master/doc/bench-array.png)\n![Array performance - Log Scale](https://raw.githubusercontent.com/P-p-H-d/mlib/master/doc/bench-array-log.png)\n\n#### Unordered Map\n\n![Unordered Map performance](https://raw.githubusercontent.com/P-p-H-d/mlib/master/doc/bench-umap.png)\n![Unordered Map performance - Log Scale](https://raw.githubusercontent.com/P-p-H-d/mlib/master/doc/bench-umap-log.png)\n\n#### Ordered Set\n\n![Ordered Set performance](https://raw.githubusercontent.com/P-p-H-d/mlib/master/doc/bench-oset.png)\n![Ordered Set performance - Log Scale](https://raw.githubusercontent.com/P-p-H-d/mlib/master/doc/bench-oset-log.png)\n\n## OPLIST\n\n### Definition\n\nAn `OPLIST` is a fundamental notion of M\\*LIB that hasn't be seen in any other library.\nIn order to know how to operate on a type, M\\*LIB needs additional information\nas the compiler doesn't know how to handle properly any type (contrary to C++).\nThis is done by giving an operator list (or oplist in short) to any macro that\nneeds to handle the type. As such, an oplist has only meaning within a macro.\nFundamentally, this is the exposed interface of a type:\nthat is to say the association of the operators defined by the library to the\neffective methods provided by the type, including their call interface.\nThis association is done only with the C preprocessor.\n\nTherefore, an oplist is an associative array of operators to methods\nin the following format:\n\n```C\n(OPERATOR1(method1), OPERATOR2(method2), ...)\n```\n\nIt starts with a parenthesis and ends with a parenthesis.\nEach association is separated by a comma.\nEach association is composed of a predefined operator (as defined below)\na method (in parentheses), and an optional API interface (see below).\n\nIn the given example,\nthe function `method1` is used to handle `OPERATOR1`.\nThe function `method2` is used to handle `OPERATOR2`, etc.\n\nIn case the same operator appears multiple times in the list,\nthe first apparition of the operator has priority,\nand its associated method will be used.\nThis enables overloading of operators in oplist in case you want to inherit oplists.\n\nThe associated method in the oplist is a preprocessor expression\nthat shall not contain a comma as first level.\n\nAn oplist has no real form from the C language point of view. It is just an abstraction\nthat disappears after the macro expansion step of the preprocessing.\nIf an oplist remains unprocessed after the C preprocessing, a compiler error will be generated.\n\n### Usage\n\nWhen you define an instance of a new container for a given type, you give the type `OPLIST`\nalongside the type for building the container.\nSome functions of the container may not be available in function of the provided interface of the `OPLIST`\n(for optional operators).\nOf if some mandatory operators are missing, a compiler error is generated.\n\nThe generated container will also provide its own oplist, which will depends on all\nthe oplists used to generate it. This oplist can also be used to generate new containers.\n\nYou can therefore use the oplist of the container to chain this new interface\nwith another container, creating container-of-container.\n![oplist and definition](https://raw.githubusercontent.com/P-p-H-d/mlib/master/doc/oplist.png)\n\n### Operators\n\n\u003e [!NOTE]\n\u003e An operator shall fail only on **abnormal error** and if it is marked as potentially raising asynchronous errors. In this case it shall throw exceptions only if exceptions are configured. Otherwise, the program shall be terminated.\n\u003e \n\u003e In this case, the objects remain initialized and valid but in an unspecified state.\n\u003e In case of in constructors, the object is not constructed and the destructor of the object has not to be called.\n\n\u003e [!NOTE]\n\u003e If an operator is not marked as raising asynchronous errors, it shall not fail or throw any exceptions in any cases.\n\nNot all operators are needed for an oplist to handle a container.\nIf some operator is missing, the associated default method of the operator is used if it exists.\n\nThe following classic operators are usually expected for an object:\n\n* `INIT(obj)`: initialize the object `obj` into a valid state (constructor). It may raise asynchronous error.\n* `INIT_SET(obj, org)`: initialize the object `obj` into the same state as the object `org` (copy constructor). It may raise asynchronous error.\n* `SET(obj, org)`: set the initialized object `obj` into the same state as the initialized object org (copy operator). It may raise asynchronous error.\n* `CLEAR(obj)`: destroy the initialized object `obj`, releasing any attached memory (destructor).\n\nOther documented operators are:\n\n* `NAME()` --\u003e `prefix`: Return the base name `prefix` used to construct the container.\n* `FIELD()` --\u003e `field name`: Return the name of the field used when constructing the container.\n* `TYPE()` --\u003e `type`: Return the base type associated to this oplist.\n* `SUBTYPE()` --\u003e `type`: Return the type of the element stored in the container (used to iterate over the container).\n* `GENTYPE()` --\u003e `type`: Return the type representing TYPE suitable for a _Generic statement.\n* `OPLIST()` --\u003e `oplist`: Return the oplist of the type of the elements stored in the container.\n* `KEY_TYPE()` --\u003e `key_t`: Return the key type for associative containers.\n* `VALUE_TYPE()` --\u003e `value_t`: Return the value type for associative containers.\n* `KEY_OPLIST()` --\u003e `oplist`: Return the oplist of the key type for associative containers.\n* `VALUE_OPLIST()` --\u003e `oplist`: Return the oplist of the value type for associative containers.\n* `NEW(type)` --\u003e `type pointer`: allocate a new object (with suitable alignment and size) and return a pointer to it. The returned object is **not initialized** (a constructor operator shall be called afterward). The default method is `M_MEMORY_ALLOC` (that allocates from the heap). It returns NULL in case of failure.\n* `DEL(\u0026obj)`: free the allocated uninitialized object `obj`. The destructor of the pointed object shall be called before freeing the memory by calling this method. The object shall have been allocated by the associated NEW method. The default method is `M_MEMORY_DEL` (that frees to the heap). `obj` shall not be NULL and shall be of the proper type.\n* `REALLOC(type, type pointer, number)` --\u003e `type pointer`: reallocate the given array referenced by type pointer (either a NULL pointer or a pointer returned by the associated `REALLOC` method itself) to an array of the number of objects of this type and return a pointer to this new array. Previously objects pointed by the pointer are kept up to the minimum of the new size and old one but may have moved from their original positions (if the array is reallocated otherwhere). New objects are not initialized (a constructor operator shall be called afterward). Freed objects are not cleared (A destructor operator shall be called before). The default is `M_MEMORY_REALLOC` (that allocates from the heap). It returns NULL in case of failure in which case the original array is not modified.\n* `FREE(\u0026obj)`: free the allocated uninitialized array object `obj`. The destructor of the pointed objects shall be called before freeing the memory by calling this method.  The objects shall have been allocated by the associated REALLOC method. The default is `M_MEMORY_FREE` (that frees to the heap).\n* `INC_ALLOC(size_t s)` --\u003e `size_t`: Define the growing policy of an array (or equivalent structure). It returns a new allocation size based on the old allocation size (`s`). Default policy is to get the maximum between `2*s` and 16. \n\n\u003e [!NOTE]\n\u003e It doesn't check for overflow: if the returned value is lower \n\u003e than the old one, the user shall raise an overflow error (memory error).\n\n* `INIT_MOVE(objd, objc)`: Initialize `objd` to the same state than `objc` by stealing as many resources as possible from `objc`, and then clear `objc` (constructor of `objd` + destructor of `objc`). It is semantically equivalent to calling `INIT_SET(objd,objc)` then `CLEAR(objc)` but is usually way faster.  Contrary to the C++ choice of using \"conservative move\" semantic (you still need to call the destructor of a moved object in C++) M\\*LIB implements a \"destructive move\" semantic (this enables better optimization). By default, all objects are assumed to be **trivially movable** (i.e. using memcpy to move an object is safe). Most C objects (even complex structure) are trivially movable and it is a very nice property to have (enabling better optimization). A notable exception are intrusive objects. If an object is not trivially movable, it shall provide an `INIT_MOVE` method or disable the `INIT_MOVE` method entirely \n\n\u003e [!NOTE]\n\u003e Some containers may assume that the objects are always trivially movable (like array).\n\u003e Moved objects shall use the same memory allocator.\n\n* `MOVE(objd, objc)`: Set `objd` to the same state than `objc` by stealing as resources as possible from `objc` and then clear `objc` (destructor of `objc`). It is equivalent to calling `SET(objd,objc)` then `CLEAR(objc)` or `CLEAR(objd)` and then `INIT_MOVE(objd, objc)`. See `INIT_MOVE` for details and constraints. TBC if this operator is really needed as calling `CLEAR` then `INIT_MOVE` is what do all known implementation, and is efficient.\n* `INIT_WITH(obj, ...)`: Initialize the object `obj` with the given variable set of arguments (constructor). The arguments are variable and can be of different types. It is up to the method of the object to decide how to initialize the object based on this initialization array. This operator is used by the `M_LET` macro to initialize objects with their given values and this operator defines what the `M_LET` macro supports. It may raise asynchronous error.\n\n\u003e [!NOTE]\n\u003eIn C11, you can use `API_1(M_INIT_WITH_THROUGH_EMPLACE_TYPE)` as method to automatically use the different emplace functions defined in `EMPLACE_TYPE` through a _Generic switch case. The `EMPLACE_TYPE` shall use the LIST format. See [emplace chapter](#Emplace-construction).\n\u003e\n* `SWAP(objd, objc)`: Swap the states of the object `objc` and the object `objd`.\n\n\u003e [!NOTE]\n\u003e  The swapped objects shall use the same allocator.\n\n* `RESET(obj)`: Reset the object to its initialized state (Emptying the object if it is a container object).\n* `EMPTY_P(obj)` --\u003e `bool`: Test if the container object is empty (true) or not.\n* `FULL_P(obj)` --\u003e `bool`: Test if the container object is full (true) or not. Default if not defined is to be not full.\n* `GET_SIZE (container)` --\u003e `size_t`: Return the number of elements in the container object.\n* `HASH (obj)` --\u003e `size_t`: return a hash of the object (not a secure hash but one that is usable for a hash table). Default is performing a hash of the memory representation of the object. This default implementation is invalid if the object holds pointer to other objects or has spare fields.\n* `EQUAL(obj1, obj2)` --\u003e `bool`: Compare the two objects for equality. Return true if both objects are equal, false otherwise. Default is using the C comparison operator. 'obj1' may be an OOR object (Out of Representation) for the Open Addressing dictionary (see `OOR_*` operators): in such cases, it shall return false.\n* `CMP(obj1, obj2)` --\u003e `int`: Provide a complete order the objects. return a negative integer if `obj1 \u003c obj2`, 0 if `obj1 = obj2`, a positive integer otherwise. Default is C comparison operator.\n\n\u003e [!NOTE]\n\u003e The equivalence between `EQUAL(a, b)` and `CMP(a, b) == 0` is not required, but is usually welcome.\n\n* `ADD(obj1, obj2, obj3)`: Set obj1 to the sum of obj2 and obj3. Default is `+` C operator. It may raise asynchronous error.\n* `SUB(obj1, obj2, obj3)`: Set obj1 to the difference of obj2 and obj3. Default is `-` C operator. It may raise asynchronous error.\n* `MUL(obj1, obj2, obj3)`: Set obj1 to the product of obj2 and obj3. Default is `*` C operator. It may raise asynchronous error.\n* `DIV(obj1, obj2, obj3)`: Set obj1 to the division of obj2 and obj3. Default is `/` C operator. It may raise asynchronous error.\n* `GET_KEY (container, key)` --\u003e `\u0026value`: Return a pointer to the value object within the container associated to the key `key` if an object is associated to this key. Otherwise it may return NULL or terminate the program with a logic error (depending on the container). The pointer to the value object remains valid until any modification of the container.\n* `SET_KEY (container, key, value)`: Associate the key object `key` to the value object `value` in the given container.  It may raise asynchronous error.\n* `SAFE_GET_KEY (container, key)` --\u003e `\u0026value`: return a pointer to the value object within the container associated to the key `key` if it exists, or create a new entry in the container and associate it to the key `key` with the default initialization before returning its pointer. The pointer to the object remains valid until any modification of the container. The returned pointer is therefore never NULL. It may raise asynchronous error.\n* `ERASE_KEY (container, key)` --\u003e `bool`: Erase the object associated to the key `key` within the container. Return true if successful, false if the key is not found (nothing is done).\n* `PUSH(container, obj)`: Push `obj` (of type `SUBTYPE()`) into the container `container`. How and where it is pushed is container dependent. It may raise asynchronous error.\n* `POP(\u0026obj, container)`: Pop an object from the container `container` and set it in the initialized object `*obj` (of type `SUBTYPE()`) if the pointer `obj` is not NULL. Which object is popped is container dependent. It may raise asynchronous error.\n* `PUSH_MOVE(container, \u0026obj)`: Push and move the object `*obj` (of type `SUBTYPE()`) into the container `container` (`*obj` destructor). How it is pushed is container dependent. `*obj` is cleared afterward and shall not be used anymore. See `INIT_MOVE` for more details and constraints. It may raise asynchronous error.\n* `POP_MOVE(\u0026obj, container)`: Pop an object from the container `container` and **init \u0026 move** it in the uninitialized object `*obj` (aka constructor). Which object is popped is container dependent. `*obj` shall be uninitialized. See `INIT_MOVE` for more details and constraints.\n\n\u003e [!NOTE]\n\u003e When using a `POP` operator (or any derived operator) on a container, this container shall have at least one object.\n\nThe iterator operators are:\n\n* `IT_TYPE()` --\u003e `type`: Return the type of the iterator object of this container.\n* `IT_FIRST(it_obj, obj)`: Set the iterator it_obj to the first sub-element of the container `obj`. What is the first element is container dependent (it may be front or back, or something else). However, iterating from FIRST to LAST (included) or END (excluded) through `IT_NEXT` ensures going through all elements of the container. If there is no sub-element in the container, it references an end of the container.\n* `IT_LAST(it_obj, obj)`: Set the iterator it_obj to the last sub-element of the container `obj`.  What is the last element is container dependent (it may be front or back, or something else). However, iterating from LAST to FIRST (included) or END (excluded) through `IT_PREVIOUS` ensures going through all elements of the container. If there is no sub-element in the container, it references an end of the container.\n* `IT_END(it_obj, obj)`: Set the iterator it_obj to an end of the container `obj`. Once an iterator has reached an end, it can't use PREVIOUS or NEXT operators. If an iterator has reached an END, it means that there is no object referenced by the iterator (kind of NULL pointer). There can be multiple representation of the end of a container, but all of then share the same properties.\n* `IT_SET(it_obj, it_obj2)`: Set the iterator it_obj to reference the same sub-element as it_obj2.\n* `IT_END_P(it_obj)` --\u003e `bool`: Return true if the iterator it_obj references an end of the container, false otherwise.\n* `IT_LAST_P(it_obj)` --\u003e `bool`: Return true if the iterator it_obj references the last element of the container (just before reaching an end) or has reached an end of the container, false otherwise.\n* `IT_EQUAL_P(it_obj, it_obj2)` --\u003e `bool`: Return true if both iterators reference the same element, false otherwise.\n* `IT_NEXT(it_obj)`: Move the iterator to the next sub-element or an end of the container if there is no more sub-element. The direction of `IT_NEXT` is container dependent. it_obj shall not be an end of the container.\n* `IT_PREVIOUS(it_obj)`: Move the iterator to the previous sub-element or an end of the container if there is no more sub-element. The direction of PREVIOUS is container dependent, but it is the reverse of the `IT_NEXT` operator. it_obj shall not be an end of the container.\n* `IT_CREF(it_obj)` --\u003e `\u0026subobj`: Return a constant pointer to the object referenced by the iterator (of type `const SUBTYPE()`). This pointer remains valid until any modifying operation on the container, or until another reference is taken from this container through an iterator (some containers may reduce theses constraints, for example a list). The iterator shall not be an end of the container.\n* `IT_REF(it_obj)` --\u003e `\u0026subobj`: Same as `IT_CREF`, but return a modifiable pointer to the object referenced by the iterator.\n* `IT_INSERT(obj, it_obj, subobj)`: Insert `subobj` after 'it_obj' in the container `obj` and update it_obj to point to the inserted object (as per `IT_NEXT` semantics). All other iterators of the same container become invalidated. If 'it_obj' is an end of the container, it inserts the object as the first one.\n* `IT_REMOVE(obj, it_obj)`: Remove it_obj from the container `obj` (clearing the associated object) and update it_obj to point to the next object (as per `IT_NEXT` semantics). As it modifies the container, all other iterators of the same container become invalidated. it_obj shall not be an end of the container.\n* `SPLICE_BACK(objd, objs, it_obj)`: Move the object of the container `objs` referenced by the iterator 'it_obj' to the container `objd`. Where it is moved is container dependent (it is recommended however to be like the `PUSH` method). Afterward 'it_obj' references the next item in 'containerSrc' (as per `IT_NEXT` semantics). 'it_obj' shall not be an end of the container. Both objects shall use the same allocator. It may raise asynchronous error.\n* `SPLICE_AT(objd, id_objd, objs, it_objs)`: Move the object referenced by the iterator `it_objs` from the container `objs` just after the object referenced by the iterator `it_objd` in the container `objd`. If `it_objd` references an end of the container, it is inserted as the first item of the container (See operator `IT_INSERT`). Afterward `it_objs` references the next item in the container `objs`, and `it_objd` references the moved item in the container `objd`. `it_objs` shall not be an end of the container. Both objects shall use the same allocator. It may raise asynchronous error.\n\n\u003e [!NOTE]\n\u003e An iterator doesn't have a constructor nor destructor methods.\n\u003e Therefore, it cannot not allocate any memory.\n\n\u003e [!NOTE]\n\u003e A reference to an object through the pointer get from the iterator\n\u003e is only valid until another reference is taken from the same\n\u003e container (potentially through another iterator),\n\u003e or the iterator is modified\n\u003e or the container itself is modified.\n\u003e This reference is therefore extremely local and should not be stored anywhere else.\n\u003e Some containers may lessen this constraint (for example list or RB-Tree).\n\n\u003e [!NOTE]\n\u003e If the container is *modified*, all iterators\n\u003e of this container become invalid and shall not be used anymore\n\u003e except if the modifying operator provided itself an updated iterator.\n\u003e Some containers may lessen this constraint.\n\nThe I/O operators are:\n\n* `OUT_STR(FILE* f, obj)`: Output `obj` as a custom formatted string into the `FILE*` stream `f`. Format is container dependent, but is human readable.\n* `IN_STR(obj, FILE* f)` --\u003e `bool`: Set `obj` to the value associated to the formatted string representation of the object in the `FILE*` stream `f`. Return true in case of success (in that case the stream `f` has been advanced to the end of the parsing of the object), false otherwise (in that case, the stream `f` is in an undetermined position but is likely where the parsing fails). It ensures that an object which is output in a FILE through `OUT_STR`, and an object which is read from this FILE through `IN_STR` are considered as equal. It may raise asynchronous error.\n* `GET_STR(string_t str, obj, bool append)`: Set `str` to a formatted string representation of the object `obj`. Append to the string if `append` is true, set it otherwise. This operator requires the module [m-string](#m-string). It may raise asynchronous error.\n* `PARSE_STR(obj, const char *str, const char **endp)` --\u003e `bool`: Set `obj` to the value associated to the formatted string representation of the object in the char stream `str`. Return true in case of success (in that case if endp is not NULL, it points to the end of the parsing of the object), false otherwise (in that case, if endp is not NULL, it points to an undetermined position but likely to be where the parsing fails). It ensures that an object which is written in a string through GET_STR, and an object which is read from this string through `PARSE_STR` are considered as equal. It may raise asynchronous error.\n* `OUT_SERIAL(m_serial_write_t *serial, obj)` --\u003e `m_serial_return_code_t`: Output `obj` into the configurable serialization stream `serial` (See [m-serial-json.h](#m-serial-json) for details and example) as per the serial object semantics. Return `M_SERIAL_OK_DONE` in case of success, or `M_SERIAL_FAIL` otherwise. It may raise asynchronous error.\n* `IN_SERIAL(obj, m_serial_read_t *serial)` --\u003e `m_serial_return_code_t`: Set `obj` to its representation from the configurable serialization stream `serial` (See [m-serial-json.h](#m-serial-json) for details and example) as per the serial object semantics. `M_SERIAL_OK_DONE` in case of success (in that case the stream `serial` has been advanced up to the complete parsing of the object), or `M_SERIAL_FAIL` otherwise (in that case, the stream `serial` is in an undetermined position but usually around the next characters after the first failure). It may raise asynchronous error.\n\nThe final operators are:\n\n* `OOR_SET(obj, int_value)`: Some containers want to store some information within the uninitialized objects (for example Open Addressing Hash Table). This method stores the integer value 'int_value' into an uninitialized object `obj`. It shall be able to differentiate between uninitialized object and initialized object (How is type dependent). The way to store this information is fully object dependent. In general, you use out-of-range value for detecting such values. The object remains uninitialized but sets to of out-of-range value (OOR). int_value can be 0 or 1.\n* `OOR_EQUAL(obj, int_value)`: This method compares the object `obj` (initialized or uninitialized) to the out-of-range value (OOR) representation associated to 'int_value' and returns true if both objects are equal, false otherwise. See `OOR_SET`.\n* `REVERSE(obj)`: Reverse the order of the items in the container `obj`. It may raise asynchronous error.\n* `SEPARATOR()` --\u003e `character`: Return the character used to separate items for I/O methods (default is ',') (for internal use only).\n* `EXT_ALGO(name, container oplist, object oplist)`: Define additional algorithms functions specialized for the containers (for internal use only).\n* `PROPERTIES()` --\u003e `( properties)`: Return internal properties of a container in a recursive oplist format. Use M_GET_PROPERTY to get the property.\n* `EMPLACE_TYPE( ... )`: Specify the types usable for \"emplacing\" the object (initializing the object in-place, constructor). See chapter [Emplace construction](#Emplace-construction). THe referenced initializing functions may raise asynchronous error.\n\n\u003e [!NOTE]\n\u003e The operator names listed above shall not be defined as macro.\n\nMore operators are expected.\n\n### Properties\n\nProperties can be stored in a sub-oplist format in the `PROPERTIES` operator.\n\nThe following properties are defined:\n\n* `LET_AS_INIT_WITH(1)` — Defined if the macro `M_LET` shall always initialize the object with `INIT_WITH` regardless of the given input. The value of the property is 1 (enabled) or 0 (disabled/default).\n* `NOCLEAR(1)` — Defined if the object `CLEAR` operator can be omitted (like for basic types or POD data). The value of the property is 1 (enabled) or 0 (disabled/default).\n\n\u003e [!NOTE]\n\u003e The properties names listed above shall not be defined as macro.\n\nMore properties are expected.\n\n### Example:\n\nLet's take the interface of the MPZ library:\n\n```C\nvoid mpz_init(mpz_t z);                    // Constructor of the object z\nvoid mpz_init_set(mpz_t z, const mpz_t s); // Copy Constructor of the object z\nvoid mpz_set(mpz_t z, const mpz_t s);      // Copy operator of the object z\nvoid mpz_clear(mpz_t z);                   // Destructor of the object z\n```\n\nA basic oplist will be:\n\n```C\n(INIT(mpz_init),SET(mpz_set),INIT_SET(mpz_init_set),CLEAR(mpz_clear),TYPE(mpz_t))\n```\n\nMuch more complete oplist can be built for this type however, enabling much more powerful generation:\nSee in the [example](https://github.com/P-p-H-d/mlib/blob/master/example/ex11-multi02.c)\n\n### Global namespace\n\nOplist can be registered globally by defining, for the type `type`, a macro named\n`M_OPL_ ## type ()` that expands to the oplist of the type.\nOnly type without any space in their name can be registered. A typedef of the type\ncan be used instead, but this typedef shall be used everywhere.\n\nExample:\n\n```C\n#define M_OPL_mpz_t() (INIT(mpz_init),SET(mpz_set),          \\\n        INIT_SET(mpz_init_set),CLEAR(mpz_clear),TYPE(mpz_t))\n```\n\nThis can simplify a lot `OPLIST` usage and it is recommended.\n\nThen each times a macro expects an oplist, you can give instead its type.\nThis make the code much easier to read and understand.\n\nThere is one exception however: the macros that are used to build oplist\n(like `ARRAY_OPLIST`) don't perform this simplification and the oplist of\nthe basic type shall be given instead\n(This is due to limitation in the C preprocessing).\n\n### API Interface Adaptation\n\nWithin an `OPLIST`, you can also specify the needed low-level transformation to perform for calling your method.\nThis is called API Interface Adaptation: it enables to transform the API requirements of the selected operator\n(which is very basic in general) to the API provided by the given method.\nAssuming that the method to call is called 'method' and the first argument of the operator is 'output',\nwhich interface is `OPERATOR(output, ...)`\nthen the following predefined adaptation are available:\n\n| API         | Method                            | Description                                                                             |\n|:------------|:----------------------------------|:----------------------------------------------------------------------------------------|\n| **API_0**   | `method(output, ...)`             | No adaptation                                                                           |\n| **API_1**   | `method(oplist, output, ...)`     | No adaptation but gives the oplist to the method                                        |\n| **API_2**   | `method(\u0026output, ...)`            | Pass by address the first argument (like with `M_IPTR`)                                 |\n| **API_3**   | `method(oplist, \u0026output, ...)`    | Pass by address the first argument (like with `M_IPTR`) and give the oplist of the type |\n| **API_4**   | `output = method(...)`            | Pass by return value the first argument                                                 |\n| **API_5**   | `output = method(oplist, ...)`    | Pass by return value the first argument and give the oplist of the type                 |\n| **API_6**   | `method(\u0026output, \u0026...)`           | Pass by address the two first arguments                                                 |\n| **API_7**   | `method(oplist, \u0026output, \u0026...)`   | Pass by address the two first argument and give the oplist of the type                  |\n\n\nThe API Adaptation to use shall be embedded in the `OPLIST` definition.\nFor example:\n\n```C\n(INIT(API_0(mpz_init)), SET(API_0(mpz_set)), INIT_SET(API_0(mpz_init_set)), CLEAR(API_0(mpz_clear)))\n```\n\nThe default adaptation is API_0 (i.e. no adaptation between operator interface and method interface).\nIf an adaptation gives an oplist to the method, the method shall be implemented as macro.\n\nLet's take the interface of a pseudo library:\n\n```C\ntypedef struct { ... } obj_t;\nobj_t *obj_init(void);                // Constructor of the object z\nobj_t *obj_init_str(const char *str); // Constructor of the object z\nobj_t *obj_clone(const obj_t *s);     // Copy Constructor of the object z\nvoid obj_clear(obj_t *z);             // Destructor of the object z\n```\n\nThe library returns a pointer to the object, so we need API_4 for these methods.\nThere is no method for the `SET` operator available. However, we can use the macro `M_SET_THROUGH_INIT_SET`\nto emulate a SET semantics by using a combination of `CLEAR` + `INIT_SET`. This enables to support\nthe type for array containers in particular. Or we can avoid this definition if we don't need it.\nA basic oplist will be:\n\n```C\n(INIT(API_4(obj_init)),SET(API_1(M_SET_THROUGH_INIT_SET)),INIT_SET(API_4(obj_clone)),CLEAR(obj_clear),TYPE(obj_t *))\n```\n\n### Generic API Interface Adaptation\n\nYou can also describe the exact transformation to perform for calling the method:\nthis is called Generic API Interface Adaptation (or GAIA).\nWith this, you can add constant values to parameter of the method,\nreorder the parameters as you wish, pass then by pointers, or even change the return value.\n\nThe API adaptation is also described in the operator mapping with the method name by using the API keyword.\nUsage in oplist:\n\n```C\n, OPERATOR( API( method, returncode, args...) ) ,\n```\n\nWithin the `API` keyword,\n\n* method is the pure method name (as like any other oplist)\n* `returncode` is the transformation to perform of the return code.\n* args are the list of the arguments of the function. It can be:\n\n`returncode` can be\n\n* `NONE` — no transformation,\n* `VOID` — cast to void,\n* `NEG` — inverse the result,\n* `EQ(val)`/`NEQ(val)`/`LT(val`)/`GT(val)`/`LE(val)`/`GE(val)` — compare the return code to the given value\n* `ARG[1-9]` — set the associated argument number of the operator to the return code\n\nAn argument can be:\n\n* a constant,\n* a variable name — probably global,\n* `ID( constant or variable)` — if the constant or variable is not a valid token,\n* `ARG[1-9]` — the associated argument number of the operator,\n* `ARGPTR[1-9]` — the pointer of the associated argument number of the operator,\n* `OPLIST` — the oplist\n\nTherefore, it supports at most 9 arguments.\n\nExample:\n\n```C\n, EQUAL( API(mpz_cmp, EQ(0), ARG1, ARG2) ) , \n```\n\nThis will transform a return value of 0 by the mpz_cmp method into a boolean for the `EQUAL` operator.\n\nAnother Example:\n\n```C\n, OUT_STR( API(mpz_out_str, VOID, ARG1, 10, ARG2) ) , \n```\n\nThis will serialize the mpz_t value in base 10 using the mpz_out_str method, and discarding the return value.\n\n### Disable an operator\n\nAn operator `OP` can be defined, omitted or disabled:\n\n* `( OP(f) )`: the function f is the method of the operator OP\n* `( OP(API_N(f)) )`: the function f is the method of the operator OP with the API transformation number N,\n* `( )`: the operator OP is omitted, and the default global operation for OP is used (if it exists).\n* `( OP(0) )`: the operator OP is disabled, and it can never be used.\n\nThis can be useful to disable an operator in an inherited oplist.\n\n### Which `OPLIST` to use?\n\nMy type is:\n\n* a C Boolean: `M_BOOL_OPLIST` (`M_BASIC_OPLIST` also works partially),\n* a C integer or a C float: `M_BASIC_OPLIST` (it can also be omitted),\n* a C enumerate: `M_ENUM_OPLIST`,\n* a pointer to something (the container do nothing on the pointed object): `M_PTR_OPLIST`,\n* a plain structure that can be init/copy/compare with memset/memcpy/memcmp: `M_POD_OPLIST`,\n* a plain structure that is passed by reference using [1] and can be init,copy,compare with `memset`, `memcpy`, `memcmp`: `M_A1_OPLIST`,\n* a type that offers `name_init`, `name_init_set`, `name_set`, `name_clear` methods: `M_CLASSIC_OPLIST`,\n* a const string (`const char *`) that is neither freed nor moved: `M_CSTR_OPLIST`,\n* a M\\*LIB string_t: `STRING_OPLIST`,\n* a M\\*LIB container: the `OPLIST` of the used container,\n* other things: you need to provide a custom `OPLIST` to your type.\n\n\u003e [!NOTE]\n\u003e The precise exported methods of the OPLIST depend on the version\n\u003e of the used C language. Typically, in C11 mode, the `M_BASIC_OPLIST`\n\u003e exports all needed methods to handle generic input/output of int/floats\n\u003e (using `_Generic` keyword) whereas it is not possible in C99 mode.\n\nThis explains why JSON import/export is only available in C11 mode\n(See below chapter).\n\nBasic usage of oplist is available in the [example](https://github.com/P-p-H-d/mlib/blob/master/example/ex-array00.c)\n\n### Oplist inheritance\n\nOplist can inherit from another one.\nThis is useful when you want to customize some specific operators while keeping other ones by default.\nFor example, internally `M_BOOL_OPLIST` inherits from `M_BASIC_OPLIST`.\n\nA typical example is if you want to provide the `OOR_SET` and `OOR_EQUAL` operators to a type\nso that it can be used in an `OA` dict.\nTo do it, you use the `M_OPEXTEND` macro. It takes as first argument the oplist you want to inherit with,\nand then you provide the additional associations between operators to methods you want to add\nor override in the inherited oplist. For example:\n\n```C\nint my_int_oor_set(char c) { return INT_MIN + c; }\nbool my_int_oor_equal(int i1, int i2) { return i1 == i2; }\n#define MY_INT_OPLIST                                              \\\n        M_OPEXTEND(M_BASIC_OPLIST, OOR_SET(API_4(my_int_oor_set)), \\\n            OOR_EQUAL(my_int_oor_equal))\n```\n\nYou can even inherit from another oplist to disable some operators in your new oplist.\nFor example:\n\n```C\n#define MY_INT_OPLIST                                              \\\n        M_OPEXTEND(M_BASIC_OPLIST, HASH(0), CMP(0), EQUAL(0))\n```\n\n`MY_INT_OPLIST` is a new oplist that handles integers but has disabled the operators `HASH`, `CMP` and `EQUAL`.\nThe main interest is to disable the generation of optional methods of a container (since they are only\nexpanded if the oplist provides some methods).\n\nUsage of inheritance and oplist is available\nin the [int example](https://github.com/P-p-H-d/mlib/blob/master/example/ex-dict05.c)\nand the [cstr example](https://github.com/P-p-H-d/mlib/blob/master/example/ex-dict06.c)\n\n### Advanced example\n\nLet's take a look at the interface of the `FILE*` interface:\n\n```C\nFILE *fopen(const char *filename, const char *mode);\nfclose(FILE *f);\n```\n\nThere is no `INIT` operator (an argument is mandatory), no `INIT_SET` operator.\nIt is only possible to open a file from a filename.\n`FILE*` contains some space, so an alias is needed.\nThere is an optional mode argument, which is a constant string, and isn't a valid preprocessing token.\nAn oplist can therefore be:\n\n```C\ntypedef FILE *m_file_t;\n#define M_OPL_m_file_t() (INIT_WITH(API(fopen, ARG1, ARG2, ID(\"wt\"))), \\\n        SET(0),INIT_SET(0),CLEAR(fclose),TYPE(m_file_t))\n```\n\nSince there is no `INIT_SET` operator available, pretty much no container can work.\nHowever, you'll be able to use a writing text `FILE*` using a `M_LET`:\n\n```C\nM_LET( (f, (\"tmp.txt\")), m_file_t) {\n  fprintf(f, \"This is a tmp file.\");\n}\n```\n\nThis is pretty useless, except if you enable exceptions...\nIn which case, this enables you to close the file even if an exception is thrown.\n\n## Memory Allocation\n\n### Customization\n\nMemory Allocation functions can be globally set by overriding the following macros before using the definition `_DEF` macros:\n\n* `M_MEMORY_ALLOC (type)` --\u003e `ptr`: return a pointer to a new object of type `type`.\n* `M_MEMORY_DEL (ptr)`: free the single object pointed by `ptr`.\n* `M_MEMORY_REALLOC (type, ptr, number)` --\u003e `ptr`: return a pointer to an array of 'number' objects of type `type`, reusing the old array pointed by `ptr`. `ptr` can be NULL, in which case the array will be created.\n* `M_MEMORY_FREE (ptr)`: free the array of objects pointed by `ptr`.\n\n`ALLOC` and `DEL` operators are supposed to allocate fixed size single element object (no array).\nThese objects are not expected to grow.\n`REALLOC` and `FREE` operators deal with allocated memory for growing objects.\nDo not mix pointers between both: a pointer allocated by `ALLOC` (resp. `REALLOC`) is supposed\nto be only freed by `DEL` (resp. `FREE`). There are separated 'free' operators to enable\nspecialization in the allocator (a good allocator can take this hint into account).\n\n`M_MEMORY_ALLOC` and `M_MEMORY_REALLOC` are supposed to return NULL in case of memory allocation failure.\nThe defaults are `malloc`, `free`, `realloc` and `free`.\n\nYou can also override the methods `NEW`, `DEL`, `REALLOC` and `DEL` in the oplist given to a container\nso that only the container will use these memory allocation functions instead of the global ones.\n\n### Out-of-memory error\n\nWhen a memory exhaustion is reached, the global macro `M_MEMORY_FULL` is called\nand the function returns immediately after.\nThe object remains in a valid (if previously valid) and unchanged state in this case.\n\nBy default, the macro prints an error message and aborts the program:\nhandling non-trivial memory errors can be hard,\ntesting them is even harder but still mandatory to avoid security holes.\nSo the default behavior is rather conservative.\n\nIt can however be overloaded to handle other policy for error handling like:\n\n* throwing an error (which is automatically done by including header [m-try](#m-try) ),\n* set a global error and handle it when the function returns [planned, not possible yet],\n* other policy.\n\nThis function takes the size in bytes of the memory that has been tried to be allocated.\n\nIf needed, this macro shall be defined ***prior*** to instantiate the structure.\n\n\u003e [!NOTE] \n\u003e A good design should handle a process entire failure (using for examples multiple\n\u003e processes for doing the job) so that even if a process stops, it should be recovered.\n\u003e See [here](http://joeduffyblog.com/2016/02/07/the-error-model/) for more\n\u003e information about why abandonment is good software practice.\n\nIn M\\*LIB, we classify the kind of errors according to this classification:\n* *logical error*: the expectations of the function are not met (null pointer passed as argument, negative argument, invalid object state, ...). In which case, the sanction is abnormal halt of the program, if it is detected, regardless of the configuration of M\\*LIB. Normally, debug build will detect such errors.\n* *abnormal error*:  errors that are unlikely to be expected during the execution of the program (like no more memory). In which case, the sanction is either abnormal halt of the program or throwing an exception.\n* *normal error*: errors that can be expected in the execution of the program (all I/O errors like file not found or invalid file format, parsing of invalid user input, no solution found, etc). In which case, the error is reported by the return code of the function or by polling for error (See `ferror`) in the data structure.\n\n\n## Emplace construction\n\nFor M\\*LIB, 'emplace' means pushing a new object in the container,\nwhile not giving it a copy of the new object, but the parameters needed\nto construct this object.\nThis is a shortcut to the pattern of creating the object with the arguments,\npushing it in the container, and deleting the created object\n(even if using `PUSH_MOVE` could simplify the design).\n\nThe containers defining an emplace like method generate the emplace functions\nbased on the provided `EMPLACE_TYPE` of the oplist. If `EMPLACE_TYPE` doesn't exist or is disabled, no emplace function is generated. Otherwise `EMPLACE_TYPE` identifies\nwhich types can be used to construct the object and which methods to use to construct then:\n\n* `EMPLACE_TYPE( typeA )`, means that the object can be constructed from `typeA` using the method of the `INIT_WITH` operator. An emplace function without suffix will be generated.\n* `EMPLACE_TYPE( (typeA, typeB, ...) )`, means that the object can be constructed from the lists of types `typeA`, `typeB`, `...` using the method of the `INIT_WITH` operator. An emplace function without suffix will be generated.\n* `EMPLACE_TYPE( LIST( (suffix, function, typeA, typeB, ...)`, (`suffix`, `function`, `typeA`, `typeB`, `...`) means that the object can be constructed from all the provided lists of types `typeA`, `typeB`, `...` using the provided method `function`. The `function` is the method to call to construct the object from the list of types. It supports API transformation if needed. As many emplace function will be generated as there are constructor function. Each generated function will be generated by suffixing it with the provided `suffix` (if suffix is empty, no suffix will be added).\n\nFor example, for an `ARRAY` definition named vec, if there is such a definition of `EMPLACE_TYPE(const char *)`, it will generate a function `vec_emplace_back(const char *)`. This function will take a `const char*` parameter, construct the object from it (for example a string_t) then push the result back on the array.\n\nAnother example, for an `ARRAY` definition named vec, if there is such a definition of `EMPLACE_TYPE( LIST( (_ui, mpz_init_set_ui, unsigned int), (_si, mpz_init_set_si, int) ) )`, it will generate two functions `vec_emplace_back_ui(unsigned int)` and `vec_emplace_back_si(int)`. These functions will take the (unsigned) int parameter, construct the object from it then push the result back on the array.\n\nIf the container is an associative array, the name will be constructed as follows:\n\n```C\nname_emplace[_key_keysuffix][_val_valsuffix]\n```\n\nwhere `keysuffix` (resp. `valsuffix`) is the emplace suffix of the key (resp. `value`) oplist.\n\nIf you take once again the example of the `FILE*`, a more complete oplist can be:\n\n```C\ntypedef FILE *m_file_t;\n#define M_OPL_m_file_t() (INIT_WITH(API_1(M_INIT_WITH_THROUGH_EMPLACE_TYPE)), \\\n        SET(0),INIT_SET(0),CLEAR(fclose),TYPE(m_file_t),                      \\\n        EMPLACE_TYPE(LIST((_str, API(fopen, ARG1, ARG2, ID(\"wb\")), char *))))\n```\n\nThe `INIT_WITH` operator will use the provided init methods in the `EMPLACE_TYPE`. \n`EMPLACE_TYPE` defines a `_str` suffix method with a GAIA for `fopen`, and accepts a `char*` as argument.\nThe GAIA specifies that the output (ARG1) is set as return value,\nARG2 is given as the first argument, and a third constant argument is used.\n\n## ERRORS \u0026 COMPILERS\n\nM\\*LIB implements internally some controls to reduce the list of errors/warnings generated by a compiler\nwhen it detects some violation in the use of oplist by use of static assertion.\nIt can also transform some type warnings into proper errors.\nIn C99 mode, it will produce illegal code with the name of the error as attribute.\nIn C11 mode, it will use static assert and produce a detailed error message.\n\nThe list of errors it can generate:\n\n* `M_LIB_NOT_AN_OPLIST`: something has been given (directly or indirectly) and it doesn't reduce as a proper oplist. You need to give an oplist for this definition.\n* `M_LIB_ERROR(ARGUMENT_OF_*_OPLIST_IS_NOT_AN_OPLIST, name, oplist)`: sub error of the previous error one, identifying the root cause. The error is in the oplist construction of the given macro. You need to give an oplist for this oplist construction.\n* `M_LIB_MISSING_METHOD`: a required operator doesn't define any method in the given oplist. You need to complete the oplist with the missing method.\n* `M_LIB_TYPE_MISMATCH`: the given oplist and the type do not match each other. You need to give the right oplist for this type.\n* `M_LIB_NOT_A_BASIC_TYPE`: The oplist `M_BASIC_OPLIST` (directly or indirectly) has been used with the given type, but the given type is not a basic C type (int/float). You need to give the right oplist for this type.\n\nYou should focus mainly on the first reported error/warning\neven if the link between what the compiler report and what the error is\nis not immediate. The error is always in one of the **oplist definition**.\n\nExamples of typical errors:\n\n* lack of inclusion of an header,\n* overriding locally operator names by macros (like `NEW`, `DEL`, `INIT`, `OPLIST`, `...`),\n* lack of `( )` or double level of `( )` around the oplist,\n* an unknown variable (example using `BASIC_OPLIST` instead of `M_BASIC_OPLIST`),\n* the name given to the oplist is not the same as the one used to define the methods,\n* use of a type instead of an oplist in the `OPLIST` definition,\n* a missing sub oplist in the `OPLIST` definition.\n\nA good way to avoid these errors is to register the oplist globally as soon\nas you define the container.\n\nIn case of difficulties, debugging can be done by generating the preprocessed file\n(by usually calling the compiler with the `-E` option instead of `-c`)\nand check what's wrong in the preprocessed file:\n\n```shell\ncc -std=c99 -E test-file.c |grep -v '^#' \u003e test-file.i\nperl -i -e 's/;/;\\n/g' test-file.i\ncc -std=c99 -c -Wall test-file.i\n```\n\nIf there is a warning reported by the compiler in the generated code,\nthen there is definitely an **error** you should fix (except if it reports\nshadowed variables), in particular cast evolving pointers.\n\nYou should also turn off the macro expansion of the errors reported by\nyour compiler. There are often completely useless and misleading:\n\n* For GCC, uses `-ftrack-macro-expansion=0`\n* For CLANG, uses `-fmacro-backtrace-limit=1`\n\nDue to the unfortunate [weak](https://en.wikipedia.org/wiki/Strong_and_weak_typing#Pointers) nature of the C language for pointers,\nyou should turn incompatible pointer type warning into an error in your compiler.\nFor GCC / CLANG, uses `-Werror=incompatible-pointer-types`\n\nFor MS Visual C++ compiler , you need the following options:\n\n```shell\n/Zc:__cplusplus /Zc:preprocessor /D__STDC_WANT_LIB_EXT1__ /EHsc\n```\n\n## External Reference\n\nMany other implementation of generic container libraries in C exist.\nFor example, a non exhaustive list is:\n\n* [BKTHOMPS/CONTAINERS](https://github.com/bkthomps/Containers)\n* [BSD tree.h](http://fxr.watson.org/fxr/source/sys/tree.h)\n* [CC](https://github.com/JacksonAllan/CC)\n* [CDSA](https://github.com/MichaelJWelsh/cdsa)\n* [CELLO](http://libcello.org/)\n* [C-Macro-Collections](https://github.com/LeoVen/C-Macro-Collections)\n* [COLLECTIONS-C](https://github.com/srdja/Collections-C)\n* [CONCURRENCY KIT](https://github.com/concurrencykit/ck)\n* CTL [by glouw](https://github.com/glouw/ctl) or [by rurban](https://github.com/rurban/ctl)\n* [GDB internal library](https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=blob;f=gdb/common/vec.h;h=41e41b5b22c9f5ec14711aac35ce4ae6bceab1e7;hb=HEAD)\n* [GLIB](https://wiki.gnome.org/Projects/GLib)\n* [KLIB](https://github.com/attractivechaos/klib)\n* [LIBCHASTE](https://github.com/mgrosvenor/libchaste)\n* [LIBCOLLECTION](https://bitbucket.org/manvscode/libcollections)\n* [LIBDICT](https://github.com/fmela/libdict)\n* [LIBDYNAMIC](https://github.com/fredrikwidlund/libdynamic)\n* [LIBLFDS](https://www.liblfds.org/)\n* [LIBSRT:  Safe Real-Time library for the C programming language](https://github.com/faragon/libsrt)\n* [NEDTRIES](https://github.com/ned14/nedtries)\n* [POTTERY](https://github.com/ludocode/pottery)\n* [QLIBC](http://wolkykim.github.io/qlibc/)\n* [SC](https://github.com/tezc/sc)\n* [SGLIB](http://sglib.sourceforge.net/)\n* [Smart pointer for GNUC](https://github.com/Snaipe/libcsptr)\n* [STB stretchy_buffer](https://github.com/nothings/stb)\n* [STC - Smart Template Container for C](https://github.com/tylov/STC)\n* [TommyDS](https://github.com/amadvance/tommyds)\n* [UTHASH](http://troydhanson.github.io/uthash/index.html)\n\nEach can be classified into one of the following concept:\n\n* Each object is handled through a pointer to void (with potential registered callbacks to handle the contained objects for the specialized methods). From a user point of view, this makes the code harder to use (as you don't have any help from the compiler) and type unsafe with a lot of cast (so no formal proof of the code is possible). This also generally generate slower code (even if using link time optimization, this penalty can be reduced). Properly used, it can yet be the most space efficient for the code, but can consume a lot more for the data due to the obligation of using pointers. This is however the easiest to design \u0026 code.\n* Macros are used to access structures in a generic way (using known fields of a structure — typically size, number, etc.). From a user point of view, this can create subtitle bug in the use of the library (as everything is done through macro expansion in the user defined code) or hard to understand warnings. This can generates fully efficient code. From a library developer point of view, this can be quite limiting in what you can offer.\n* Macros detect the type of the argument passed as parameter using _Generics, and calls the associated methods of the switch. The difficulty is how to add pure user types in this generic switch.\n* A known structure is put in an intrusive way in the type of all the objects you wan to handle. From a user point of view, he needs to modify its structure and has to perform all the allocation \u0026 deallocation code itself (which is good or bad depending on the context). This can generate efficient code (both in speed and size). From a library developer point of view, this is easy to design \u0026 code. You need internally a cast to go from a pointer to the known structure to the pointed object (a reverse of offsetof) that is generally type unsafe (except if mixed with the macro generating concept). This is quite limitation in what you can do: you can't move your objects so any container that has to move some objects is out-of-question (which means that you cannot use the most efficient container).\n* Header files are included multiple times with different contexts (some different values given to defined macros) in order to generate different code for each type. From a user point of view, this creates a new step before using the container: an instantiating stage that has to be done once per type and per compilation unit (The user is responsible to create only one instance of the container, which can be troublesome if the library doesn't handle proper prefix for its naming convention). The debug of the library is generally easy and can generate fully specialized \u0026 efficient code. Incorrectly used, this can generate a lot of code bloat. Properly used, this can even create smaller code than the void pointer variant. The interface used to configure the library can be quite tiresome in case of a lot of specialized methods to configure: it doesn't enable to chain the configuration from a container to another one easily. It also cannot have heavy customization of the code.\n* Macros are used to generate context-dependent C code enabling to generate code for different type. This is pretty much like the headers solution but with added flexibility. From a user point of view, this creates a new step before using the container: an instantiating stage that has to be done once per type and per compilation unit (The user is responsible to create only one instance of the container, which can be troublesome if the library doesn't handle proper prefix for its naming convention). This can generate fully specialized \u0026 efficient code. Incorrectly used, this can generate a lot of code bloat. Properly used, this can even create smaller code than the void pointer variant. From a library developer point of view, the library is harder to design and to debug: everything being expanded in one line, you can't step in the library (there is however a solution to overcome this limitation by adding another stage to the compilation process). You can however see the generated code by looking at the preprocessed file. You can perform heavy context-dependent customization of the code (transforming the macro preprocessing step into its own language). Properly done, you can also chain the methods from a container to another one easily, enabling expansion of the library. Errors within the macro expansion are generally hard to decipher, but errors in code using containers are easy to read and natural.\n\nM\\*LIB category is mainly the last one.\nSome macros are also defined to access structure in a generic way, but they are optional.\nThere are also intrusive containers.\n\nM\\*LIB main added value compared to other libraries is its oplist feature\nenabling it to chain the containers and/or use complex types in containers:\nlist of array of dictionary of C++ objects are perfectly supported by M\\*LIB.\n\nFor the macro-preprocessing part, other libraries and reference also exist. For example:\n\n* [Boost preprocessor](http://www.boost.org/doc/libs/1_63_0/libs/preprocessor/doc/index.html)\n* [C99 Lambda](https://github.com/Leushenko/C99-Lambda)\n* [C Preprocessor Tricks, Tips and Idioms](https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms)\n* [CPP MAGIC](http://jhnet.co.uk/articles/cpp_magic)\n* [MAP MACRO](https://github.com/swansontec/map-macro)\n* [metalang99](https://github.com/Hirrolot/metalang99)\n* [OrderPP](https://github.com/rofl0r/order-pp)\n* [P99](http://p99.gforge.inria.fr/p99-html/)\n* [Zlang](https://github.com/pfultz2/ZLang)\n\nYou can also consult [awesome-c-preprocessor](https://github.com/Hirrolot/awesome-c-preprocessor) for a more comprehensive list of libraries.\n\nFor the string part, there is the following libraries for example:\n\n* [POTTERY STRING](https://github.com/ludocode/pottery/tree/develop/util/pottery/string)\n* [SDS](https://github.com/antirez/sds)\n* [STC - C99 Standard Container library](https://github.com/tylov/C99Containers)\n* [STR -yet another string library for C language](https://github.com/maxim2266/str)\n* [The Better String Library](http://bstring.sourceforge.net/) with a page that lists a lot of other string libraries.\n* [VSTR](http://www.and.org/vstr/) with a [page](http://www.and.org/vstr/comparison) that lists a lot of other string libraries.\n\n_________________\n\n## API Documentation\n\nThe M\\*LIB reference card is available [here](http://htmlpreview.github.io/?https://github.com/P-p-H-d/mlib/blob/master/doc/Container.html).\n\n### Generic methods\n\nThe generated containers tries to generate and provide a consistent interface:\ntheir methods would behave the same for all generated containers.\nThis chapter will explain the generic interface.\nIn case of difference, it will be explained in the specific container.\n\nIn the following description:\n\n* `name` is the prefix used for the container generation,\n* `name_t` refers to the type of the container,\n* `name_it_t` refers to the iterator type of the container,\n* `type_t` refers to the type of the object stored in the container,\n* `key_type_t` refers to the type of the key object used to associate an element to,\n* `value_type_t` refers to the type of the value object used to associate an element to.\n* `name_itref_t` refers to a pair of key and value for associative arrays.\n\nAn object shall be initialized (aka constructor) before being used by other methods.\nIt shall be cleared (aka destructor) after being used and before program termination.\nAn iterator has not destructor but shall be set before being used.\n\nA container takes as input the\n\n* `name` — it is a mandatory argument that is the prefix used to generate all functions and types,\n* `type` — it is a mandatory argument that the basic element of the container,\n* `oplist` — it is an optional argument that defines the methods associated to the type. The provided oplist (if provided) shall be the one that is associated to the type, otherwise it won't generate compilable code. If there is no oplist parameter provided, a globally registered oplist associated to the type is used if possible, or the basic oplist for basic C types is used. This oplist will be used to handle internally the objects of the container.\n\nThe `type` given to any templating macro can be either\nan integer, a float, a boolean, an enum, a named structure, a named union, a pointer to such types,\nor a typedef alias of any C type:\nin fact, the only constraint is that the preprocessing concatenation between `type` and `variable` into\n'type variable' shall be a valid C expression.\nTherefore the `type` cannot be a C array or a function pointer\nand you shall use a typedef as an intermediary named type for such types.\n\nThe output parameters are listed fist, then the input/output parameters and finally the input parameters.\n\nThis generic interface is specified as follow:\n\n##### `void name_init(name_t container)`\n\nInitialize the container `container` (aka constructor) to an empty container.\nAlso called the default constructor of the container.\n\n##### `void name_init_set(name_t container, const name_t ref)`\n\nInitialize the container `container` (aka constructor) and set it to a copy of `ref`.\nThis method is only created if the `INIT_SET` \u0026 `SET` methods are provided.\nAlso called the copy constructor of the container.\n\n##### `void name_set(name_t container, const name_t ref)`\n\nSet the container `container` to the copy of `ref`.\nThis method is only created if the `INIT_SET` and `SET` methods are provided.\n\n##### `void name_init_move(name_t container, name_t ref)`\n\nInitialize the container `container` (aka constructor)\nby stealing as many resources from `ref` as possible.\nAfter-wise `ref` is cleared and can no longer be used (aka destructor).\n\n##### `void name_move(name_t container, name_t ref)`\n\nSet the container `container` (aka constructor)\nby stealing as many resources from `ref` as possible.\nAfter-wise `ref` is cleared and can no longer be used (aka destructor).\n\n##### `void name_clear(name_t container)`\n\nClear the container `container` (aka destructor),\ncalling the `CLEAR` method of all the objects of the container and freeing memory.\nThe object can't be used anymore, except to be reinitialized with a constructor.\n\n##### `void name_reset(name_t container)`\n\nReset the container clearing and freeing all objects stored in it.\nThe container becomes empty but remains initialized.\n\n##### `type_t *name_back(const name_t container)`\n\nReturn a pointer to the data stored in the back of the container.\nThis pointer should not be stored in a global variable.\n\n##### `type_t *name_front(const name_t container)`\n\nReturn a pointer to the data stored in the front of the container.\nThis pointer should not be stored in a global variable.\n\n##### `void name_push(name_t container, const type_t value)`\n##### `void name_push_back(name_t container, const type_t value)`\n##### `void name_push_front(name_t container, const type_t value)`\n\nPush a new element in the container `container` as a copy of the object `value`.\nThis method is created only if the `INIT_SET` operator is provided.\n\nThe `_back` suffixed method will push it in the back of the container.\nThe `_front` suffixed method will push it in the front of the container.\n\n##### `type_t *name_push_raw(name_t container)`\n##### `type_t *name_push_back_raw(name_t container)`\n##### `type_t *name_push_front_raw(name_t container)`\n\nPush a new element in the container `container`\nwithout initializing it and returns a pointer to the **non-initialized** data.\nThe first thing to do after calling this function shall be to initialize the data\nusing the proper constructor of the object of type `type_t`.\nThis enables using more specialized constructor than the generic copy one.\nThe user should use other `_push` function if possible rather than this one\nas it is low level and error prone.\nThis pointer should not be stored in a global variable.\n\nThe `_back` suffixed method will push it in the back of the container.\nThe `_front` suffixed method will push it in the front of the container.\n\n##### `type_t *name_push_new(name_t container)`\n##### `type_t *name_push_back_new(name_t container)`\n##### `type_t *name_push_front_new(name_t container)`\n\nPush a new element in the container `container`\nand initialize it with the default constructor associated to the type `type_t`.\nReturn a pointer to the initialized object.\nThis pointer should not be stored in a global variable.\nThis method is only created if the `INIT` method is provided.\n\nThe `_back` suffixed method will push it in the back of the container.\nThe `_front` suffixed method will push it in the front of the container.\n\n##### `void name_push_move(name_t container, type_t *value)`\n##### `void name_push_back_move(name_t container, type_t *value)`\n##### `void name_push_front_move(name_t container, type_t *value)`\n\nPush a new element in the container `container`\nas a move from the object `*value`:\nit will therefore steal as much resources from `*value` as possible.\nAfterward `*value` is cleared and cannot longer be used (aka. destructor).\n\nThe `_back` suffixed method will push it in the back of the container.\nThe `_front` suffixed method will push it in the front of the container.\n\n##### `void name_emplace[suffix](name_t container, args...)`\n##### `void name_emplace_back[suffix](name_t container, args...)`\n##### `void name_emplace_front[suffix](name_t container, args...)`\n\nPush a new element in the container `container`\nby initializing it with the provided arguments.\nThe provided arguments shall therefore match one of the constructor provided\nby the `EMPLACE_TYPE` operator.\nThere is one generated method per suffix defined in the `EMPLACE_TYPE` operator,\nand the `suffix` in the generated method name corresponds to the suffix defined \nin the `EMPLACE_TYPE` operator (it can be empty).\nThis method is created only if the `EMPLACE_TYPE` operator is provided.\nSee [emplace](#Emplace-construction) chapter for more details.\n\nThe `_back` suffixed method will push it in the back of the container.\nThe `_front` suffixed method will push it in the front of the container.\n\n##### `void name_pop(type_t *data, name_t container)`\n##### `void name_pop_back(type_t *data, name_t container)`\n##### `void name_pop_front(type_t *data, name_t container)`\n\nPop a element from the container `container`;\nand set `*data` to this value if data is not the NULL pointer,\notherwise it only pops the data.\nThis method is created if the `SET` or `INIT_MOVE` operator is provided.\n\nThe `_back` suffixed method will pop it from the back of the container.\nThe `_front` suffixed method will pop it from the front of the container.\n\n##### `void name_pop_move(type_t *data, name_t container)`\n##### `void name_pop_move_back(type_t *data, name_t container)`\n##### `void name_pop_move_front(type_t *data, name_t container)`\n\nPop a element from the container `container`\nand initialize and set `*data` to this value (aka. constructor)\nby stealing as much resources from the container as possible.\ndata shall not be a NULL pointer.\n\nThe `_back` suffixed method will pop it from the back of the container.\nThe `_front` suffixed method will pop it from the front of the container.\n\n##### `bool name_empty_p(const name_t container)`\n\nReturn true if the container is empty, false otherwise.\n\n##### `void name_swap(name_t container1, name_t container2)`\n\nSwap the container `container1` and `container2`.\n\n##### `void name_set_at(name_t container, size_t key, type_t value)`\n##### `void name_set_at(name_t container, key_type_t key, value_type_t value)` [for associative array]\n\nSet the element associated to `key` of the container `container` to `value`.\n\nIf the container is sequence-like (like array), the key is an integer.\nThe selected element is the `key`-th element of the container,\nThe index `key` shall be within the size of the container.\nThis method is created if the `INIT_SET` operator is provided.\n\nIf the container is associative-array like,\nthe selected element is the `value` object associated to the `key` object in the container.\nIt is created if it doesn't exist, overwritten otherwise.\n\n##### `void name_emplace_key[keysuffix](name_t container, keyargs..., value_type_t value)` [for associative array]\n##### `void name_emplace_val[valsuffix](name_t container, key_type_t key, valargs...)` [for associative array]\n##### `void name_emplace_key[keysuffix]_val[valsuffix](name_t container, keyargs..., valargs...)` [for associative array]\n\nSet the element associated to `key` of the container `container` to `value`.\n`key` (resp. value) is constructed from the provided args `keyargs` (resp. `valargs`) if not provided.\n\n`keyargs` (resp. `valargs`) shall therefore match one of the constructor provided\nby the `EMPLACE_TYPE` operator of the key (resp. the value).\n\nThere is:\n\n* one generated method per suffix defined in the `EMPLACE_TYPE` operator of the key,\n* one generated method per suffix defined in the `EMPLACE_TYPE` operator of the value,\n* one generated method per pair of suffix defined in the `EMPLACE_TYPE` operators of the key and value,\n\nThe `suffix` in the generated method name corresponds to the suffix defined in\nin the `EMPLACE_TYPE` operator (it can be empty).\nThis method is created only if one `EMPLACE_TYPE` operator is provided.\nSee [emplace](#Emplace-construction) chapter for more details.\n\n##### `type_t *name_get(const name_t container, size_t key)` [for sequence-like]\n##### `const type_t *name_cget(const name_t container, size_t key)` [for sequence-like]\n##### `type_t *name_get(const name_t container, const type_t key)` [for set-like]\n##### `const type_t *name_cget(const name_t container, const type_t key)` [for set-like]\n##### `value_type_t *name_get(const name_t container, const key_type_t key)` [for associative array]\n##### `const value_type_t *name_cget(const name_t container, const key_type_t key)` [for associative array]\n\nReturn a modifiable (resp. constant) pointer to\nthe element associated to `key` in the container.\n\nIf the container is sequence-like, the key is an integer.\nThe selected element is the `key`-th element of the container,\nthe front being at the index 0, the last at the index (`size-1`).\nThe index `key` shall be within the size of the container.\nTherefore, it will never return NULL in this case.\n\nIf the container is associative array like,\nthe selected element is the `value` object associated to the `key` object in the container.\nIf the key is not found, it returns NULL.\n\nIf the container is set-like,\nthe selected element is the `value` object which is equal to the `key` object in the container.\nIf the key is not found, it returns NULL.\n\nThis pointer remains valid until the container is modified by another method.\nThis pointer should not be stored in a global variable.\n\n##### `type_t *name_get_emplace[suffix](const name_t container, args...)` [for set-like]\n##### `value_type_t * name_get_emplace[suffix](name_t container, args...)` [for associative array]\n\nReturn a modifiable (resp. constant) pointer to\nthe element associated to the key constructed from `args` in the container.\nThe selected element is the `value` object associated to the `key` object in the container\nfor an associative array, or the element itself for a set.\nIf the key is not found, it returns NULL.\n\nThis pointer remains valid until the container is modified by another method.\nThis pointer should not be stored in a global variable.\n\n##### `type_t *name_safe_get(name_t container, size_t key)` [for sequence]\n##### `type_t *name_safe_get(name_t container, const type_t key)` [for set]\n##### `value_type_t *name_safe_get(name_t container, const key_type_t key)` [for associative array]\n\nReturn a modifiable pointer to\nthe element associated to `key` in the container,\ncreating a new element if it doesn't exist (ensuring therefore a safe `get` operation).\n\nIf the container is sequence-like, key_type_t is an alias for size_t and key an integer,\nthe selected element is the `key`-th element of the container.\nIf the element doesn't exist, the container size will be increased\nif needed (creating new elements with the `INIT` operator),\nwhich might increase the container to much in some cases.\n\nThe returned pointer cannot be NULL.\nThis method is only created if the `INIT` method is provided.\nThis pointer remains valid until the array is modified by another method.\nThis pointer should not be stored in a global variable.\n\n##### `bool name_erase(name_t container, const size_t key)`\n##### `bool name_erase(name_t container, const type_t key)` [for set]\n##### `bool name_erase(name_t container, const key_type_t key)` [for associative array]\n\nRemove the element referenced by the key `key` in the container `container`.\nDo nothing if `key` is no present in the container.\nReturn true if the key was present and erased, false otherwise.\n\n##### `size_t name_size(const name_t container)`\n\nReturn the number elements of the container (its size).\nReturn 0 if there is no element.\n\n##### `size_t name_capacity(const name_t container)`\n\nReturn the capacity of the container, i.e. the maximum number of elements\nsupported by the container before a reserve operation is needed to accommodate\nnew elements.\n\n##### `void name_resize(name_t container, size_t size)`\n\nResize the container `container` to the size `size`,\nincreasing or decreasing the size of the container\nby initializing new elements or clearing existing ones.\nThis method is only created if the INIT method is provided.\n\n##### `void name_reserve(name_t container, size_t capacity)`\n\nExtend or reduce the capacity of the `container` to a rounded value based on `capacity`.\nIf the given capacity is below the current size of the container,\nthe capacity is set to a rounded value based on the size of the container.\nTherefore a capacity of 0 is used to perform a shrink-to-fit operation on the container,\ni.e. reducing the container usage to the minimum possible allocation.\n\n##### `void name_it(name_it_t it, const name_t container)`\n\nSet the iterator `it` to the first element of the container `container`.\nThere is no destructor associated to this initialization.\n\n##### `void name_it_set(name_it_t it, const name_it_t ref)`\n\nSet the iterator `it` to the iterator `ref`.\nThere is no destructor associated to this initialization.\n\n##### `void name_it_end(name_it_t it, const name_t container)`\n\nSet the iterator `it` to a non valid element of the container.\nThere is no destructor associated to this initialization.\n\n##### `bool name_end_p(const name_it_t it)`\n\nReturn true if the iterator doesn't reference a valid element anymore.\n\n##### `bool name_last_p(const name_it_t it)`\n\nReturn true if the iterator references the last element of the container\nor if the iterator doesn't reference a valid element anymore.\n\n##### `bool name_it_equal_p(const name_it_t it1, const name_it_t it2)`\n\nReturn true if the iterator `it1` references the same element than the iterator `it2`.\n\n##### `void name_next(name_it_t it)`\n\nMove the iterator to the next element of the container.\n\n##### `void name_previous(name_it_t it)`\n\nMove the iterator `it` to the previous element of the container.\n\n##### `type_t *name_ref(name_it_t it)`\n##### `const type_t *name_cref(const name_it_t it)`\n##### `name_itref_t *name_ref(name_it_t it)`  [for associative array]\n##### `const name_itref_t *name_cref(name_it_t it)`  [for associative array]\n\nReturn a modifiable (resp. constant) pointer to the element pointed by the iterator.\nFor associative-array like container, this element is the pair composed of\nthe key (`key` field) and the associated value (`value` field);\notherwise this element is simply the basic type of the container (`type_t`).\n\nThis pointer should not be stored in a global variable.\nThis pointer remains valid until the container is modified by another method.\n\n##### `void name_insert(name_t container, const name_it_t it, const type_t x)`\n\nInsert the object `x` after the position referenced by the iterator `it` in the container `container`\nor if the iterator `it` doesn't reference anymore to a valid element of the container,\nit is added as the first element of the container.\n`it` shall be an iterator of the container `container`.\n\n##### `void name_remove(name_t container, name_it_t it)`\n\nRemove the element referenced by the iterator `it` from the container `container`.\n`it` shall be an iterator of the container `container`.\nAfterwards, `it` references the next element of the container if it exists,\nor not a valid element otherwise.\n\n##### `bool name_equal_p(const name_t container1, const name_t container2)`\n\nReturn true if both containers `container1` and `container2` are considered equal.\nThis method is only created if the `EQUAL` method is provided.\n\n##### `size_t name_hash(const name_t container)`\n\nReturn a fast hash value of the container `container`,\nsuitable to be used by a dictionary.\nThis method is only created if the `HASH` method is provided.\n\n##### `void name_get_str(string_t str, const name_t container, bool append)`\n\nSet `str` to the formatted string representation of the container `container` if `append` is false\nor append `str` with this representation if `append` is true.\nThis method is only created if the `GET_STR` method is provided.\n\n##### `bool name_parse_str(name_t container, const char str[], const char **endp)`\n\nParse the formatted string `str`,\nthat is assumed to be a string representation of a container,\nand set `container` to this representation.\nIt returns true if success, false otherwise.\nIf `endp` is not NULL, it sets `*endp` to the pointer of the first character not\ndecoded by the function (or where the parsing fails).\nThis method is only created if the `PARSE_STR` \u0026 `INIT` methods are provided.\n\nIt is ensured that the container gets from parsing a formatted string representation\ngets from `name_get_str` and the original container are equal.\n\n##### `void name_out_str(FILE *file, const name_t container)`\n\nGenerate a formatted string representation of the container `container`\nand outputs it into the file `FILE*`.\nThe file `FILE*` shall be opened in write text mode and without error.\nThis method is only created if the `OUT_STR` methods is provided.\n\n##### `bool name_in_str(name_t container, FILE *file)`\n\nRead from the file `FILE*` a formatted string representation of a container\nand set `container` to this representation.\nIt returns true if success, false otherwise.\nThis method is only created if the `IN_STR` \u0026 `INIT` methods are provided.\n\nIt is ensured that the container gets from parsing a formatted string representation\ngets from name_out_str and the original container are equal.\n\n##### `m_serial_return_code_t name_out_serial(m_serial_write_t serial, const name_t container)`\n\nOutput the container `container` into the serializing object `serial`.\nHow and where it is output depends on the serializing object.\nIt returns `M_SERIAL_OK_DONE` in case of success,\nor `M_SERIAL_FAILURE` in case of failure.\nIn case of failure, the serializing object is in an unspecified but valid state.\nThis method is only created if the `OUT_SERIAL` methods is provided.\n\n##### `m_serial_return_code_t name_in_serial(name_t container, m_serial_read_t serial)`\n\nRead from the serializing object `serial` a representation of a container\nand set `container` to this representation.\nIt returns `M_SERIAL_OK_","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FP-p-H-d%2Fmlib","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FP-p-H-d%2Fmlib","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FP-p-H-d%2Fmlib/lists"}