From f62808070134f6ab9dcd0445586c7a2d3c4ec455 Mon Sep 17 00:00:00 2001 From: Tyge Løvset <60263450+tylov@users.noreply.github.com> Date: Sat, 19 Sep 2020 18:08:29 +0200 Subject: Update README.md --- README.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index be345390..dcbe0b88 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ An elegant, fully typesafe, generic, customizable, user-friendly, consistent, an The usage of the containers is vert similar to the C++ standard containers, so it should be easy if you are familiar with them. All containers mentioned above, except cstr_t and cbitset_t are generic and typesafe (similar to templates in C++). No casting is used. A simple example: -``` +```C #include using_cvec(i, int); @@ -47,7 +47,7 @@ Installation ------------ Because it is headers only, files can simply be included in your program. The functions will be inlined by default. If containers are extensively used accross many tranlation units with common instantiated container types, it is recommended to build as a library, to minimize executable size. To enable this mode, specify **-DSTC_HEADER** as compiler option, and put all the instantiations of the containers used in one C file, like this: -``` +```C #define STC_IMPLEMENTATION #include #include @@ -117,13 +117,13 @@ cmap discussion **cmap/cset** are the most complex of the containers (although, currently less than 500 lines of code). It uses open hashing, but does not rely on power-of-two size table, nor prime number lengths, and it does not have tombstone buckets. It is still among the fastest hash-tables, as shown above. The default max load-factor is 0.85, and it shrinks (and rehashes) when load-factor goes below 0.15, by default (can be set per hash container). You can customize the destroy-, hash- and equals- function. **cmap/cset** also supports a few other arguments in the declare-statement that allows to define a convertion from a raw/literal type to the key-type specified. This is very useful when e.g. having cstr as key, as it enables the usage of string literals as key in *put() and find()* functions, instead of requering a constructed cstr. Without it, the code would become: -``` +```C using_cmap(si, cstr_t, int); // don't do this. ... cmap_si_put(&map, cstr("mykey"), 12); ``` This is a problem because cstr_t key may exist in the map, and it would need to destroy the current key and replace it with the new to avoid memory leak. Lookup would also be problematic: -``` +```C cstr lookup = cstr("mykey"); int x = cmap_si_find(&map, lookup)->value; cstr_del(&lookup); @@ -133,7 +133,7 @@ To avoid this, use - *using_cmap_strval(tag, keytype)* - *using_cmap_str()* // cstr_t -> cstr_t - *using_cset_str()* // cstr_t set -``` +```C using_cmap_strkey(si, int); ... cmap_si map = cmap_INIT; @@ -151,7 +151,7 @@ Example usages The examples folder contains further examples. **cstr** string example. -``` +```C #include int main() { @@ -179,7 +179,7 @@ int main() { } ``` **cvec** of *int64_t*. -``` +```C #include using_cvec(ix, int64_t); // ix is just an example type tag name. @@ -197,7 +197,7 @@ int main() { } ``` **cvec** of *cstr_t*. -``` +```C #include #include using_cvec_str(); @@ -217,7 +217,7 @@ int main() { } ``` **cmap** of *int -> int*. -``` +```C #include #include using_cmap(ii, int, int); @@ -232,7 +232,7 @@ int main() { } ``` **cset** of *cstr*. -``` +```C #include #include using_cset_str(); // cstr set. See the discussion above. @@ -251,7 +251,7 @@ int main() { } ``` **cmap** of *cstr -> cstr*. Both cstr keys and values are created internally via *cstr()* from const char* inputs. -``` +```C #include #include using_cmap_str(); @@ -271,7 +271,7 @@ int main() { } ``` **clist** of *int64_t*. Similar to c++ *std::forward_list*, but can do both *push_front()* and *push_back()* as well as *pop_front()*. -``` +```C #include #include #include @@ -310,7 +310,7 @@ int main() { } ``` **carray**. 1d, 2d and 3d arrays, allocated from heap in one memory block. *carray3* may have sub-array "views" of *carray2* and *carray1* etc., as shown in the following example: -``` +```C #include #include using_carray(f, float); -- cgit v1.2.3 From a047bfa20b825ec67a901a81546601cb06d61f18 Mon Sep 17 00:00:00 2001 From: Tyge Løvset <60263450+tylov@users.noreply.github.com> Date: Sat, 19 Sep 2020 18:10:07 +0200 Subject: Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dcbe0b88..6c2a7913 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -STC - C99 STandard Container library +STC - C99 Standard Container library ==================================== Introduction -- cgit v1.2.3 From 339bb8a0a791ece66c91caee2b610e17881674f0 Mon Sep 17 00:00:00 2001 From: Tyge Løvset <60263450+tylov@users.noreply.github.com> Date: Sat, 19 Sep 2020 18:20:10 +0200 Subject: Update README.md --- examples/README.md | 63 ++++++++++++++++++++++++++---------------------------- 1 file changed, 30 insertions(+), 33 deletions(-) diff --git a/examples/README.md b/examples/README.md index 74ac4384..a30991b1 100644 --- a/examples/README.md +++ b/examples/README.md @@ -5,60 +5,57 @@ This folder contains various examples and benchmarks. Custom key example ------------------ -This demonstrates how to customize **cmap** with a user-defined key-type. When your key type consists of several members, you will usually have the hash function calculate hash values for the individual members, and then somehow combine them into one hash value for the entire object. If your key-type stores dynamic memory (e.g. cstr_t, as we will use), it is recommended to define a "view/raw"-struct of the your data first. In addition, you must define two functions: +This demonstrates how to customize **cmap** with a user-defined key-type. When your key type consists of several members, you will usually have the hash function calculate hash values for the individual members, and then somehow combine them into one hash value for the entire object. If your key-type stores dynamic memory (e.g. cstr_t, as we will use), it is recommended to define a "raw"-struct of the your data first. In addition, you must define two functions: 1. A hash function; calculates the hash value given an object of the key-type. 2. A comparison function for equality; -``` +```C #include #include #include -// Viking view struct - -typedef struct VikingVw { - const char* name; - const char* country; -} VikingVw; - - -uint32_t vikingvw_hash(const VikingVw* vw, size_t ignore) { - uint32_t hash = c_string_hash(vw->name) ^ c_string_hash(w->country); - return hash; -} -static inline int vikingvw_equals(const VikingVw* x, const VikingVw* y) { - return strcmp(x->name, y->name) == 0 && strcmp(x->country, y->country) == 0; -} -``` -And the Viking data struct with destroy and convertion functions between VikingVw <-> Viking structs. -``` typedef struct Viking { cstr_t name; cstr_t country; } Viking; - void viking_del(Viking* vk) { cstr_del(&vk->name); cstr_del(&vk->country); } +``` +And the Viking data struct with destroy and convertion functions between VikingVw <-> Viking structs. +```C +// Viking raw struct -static inline VikingVw viking_toVw(Viking* vk) { - VikingVw vw = {vk->name.str, vk->country.str}; return vw; +typedef struct VikingRaw { + const char* name; + const char* country; +} VikingRaw; + +uint32_t vikingraw_hash(const VikingRaw* vw, size_t ignore) { + uint32_t hash = c_string_hash(vw->name) ^ c_string_hash(w->country); + return hash; +} +static inline int vikingraw_equals(const VikingRaw* x, const VikingRaw* y) { + return strcmp(x->name, y->name) == 0 && strcmp(x->country, y->country) == 0; } -static inline Viking viking_fromVw(VikingVw vw) { // note: parameter is by value + +static inline VikingRaw viking_toRaw(Viking* vk) { + VikingRaw vw = {vk->name.str, vk->country.str}; return vw; +} +static inline Viking viking_fromRaw(VikingRaw vw) { // note: parameter is by value Viking vk = {cstr(vw.name), cstr(vw.country)}; return vk; } ``` With this in place, we use the full using_cmap() macro to define {Viking -> int} hash map type: ``` -using_cmap(vk, Viking, int, c_default_del, vikingvw_equals, vikingvw_hash, - viking_del, VikingVw, viking_toVw, viking_fromVw); -``` -cmap_vk uses vikingvw_hash() for hash value calculations, and vikingvw_equals() for equality test. cmap_vk_del() will free all memory allocated for Viking keys and the hash table values. -Finally, main which also demos the generic c_push_items() of multiple elements: +using_cmap(vk, Viking, int, c_default_del, vikingraw_equals, vikingraw_hash, + viking_del, VikingRaw, viking_toRaw, viking_fromRaw); ``` +cmap_vk uses vikingraw_hash() for hash value calculations, and vikingraw_equals() for equality test. cmap_vk_del() will free all memory allocated for Viking keys and the hash table values. Finally, main which also demos the generic c_push_items() of multiple elements: +```C int main() { cmap_vk vikings = cmap_INIT; c_push_items(&vikings, cmap_vk, { @@ -66,13 +63,13 @@ int main() { { {"Olaf", "Denmark"}, 24 }, { {"Harald", "Iceland"}, 12 }, }); - VikingVw look = {"Einar", "Norway"}; + VikingRaw look = {"Einar", "Norway"}; cmap_vk_entry_t *e = cmap_vk_find(&vikings, look); - e->value += 5; // update - cmap_vk_emplace(&vikings, look, 0)->value += 5; // again + e->second += 5; // update + cmap_vk_emplace(&vikings, look, 0)->second += 5; // again c_foreach (k, cmap_vk, vikings) { - printf("%s of %s has %d hp\n", k.get->key.name.str, k.get->key.country.str, k.get->value); + printf("%s of %s has %d hp\n", k.get->first.name.str, k.get->first.country.str, k.get->second); } cmap_vk_del(&vikings); } -- cgit v1.2.3 From 4f4456758bda455062018f5367788de125dda629 Mon Sep 17 00:00:00 2001 From: Tyge Løvset <60263450+tylov@users.noreply.github.com> Date: Sat, 19 Sep 2020 18:25:12 +0200 Subject: Update README.md --- examples/README.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/examples/README.md b/examples/README.md index a30991b1..ae8792cf 100644 --- a/examples/README.md +++ b/examples/README.md @@ -5,11 +5,12 @@ This folder contains various examples and benchmarks. Custom key example ------------------ -This demonstrates how to customize **cmap** with a user-defined key-type. When your key type consists of several members, you will usually have the hash function calculate hash values for the individual members, and then somehow combine them into one hash value for the entire object. If your key-type stores dynamic memory (e.g. cstr_t, as we will use), it is recommended to define a "raw"-struct of the your data first. In addition, you must define two functions: +This demonstrates how to customize **cmap** with a user-defined key-type. When your key type consists of several members, you will usually have the hash function calculate hash values for the individual members, and then somehow combine them into one hash value for the entire object. If your key-type stores dynamic memory (e.g. cstr_t, as we will use), it is highly recommended to define a "raw"-struct representaion for your dynamic data struct. In addition, you must define two functions: 1. A hash function; calculates the hash value given an object of the key-type. - 2. A comparison function for equality; + +First, the Viking struct with destructor function: ```C #include #include @@ -25,7 +26,7 @@ void viking_del(Viking* vk) { cstr_del(&vk->country); } ``` -And the Viking data struct with destroy and convertion functions between VikingVw <-> Viking structs. +And the Viking raw struct with convertion functions between Viking and VikingRaw structs: ```C // Viking raw struct @@ -63,10 +64,12 @@ int main() { { {"Olaf", "Denmark"}, 24 }, { {"Harald", "Iceland"}, 12 }, }); + VikingRaw look = {"Einar", "Norway"}; + cmap_vk_entry_t *e = cmap_vk_find(&vikings, look); - e->second += 5; // update - cmap_vk_emplace(&vikings, look, 0)->second += 5; // again + e->second += 5; // add + cmap_vk_emplace(&vikings, look, 0)->second += 5; // update again c_foreach (k, cmap_vk, vikings) { printf("%s of %s has %d hp\n", k.get->first.name.str, k.get->first.country.str, k.get->second); -- cgit v1.2.3 From 4d25e3c27016349ce91e1e619d48fd086c8dd179 Mon Sep 17 00:00:00 2001 From: Tyge Løvset <60263450+tylov@users.noreply.github.com> Date: Sat, 19 Sep 2020 18:29:10 +0200 Subject: Update README.md --- examples/README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/README.md b/examples/README.md index ae8792cf..96a02584 100644 --- a/examples/README.md +++ b/examples/README.md @@ -26,7 +26,7 @@ void viking_del(Viking* vk) { cstr_del(&vk->country); } ``` -And the Viking raw struct with convertion functions between Viking and VikingRaw structs: +And the Viking raw struct with hash, equals, and convertion functions between Viking and VikingRaw structs: ```C // Viking raw struct @@ -51,18 +51,18 @@ static inline Viking viking_fromRaw(VikingRaw vw) { // note: parameter is by val } ``` With this in place, we use the full using_cmap() macro to define {Viking -> int} hash map type: -``` +```C using_cmap(vk, Viking, int, c_default_del, vikingraw_equals, vikingraw_hash, - viking_del, VikingRaw, viking_toRaw, viking_fromRaw); + viking_del, VikingRaw, viking_toRaw, viking_fromRaw); ``` cmap_vk uses vikingraw_hash() for hash value calculations, and vikingraw_equals() for equality test. cmap_vk_del() will free all memory allocated for Viking keys and the hash table values. Finally, main which also demos the generic c_push_items() of multiple elements: ```C int main() { cmap_vk vikings = cmap_INIT; c_push_items(&vikings, cmap_vk, { - { {"Einar", "Norway"}, 20 }, - { {"Olaf", "Denmark"}, 24 }, - { {"Harald", "Iceland"}, 12 }, + {{"Einar", "Norway"}, 20}, + {{"Olaf", "Denmark"}, 24}, + {{"Harald", "Iceland"}, 12}, }); VikingRaw look = {"Einar", "Norway"}; -- cgit v1.2.3