diff options
| author | Tyge Løvset <[email protected]> | 2020-07-16 23:42:08 +0200 |
|---|---|---|
| committer | Tyge Løvset <[email protected]> | 2020-07-16 23:42:08 +0200 |
| commit | 44c2d2e9a40da9a4c10d128bbad38e3d1802d361 (patch) | |
| tree | a5bbdaca6ea1fc81e2cea324974f47ade08f25b0 | |
| parent | 5f004f4f91b4a383005c763ea925cf655ba2d7c2 (diff) | |
| download | STC-modified-44c2d2e9a40da9a4c10d128bbad38e3d1802d361.tar.gz STC-modified-44c2d2e9a40da9a4c10d128bbad38e3d1802d361.zip | |
API CHANGES: CHash now splitted to CMap / CSet, still in chash.h header. Renamed cstring.h -> cstr.h, cvector.h -> cvec.h
| -rw-r--r-- | README.md | 104 | ||||
| -rw-r--r-- | examples/README.md | 24 | ||||
| -rw-r--r-- | examples/advanced.c | 26 | ||||
| -rw-r--r-- | examples/benchmark.c | 18 | ||||
| -rw-r--r-- | examples/complex.c | 16 | ||||
| -rw-r--r-- | examples/demos.c | 66 | ||||
| -rw-r--r-- | examples/geek1.c | 185 | ||||
| -rw-r--r-- | examples/geek2.c | 122 | ||||
| -rw-r--r-- | examples/geek3.c | 50 | ||||
| -rw-r--r-- | examples/geek4.c | 262 | ||||
| -rw-r--r-- | examples/geek5.c | 140 | ||||
| -rw-r--r-- | examples/geek6.c | 124 | ||||
| -rw-r--r-- | examples/mapmap.c | 20 | ||||
| -rw-r--r-- | examples/prime.c | 45 | ||||
| -rw-r--r-- | stc/chash.h | 348 | ||||
| -rw-r--r-- | stc/cstr.h (renamed from stc/cstring.h) | 0 | ||||
| -rw-r--r-- | stc/cvec.h (renamed from stc/cvector.h) | 0 |
17 files changed, 1254 insertions, 296 deletions
@@ -49,17 +49,17 @@ Because it is headers only, files can simply be included in your program. The fu #include <stc/chash.h>
#include <stc/cvector.h>
-declare_CHash(ii, int, int); // map
-declare_CHash(ix, int64_t); // set
+declare_CMap(ii, int, int); // map
+declare_CMap(ix, int64_t); // set
declare_CVec(i, int);
...
```
Performance
-----------
-This library is very efficent. Containers have templated intrusive elements. One of the most performance critical containers is the **CHash map / CHash set**. Thankfully, CHash is among the fastest C/C++ map implementations available: **examples/benchmark.c** compiled with g++ v9.2.0 -O3 on windows (the results are similar with VC++ and g++ on linux):
+This library is very efficent. Containers have templated intrusive elements. One of the most performance critical containers is the **CMap map / CMap set**. Thankfully, CMap is among the fastest C/C++ map implementations available: **examples/benchmark.c** compiled with g++ v9.2.0 -O3 on windows (the results are similar with VC++ and g++ on linux):
-**CMAP**=*CHash map*, KMAP=*khash*, UMAP=*std::unordered_map*, BMAP=*ska::bytell_hash_map*, FMAP=*ska::flat_hash_map*, RMAP=*robin_hood::unordered_map*
+**CMAP**=*CMap map*, KMAP=*khash*, UMAP=*std::unordered_map*, BMAP=*ska::bytell_hash_map*, FMAP=*ska::flat_hash_map*, RMAP=*robin_hood::unordered_map*
```
Random keys are in range [0, 2^20):
map<uint64_t, uint64_t>: 7000000 repeats of Insert random key + (try to) remove a different random key:
@@ -92,35 +92,35 @@ Memory efficiency The containers are memory efficent, i.e. they occupy as little memory as practical possible.
- **CStr**, **CVec**: Representaion: one pointer size. The size and capacity is stored as part of the heap allocation that also holds the vector elements.
- **CList**: Representation: one pointer size. Each node allocates block storing value and next pointer.
-- **CHash set**: Representation: 4 pointers size. The CHash set uses one table of keys, and one table of "used/hash-value", which occupies one byte per bucket.
-- **CHash map**: Same as CHash set, but this uses a table of (key, value) pairs, not only keys.
+- **CSet**: Representation: 4 pointers size. CSet uses one table of keys, and one table of "used/hash-value", which occupies only one byte per bucket.
+- **CMap**: Same as CSet, but this uses a table of (key, value) pairs, not only keys.
- **CArray**: CArray1, CArray2 and CArray3. Representation: One pointers, plus 1, 2, or 3 size_t variables to store dimensions. Elements are stored as one memory block.
-CHash and CVec discussion
+CMap, CSet and CVec discussion
----------------------------
-**CHash** is the most complex of the containers (although, currently only ~370 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. Still, it is 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).
+**CMap/CSet** are the most complex of the containers (although, currently only ~370 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 may customize the destroy-, hash- and equals- function. It 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 handy when e.g. having CStr as key, as it enables the usage of string literals as key in *put() and *get() functions, instead of requering a constructed CStr. Without it, you would have to write:
```
-declare_CHash(si, CStr, int);
+declare_CMap(si, CStr, int);
...
-chash_si_put(&map, cstr_make("mykey"), 12);
+cmap_si_put(&map, cstr_make("mykey"), 12);
```
but the main incovenience is with lookup:
```
CStr lookup = cstr_make("mykey");
-int x = chash_si_get(&map, lookup)->value;
+int x = cmap_si_get(&map, lookup)->value;
cstr_destroy(&lookup);
```
-To avoid this, use *declare_CHash_str()*:
+To avoid this, use *declare_CMap_str()*:
```
-declare_CHash_str(si, int);
+declare_CMap_str(si, int);
...
-CHash_si map = chash_init;
-chash_si_put(&map, "mykey", 12); // constructs a CStr key from the const char* internally.
-int x = chash_si_get(&map, "mykey")->value; // no allocation of string key happens here.
-chash_si_destroy(&map);
+CMap_si map = cmap_init;
+cmap_si_put(&map, "mykey", 12); // constructs a CStr key from the const char* internally.
+int x = cmap_si_get(&map, "mykey")->value; // no allocation of string key happens here.
+cmap_si_destroy(&map);
```
An alternative would be to use *char* * as key type, but you would have to manage the memory of the hash char* keys yourself.
Note that this customization is also available for **CVec**, but only affects the *find()* function currently. See *declare_CVec_str()*.
@@ -130,9 +130,9 @@ Also look at **examples/advanced.c**, it demonstrates how to use a custom struct Example usages
--------------
The first example has a very complex nested container type, which demonstrates the power of this library. Look at the simpler examples below to understand it better. The example adds an element into the data structure, and then accesses it. The type used, with c++ template syntax is:
-**CHashMap**< **CStr**, **CHashMap**< *int*, **CList**< **CArray2**< *float* >>>>
+**CMapMap**< **CStr**, **CMapMap**< *int*, **CList**< **CArray2**< *float* >>>>
-Note: The *chash_sm_destroy(&theMap)* call below, will destroy all the nested containers including the memory allocated for CStr keys in theMap object.
+Note: The *cmap_sm_destroy(&theMap)* call below, will destroy all the nested containers including the memory allocated for CStr keys in theMap object.
```
#include "stc/cstring.h"
#include "stc/chash.h"
@@ -143,31 +143,31 @@ void check_destroy(float* v) {printf("destroy %g\n", *v);} declare_CArray(f, float, check_destroy); // normally omit the last argument - float type need no destroy.
declare_CList(t2, CArray2_f, carray2_f_destroy, c_noCompare);
-declare_CHash(il, int, CList_t2, clist_t2_destroy);
-declare_CHash_str(sm, CHash_il, chash_il_destroy);
+declare_CMap(il, int, CList_t2, clist_t2_destroy);
+declare_CMap_str(sm, CMap_il, cmap_il_destroy);
int main() {
int xdim = 4, ydim = 6;
int x = 2, y = 5, entry = 42;
- CHash_sm theMap = chash_init;
+ CMap_sm theMap = cmap_init;
{
// Construct.
CArray2_f table = carray2_f_make(xdim, ydim, 0.f);
CList_t2 tableList = clist_init;
- CHash_il listMap = chash_init;
+ CMap_il listMap = cmap_init;
// Put in some data.
carray2_f_data(table, x)[y] = 3.1415927; // table[x][y]
clist_t2_pushBack(&tableList, table);
- chash_il_put(&listMap, entry, tableList);
- chash_sm_put(&theMap, "First", listMap);
+ cmap_il_put(&listMap, entry, tableList);
+ cmap_sm_put(&theMap, "First", listMap);
}
// Access the data entry
- CArray2_f table = clist_back(chash_il_get(&chash_sm_get(&theMap, "First")->value, entry)->value);
+ CArray2_f table = clist_back(cmap_il_get(&cmap_sm_get(&theMap, "First")->value, entry)->value);
printf("value is: %f\n", carray2_f_value(table, x, y));
- chash_sm_destroy(&theMap); // free up the whole shebang!
+ cmap_sm_destroy(&theMap); // free up the whole shebang!
}
```
**CStr**
@@ -232,54 +232,54 @@ int main() { cvec_cs_destroy(&names);
}
```
-**CHash map** of *int -> int*
+**CMap** of *int -> int*
```
#include <stdio.h>
#include "stc/chash.h"
-declare_CHash(ii, int, int);
+declare_CMap(ii, int, int);
int main() {
- CHash_ii nums = chash_init;
- chash_ii_put(&nums, 8, 64);
- chash_ii_put(&nums, 11, 121);
+ CMap_ii nums = cmap_init;
+ cmap_ii_put(&nums, 8, 64);
+ cmap_ii_put(&nums, 11, 121);
- printf("%d\n", chash_ii_get(nums, 8)->value);
- chash_ii_destroy(&nums);
+ printf("%d\n", cmap_ii_get(nums, 8)->value);
+ cmap_ii_destroy(&nums);
}
```
-**CHash set** of *CStr*
+**CSet** of *CStr*
```
#include "stc/cstring.h"
#include "stc/chash.h"
-declare_CHash_str(s); // CStr set. See the discussion above.
+declare_CSet_str(s); // CStr set. See the discussion above.
int main() {
- CHash_s words = chash_init;
- chash_s_put(&words, "Hello");
- chash_s_put(&words, "Groovy");
- chash_s_erase(&words, "Hello");
+ CSet_s words = cset_init;
+ cset_s_put(&words, "Hello");
+ cset_s_put(&words, "Groovy");
+ cset_s_erase(&words, "Hello");
// iterate the map:
- c_foreach (i, chash_s, words)
+ c_foreach (i, cset_s, words)
printf("%s\n", i.item->key.str);
- chash_s_destroy(&words);
+ cset_s_destroy(&words);
}
```
-**CHash map** of *CStr -> CStr*. Temporary CStr values are created by *cstr_make()*, and moved into the container
+**CMap** of *CStr -> CStr*. Temporary CStr values are created by *cstr_make()*, and moved into the container
```
#include "stc/cstring.h"
#include "stc/chash.h"
-declare_CHash_str(ss, CStr, cstr_destroy);
+declare_CMap_str(ss, CStr, cstr_destroy);
int main() {
- CHash_ss table = chash_init;
- chash_ss_put(&table, "Make", cstr_make("my"));
- chash_ss_put(&table, "Sunny", cstr_make("day"));
- printf("Sunny: %s\n", chash_ss_get(table, "Sunny")->value.str);
- chash_ss_erase(&table, "Make");
-
- printf("size %d\n", chash_size(table));
- chash_ss_destroy(&table); // frees key and value CStrs, and hash table (CVec).
+ CMap_ss table = cmap_init;
+ cmap_ss_put(&table, "Make", cstr_make("my"));
+ cmap_ss_put(&table, "Sunny", cstr_make("day"));
+ printf("Sunny: %s\n", cmap_ss_get(table, "Sunny")->value.str);
+ cmap_ss_erase(&table, "Make");
+
+ printf("size %d\n", cmap_size(table));
+ cmap_ss_destroy(&table); // frees key and value CStrs, and hash table (CVec).
}
```
**CList** of *int64_t*. Similar to c++ *std::forward_list*, but can do both *pushFront()* and *pushBack()*.
diff --git a/examples/README.md b/examples/README.md index b77fb94e..cd6ac4ff 100644 --- a/examples/README.md +++ b/examples/README.md @@ -6,7 +6,7 @@ Contains various examples and benchmarks. advanced.c Example
------------------
-This demonstrates how to customize **CHash map** with a user-defined key-type. You need to define two things:
+This demonstrates how to customize hash **CMap** with a user-defined key-type. You need to define two things:
1. A hash function; calculates the hash value given an object of the key-type.
@@ -58,28 +58,28 @@ Viking viking_fromVw(VikingVw vw) { }
```
-With this in place, we use the full declare_CHash() macro to define {Viking -> int} hash map type:
+With this in place, we use the full declare_CMap() macro to define {Viking -> int} hash map type:
```
-declare_CHash(vk, MAP, Viking, int, c_emptyDestroy, vikingvw_hash, vikingvw_equals,
- viking_destroy, VikingVw, viking_getVw, viking_fromVw);
+declare_CMap(vk, Viking, int, c_emptyDestroy, vikingvw_hash, vikingvw_equals,
+ viking_destroy, VikingVw, viking_getVw, viking_fromVw);
```
-CHash_vk uses vikingvw_hash() for hash value calculations, and vikingvw_equals() for equality test. chash_vk_destroy() will free all memory allocated for Viking keys and the hash table values.
+CMap_vk uses vikingvw_hash() for hash value calculations, and vikingvw_equals() for equality test. cmap_vk_destroy() will free all memory allocated for Viking keys and the hash table values.
Finally, the demo:
```
int main()
{
- CHash_vk vikings = chash_init;
+ CMap_vk vikings = cmap_init;
// emplace constructs the keys
- chash_vk_put(&vikings, (VikingVw) {"Einar", "Norway"}, 20);
- chash_vk_put(&vikings, (VikingVw) {"Olaf", "Denmark"}, 24);
- chash_vk_put(&vikings, (VikingVw) {"Harald", "Iceland"}, 12);
+ cmap_vk_put(&vikings, (VikingVw) {"Einar", "Norway"}, 20);
+ cmap_vk_put(&vikings, (VikingVw) {"Olaf", "Denmark"}, 24);
+ cmap_vk_put(&vikings, (VikingVw) {"Harald", "Iceland"}, 12);
- CHashEntry_vk* e = chash_vk_get(&vikings, (VikingVw) {"Einar", "Norway"});
+ CMapEntry_vk* e = cmap_vk_get(&vikings, (VikingVw) {"Einar", "Norway"});
e->value += 5; // update
- c_foreach (k, chash_vk, vikings) {
+ c_foreach (k, cmap_vk, vikings) {
printf("%s of %s has %d hp\n", k.item->key.name.str, k.item->key.country.str, k.item->value);
}
- chash_vk_destroy(&vikings);
+ cmap_vk_destroy(&vikings);
}
```
diff --git a/examples/advanced.c b/examples/advanced.c index e8b62fe2..c4c13f10 100644 --- a/examples/advanced.c +++ b/examples/advanced.c @@ -1,5 +1,5 @@ /* - * To be able to use CHash with a user-defined key-type, you need to define two things: + * To be able to use CMap with a user-defined key-type, you need to define two things: * 1. A hash function; this must be a function that calculates the hash value given * an object of the key-type. * 2. A comparison function for equality. @@ -52,29 +52,29 @@ Viking viking_fromVw(VikingVw vw) { } -// Using the full declare_CHash() macro to define [Viking -> int] hash map type: -declare_CHash(vk, MAP, Viking, int, c_emptyDestroy, vikingvw_hash, vikingvw_equals, - viking_destroy, VikingVw, viking_getVw, viking_fromVw); +// Using the full declare_CMap() macro to define [Viking -> int] hash map type: +declare_CMap(vk, Viking, int, c_emptyDestroy, vikingvw_hash, vikingvw_equals, + viking_destroy, VikingVw, viking_getVw, viking_fromVw); -// CHash_vk uses vikingvw_hash() for hash value calculations, and vikingvw_equals() for equality test. -// chash_vk_destroy() will free all memory allocated for Viking keys and the hash table values. +// CMap_vk uses vikingvw_hash() for hash value calculations, and vikingvw_equals() for equality test. +// cmap_vk_destroy() will free all memory allocated for Viking keys and the hash table values. // Main ---------------------------- int main() { - CHash_vk vikings = chash_init; + CMap_vk vikings = cmap_init; // emplace constructs the keys - chash_vk_put(&vikings, (VikingVw) {"Einar", "Norway"}, 20); - chash_vk_put(&vikings, (VikingVw) {"Olaf", "Denmark"}, 24); - chash_vk_put(&vikings, (VikingVw) {"Harald", "Iceland"}, 12); + cmap_vk_put(&vikings, (VikingVw) {"Einar", "Norway"}, 20); + cmap_vk_put(&vikings, (VikingVw) {"Olaf", "Denmark"}, 24); + cmap_vk_put(&vikings, (VikingVw) {"Harald", "Iceland"}, 12); - CHashEntry_vk* e = chash_vk_get(&vikings, (VikingVw) {"Einar", "Norway"}); + CMapEntry_vk* e = cmap_vk_get(&vikings, (VikingVw) {"Einar", "Norway"}); e->value += 5; // update - c_foreach (k, chash_vk, vikings) { + c_foreach (k, cmap_vk, vikings) { printf("%s of %s has %d hp\n", k.item->key.name.str, k.item->key.country.str, k.item->value); } - chash_vk_destroy(&vikings); + cmap_vk_destroy(&vikings); } diff --git a/examples/benchmark.c b/examples/benchmark.c index 12449e27..45d16135 100644 --- a/examples/benchmark.c +++ b/examples/benchmark.c @@ -19,7 +19,7 @@ static inline uint32_t fibonacci_hash(const void* data, size_t len) { const uint64_t key = *(const uint64_t *) data;
return (uint32_t) (key * 11400714819323198485llu);
}
-declare_CHash(ii, int64_t, int64_t, c_emptyDestroy, fibonacci_hash);
+declare_CMap(ii, int64_t, int64_t, c_emptyDestroy, fibonacci_hash);
KHASH_MAP_INIT_INT64(ii, uint64_t)
@@ -31,14 +31,14 @@ sfc64_random_t rng; #define RAND(N) (sfc64_random(&rng) & ((1 << N) - 1))
-#define CMAP_SETUP(tag, Key, Value) CHash_##tag map = chash_init \
- /* ; chash_##tag##_setLoadFactors(&map, maxLoadFactor, 0.0)*/
-#define CMAP_PUT(tag, key, val) chash_##tag##_put(&map, key, val)->value
-#define CMAP_ERASE(tag, key) chash_##tag##_erase(&map, key)
-#define CMAP_FIND(tag, key) (chash_##tag##_get(map, key) != NULL)
-#define CMAP_SIZE(tag) chash_size(map)
-#define CMAP_BUCKETS(tag) chash_bucketCount(map)
-#define CMAP_CLEAR(tag) chash_##tag##_destroy(&map)
+#define CMAP_SETUP(tag, Key, Value) CMap_##tag map = cmap_init \
+ /* ; cmap_##tag##_setLoadFactors(&map, maxLoadFactor, 0.0)*/
+#define CMAP_PUT(tag, key, val) cmap_##tag##_put(&map, key, val)->value
+#define CMAP_ERASE(tag, key) cmap_##tag##_erase(&map, key)
+#define CMAP_FIND(tag, key) (cmap_##tag##_get(map, key) != NULL)
+#define CMAP_SIZE(tag) cmap_size(map)
+#define CMAP_BUCKETS(tag) cmap_bucketCount(map)
+#define CMAP_CLEAR(tag) cmap_##tag##_destroy(&map)
#define KMAP_SETUP(tag, Key, Value) khash_t(ii)* map = kh_init(ii); khiter_t ki; int ret
#define KMAP_PUT(tag, key, val) (*(ki = kh_put(ii, map, key, &ret), map->vals[ki] = val, &map->vals[ki]))
diff --git a/examples/complex.c b/examples/complex.c index 3ecf6a1f..4434c9c9 100644 --- a/examples/complex.c +++ b/examples/complex.c @@ -7,31 +7,31 @@ void check_destroy(float* v) {printf("destroy %g\n", *v);} declare_CArray(f, float, check_destroy); // normally omit the last argument - float type need no destroy.
declare_CList(t2, CArray2_f, carray2_f_destroy, c_noCompare);
-declare_CHash(il, int, CList_t2, clist_t2_destroy);
-declare_CHash_str(sm, CHash_il, chash_il_destroy);
+declare_CMap(il, int, CList_t2, clist_t2_destroy);
+declare_CMap_str(sm, CMap_il, cmap_il_destroy);
int main() {
int xdim = 4, ydim = 6;
int x = 1, y = 5, tableKey = 42;
const char* strKey = "first";
- CHash_sm theMap = chash_init;
+ CMap_sm theMap = cmap_init;
{ // Construct.
CArray2_f table = carray2_f_make(ydim, xdim, 0.f);
printf("table: (%zu, %zu)\n", carray2_ydim(table), carray2_xdim(table));
CList_t2 tableList = clist_init;
- CHash_il listMap = chash_init;
+ CMap_il listMap = cmap_init;
// Put in some data.
carray2_f_data(table, y)[x] = 3.1415927; // table[y][x]
clist_t2_pushBack(&tableList, table);
- chash_il_put(&listMap, tableKey, tableList);
- chash_sm_put(&theMap, strKey, listMap);
+ cmap_il_put(&listMap, tableKey, tableList);
+ cmap_sm_put(&theMap, strKey, listMap);
}
{ // Access the data entry
- CArray2_f table = clist_back(chash_il_get(&chash_sm_get(&theMap, strKey)->value, tableKey)->value);
+ CArray2_f table = clist_back(cmap_il_get(&cmap_sm_get(&theMap, strKey)->value, tableKey)->value);
printf("value (%d, %d) is: %f\n", y, x, carray2_f_value(table, y, x));
}
- chash_sm_destroy(&theMap); // free up the whole shebang!
+ cmap_sm_destroy(&theMap); // free up the whole shebang!
}
\ No newline at end of file diff --git a/examples/demos.c b/examples/demos.c index 20ecd3a0..3bff2b5c 100644 --- a/examples/demos.c +++ b/examples/demos.c @@ -99,75 +99,75 @@ void listdemo1() clist_ix_destroy(&nums);
}
-declare_CHash_set(i, int); // alias: declare_CHash(i, int);
+declare_CSet(i, int);
void setdemo1()
{
printf("\nSETDEMO1\n");
- CHash_i nums = chash_init;
- chash_i_put(&nums, 8);
- chash_i_put(&nums, 11);
+ CSet_i nums = cset_init;
+ cset_i_put(&nums, 8);
+ cset_i_put(&nums, 11);
- c_foreach (i, chash_i, nums)
+ c_foreach (i, cset_i, nums)
printf("set: %d\n", i.item->key);
- chash_i_destroy(&nums);
+ cset_i_destroy(&nums);
}
-declare_CHash(ii, int, int);
+declare_CMap(ii, int, int);
void mapdemo1()
{
printf("\nMAPDEMO1\n");
- CHash_ii nums = chash_init;
- chash_ii_put(&nums, 8, 64);
- chash_ii_put(&nums, 11, 121);
+ CMap_ii nums = cmap_init;
+ cmap_ii_put(&nums, 8, 64);
+ cmap_ii_put(&nums, 11, 121);
- printf("get 8: %d\n", chash_ii_get(&nums, 8)->value);
- chash_ii_destroy(&nums);
+ printf("get 8: %d\n", cmap_ii_get(&nums, 8)->value);
+ cmap_ii_destroy(&nums);
}
-declare_CHash_str(si, int); // Shorthand macro for the general declare_CHash expansion.
+declare_CMap_str(si, int); // Shorthand macro for the general declare_CMap expansion.
void mapdemo2()
{
printf("\nMAPDEMO2\n");
- CHash_si nums = chash_init;
- chash_si_put(&nums, "Hello", 64);
- chash_si_put(&nums, "Groovy", 121);
- chash_si_put(&nums, "Groovy", 200); // overwrite previous
+ CMap_si nums = cmap_init;
+ cmap_si_put(&nums, "Hello", 64);
+ cmap_si_put(&nums, "Groovy", 121);
+ cmap_si_put(&nums, "Groovy", 200); // overwrite previous
// iterate the map:
- for (chash_si_iter_t i = chash_si_begin(&nums); i.item; i = chash_si_next(i))
+ for (cmap_si_iter_t i = cmap_si_begin(&nums); i.item; i = cmap_si_next(i))
printf("long: %s: %d\n", i.item->key.str, i.item->value);
// or rather use the short form:
- c_foreach (i, chash_si, nums)
+ c_foreach (i, cmap_si, nums)
printf("short: %s: %d\n", i.item->key.str, i.item->value);
- chash_si_destroy(&nums);
+ cmap_si_destroy(&nums);
}
-declare_CHash_str(ss, CStr, cstr_destroy);
+declare_CMap_str(ss, CStr, cstr_destroy);
void mapdemo3()
{
printf("\nMAPDEMO3\n");
- CHash_ss table = chash_init;
- chash_ss_put(&table, "Map", cstr_make("test"));
- chash_ss_put(&table, "Make", cstr_make("my"));
- chash_ss_put(&table, "Sunny", cstr_make("day"));
- CHashEntry_ss *e = chash_ss_get(&table, "Make");
- printf("size %zu: remove: Make: %s\n", chash_size(table), e->value.str);
- chash_ss_erase(&table, "Make");
- //chash_ss_eraseEntry(&table, e);
-
- printf("size %zu\n", chash_size(table));
- c_foreach (i, chash_ss, table)
+ CMap_ss table = cmap_init;
+ cmap_ss_put(&table, "Map", cstr_make("test"));
+ cmap_ss_put(&table, "Make", cstr_make("my"));
+ cmap_ss_put(&table, "Sunny", cstr_make("day"));
+ CMapEntry_ss *e = cmap_ss_get(&table, "Make");
+ printf("size %zu: remove: Make: %s\n", cmap_size(table), e->value.str);
+ cmap_ss_erase(&table, "Make");
+ //cmap_ss_eraseEntry(&table, e);
+
+ printf("size %zu\n", cmap_size(table));
+ c_foreach (i, cmap_ss, table)
printf("entry: %s: %s\n", i.item->key.str, i.item->value.str);
- chash_ss_destroy(&table); // frees key and value CStrs, and hash table (CVec).
+ cmap_ss_destroy(&table); // frees key and value CStrs, and hash table (CVec).
}
diff --git a/examples/geek1.c b/examples/geek1.c new file mode 100644 index 00000000..2aecaa8d --- /dev/null +++ b/examples/geek1.c @@ -0,0 +1,185 @@ +// https://www.geeksforgeeks.org/maximize-the-number-of-sum-pairs-which-are-divisible-by-k/
+// Given an array of N integers and an integer K. The task is to print the maximum number
+// of pairs(a[i] + a[j]) possible which are divisible by K.
+
+
+int a[] = { 1, 2, 2, 3, 2, 4, 10 };
+//int a[] = { 1, 2, 2, 3, 2, 4, 10, 8, 9, 3, 2, 4 };
+
+
+#ifndef __cplusplus
+// C program to implement the above approach
+#include <stdio.h>
+#include <stc/chash.h>
+
+declare_CMap(ii, int, int);
+
+// Function to maximize the number of pairs
+int findMaximumPairs(int a[], int n, int k)
+{
+
+ // Hash-table
+ CMap_ii hash = cmap_init;
+ for (int i = 0; i < n; i++) {
+ cmap_ii_at(&hash, a[i] % k, 0)->value++;
+ }
+
+ int count = 0;
+
+ // Iterate for all numbers less than hash values
+ c_foreach (it, cmap_ii, hash) {
+
+ // If the number is 0
+ if (it.item->key == 0) {
+ // We take half since same number
+ count += it.item->value / 2;
+ cmap_ii_put(&hash, it.item->key, it.item->key & 1);
+ } else {
+ int first = it.item->key;
+ int second = k - it.item->key;
+
+ CMapEntry_ii *hf = cmap_ii_get(&hash, first),
+ *hs = cmap_ii_at(&hash, second, 0);
+ // Check for minimal occurrence
+ if (hf->value < hs->value) {
+ // Take the minimal
+ count += hf->value;
+
+ // Subtract the pairs used
+ hs->value -= hf->value;
+ hf->value = 0;
+ }
+ else if (hf->value > hs->value) {
+ // Take the minimal
+ count += hs->value;
+
+ // Subtract the pairs used
+ hf->value -= hs->value;
+ hs->value = 0;
+ }
+ else {
+ // Check if numbers are same
+ if (first == second) {
+
+ // If same then number of pairs will be half
+ count += it.item->value / 2;
+
+ // Check for remaining
+ hf->value = (it.item->key & 1);
+ }
+ else {
+ // Store the number of pairs
+ count += hf->value;
+ hf->value = 0;
+ hs->value = 0;
+ }
+ }
+ }
+ }
+
+ return count;
+}
+
+// Driver code
+int main()
+{
+ int n = sizeof(a) / sizeof(a[0]);
+ int k = 2;
+ printf("C : %d\n", findMaximumPairs(a, n, k));
+
+ return 0;
+}
+
+
+#else
+
+
+// C++ program to implement the above
+// approach
+#include <bits/stdc++.h>
+using namespace std;
+
+// Function to maximize the number of pairs
+int findMaximumPairs(int a[], int n, int k)
+{
+
+ // Hash-table
+ unordered_map<int, int> hash;
+ for (int i = 0; i < n; i++)
+ hash[a[i] % k]++;
+
+ int count = 0;
+
+ // Iterate for all numbers less than hash values
+ for (auto it : hash) {
+
+ // If the number is 0
+ if (it.first == 0) {
+
+ // We take half since same number
+ count += it.second / 2;
+ if (it.first % 2 == 0)
+ hash[it.first] = 0;
+ else
+ hash[it.first] = 1;
+ }
+ else {
+
+ int first = it.first;
+ int second = k - it.first;
+
+ // Check for minimal occurrence
+ if (hash[first] < hash[second]) {
+ // Take the minimal
+ count += hash[first];
+
+ // Subtract the pairs used
+ hash[second] -= hash[first];
+ hash[first] = 0;
+ }
+ else if (hash[first] > hash[second]) {
+ // Take the minimal
+ count += hash[second];
+
+ // Subtract the pairs used
+ hash[first] -= hash[second];
+ hash[second] = 0;
+ }
+ else {
+ // Check if numbers are same
+ if (first == second) {
+
+ // If same then number of pairs will be half
+ count += it.second / 2;
+
+ // Check for remaining
+ if (it.first % 2 == 0)
+ hash[it.first] = 0;
+ else
+ hash[it.first] = 1;
+ }
+ else {
+
+ // Store the number of pairs
+ count += hash[first];
+ hash[first] = 0;
+ hash[second] = 0;
+ }
+ }
+ }
+ }
+
+ return count;
+}
+
+// Driver code
+int main()
+{
+ int n = sizeof(a) / sizeof(a[0]);
+ int k = 2;
+ cout << "C++ : " << findMaximumPairs(a, n, k);
+
+ return 0;
+}
+
+#endif
\ No newline at end of file diff --git a/examples/geek2.c b/examples/geek2.c new file mode 100644 index 00000000..53688dd3 --- /dev/null +++ b/examples/geek2.c @@ -0,0 +1,122 @@ +#ifndef __cplusplus
+
+#include <stc/chash.h>
+#include <stc/cstring.h>
+
+declare_CMap_str(ss, CStr, cstr_destroy);
+declare_CSet_str(ss);
+
+int main()
+{
+ // Lets use an explicit type signature (which would
+ // be `CMap<String, String>` in this example).
+ CMap_ss book_reviews = cmap_init;
+ CSet_ss set = cset_init;
+ cset_ss_put(&set, "Hello");
+ cset_ss_put(&set, "You");
+ cset_ss_put(&set, "Tube");
+ c_foreach (i, cset_ss, set)
+ printf("%s ", i.item->key.str); puts("");
+
+ // Review some books.
+ cmap_ss_put(&book_reviews,
+ "Adventures of Huckleberry Finn",
+ cstr_make("My favorite book.")
+ );
+ cmap_ss_put(&book_reviews,
+ "Grimms' Fairy Tales",
+ cstr_make("Masterpiece.")
+ );
+ cmap_ss_put(&book_reviews,
+ "Pride and Prejudice",
+ cstr_make("Very enjoyable.")
+ );
+ cmap_ss_put(&book_reviews,
+ "The Adventures of Sherlock Holmes",
+ cstr_make("Eye lyked it alot.")
+ );
+
+ // Check for a specific one.
+ // When collections store owned values (String), they can still be
+ // queried using references (&str).
+ if (! cmap_ss_get(&book_reviews, "Les Misérables")) {
+ printf("We've got %zu reviews, but Les Misérables ain't one.\n",
+ book_reviews.size);
+ }
+
+ // oops, this review has a lot of spelling mistakes, let's delete it.
+ cmap_ss_erase(&book_reviews, "The Adventures of Sherlock Holmes");
+
+ // Look up the values associated with some keys.
+ const char* to_find[] = {"Pride and Prejudice", "Alice's Adventure in Wonderland", NULL};
+ for (const char** book = to_find; *book; ++book) {
+ CMapEntry_ss* review = cmap_ss_get(&book_reviews, *book);
+ if (review) printf("%s: %s\n", *book, review->value.str);
+ else printf("%s is unreviewed.\n", *book);
+ }
+
+ // Look up the value for a key (will panic if the key is not found).
+ printf("Review for Jane: %s\n", cmap_ss_get(&book_reviews, "Pride and Prejudice")->value.str);
+
+ // Iterate over everything.
+ c_foreach (i, cmap_ss, book_reviews) {
+ printf("- %s: \"%s\"\n", i.item->key.str, i.item->value.str);
+ }
+ cmap_ss_destroy(&book_reviews);
+}
+
+#else // ======================================================
+
+use std::collections::HashMap;
+
+// Type inference lets us omit an explicit type signature (which
+// would be `HashMap<String, String>` in this example).
+let mut book_reviews = HashMap::new();
+
+// Review some books.
+book_reviews.insert(
+ "Adventures of Huckleberry Finn".to_str(),
+ "My favorite book.".to_str(),
+);
+book_reviews.insert(
+ "Grimms' Fairy Tales".to_str(),
+ "Masterpiece.".to_str(),
+);
+book_reviews.insert(
+ "Pride and Prejudice".to_str(),
+ "Very enjoyable.".to_str(),
+);
+book_reviews.insert(
+ "The Adventures of Sherlock Holmes".to_str(),
+ "Eye lyked it alot.".to_str(),
+);
+
+// Check for a specific one.
+// When collections store owned values (String), they can still be
+// queried using references (&str).
+if !book_reviews.contains_key("Les Misérables") {
+ println!("We've got {} reviews, but Les Misérables ain't one.",
+ book_reviews.len());
+}
+
+// oops, this review has a lot of spelling mistakes, let's delete it.
+book_reviews.remove("The Adventures of Sherlock Holmes");
+
+// Look up the values associated with some keys.
+let to_find = ["Pride and Prejudice", "Alice's Adventure in Wonderland"];
+for &book in &to_find {
+ match book_reviews.get(book) {
+ Some(review) => println!("{}: {}", book, review),
+ None => println!("{} is unreviewed.", book)
+ }
+}
+
+// Look up the value for a key (will panic if the key is not found).
+println!("Review for Jane: {}", book_reviews["Pride and Prejudice"]);
+
+// Iterate over everything.
+for (book, review) in &book_reviews {
+ println!("{}: \"{}\"", book, review);
+}
+
+#endif
\ No newline at end of file diff --git a/examples/geek3.c b/examples/geek3.c new file mode 100644 index 00000000..ec58ccea --- /dev/null +++ b/examples/geek3.c @@ -0,0 +1,50 @@ +// xx3.c
+
+#include <stc/chash.h>
+#include <stc/cstring.h>
+
+declare_CMap_str(si, int);
+declare_CMap_str(ss, CStr, cstr_destroy);
+
+int main ()
+{
+ CMap_si mymap = cmap_init;
+ cmap_si_put(&mymap, "Mars", 3000);
+ cmap_si_put(&mymap, "Saturn", 60000);
+ cmap_si_put(&mymap, "Jupiter", 70000);
+
+ // ...
+ cmap_si_put(&mymap, "Mars", 3396);
+ cmap_si_at(&mymap, "Saturn", 0)->value += 272;
+ cmap_si_put(&mymap, "Jupiter", cmap_si_at(&mymap, "Saturn", 0)->value + 9638);
+ cmap_si_at(&mymap, "Sun", 0)->value += 1000;
+ cmap_si_at(&mymap, "Sun", 0)->value += 1000;
+
+ c_foreach (x, cmap_si, mymap) {
+ printf("%s: %d\n", x.item->key.str, x.item->value);
+ }
+ cmap_si_destroy(&mymap);
+
+ puts("------------------------");
+
+ // Create an unordered_map of three strings (that map to strings)
+ CMap_ss u = cmap_init;
+ cmap_ss_put(&u, "RED", cstr_make("#FF0000"));
+ cmap_ss_put(&u, "GREEN", cstr_make("#00FF00"));
+ cmap_ss_put(&u, "BLUE", cstr_make("#0000FF"));
+
+ // Iterate and print keys and values of unordered_map
+ c_foreach (n, cmap_ss, u) {
+ printf("%s: %s\n", n.item->key.str, n.item->value.str);
+ }
+
+ // Add two new entries to the unordered_map
+ cmap_ss_put(&u, "BLACK", cstr_make("#000000"));
+ cmap_ss_put(&u, "WHITE", cstr_make("#FFFFFF"));
+
+ // Output values by key
+ printf("The HEX of color RED is:[%s]\n", cmap_ss_get(&u, "RED")->value.str);
+ printf("The HEX of color BLACK is:[%s]\n", cmap_ss_get(&u, "BLACK")->value.str);
+ cmap_ss_destroy(&u);
+ return 0;
+}
\ No newline at end of file diff --git a/examples/geek4.c b/examples/geek4.c new file mode 100644 index 00000000..c514e601 --- /dev/null +++ b/examples/geek4.c @@ -0,0 +1,262 @@ +// https://www.geeksforgeeks.org/count-of-words-that-are-present-in-all-the-given-sentences/
+// https://www.geeksforgeeks.org/tag/cpp-unordered_map/
+/*
+Count of words that are present in all the given sentences
+Given n sentences. The task is to count the number of words that appear in all of these
+sentences. Note that every word consists of only lowercase English alphabets.
+
+Examples:
+
+Input: arr[] = {
+ "there is a cow",
+ "cow is our mother",
+ "cow gives us milk and milk is sweet",
+ "there is a boy who loves cow"}
+Output: 2
+Only the words "is" and "cow" appear in all of the sentences.
+
+Input: arr[] = {
+ "abc aac abcd ccc",
+ "ac aa abc cca",
+ "abca aaac abcd ccc"}
+Output: 0
+
+Naive Approach: The naive approach is to take every word of the first sentence and compare it
+ with rest of the lines if it is also present in all lines then increment the count.
+
+
+Efficient Approach: For all the words of the first sentence, we can check if it is also present in
+ all the other sentences in constant time by using a map. Store all the words
+ of the first sentence in a map and check how many of these stored words are
+ present in all of the other sentences.
+*/
+#ifndef __cplusplus
+// C implementation of the approach
+
+#include <stc/chash.h>
+#include <stc/cvector.h>
+#include <stc/cstring.h>
+
+declare_CVec_str(s);
+declare_CMap_str(sb, bool);
+declare_CVec(sb, CMapEntry_sb, cmapentry_sb_destroy, c_noCompare);
+
+// Function to return the count of common words
+// in all the sentences
+int commonWords(CVec_s S)
+{
+ int m, n, i, j;
+
+
+ // To store all the words of first string
+ CVec_sb ans = cvec_init;
+
+ // m will store number of strings in given vector
+ m = cvec_size(S);
+
+ i = 0;
+
+ // Extract all words of first string and store it in ans
+ while (i < cstr_size(S.data[0])) {
+ // To store separate words
+ CStr word = cstr_init;
+ CMapEntry_sb tmp = {cstr_init, false};
+
+ while (i < cstr_size(S.data[0]) && S.data[0].str[i] != ' ') {
+ cstr_appendC(&word, S.data[0].str[i]);
+ i++;
+ }
+
+ // Increase i to get at starting index
+ // of the next word
+ i++;
+
+ // If str is not empty store it in map
+ if (!cstr_empty(word)) {
+ tmp.key = cstr_move(&word);
+ tmp.value = true;
+ cvec_sb_pushBack(&ans, tmp);
+ }
+ }
+
+ // Start from 2nd line check if any word of
+ // the first string did not match with
+ // some word in the current line
+ for (j = 1; j < m; j++) {
+ // It will be used to check if a word is present
+ // in a particuler string
+ CMap_sb has = cmap_init;
+ i = 0;
+
+ while (i < cstr_size(S.data[j])) {
+ CStr word = cstr_init;
+ while (i < cstr_size(S.data[j]) && S.data[j].str[i] != ' ') {
+ cstr_appendC(&word, S.data[j].str[i]);
+ i++;
+ }
+ i++;
+ if (!cstr_empty(word)) {
+ cmap_sb_put(&has, word.str, true);
+ }
+ cstr_destroy(&word);
+ }
+
+ // Check all words of this vector
+ // if it is not present in current line
+ // make it false
+ for (int k = 0; k < cvec_size(ans); k++) {
+ if (ans.data[k].value != false
+ && cmap_sb_at(&has, ans.data[k].key.str, false)->value == false) {
+ ans.data[k].value = false;
+ }
+
+ // This line is used to consider only distinct words
+ else if (ans.data[k].value != false
+ && cmap_sb_at(&has, ans.data[k].key.str, false)->value == true) {
+ cmap_sb_put(&has, ans.data[k].key.str, false);
+ }
+ }
+ cmap_sb_destroy(&has);
+ }
+
+ // This function will print
+ // the count of common words
+ int cnt = 0;
+
+ // If current word appears in all the sentences
+ for (int k = 0; k < cvec_size(ans); k++) {
+ if (ans.data[k].value == true)
+ cnt++;
+ }
+
+ cvec_sb_destroy(&ans);
+ return cnt;
+}
+
+// Driver code
+int main()
+{
+ CVec_s S = cvec_init;
+ cvec_s_pushBack(&S, cstr_make("there is a cow"));
+ cvec_s_pushBack(&S, cstr_make("cow is our mother"));
+ cvec_s_pushBack(&S, cstr_make("cow gives us milk and milk is sweet"));
+ cvec_s_pushBack(&S, cstr_make("there is a boy who loves cow"));
+
+ printf("%d\n", commonWords(S));
+ cvec_s_destroy(&S);
+ return 0;
+}
+
+
+#else // ========================= c++ =======================
+
+
+// C++ implementation of the approach
+#include <bits/stdc++.h>
+using namespace std;
+
+// Function to return the count of common words
+// in all the sentences
+int commonWords(vector<string> S)
+{
+ int m, n, i, j;
+
+ // To store separate words
+ string word;
+
+ // It will be used to check if a word is present
+ // in a particuler string
+ unordered_map<string, bool> has;
+
+ // To store all the words of first string
+ vector<pair<string, bool> > ans;
+
+ pair<string, bool> tmp;
+
+ // m will store number of strings in given vector
+ m = S.size();
+
+ i = 0;
+
+ // Extract all words of first string and store it in ans
+ while (i < S[0].size()) {
+ word = "";
+ while (i < S[0].size() && S[0][i] != ' ') {
+ word += S[0][i];
+ i++;
+ }
+
+ // Increase i to get at starting index
+ // of the next word
+ i++;
+
+ // If word is not empty store it in map
+ if (word != "") {
+ tmp = make_pair(word, true);
+ ans.push_back(tmp);
+ }
+ }
+
+ // Start from 2nd line check if any word of
+ // the first string did not match with
+ // some word in the current line
+ for (j = 1; j < m; j++) {
+ has.clear();
+ i = 0;
+
+ while (i < S[j].size()) {
+ word = "";
+ while (i < S[j].size() && S[j][i] != ' ') {
+ word += S[j][i];
+ i++;
+ }
+ i++;
+ if (word != "") {
+ has[word] = true;
+ }
+ }
+
+ // Check all words of this vector
+ // if it is not present in current line
+ // make it false
+ for (int k = 0; k < ans.size(); k++) {
+ if (ans[k].second != false
+ && has[ans[k].first] == false) {
+ ans[k].second = false;
+ }
+
+ // This line is used to consider only distinct words
+ else if (ans[k].second != false
+ && has[ans[k].first] == true) {
+ has[ans[k].first] = false;
+ }
+ }
+ }
+
+ // This function will print
+ // the count of common words
+ int cnt = 0;
+
+ // If current word appears in all the sentences
+ for (int k = 0; k < ans.size(); k++) {
+ if (ans[k].second == true)
+ cnt++;
+ }
+
+ return cnt;
+}
+
+// Driver code
+int main()
+{
+ vector<string> S;
+ S.push_back("there is a cow");
+ S.push_back("cow is our mother");
+ S.push_back("cow gives us milk and milk is sweet");
+ S.push_back("there is a boy who loves cow");
+
+ cout << commonWords(S);
+
+ return 0;
+}
+#endif
\ No newline at end of file diff --git a/examples/geek5.c b/examples/geek5.c new file mode 100644 index 00000000..759d22e3 --- /dev/null +++ b/examples/geek5.c @@ -0,0 +1,140 @@ +/*
+https://www.geeksforgeeks.org/number-of-times-the-given-string-occurs-in-the-array-in-the-range-l-r/
+
+Number of times the given string occurs in the array in the range [l, r]
+Given an array of strings arr[] and two integers l and r, the task is to find the number of times
+the given string str occurs in the array in the range [l, r] (1-based indexing). Note that the
+strings contain only lowercase letters.
+
+Examples:
+
+Input: arr[] = {"abc", "def", "abc"}, L = 1, R = 2, str = "abc"
+Output: 1
+
+Input: arr[] = {"abc", "def", "abc"}, L = 1, R = 3, str = "ghf"
+Output: 0
+*/
+
+#ifndef __cplusplus
+
+#include <stc/chash.h>
+#include <stc/cvector.h>
+#include <stc/cstring.h>
+
+declare_CVec(i, int);
+declare_CMap_str(sv, CVec_i, cvec_i_destroy);
+
+
+// Function to return the number of occurrences of
+int NumOccurrences(const char* arr[], int n, const char* str, int L, int R)
+{
+ // To store the indices of strings in the array
+ CMap_sv M = cmap_init;
+ for (int i = 0; i < n; i++) {
+ const char* temp = arr[i];
+ CMapEntry_sv* it = cmap_sv_get(&M, temp);
+
+ // If current string doesn't
+ // have an entry in the map
+ // then create the entry
+ if (it == NULL) {
+ CVec_i A = cvec_init;
+ cvec_i_pushBack(&A, i + 1);
+ cmap_sv_put(&M, temp, A);
+ }
+ else {
+ cvec_i_pushBack(&it->value, i + 1);
+ }
+ }
+
+ CMapEntry_sv* it = cmap_sv_get(&M, str);
+
+ // If the given string is not
+ // present in the array
+ if (it == NULL)
+ return 0;
+
+ // If the given string is present
+ // in the array
+ CVec_i A = it->value;
+ int y = 0, x = 0;
+ for (; y < cvec_size(A); ++y) if (A.data[y] > R) break;
+ for (; x < cvec_size(A); ++x) if (A.data[x] > L - 1) break;
+
+ cmap_sv_destroy(&M);
+ return (y - x);
+}
+
+// Driver code
+int main()
+{
+ const char* arr[] = { "abc", "abcabc", "abc" };
+ int n = sizeof(arr) / sizeof(*arr);
+ int L = 1;
+ int R = 3;
+ const char* str = "abc";
+
+ printf("%d\n", NumOccurrences(arr, n, str, L, R));
+
+ return 0;
+}
+
+#else // =============================== c++ ==================================
+
+// C++ implementation of the approach
+#include <bits/stdc++.h>
+using namespace std;
+
+// Function to return the number of occurrences of
+int NumOccurrences(string arr[], int n, string str, int L, int R)
+{
+ // To store the indices of strings in the array
+ unordered_map<string, vector<int> > M;
+ for (int i = 0; i < n; i++) {
+ string temp = arr[i];
+ auto it = M.find(temp);
+
+ // If current string doesn't
+ // have an entry in the map
+ // then create the entry
+ if (it == M.end()) {
+ vector<int> A;
+ A.push_back(i + 1);
+ M.insert(make_pair(temp, A));
+ }
+ else {
+ it->second.push_back(i + 1);
+ }
+ }
+
+ auto it = M.find(str);
+
+ // If the given string is not
+ // present in the array
+ if (it == M.end())
+ return 0;
+
+ // If the given string is present
+ // in the array
+ vector<int> A = it->second;
+ int y = upper_bound(A.begin(), A.end(), R) - A.begin();
+ int x = upper_bound(A.begin(), A.end(), L - 1) - A.begin();
+
+ return (y - x);
+}
+
+// Driver code
+int main()
+{
+ string arr[] = { "abc", "abcabc", "abc" };
+ int n = sizeof(arr) / sizeof(string);
+ int L = 1;
+ int R = 3;
+ string str = "abc";
+
+ cout << NumOccurrences(arr, n, str, L, R);
+
+ return 0;
+}
+
+#endif
\ No newline at end of file diff --git a/examples/geek6.c b/examples/geek6.c new file mode 100644 index 00000000..369867e9 --- /dev/null +++ b/examples/geek6.c @@ -0,0 +1,124 @@ +// https://www.geeksforgeeks.org/find-the-smallest-positive-number-missing-from-an-unsorted-array-hashing-implementation/
+/*
+Find the smallest positive number missing from an unsorted array : Hashing Implementation
+Given an unsorted array with both positive and negative elements including 0. The task is
+to find the smallest positive number missing from the array in O(N) time.
+
+Examples:
+
+Input: arr[] = {-5, 2, 0, -1, -10, 15}
+Output: 1
+
+Input: arr[] = {0, 1, 2, 3, 4, 5}
+Output: 6
+
+Input: arr[] = {1, 1, 1, 0, -1, -2}
+Output: 2
+
+We can use hashing to solve this problem. The idea is to build a hash table of all positive
+elements in the given array. Once the hash table is built. We can look in the hash table for
+all positive integers, starting from 1. As soon as we find a number which is not there in the
+hash table, we return it.
+We can use the unordered_map in C++ to implement the hash which allow to perform look up
+operation in almost O(1) time complexity.
+*/
+
+#ifndef __cplusplus
+
+// C program to find the smallest
+// positive missing number
+
+#include <stdio.h>
+#include <stc/chash.h>
+declare_CSet(i, int);
+
+// Function to find the smallest positive
+// missing number
+int missingNumber(int a[], int n)
+{
+ // Declaring an unordered_map
+ CSet_i mp = cset_init;
+
+ // if array value is positive
+ // store it in map
+ for (int i = 0; i < n; i++) {
+ if (a[i] > 0)
+ cset_i_put(&mp, a[i]);
+ }
+
+ // index value set to 1
+ int index = 1;
+
+ // Return the first value starting
+ // from 1 which does not exists in map
+ while (1) {
+ if (cset_i_get(&mp, index) == NULL) {
+ return index;
+ }
+
+ index++;
+ }
+ cset_i_destroy(&mp);
+}
+
+// Driver code
+int main()
+{
+ int a[] = { 1, 1, 1, 0, -1, -2 };
+ int size = sizeof(a) / sizeof(a[0]);
+
+ printf("Smallest positive missing number is : %d\n",
+ missingNumber(a, size));
+
+ return 0;
+}
+
+#else
+
+// C++ program to find the smallest
+// positive missing number
+
+#include <bits/stdc++.h>
+using namespace std;
+
+// Function to find the smallest positive
+// missing number
+int missingNumber(int a[], int n)
+{
+ // Declaring an unordered_map
+ unordered_map<int, int> mp;
+
+ // if array value is positive
+ // store it in map
+ for (int i = 0; i < n; i++) {
+ if (a[i] > 0)
+ mp[a[i]]++;
+ }
+
+ // index value set to 1
+ int index = 1;
+
+ // Return the first value starting
+ // from 1 which does not exists in map
+ while (1) {
+ if (mp.find(index) == mp.end()) {
+ return index;
+ }
+
+ index++;
+ }
+}
+
+// Driver code
+int main()
+{
+ int a[] = { 1, 1, 1, 0, -1, -2 };
+ int size = sizeof(a) / sizeof(a[0]);
+
+ cout << "Smallest positive missing number is : "
+ << missingNumber(a, size) << endl;
+
+ return 0;
+}
+
+#endif
\ No newline at end of file diff --git a/examples/mapmap.c b/examples/mapmap.c new file mode 100644 index 00000000..77c71fe9 --- /dev/null +++ b/examples/mapmap.c @@ -0,0 +1,20 @@ +
+#include <stdio.h>
+#include <stc/chash.h>
+
+static void test_destr(int* x) {
+ printf("destroy int: %d\n", *x);
+}
+
+declare_CMap(ii, int, int, test_destr);
+declare_CMap(im, int, CMap_ii, cmap_ii_destroy);
+
+int main(void) {
+ CMap_im m = cmap_init;
+ CMap_ii x = cmap_init;
+ cmap_ii_put(&cmap_im_put(&m, 100, x)->value, 200, 300);
+ cmap_ii_put(&cmap_im_get(&m, 100)->value, 200, 400); // update
+ cmap_ii_put(&cmap_im_put(&m, 110, x)->value, 200, 500);
+
+ cmap_im_destroy(&m);
+}
\ No newline at end of file diff --git a/examples/prime.c b/examples/prime.c new file mode 100644 index 00000000..65b51057 --- /dev/null +++ b/examples/prime.c @@ -0,0 +1,45 @@ +#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "stc/cvector.h"
+
+static inline void setBit(uint32_t* a, const size_t i) { a[i >> 5] |= 1u << (i & 31); }
+static inline void clearBit(uint32_t* a, const size_t i) { a[i >> 5] &= ~(1u << (i & 31)); }
+static inline bool testBit(uint32_t* a, const size_t i) { return (a[i >> 5] & (1u << (i & 31))) != 0; }
+
+declare_CVec(i, uint32_t);
+
+static inline void sieveOfEratosthenes(size_t n)
+{
+ CVec_i prime = cvec_i_make((n >> 5) + 1, 0xffffffff);
+
+ printf("n: %zu, ints: %zu\n", n, cvec_size(prime));
+ clearBit(prime.data, 0);
+ clearBit(prime.data, 1);
+
+ for (size_t i = 2; i <= n; ++i)
+ {
+ // If prime[i] is not changed, then it is a prime
+ if (testBit(prime.data, i) && i*i <= n)
+ {
+ for (size_t j = i*i; j <= n; j += i) {
+ clearBit(prime.data, j);
+ }
+ }
+ }
+ puts("done");
+ // Print all prime numbers
+ size_t count = 0;
+ for (size_t i = 1; i <= n; ++i)
+ if (testBit(prime.data, i)) ++count; // printf("%zu\n", i);
+
+ printf("primes: %zu\n", count);
+ cvec_i_destroy(&prime);
+}
+
+int main(void)
+{
+ sieveOfEratosthenes(1000000000);
+}
\ No newline at end of file diff --git a/stc/chash.h b/stc/chash.h index e6143b5e..050907d3 100644 --- a/stc/chash.h +++ b/stc/chash.h @@ -24,209 +24,219 @@ /* // Example:
#include <stdio.h>
#include <stc/chash.h>
-declare_CHash(sx, int); // Set of int
-declare_CHash(mx, int, char); // Map of int -> char
+declare_CSet(sx, int); // Set of int
+declare_CMap(mx, int, char); // Map of int -> char
int main(void) {
- CHash_sx s = chash_init;
- chash_sx_put(&s, 5);
- chash_sx_put(&s, 8);
- c_foreach (i, chash_sx, s) printf("set %d\n", i.item->key);
- chash_mx_destroy(&s);
+ CSet_sx s = cset_init;
+ cset_sx_put(&s, 5);
+ cset_sx_put(&s, 8);
+ c_foreach (i, cset_sx, s) printf("set %d\n", i.item->key);
+ cset_sx_destroy(&s);
- CHash_mx m = chash_init;
- chash_mx_put(&m, 5, 'a');
- chash_mx_put(&m, 8, 'b');
- chash_mx_put(&m, 12, 'c');
- CHashEntry_mx *e = chash_mx_get(&m, 10); // = NULL
- char val = chash_mx_get(&m, 5)->value;
- chash_mx_put(&m, 5, 'd'); // update
- chash_mx_erase(&m, 8);
- c_foreach (i, chash_mx, m) printf("map %d: %c\n", i.item->key, i.item->value);
- chash_mx_destroy(&m);
+ CMap_mx m = cmap_init;
+ cmap_mx_put(&m, 5, 'a');
+ cmap_mx_put(&m, 8, 'b');
+ cmap_mx_put(&m, 12, 'c');
+ CMapEntry_mx *e = cmap_mx_get(&m, 10); // = NULL
+ char val = cmap_mx_get(&m, 5)->value;
+ cmap_mx_put(&m, 5, 'd'); // update
+ cmap_mx_erase(&m, 8);
+ c_foreach (i, cmap_mx, m) printf("map %d: %c\n", i.item->key, i.item->value);
+ cmap_mx_destroy(&m);
}
*/
-
#ifndef CHASH__H__
#define CHASH__H__
#include <stdlib.h>
#include "cdefs.h"
-#define chash_init {NULL, NULL, 0, 0, 0.85f, 0.15f}
-#define chash_size(map) ((size_t) (map).size)
-#define chash_bucketCount(map) ((size_t) (map).buckets)
-#define chash_entryIndex(map, entryPtr) ((entryPtr) - (map).table)
+#define cmap_init {NULL, NULL, 0, 0, 0.85f, 0.15f}
+#define cmap_size(m) ((size_t) (m).size)
+#define cmap_bucketCount(m) ((size_t) (m).buckets)
+#define cset_init cmap_init
+#define cset_size(s) cmap_size(s)
+#define cset_bucketCount(s) cmap_bucketCount(s)
+
/* https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction */
-#define chash_reduce(x, N) ((uint32_t) (((uint64_t) (x) * (N)) >> 32))
+#define chash_reduce(x, N) ((uint32_t) (((uint64_t) (x) * (N)) >> 32))
+#define chash_entryIndex(h, entryPtr) ((entryPtr) - (h).table)
enum {chash_HASH = 0x7f, chash_USED = 0x80};
-#define declare_CHash(...) \
- c_MACRO_OVERLOAD(declare_CHash, __VA_ARGS__)
+#define declare_CMap(...) \
+ c_MACRO_OVERLOAD(declare_CMap, __VA_ARGS__)
+
+#define declare_CMap_3(tag, Key, Value) \
+ declare_CMap_4(tag, Key, Value, c_emptyDestroy)
-#define declare_CHash_2(tag, Key) \
- declare_CHash_set_2(tag, Key)
+#define declare_CMap_4(tag, Key, Value, valueDestroy) \
+ declare_CMap_5(tag, Key, Value, valueDestroy, c_defaultHash)
-#define declare_CHash_3(tag, Key, Value) \
- declare_CHash_6(tag, Key, Value, c_emptyDestroy, c_defaultHash, c_defaultEquals)
+#define declare_CMap_5(tag, Key, Value, valueDestroy, keyHash) \
+ declare_CMap_6(tag, Key, Value, valueDestroy, keyHash, c_defaultEquals)
-#define declare_CHash_4(tag, Key, Value, valueDestroy) \
- declare_CHash_6(tag, Key, Value, valueDestroy, c_defaultHash, c_defaultEquals)
+#define declare_CMap_6(tag, Key, Value, valueDestroy, keyHash, keyEquals) \
+ declare_CMap_10(tag, Key, Value, valueDestroy, keyHash, keyEquals, \
+ c_emptyDestroy, Key, c_defaultGetRaw, c_defaultInitRaw)
-#define declare_CHash_5(tag, Key, Value, valueDestroy, keyHash) \
- declare_CHash_6(tag, Key, Value, valueDestroy, keyHash, c_defaultEquals)
+#define declare_CMap_10(tag, Key, Value, valueDestroy, keyHashRaw, keyEqualsRaw, \
+ keyDestroy, RawKey, keyGetRaw, keyInitRaw) \
+ declare_CHASH(tag, CMap, cmap, Key, Value, valueDestroy, keyHashRaw, keyEqualsRaw, \
+ keyDestroy, RawKey, keyGetRaw, keyInitRaw)
-#define declare_CHash_6(tag, Key, Value, valueDestroy, keyHash, keyEquals) \
- declare_CHash_11(tag, MAP, Key, Value, valueDestroy, keyHash, keyEquals, \
- c_emptyDestroy, Key, c_defaultGetRaw, c_defaultInitRaw)
+/* CSet: */
+#define declare_CSet(...) \
+ c_MACRO_OVERLOAD(declare_CSet, __VA_ARGS__)
-/* CHash_set: */
-#define declare_CHash_set(...) \
- c_MACRO_OVERLOAD(declare_CHash_set, __VA_ARGS__)
+#define declare_CSet_2(tag, Key) \
+ declare_CSet_3(tag, Key, c_emptyDestroy)
-#define declare_CHash_set_2(tag, Key) \
- declare_CHash_set_5(tag, Key, c_emptyDestroy, c_defaultHash, c_defaultEquals)
+#define declare_CSet_3(tag, Key, keyDestroy) \
+ declare_CSet_4(tag, Key, keyDestroy, c_defaultHash)
-#define declare_CHash_set_3(tag, Key, keyDestroy) \
- declare_CHash_set_5(tag, Key, keyDestroy, c_defaultHash, c_defaultEquals)
+#define declare_CSet_4(tag, Key, keyDestroy, keyHash) \
+ declare_CSet_5(tag, Key, keyDestroy, keyHash, c_defaultEquals)
-#define declare_CHash_set_4(tag, Key, keyDestroy, keyHash) \
- declare_CHash_set_5(tag, Key, keyDestroy, keyHash, c_defaultEquals)
+#define declare_CSet_5(tag, Key, keyDestroy, keyHash, keyEquals) \
+ declare_CSet_8(tag, Key, keyDestroy, keyHash, keyEquals, \
+ Key, c_defaultGetRaw, c_defaultInitRaw)
-#define declare_CHash_set_5(tag, Key, keyDestroy, keyHash, keyEquals) \
- declare_CHash_11(tag, SET, Key, void, void, keyHash, keyEquals, \
- keyDestroy, Key, c_defaultGetRaw, c_defaultInitRaw)
+#define declare_CSet_8(tag, Key, keyDestroy, keyHashRaw, keyEqualsRaw, \
+ RawKey, keyGetRaw, keyInitRaw) \
+ declare_CHASH(tag, CSet, cset, Key, void, void, keyHashRaw, keyEqualsRaw, \
+ keyDestroy, RawKey, keyGetRaw, keyInitRaw)
-/* CHash_string: */
-#define declare_CHash_str(...) \
- c_MACRO_OVERLOAD(declare_CHash_string, __VA_ARGS__)
+/* CSet_str, CMap_str: */
+#define declare_CSet_str(tag) \
+ declare_CMAPSTR(tag, CSet, cset, void, void)
-#define declare_CHash_string_1(tag) \
- declare_CHash_string_4(tag, SET, void, void)
+#define declare_CMap_str(...) \
+ c_MACRO_OVERLOAD(declare_CMap_str, __VA_ARGS__)
-#define declare_CHash_string_2(tag, Value) \
- declare_CHash_string_4(tag, MAP, Value, c_emptyDestroy)
+#define declare_CMap_str_2(tag, Value) \
+ declare_CMAPSTR(tag, CMap, cmap, Value, c_emptyDestroy)
-#define declare_CHash_string_3(tag, Value, ValueDestroy) \
- declare_CHash_string_4(tag, MAP, Value, ValueDestroy)
+#define declare_CMap_str_3(tag, Value, ValueDestroy) \
+ declare_CMAPSTR(tag, CMap, cmap, Value, ValueDestroy)
-#define declare_CHash_string_4(tag, type, Value, valueDestroy) \
- declare_CHash_11(tag, type, CStr, Value, valueDestroy, cstr_hashRaw, cstr_equalsRaw, \
- cstr_destroy, const char*, cstr_getRaw, cstr_make)
+#define declare_CMAPSTR(tag, CType, ctype, Value, valueDestroy) \
+ declare_CHASH(tag, CType, ctype, CStr, Value, valueDestroy, cstr_hashRaw, \
+ cstr_equalsRaw, cstr_destroy, const char*, cstr_getRaw, cstr_make)
-#define _chash1_SET(x)
-#define _chash2_SET(x, y) x
-#define _chash1_MAP(x) x
-#define _chash2_MAP(x, y) x, y
+#define OPT_1_cset(x)
+#define OPT_2_cset(x, y) x
+#define OPT_1_cmap(x) x
+#define OPT_2_cmap(x, y) x, y
-/* CHash full: use 'void' for Value if type is SET */
-#define declare_CHash_11(tag, type, Key, Value, valueDestroy, keyHashRaw, keyEqualsRaw, \
- keyDestroy, RawKey, keyGetRaw, keyInitRaw) \
-typedef struct CHashEntry_##tag { \
+/* CHASH full: use 'void' for Value if <CType, ctype> is <CSet, cset> */
+#define declare_CHASH(tag, CType, ctype, Key, Value, valueDestroy, keyHashRaw, keyEqualsRaw, \
+ keyDestroy, RawKey, keyGetRaw, keyInitRaw) \
+typedef struct CType##Entry_##tag { \
Key key; \
- _chash1_##type(Value value;) \
-} CHashEntry_##tag; \
+ OPT_1_##ctype(Value value;) \
+} CType##Entry_##tag; \
\
STC_INLINE void \
-chashentry_##tag##_destroy(CHashEntry_##tag* e) { \
+ctype##entry_##tag##_destroy(CType##Entry_##tag* e) { \
keyDestroy(&e->key); \
- _chash1_##type(valueDestroy(&e->value);) \
+ OPT_1_##ctype(valueDestroy(&e->value);) \
} \
\
-typedef RawKey CHashRawKey_##tag; \
+typedef RawKey CType##RawKey_##tag; \
\
-typedef struct CHash_##tag { \
- CHashEntry_##tag* table; \
+typedef struct CType##_##tag { \
+ CType##Entry_##tag* table; \
uint8_t* _hashx; \
uint32_t size, buckets; \
float maxLoadFactor; \
float shrinkLimitFactor; \
-} CHash_##tag; \
+} CType##_##tag; \
\
typedef struct { \
- CHashEntry_##tag *item, *_end; \
+ CType##Entry_##tag *item, *_end; \
uint8_t* _hx; \
-} CHashIter_##tag, chash_##tag##_iter_t; \
+} CType##Iter_##tag, ctype##_##tag##_iter_t; \
\
-STC_API CHash_##tag \
-chash_##tag##_make(size_t initialSize); \
+STC_API CType##_##tag \
+ctype##_##tag##_make(size_t initialSize); \
STC_API void \
-chash_##tag##_destroy(CHash_##tag* self); \
+ctype##_##tag##_destroy(CType##_##tag* self); \
STC_API void \
-chash_##tag##_clear(CHash_##tag* self); \
+ctype##_##tag##_clear(CType##_##tag* self); \
STC_API void \
-chash_##tag##_setLoadFactors(CHash_##tag* self, float maxLoadFactor, float shrinkLimitFactor); \
-STC_API CHashEntry_##tag* \
-chash_##tag##_get(const CHash_##tag* self, CHashRawKey_##tag rawKey); \
-STC_API CHashEntry_##tag* \
-chash_##tag##_put(CHash_##tag* self, _chash2_##type(CHashRawKey_##tag rawKey, Value value)); \
-_chash1_##type( STC_API CHashEntry_##tag* \
-chash_##tag##_at(CHash_##tag* self, CHashRawKey_##tag rawKey, Value initValue);) \
+ctype##_##tag##_setLoadFactors(CType##_##tag* self, float maxLoadFactor, float shrinkLimitFactor); \
+STC_API CType##Entry_##tag* \
+ctype##_##tag##_get(const CType##_##tag* self, CType##RawKey_##tag rawKey); \
+STC_API CType##Entry_##tag* \
+ctype##_##tag##_put(CType##_##tag* self, OPT_2_##ctype(CType##RawKey_##tag rawKey, Value value)); \
+OPT_1_##ctype(STC_API CType##Entry_##tag* \
+ctype##_##tag##_at(CType##_##tag* self, CType##RawKey_##tag rawKey, Value initValue);) \
STC_INLINE void \
-chash_##tag##_swap(CHash_##tag* a, CHash_##tag* b) { c_swap(CHash_##tag, *a, *b); } \
+ctype##_##tag##_swap(CType##_##tag* a, CType##_##tag* b) { c_swap(CType##_##tag, *a, *b); } \
STC_API size_t \
-chash_##tag##_reserve(CHash_##tag* self, size_t size); \
+ctype##_##tag##_reserve(CType##_##tag* self, size_t size); \
STC_API bool \
-chash_##tag##_eraseEntry(CHash_##tag* self, CHashEntry_##tag* entry); \
+ctype##_##tag##_eraseEntry(CType##_##tag* self, CType##Entry_##tag* entry); \
STC_API bool \
-chash_##tag##_erase(CHash_##tag* self, CHashRawKey_##tag rawKey); \
-STC_API chash_##tag##_iter_t \
-chash_##tag##_begin(CHash_##tag* map); \
-STC_API chash_##tag##_iter_t \
-chash_##tag##_next(chash_##tag##_iter_t it); \
+ctype##_##tag##_erase(CType##_##tag* self, CType##RawKey_##tag rawKey); \
+STC_API ctype##_##tag##_iter_t \
+ctype##_##tag##_begin(CType##_##tag* map); \
+STC_API ctype##_##tag##_iter_t \
+ctype##_##tag##_next(ctype##_##tag##_iter_t it); \
\
-implement_CHash_11(tag, type, Key, Value, valueDestroy, keyHashRaw, keyEqualsRaw, \
- keyDestroy, RawKey, keyGetRaw, keyInitRaw) \
-typedef Key CHashKey_##tag; \
-typedef Value CHashValue_##tag
+implement_CHASH(tag, CType, ctype, Key, Value, valueDestroy, keyHashRaw, keyEqualsRaw, \
+ keyDestroy, RawKey, keyGetRaw, keyInitRaw) \
+typedef Key CType##Key_##tag; \
+typedef Value CType##Value_##tag
/* -------------------------- IMPLEMENTATION ------------------------- */
#if !defined(STC_HEADER) || defined(STC_IMPLEMENTATION)
-#define implement_CHash_11(tag, type, Key, Value, valueDestroy, keyHashRaw, keyEqualsRaw, \
- keyDestroy, RawKey, keyGetRaw, keyInitRaw) \
+#define implement_CHASH(tag, CType, ctype, Key, Value, valueDestroy, keyHashRaw, keyEqualsRaw, \
+ keyDestroy, RawKey, keyGetRaw, keyInitRaw) \
\
-STC_API CHash_##tag \
-chash_##tag##_make(size_t initialSize) { \
- CHash_##tag h = chash_init; \
- chash_##tag##_reserve(&h, initialSize); \
+STC_API CType##_##tag \
+ctype##_##tag##_make(size_t initialSize) { \
+ CType##_##tag h = ctype##_init; \
+ ctype##_##tag##_reserve(&h, initialSize); \
return h; \
} \
\
STC_API void \
-chash_##tag##_destroy(CHash_##tag* self) { \
- if (chash_size(*self)) { \
- size_t cap = chash_bucketCount(*self); \
- CHashEntry_##tag* e = self->table, *end = e + cap; \
+ctype##_##tag##_destroy(CType##_##tag* self) { \
+ if (ctype##_size(*self)) { \
+ size_t cap = ctype##_bucketCount(*self); \
+ CType##Entry_##tag* e = self->table, *end = e + cap; \
uint8_t *hashx = self->_hashx; \
- for (; e != end; ++e) if (*hashx++) chashentry_##tag##_destroy(e); \
+ for (; e != end; ++e) if (*hashx++) ctype##entry_##tag##_destroy(e); \
} \
free(self->_hashx); \
free(self->table); \
} \
\
-STC_API void chash_##tag##_clear(CHash_##tag* self) { \
- chash_##tag##_destroy(self); \
+STC_API void ctype##_##tag##_clear(CType##_##tag* self) { \
+ ctype##_##tag##_destroy(self); \
self->buckets = self->size = 0; \
} \
\
STC_API void \
-chash_##tag##_setLoadFactors(CHash_##tag* self, float maxLoadFactor, float shrinkLimitFactor) { \
+ctype##_##tag##_setLoadFactors(CType##_##tag* self, float maxLoadFactor, float shrinkLimitFactor) { \
self->maxLoadFactor = maxLoadFactor; \
self->shrinkLimitFactor = shrinkLimitFactor; \
} \
\
STC_API size_t \
-chash_##tag##_bucket(const CHash_##tag* self, const CHashRawKey_##tag* rawKeyPtr, uint32_t* hxPtr) { \
- uint32_t hash = keyHashRaw(rawKeyPtr, sizeof(CHashRawKey_##tag)); \
+ctype##_##tag##_bucket(const CType##_##tag* self, const CType##RawKey_##tag* rawKeyPtr, uint32_t* hxPtr) { \
+ uint32_t hash = keyHashRaw(rawKeyPtr, sizeof(CType##RawKey_##tag)); \
uint32_t sx, hx = (hash & chash_HASH) | chash_USED; \
- size_t cap = chash_bucketCount(*self); \
+ size_t cap = ctype##_bucketCount(*self); \
size_t idx = chash_reduce(hash, cap); \
uint8_t* hashx = self->_hashx; \
while ((sx = hashx[idx])) { \
if (sx == hx) { \
- CHashRawKey_##tag r = keyGetRaw(&self->table[idx].key); \
+ CType##RawKey_##tag r = keyGetRaw(&self->table[idx].key); \
if (keyEqualsRaw(&r, rawKeyPtr)) break; \
} \
if (++idx == cap) idx = 0; \
@@ -235,43 +245,43 @@ chash_##tag##_bucket(const CHash_##tag* self, const CHashRawKey_##tag* rawKeyPtr return idx; \
} \
\
-STC_API CHashEntry_##tag* \
-chash_##tag##_get(const CHash_##tag* self, CHashRawKey_##tag rawKey) { \
- if (chash_size(*self) == 0) return NULL; \
+STC_API CType##Entry_##tag* \
+ctype##_##tag##_get(const CType##_##tag* self, CType##RawKey_##tag rawKey) { \
+ if (ctype##_size(*self) == 0) return NULL; \
uint32_t hx; \
- size_t idx = chash_##tag##_bucket(self, &rawKey, &hx); \
+ size_t idx = ctype##_##tag##_bucket(self, &rawKey, &hx); \
return self->_hashx[idx] ? &self->table[idx] : NULL; \
} \
\
-static inline void _chash_##tag##_reserveExpand(CHash_##tag* self) { \
- if (chash_size(*self) + 1 >= chash_bucketCount(*self) * self->maxLoadFactor) \
- chash_##tag##_reserve(self, (size_t) 7 + (1.6 * chash_bucketCount(*self))); \
+static inline void ctype##_##tag##_reserveExpand_(CType##_##tag* self) { \
+ if (ctype##_size(*self) + 1 >= ctype##_bucketCount(*self) * self->maxLoadFactor) \
+ ctype##_##tag##_reserve(self, (size_t) 7 + (1.6 * ctype##_bucketCount(*self))); \
} \
\
-STC_API CHashEntry_##tag* \
-chash_##tag##_put(CHash_##tag* self, _chash2_##type(CHashRawKey_##tag rawKey, Value value)) { \
- _chash_##tag##_reserveExpand(self); \
+STC_API CType##Entry_##tag* \
+ctype##_##tag##_put(CType##_##tag* self, OPT_2_##ctype(CType##RawKey_##tag rawKey, Value value)) { \
+ ctype##_##tag##_reserveExpand_(self); \
uint32_t hx; \
- size_t idx = chash_##tag##_bucket(self, &rawKey, &hx); \
- CHashEntry_##tag* e = &self->table[idx]; \
+ size_t idx = ctype##_##tag##_bucket(self, &rawKey, &hx); \
+ CType##Entry_##tag* e = &self->table[idx]; \
if (self->_hashx[idx]) \
- _chash1_##type(valueDestroy(&e->value)) ; \
+ OPT_1_##ctype(valueDestroy(&e->value)) ; \
else { \
e->key = keyInitRaw(rawKey); \
self->_hashx[idx] = (uint8_t) hx; \
++self->size; \
} \
- _chash1_##type(e->value = value;) \
+ OPT_1_##ctype(e->value = value;) \
return e; \
} \
\
-_chash1_##type( \
-STC_API CHashEntry_##tag* \
-chash_##tag##_at(CHash_##tag* self, CHashRawKey_##tag rawKey, Value initValue) { \
- _chash_##tag##_reserveExpand(self); \
+OPT_1_##ctype( \
+STC_API CType##Entry_##tag* \
+ctype##_##tag##_at(CType##_##tag* self, CType##RawKey_##tag rawKey, Value initValue) { \
+ ctype##_##tag##_reserveExpand_(self); \
uint32_t hx; \
- size_t idx = chash_##tag##_bucket(self, &rawKey, &hx); \
- CHashEntry_##tag* e = &self->table[idx]; \
+ size_t idx = ctype##_##tag##_bucket(self, &rawKey, &hx); \
+ CType##Entry_##tag* e = &self->table[idx]; \
if (! self->_hashx[idx]) { \
e->key = keyInitRaw(rawKey); \
self->_hashx[idx] = (uint8_t) hx; \
@@ -282,24 +292,24 @@ chash_##tag##_at(CHash_##tag* self, CHashRawKey_##tag rawKey, Value initValue) { }) \
\
STC_API size_t \
-chash_##tag##_reserve(CHash_##tag* self, size_t newcap) { \
- size_t oldcap = chash_bucketCount(*self); newcap |= 1; \
- if (chash_size(*self) >= newcap * self->maxLoadFactor) return oldcap; \
- CHash_##tag tmp = { \
- c_new_N(CHashEntry_##tag, newcap), \
+ctype##_##tag##_reserve(CType##_##tag* self, size_t newcap) { \
+ size_t oldcap = ctype##_bucketCount(*self); newcap |= 1; \
+ if (ctype##_size(*self) >= newcap * self->maxLoadFactor) return oldcap; \
+ CType##_##tag tmp = { \
+ c_new_N(CType##Entry_##tag, newcap), \
(uint8_t *) calloc(newcap, sizeof(uint8_t)), \
self->size, (uint32_t) newcap, \
self->maxLoadFactor, self->shrinkLimitFactor \
}; \
- chash_##tag##_swap(self, &tmp); \
+ ctype##_##tag##_swap(self, &tmp); \
\
- CHashEntry_##tag* e = tmp.table, *slot = self->table; \
+ CType##Entry_##tag* e = tmp.table, *slot = self->table; \
uint8_t* hashx = self->_hashx; \
uint32_t hx; \
for (size_t i = 0; i < oldcap; ++i, ++e) \
if (tmp._hashx[i]) { \
- CHashRawKey_##tag r = keyGetRaw(&e->key); \
- size_t idx = chash_##tag##_bucket(self, &r, &hx); \
+ CType##RawKey_##tag r = keyGetRaw(&e->key); \
+ size_t idx = ctype##_##tag##_bucket(self, &r, &hx); \
slot[idx] = *e, \
hashx[idx] = (uint8_t) hx; \
} \
@@ -309,11 +319,11 @@ chash_##tag##_reserve(CHash_##tag* self, size_t newcap) { \ } \
\
STC_API bool \
-chash_##tag##_eraseEntry(CHash_##tag* self, CHashEntry_##tag* entry) { \
- size_t i = chash_entryIndex(*self, entry), j = i, k, cap = chash_bucketCount(*self); \
- CHashEntry_##tag* slot = self->table; \
+ctype##_##tag##_eraseEntry(CType##_##tag* self, CType##Entry_##tag* entry) { \
+ size_t i = chash_entryIndex(*self, entry), j = i, k, cap = ctype##_bucketCount(*self); \
+ CType##Entry_##tag* slot = self->table; \
uint8_t* hashx = self->_hashx; \
- CHashRawKey_##tag r; \
+ CType##RawKey_##tag r; \
if (! hashx[i]) \
return false; \
do { /* deletion from hash table without tombstone */ \
@@ -321,46 +331,46 @@ chash_##tag##_eraseEntry(CHash_##tag* self, CHashEntry_##tag* entry) { \ if (! hashx[j]) \
break; \
r = keyGetRaw(&slot[j].key); \
- k = chash_reduce(keyHashRaw(&r, sizeof(CHashRawKey_##tag)), cap); \
+ k = chash_reduce(keyHashRaw(&r, sizeof(CType##RawKey_##tag)), cap); \
if ((j < i) ^ (k <= i) ^ (k > j)) /* is k outside (i, j]? */ \
slot[i] = slot[j], hashx[i] = hashx[j], i = j; \
} while (true); \
hashx[i] = 0; \
- chashentry_##tag##_destroy(&slot[i]); \
+ ctype##entry_##tag##_destroy(&slot[i]); \
--self->size; \
return true; \
} \
\
STC_API bool \
-chash_##tag##_erase(CHash_##tag* self, CHashRawKey_##tag rawKey) { \
- if (chash_size(*self) == 0) \
+ctype##_##tag##_erase(CType##_##tag* self, CType##RawKey_##tag rawKey) { \
+ if (ctype##_size(*self) == 0) \
return false; \
- size_t cap = chash_bucketCount(*self); \
- if (chash_size(*self) < cap * self->shrinkLimitFactor && cap * sizeof(CHashEntry_##tag) > 1024) \
- chash_##tag##_reserve(self, (size_t) (chash_size(*self) * 1.2f / self->maxLoadFactor)); \
+ size_t cap = ctype##_bucketCount(*self); \
+ if (ctype##_size(*self) < cap * self->shrinkLimitFactor && cap * sizeof(CType##Entry_##tag) > 1024) \
+ ctype##_##tag##_reserve(self, (size_t) (ctype##_size(*self) * 1.2f / self->maxLoadFactor)); \
uint32_t hx; \
- size_t i = chash_##tag##_bucket(self, &rawKey, &hx); \
- return chash_##tag##_eraseEntry(self, self->table + i); \
+ size_t i = ctype##_##tag##_bucket(self, &rawKey, &hx); \
+ return ctype##_##tag##_eraseEntry(self, self->table + i); \
} \
\
-STC_API chash_##tag##_iter_t \
-chash_##tag##_begin(CHash_##tag* map) { \
+STC_API ctype##_##tag##_iter_t \
+ctype##_##tag##_begin(CType##_##tag* map) { \
uint8_t* hx = map->_hashx; \
- CHashEntry_##tag* e = map->table, *end = e + chash_bucketCount(*map); \
+ CType##Entry_##tag* e = map->table, *end = e + ctype##_bucketCount(*map); \
while (e != end && !*hx) ++e, ++hx; \
- chash_##tag##_iter_t it = {e == end ? NULL : e, end, hx}; return it; \
+ ctype##_##tag##_iter_t it = {e == end ? NULL : e, end, hx}; return it; \
} \
\
-STC_API chash_##tag##_iter_t \
-chash_##tag##_next(chash_##tag##_iter_t it) { \
+STC_API ctype##_##tag##_iter_t \
+ctype##_##tag##_next(ctype##_##tag##_iter_t it) { \
do { ++it.item, ++it._hx; } while (it.item != it._end && !*it._hx); \
if (it.item == it._end) it.item = NULL; \
return it; \
}
#else
-#define implement_CHash_11(tag, type, Key, Value, valueDestroy, keyHashRaw, keyEqualsRaw, \
- keyDestroy, RawKey, keyGetRaw, keyInitRaw)
+#define implement_CHASH(tag, CType, ctype, Key, Value, valueDestroy, keyHashRaw, keyEqualsRaw, \
+ keyDestroy, RawKey, keyGetRaw, keyInitRaw)
#endif
#endif
diff --git a/stc/cstring.h b/stc/cstr.h index 8380e8dd..8380e8dd 100644 --- a/stc/cstring.h +++ b/stc/cstr.h diff --git a/stc/cvector.h b/stc/cvec.h index e864bb34..e864bb34 100644 --- a/stc/cvector.h +++ b/stc/cvec.h |
