From ed0f538fb7e1d00de869c537c7000c64a165bdc4 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sat, 30 Dec 2023 16:22:46 +0100 Subject: [PATCH] Add documentation of generic interface --- README.md | 173 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 171 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index eebd71b8..6a62f7d1 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ M\*LIB: Generic type-safe Container Library for C language 27. [Memory pool](#m-mempool) 28. [JSON Serialization](#m-serial-json) 29. [Binary Serialization](#m-serial-bin) + 30. [Generic interface](#m-generic) 12. [Global User Customization](#global-user-customization) 13. [License](#license) @@ -179,6 +180,7 @@ Other headers offering other functionality are: * [m-worker.h](#m-worker): header for providing an easy pool of workers on separated threads to handle work orders (used for parallel tasks), * [m-serial-json.h](#m-serial-json): header for importing / exporting the containers in [JSON format](https://en.wikipedia.org/wiki/JSON), * [m-serial-bin.h](#m-serial-bin): header for importing / exporting the containers in an adhoc fast binary format, +* [m-generic.h](#m-generic): header for using a common interface for all registered types, * m-genint.h: internal header for generating unique integers in a concurrent context, * [m-core.h](#m-core): header for meta-programming with the C preprocessor (used by all other headers). @@ -492,15 +494,17 @@ of the library. The 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: ```C - let(list, list_uint_t) { + M_LET(list, list_uint_t) { push(list, 42); push(list, 17); for each (item, list) { - print(item, "\n"); + M_PRINT(*item, "\n"); } } ``` +See #M-GENERIC header for details. + ## Performance M\*LIB performance is compared to the one of GNU C++ STL (v10.2) in the following graphs. @@ -8411,6 +8415,171 @@ otherwise the behavior of the object is undefined. Clear the serialization object 'serial'. +### M-GENERIC + +This header is for registering and using a generic interface, regardless of the real type. +More precisely it provides way of registering the oplist of a type. Then a variable of this type can be used in macro-like functions (init, clear, push, ...) and the associated method of this oplist will be used to handle the variable. +If no type is associated to this variable, an error is reported by the compiler. + +This header needs a C23 compliant compiler or a C11 compiler providing the typeof extension (like GCC, CLANG, MSVC). +NOTE: TCC is not supported yet due to some bugs in the compiler. + +This provide the same level of flexibility of the C++. However there is some drawbacks of using this generic interface: + +* error messages can be more complex, +* compilation time increase a lot (on pair with C++) + +This header is still a WIP and is currently more a demo (Not ready for production). + +#### Example + +A concrete example of the generic header is the following. +It reuses the basic example of the introduction of the library. + +```C +#include "m-list.h" +#include "m-generic.h" + +LIST_DEF(list_uint, unsigned int) + +// Register oplist for M_LET & M_EACH : +#define M_OPL_list_uint_t() LIST_OPLIST(list_uint, M_BASIC_OPLIST) + +// Register for Generic (Organization, Component & Oplist) +#define M_GENERIC_ORG_1() (USER) +#define M_GENERIC_ORG_USER_COMP_1() (CORE) +#define M_GENERIC_ORG_USER_COMP_CORE_OPLIST_1() M_OPL_list_uint_t() + +int main(void) +{ + M_LET(list, list_uint_t) { + push(list, 42); + push(list, 17); + for each(item, list) { + M_PRINT("ITEM=", *item, "\n"); + } + M_PRINT("List = ", list, "\n"); + } +} +``` + + +#### Registration + +To register an oplist you need to register three things: + +* the *integration user* (user responsible for the integration of the whole program) registers all the *organizations* by mapping an integer from 1 to 50 to the short name of the organization. +* the *organization user* (user responsible for the integration produced by an organization, typically a library or the program except its libraries) chooses the short name of the organization and registers all the *components* of this organization by mapping an integer from 1 to 50 to the short name of the component. +* the *component user* (user responsible for a component of a library or a program) registers all the *oplists* of this component by mapping an integer from 1 to 50 to the oplist. + +This 3 levels registration is used to enable support for complex integration in real project. So, it maps the basic structure of a program so that each independent layer can register its own oplists independently of the others, and only the final integrator maps everything together. + +To register an organization the *integration user* shall define a macro like this for all organizations: + +```C +#define M_GENERIC_ORG_() () +``` +with + +* replaced by a unique integer in the range 1 to 50 +* replaced by the short name of the organization. + + +To register a component the *organization user* shall define a macro like this for all components: + +```C +#define M_GENERIC_ORG__COMP_() () +``` +with + +* replaced by a unique integer in the range 1 to 50 +* replaced by the short name of the organization. +* replaced by the short name of the component. + + +To register an oplist the *component user* shall define a macro like this for all oplists: + +```C +#define M_GENERIC_ORG__COMP__OPLIST_() +``` +with + +* replaced by a unique integer in the range 1 to 50 +* replaced by the short name of the organization. +* replaced by the short name of the component. +* replaced by the oplist (no need for extra parenthesis). + + +Theses macros should be defined in the header associated to their responsibility. +To register something, you don't need to include the m-register header file. + + +#### Usage + +The following macro functions are defined. They have the same behavior as their corresponding OPERATOR of the oplists: + +* init(x) +* init_set(x, y) +* init_move(x, y) +* move(x, y) +* set(x, y) +* clear(x) +* swap(x, y) +* hash(x) +* equal(x, y) +* cmp(x, y) +* sort(x) +* splice_back(d, s, i) +* splice_at(d, id, s, is) +* it_first(x, y) +* it_last(x, y) +* it_end(x, y) +* it_set(d, s) +* it_end_p(i) +* it_last_p(i) +* it_next(i) +* it_previous(i) +* it_ref(i) +* it_cref(i) +* it_equal(x, y) +* it_insert(c, i, o) +* it_remove(c, i) +* empty_p(x) +* add(x, y) +* sub(x, y) +* mul(x, y) +* div(x, y) +* reset(x) +* get(x, y) +* set_at(x, y, z) +* safe_get(x, y) +* erase(x, y) +* get_size(x) +* push(x, y) +* pop(x, y) +* push_move(x, y) +* pop_move(x, y) +* reverse(x) +* get_str(s, c, b) +* parse_str(c, s, e) +* out_str(x, y) +* in_str(x, y) +* out_serial(x, y) +* in_serial(x, y) + +The following macro are defined and represents a type associated to the variable. They have the same behavior as their corresponding OPERATOR of the oplists and use the typeof keyword: + +* it_type(x) +* sub_type(x) +* key_type(x) +* value_type(x) + +The following macro is defined and enabled to iterate over a container (See example): + +* each(item, container) + +Note that only short names are defined in this header which may be incompatible with your own namespace (This header is still a WIP) + ## Global User Customization