diff options
| author | Tyge Løvset <[email protected]> | 2022-04-24 13:31:11 +0200 |
|---|---|---|
| committer | Tyge Løvset <[email protected]> | 2022-04-24 13:31:11 +0200 |
| commit | 6d8406e66c029d4c672bb7531aabec7eb1d079d8 (patch) | |
| tree | 4bd1e513a04000d3e4140857fcae032f05abeba0 | |
| parent | 2b74b8a880d48232892ca84ac29efacd66905cd4 (diff) | |
| download | STC-modified-6d8406e66c029d4c672bb7531aabec7eb1d079d8.tar.gz STC-modified-6d8406e66c029d4c672bb7531aabec7eb1d079d8.zip | |
Created VERSION 3.5. See News section in docs for changes.
| -rw-r--r-- | README.md | 13 | ||||
| -rw-r--r-- | benchmarks/misc/sso_bench.c | 52 | ||||
| -rw-r--r-- | benchmarks/misc/sso_bench.cpp (renamed from benchmarks/misc/sso_bench2.cpp) | 17 | ||||
| -rw-r--r-- | benchmarks/misc/string_bench.c | 153 | ||||
| -rw-r--r-- | benchmarks/misc/string_bench.cpp | 199 | ||||
| -rw-r--r-- | benchmarks/misc/string_bench_STC.cpp | 298 | ||||
| -rw-r--r-- | benchmarks/misc/string_bench_STD.cpp | 370 | ||||
| -rw-r--r-- | docs/cstr_api.md | 1 | ||||
| -rw-r--r-- | docs/csview_api.md | 2 | ||||
| -rw-r--r-- | include/stc/ccommon.h | 19 | ||||
| -rw-r--r-- | include/stc/cstr.h | 74 | ||||
| -rw-r--r-- | include/stc/csview.h | 17 | ||||
| -rw-r--r-- | include/stc/template.h | 5 |
13 files changed, 746 insertions, 474 deletions
@@ -3,12 +3,13 @@ STC - Smart Template Containers for C ===================================== -News: Version 3 released (Jan 2022) ------------------------------------ -This version introduces lots of enhancements, bugfixes and additions. There are also -a number of [breaking changes](#brief-summary-of-changes) and [a migration guide from version 2 to 3](#migration-guide-from-version-2-to-3). -With version 3, the API is freezed as far as possible. Any changes will be handled with long -lasting deprecations, so you may develop production code using it. +News: Version 3.5 released (Mar 2022) +------------------------------------- +- Swapped to new **cstr** (*short string optimized*, aka SSO). Note that `cstr_str(&s)` must be used, `s.str` is no longer usable. +- Added general `i_clone` template parameter: containers with smart pointers (**carc**, **cbox**) can now be correctly cloned. +- Optimized *c_default_hash()*. Therefore *c_hash32()* and *c_hash64()* are removed (same speed). +- Added *.._push()* and *.._emplace()* function to all containers to allow for more generic coding. +- Added some examples and benchmarks for SSO and heterogenous lookup comparison with c++20 (string_bench_*.cpp). Introduction ------------ diff --git a/benchmarks/misc/sso_bench.c b/benchmarks/misc/sso_bench.c deleted file mode 100644 index f2714be1..00000000 --- a/benchmarks/misc/sso_bench.c +++ /dev/null @@ -1,52 +0,0 @@ -// https://gobyexample.com/maps -#include <stc/cstr.h> -#define i_type Map -#define i_key_str -#define i_val int -#include <stc/cmap.h> -#define i_type Vec -#define i_val_str -#include <stc/cvec.h> - -#include <time.h> -#include <stc/crandom.h> - -void rndstr(char buf[64], int max) { - unsigned n = crandom() % max; - static char chr[64] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_"; - c_forrange (i, n) - buf[i] = chr[crandom() & 63]; - buf[n] = '\0'; -} - -enum {N = 10000000}; - -int main(void) { - - c_auto (Vec, vec) - c_auto (Map, map) { - char buf[128]; - - csrandom(time(NULL)); - printf("map\n"); - clock_t t0 = clock(), t1, t2; - c_forrange (i, int, N) { - rndstr(buf, 64); - Map_emplace(&map, buf, i); - } - t1 = clock(); - printf("vec\n"); - c_apply_cnt(v, Vec_push(&vec, cstr_clone(v->first)), Map, map); - t2 = clock(); - puts("map items:"); - int k = 0; - c_forpair (k, v, Map, map) - if (k++ == 5) break; else printf(" %s: %d\n", cstr_str(&_.k), _.v); - puts("vec items:"); - k = 0; - c_foreach (i, Vec, vec) - if (k++ == 5) break; else printf(" %s\n", cstr_str(i.ref)); - - printf("\nmap insert: %d ms\nvec pushes: %d ms\n", (int)((t1 - t0)*10000/CLOCKS_PER_SEC), (int)((t2 - t1)*10000/CLOCKS_PER_SEC)); - } -} diff --git a/benchmarks/misc/sso_bench2.cpp b/benchmarks/misc/sso_bench.cpp index 1355a727..08444320 100644 --- a/benchmarks/misc/sso_bench2.cpp +++ b/benchmarks/misc/sso_bench.cpp @@ -32,7 +32,7 @@ static void sromutrio(uint64_t seed) { static const char CHARS[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=+-"; static const int BENCHMARK_SIZE = 5000000; -static const int MAX_STRING_LENGTH = 20; +static const int MAX_STRING_LENGTH = 25; using time_point = std::chrono::high_resolution_clock::time_point; @@ -53,7 +53,7 @@ void addRandomString_STC(svec& vec, const int length) { p[i] = CHARS[romutrio() & 63]; } cstr_append_s(&s, s); - svec_push(&vec, s); + svec_push_back(&vec, s); } template <class L, typename R> @@ -74,7 +74,8 @@ void benchmark(L& vec, const int length, R addRandomString) { int main() { - sromutrio(1234); + uint64_t seed = 4321; + sromutrio(seed); std::cerr << "length\ttime\tstd::string\n"; for (int k = 0; k < 4; k++) { std::vector<std::string> vec; vec.reserve(BENCHMARK_SIZE); @@ -82,7 +83,7 @@ int main() { std::cout << '\t' << vec[0] << '\n'; } - sromutrio(1234); + sromutrio(seed); std::cerr << "\nlength\ttime\tSTC string\n"; for (int k = 0; k < 4; k++) { svec vec = svec_with_capacity(BENCHMARK_SIZE); @@ -91,7 +92,7 @@ int main() { svec_drop(&vec); } - sromutrio(1234); + sromutrio(seed); std::cerr << "length\ttime\tstd::string\n"; for (int length = 1; length <= MAX_STRING_LENGTH; length++) { std::vector<std::string> vec; vec.reserve(BENCHMARK_SIZE); @@ -99,7 +100,7 @@ int main() { std::cout << '\t' << vec[0] << '\n'; } - sromutrio(1234); + sromutrio(seed); std::cerr << "\nlength\ttime\tSTC string\n"; for (int length = 1; length <= MAX_STRING_LENGTH; length++) { svec vec = svec_with_capacity(BENCHMARK_SIZE); @@ -108,7 +109,7 @@ int main() { svec_drop(&vec); } - std::cerr << "size std::string : " << sizeof(std::string) << std::endl - << "size STC string : " << sizeof(cstr) << std::endl; + std::cerr << "sizeof std::string : " << sizeof(std::string) << std::endl + << "sizeof STC string : " << sizeof(cstr) << std::endl; return 0; } diff --git a/benchmarks/misc/string_bench.c b/benchmarks/misc/string_bench.c deleted file mode 100644 index fb2a70b2..00000000 --- a/benchmarks/misc/string_bench.c +++ /dev/null @@ -1,153 +0,0 @@ -// https://www.codeproject.com/Tips/5255442/Cplusplus14-20-Heterogeneous-Lookup-Benchmark
-// https://github.com/shaovoon/cpp_hetero_lookup_bench
-
-#include <time.h>
-
-#define i_val_str
-#include <stc/cvec.h>
-
-#define i_key_str
-#define i_val size_t
-#include <stc/cmap.h>
-
-#define i_key_str
-#define i_val size_t
-#include <stc/csmap.h>
-
-
-cvec_str read_file(const char* name)
-{
- cvec_str data = cvec_str_init();
- c_auto (cstr, line)
- c_autovar (FILE* f = fopen(name, "r"), fclose(f))
- while (cstr_getline(&line, f))
- cvec_str_emplace_back(&data, cstr_str(&line));
- return data;
-}
-
-void initShortStringVec(cvec_str* vs)
-{
- cvec_str_clear(vs);
-
- *vs = read_file("names.txt");
- size_t lengths = 0;
- c_foreach (i, cvec_str, *vs)
- {
- cstr_append_s(i.ref, *i.ref);
- cstr_append_s(i.ref, *i.ref);
- lengths += cstr_size(*i.ref);
- }
- printf("avg len: %f\n", (float)lengths / cvec_str_size(*vs));
-}
-
-void initLongStringVec(cvec_str* vs)
-{
- cvec_str_clear(vs);
- *vs = read_file("names.txt");
- cstr* s = vs->data;
- size_t lengths = 0;
- cstr_append_s(s, s[1]);
- cstr_append_s(s, s[2]);
- cstr_append_s(s, s[3]);
- for (int i=1; i < cvec_str_size(*vs); ++i)
- {
- cstr* t = vs->data + i;
- cstr_append_s(t, *t);
- cstr_append_s(t, *t);
- cstr_append_s(t, *s);
- cstr_append_s(t, *t);
- cstr_append_s(t, *t);
- lengths += cstr_size(*t);
- }
- printf("avg len: %f\n", (float)lengths / cvec_str_size(*vs));
-}
-
-struct Maps {
- csmap_str* snormal;
- cmap_str* unormal;
-};
-
-void initMaps(cvec_str vs, struct Maps maps)
-{
- csmap_str_clear(maps.snormal);
- cmap_str_clear(maps.unormal);
-
- for (size_t i = 0; i < cvec_str_size(vs); ++i)
- {
- cstr str = *cvec_str_at(&vs, i);
- csmap_str_insert(maps.snormal, cstr_clone(str), i);
- cmap_str_insert(maps.unormal, cstr_clone(str), i);
- }
-}
-
-void benchmark(cvec_str vec_string, struct Maps maps);
-
-static const size_t MAX_LOOP = 2000;
-
-int main()
-{
- c_auto (cvec_str, vec_string)
- c_auto (csmap_str, snormal)
- c_auto (cmap_str, unormal)
- {
- struct Maps maps = { &snormal, &unormal };
-
- initShortStringVec(&vec_string);
- initMaps(vec_string, maps);
-
- puts("Short String Benchmark");
- puts("======================");
-
- benchmark(vec_string, maps);
-
- puts("\nLong String Benchmark");
- puts("======================");
-
- initLongStringVec(&vec_string);
- initMaps(vec_string, maps);
-
- benchmark(vec_string, maps);
- }
-}
-
-void benchmark(cvec_str vec_string, struct Maps maps)
-{
- size_t grandtotal = 0;
- size_t total;
- clock_t stopwatch;
-
- total = 0;
- printf("%32s", "Trans Map with char*");
- stopwatch = clock();
- for (size_t i = 0; i < MAX_LOOP; ++i)
- {
- csmap_str_iter it, end = csmap_str_end(maps.snormal);
- for (size_t j = 0; j < cvec_str_size(vec_string); ++j)
- {
- csmap_str_find_it(maps.snormal, cstr_str(&vec_string.data[j]), &it);
- if (it.ref != end.ref)
- total += it.ref->second;
- }
- }
- grandtotal += total;
- printf(" timing:%5.0fms\n", (clock() - stopwatch) / (float)CLOCKS_PER_SEC * 1000.0f);
-
-
- total = 0;
- printf("%32s", "Trans Unord Map with char*");
- stopwatch = clock();
- for (size_t i = 0; i < MAX_LOOP; ++i)
- {
- cmap_str_iter it, end = cmap_str_end(maps.unormal);
- for (size_t j = 0; j < cvec_str_size(vec_string); ++j)
- {
- it = cmap_str_find(maps.unormal, cstr_str(&vec_string.data[j]));
- if (it.ref != end.ref)
- total += it.ref->second;
- }
- }
- grandtotal += total;
- printf(" timing:%5.0fms\n", (clock() - stopwatch) / (float)CLOCKS_PER_SEC * 1000.0f);
-
- printf("C grandtotal: %" PRIuMAX " <--- Ignore this\n", grandtotal);
-}
diff --git a/benchmarks/misc/string_bench.cpp b/benchmarks/misc/string_bench.cpp deleted file mode 100644 index 65bf7a0e..00000000 --- a/benchmarks/misc/string_bench.cpp +++ /dev/null @@ -1,199 +0,0 @@ -// https://www.codeproject.com/Tips/5255442/Cplusplus14-20-Heterogeneous-Lookup-Benchmark
-// https://github.com/shaovoon/cpp_hetero_lookup_bench
-
-#include <iostream>
-#include <iomanip>
-#include <chrono>
-#include <string>
-#include <vector>
-#include <map>
-#include <unordered_map>
-
-#define i_val_str
-#include <stc/cvec.h>
-
-
-std::vector<std::string> read_file(const char* name)
-{
- std::vector<std::string> data;
- c_auto (cstr, line)
- c_autovar (FILE* f = fopen(name, "r"), fclose(f))
- while (cstr_getline(&line, f))
- data.emplace_back(cstr_str(&line));
- return data;
-}
-
-class timer
-{
-public:
- timer() = default;
- void start(const std::string& text_)
- {
- text = text_;
- begin = std::chrono::high_resolution_clock::now();
- }
- void stop()
- {
- auto end = std::chrono::high_resolution_clock::now();
- auto dur = end - begin;
- auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(dur).count();
- std::cout << std::setw(32) << text << " timing:" << std::setw(5) << ms << "ms" << std::endl;
- }
-
-private:
- std::string text;
- std::chrono::high_resolution_clock::time_point begin;
-};
-
-void initShortStringVec(std::vector<std::string>& vs)
-{
- vs.clear();
- vs = read_file("names.txt");
- size_t num = 0;
-
- for (size_t i = 0; i < vs.size(); ++i)
- {
- num += vs[i].size();
- }
- printf("avg len: %f\n", (float)num / vs.size());
-}
-
-void initLongStringVec(std::vector<std::string>& vs)
-{
- vs.clear();
- vs = read_file("names.txt");
- size_t num = 0;
- vs[0] += vs[1];
- vs[0] += vs[2];
- vs[0] += vs[3];
- for (size_t i = 1; i < vs.size(); ++i)
- {
- vs[i] += vs[i];
- vs[i] += vs[i];
- vs[i] += vs[0];
- vs[i] += vs[i];
- vs[i] += vs[i];
- num += vs[i].size();
- }
- printf("avg len: %f\n", (float)num / vs.size());
-}
-
-void initMapNormal(const std::vector<std::string>& vs,
- std::map<std::string, size_t>& mapNormal,
- std::unordered_map<std::string, size_t>& unordmapNormal)
-{
- mapNormal.clear();
- unordmapNormal.clear();
- for (size_t i = 0; i < vs.size(); ++i)
- {
- mapNormal.insert(std::make_pair(vs.at(i), i));
- unordmapNormal.insert(std::make_pair(vs.at(i), i));
- }
-}
-/*
-struct string_hash {
- using is_transparent = void;
- using hash_type = std::hash<std::string_view>; // just a helper local type
- size_t operator()(const std::string& txt) const { return hash_type{}(txt); }
- size_t operator()(const char* txt) const { return hash_type{}(txt); }
-};*/
-
-void benchmark(
- const std::vector<std::string>& vec_string,
- const std::map<std::string, size_t>& mapNormal,
- const std::unordered_map<std::string, size_t>& unordmapNormal);
-
-const size_t MAX_LOOP = 2000;
-
-int main()
-{
- std::vector<std::string> vec_string;
-
- std::map<std::string, size_t> mapNormal;
- std::unordered_map<std::string, size_t> unordmapNormal;
-
- initShortStringVec(vec_string);
- initMapNormal(vec_string, mapNormal, unordmapNormal);
-
- std::cout << "Short String Benchmark" << std::endl;
- std::cout << "======================" << std::endl;
-
- benchmark(vec_string, mapNormal, unordmapNormal);
-
- std::cout << "Long String Benchmark" << std::endl;
- std::cout << "=====================" << std::endl;
-
- initLongStringVec(vec_string);
- initMapNormal(vec_string, mapNormal, unordmapNormal);
-
- benchmark(vec_string, mapNormal, unordmapNormal);
- return 0;
-}
-
-void benchmark(
- const std::vector<std::string>& vec_string,
- const std::map<std::string, size_t>& mapNormal,
- const std::unordered_map<std::string, size_t>& unordmapNormal)
-{
- size_t grandtotal = 0;
- size_t total = 0;
- timer stopwatch;
-
- total = 0;
- stopwatch.start("Normal Map with string");
- for (size_t i = 0; i < MAX_LOOP; ++i)
- {
- for (size_t j = 0; j < vec_string.size(); ++j)
- {
- const auto& it = mapNormal.find(vec_string[j]);
- if(it!=mapNormal.cend())
- total += it->second;
- }
- }
- grandtotal += total;
- stopwatch.stop();
-
- total = 0;
- stopwatch.start("Normal Map with char*");
- for (size_t i = 0; i < MAX_LOOP; ++i)
- {
- for (size_t j = 0; j < vec_string.size(); ++j)
- {
- const auto& it = mapNormal.find(vec_string[j].c_str());
- if (it != mapNormal.cend())
- total += it->second;
- }
- }
- grandtotal += total;
- stopwatch.stop();
-
- total = 0;
- stopwatch.start("Normal Unord Map with string");
- for (size_t i = 0; i < MAX_LOOP; ++i)
- {
- for (size_t j = 0; j < vec_string.size(); ++j)
- {
- const auto& it = unordmapNormal.find(vec_string[j]);
- if (it != unordmapNormal.cend())
- total += it->second;
- }
- }
- grandtotal += total;
- stopwatch.stop();
-
- total = 0;
- stopwatch.start("Normal Unord Map with char*");
- for (size_t i = 0; i < MAX_LOOP; ++i)
- {
- for (size_t j = 0; j < vec_string.size(); ++j)
- {
- const auto& it = unordmapNormal.find(vec_string[j].c_str());
- if (it != unordmapNormal.cend())
- total += it->second;
- }
- }
- grandtotal += total;
- stopwatch.stop();
-
- std::cout << "C++ grandtotal:" << grandtotal << " <--- Ignore this\n" << std::endl;
-}
\ No newline at end of file diff --git a/benchmarks/misc/string_bench_STC.cpp b/benchmarks/misc/string_bench_STC.cpp new file mode 100644 index 00000000..ed0e3243 --- /dev/null +++ b/benchmarks/misc/string_bench_STC.cpp @@ -0,0 +1,298 @@ +// https://www.codeproject.com/Tips/5255442/Cplusplus14-20-Heterogeneous-Lookup-Benchmark +// https://github.com/shaovoon/cpp_hetero_lookup_bench + +#include <iostream> +#include <iomanip> +#include <chrono> +#include <stc/cstr.h> // string +#include <stc/csview.h> // string_view + +#define i_key_str +#include <stc/cvec.h> // vec of cstr with const char* lookup + +#define i_type cvec_sv // override default type name (cvec_csview) +#define i_key csview +#define i_cmp csview_cmp +#include <stc/cvec.h> // cvec_vs: vec of csview + +#define i_key_str +#define i_val size_t +#include <stc/csmap.h> // sorted map of cstr, const char* lookup + +#define i_key_ssv +#define i_val size_t +#include <stc/csmap.h> // sorted map of cstr, csview lookup + +#define i_key_str +#define i_val size_t +#include <stc/cmap.h> // unordered map of cstr, const char* lookup + +#define i_key_ssv +#define i_val size_t +#include <stc/cmap.h> // unordered map of cstr, csview lookup + + +cvec_str read_file(const char* name) +{ + cvec_str data = cvec_str_init(); + c_auto (cstr, line) + c_autovar (FILE* f = fopen(name, "r"), fclose(f)) + while (cstr_getline(&line, f)) + cvec_str_emplace_back(&data, cstr_str(&line)); + return data; +} + +class timer +{ +public: + timer() = default; + void start(const std::string& text_) + { + text = text_; + begin = std::chrono::high_resolution_clock::now(); + } + void stop() + { + auto end = std::chrono::high_resolution_clock::now(); + auto dur = end - begin; + auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(dur).count(); + std::cout << std::setw(32) << text << " timing:" << std::setw(5) << ms << "ms" << std::endl; + } + +private: + std::string text; + std::chrono::high_resolution_clock::time_point begin; +}; + +void initShortStringVec(cvec_str* vs, cvec_sv* vsv) +{ + cvec_str_clear(vs); + cvec_sv_clear(vsv); + + *vs = read_file("names.txt"); +/* + cvec_str_emplace_back(vs, "Susan"); + cvec_str_emplace_back(vs, "Jason"); + cvec_str_emplace_back(vs, "Lily"); + cvec_str_emplace_back(vs, "Michael"); + cvec_str_emplace_back(vs, "Mary"); + + cvec_str_emplace_back(vs, "Jerry"); + cvec_str_emplace_back(vs, "Jenny"); + cvec_str_emplace_back(vs, "Klaus"); + cvec_str_emplace_back(vs, "Celine"); + cvec_str_emplace_back(vs, "Kenny"); + + cvec_str_emplace_back(vs, "Kelly"); + cvec_str_emplace_back(vs, "Jackson"); + cvec_str_emplace_back(vs, "Mandy"); + cvec_str_emplace_back(vs, "Terry"); + cvec_str_emplace_back(vs, "Sandy"); + + cvec_str_emplace_back(vs, "Billy"); + cvec_str_emplace_back(vs, "Cindy"); + cvec_str_emplace_back(vs, "Phil"); + cvec_str_emplace_back(vs, "Lindy"); + cvec_str_emplace_back(vs, "David"); +*/ + size_t num = 0; + c_foreach (i, cvec_str, *vs) + { + cvec_sv_push_back(vsv, csview_from_s(i.ref)); + num += cstr_size(*i.ref); + } + std::cout << "num strings: " << cvec_sv_size(*vsv) << std::endl; + std::cout << "avg str len: " << num / (float)cvec_sv_size(*vsv) << std::endl; +} + +void initLongStringVec(cvec_str* vs, cvec_sv* vsv) +{ + cvec_str_clear(vs); + cvec_sv_clear(vsv); + + *vs = read_file("names.txt"); + c_foreach (i, cvec_str, *vs) { + cstr_append_s(i.ref, *i.ref); + cstr_append_s(i.ref, *i.ref); + cstr_append_s(i.ref, *i.ref); + } +/* + cvec_str_emplace_back(vs, "Susan Susan Susan Susan Susan Susan"); + cvec_str_emplace_back(vs, "Jason Jason Jason Jason Jason Jason"); + cvec_str_emplace_back(vs, "Lily Lily Lily Lily Lily Lily"); + cvec_str_emplace_back(vs, "Michael Michael Michael Michael Michael Michael"); + cvec_str_emplace_back(vs, "Mary Mary Mary Mary Mary Mary"); + + cvec_str_emplace_back(vs, "Jerry Jerry Jerry Jerry Jerry Jerry"); + cvec_str_emplace_back(vs, "Jenny Jenny Jenny Jenny Jenny Jenny"); + cvec_str_emplace_back(vs, "Klaus Klaus Klaus Klaus Klaus Klaus"); + cvec_str_emplace_back(vs, "Celine Celine Celine Celine Celine Celine"); + cvec_str_emplace_back(vs, "Kenny Kenny Kenny Kenny Kenny Kenny"); + + cvec_str_emplace_back(vs, "Kelly Kelly Kelly Kelly Kelly Kelly"); + cvec_str_emplace_back(vs, "Jackson Jackson Jackson Jackson Jackson Jackson"); + cvec_str_emplace_back(vs, "Mandy Mandy Mandy Mandy Mandy Mandy"); + cvec_str_emplace_back(vs, "Terry Terry Terry Terry Terry Terry"); + cvec_str_emplace_back(vs, "Sandy Sandy Sandy Sandy Sandy Sandy"); + + cvec_str_emplace_back(vs, "Billy Billy Billy Billy Billy Billy"); + cvec_str_emplace_back(vs, "Cindy Cindy Cindy Cindy Cindy Cindy"); + cvec_str_emplace_back(vs, "Phil Phil Phil Phil Phil Phil"); + cvec_str_emplace_back(vs, "Lindy Lindy Lindy Lindy Lindy Lindy"); + cvec_str_emplace_back(vs, "David David David David David David"); +*/ + size_t num = 0; + c_foreach (i, cvec_str, *vs) + { + cvec_sv_push_back(vsv, csview_from_s(i.ref)); + num += cstr_size(*i.ref); + } + std::cout << "num strings: " << cvec_sv_size(*vsv) << std::endl; + std::cout << "avg str len: " << num / (float)cvec_sv_size(*vsv) << std::endl; +} + +void initMaps(const cvec_str* vs, csmap_str* mapTrans, csmap_ssv* mapSview, + cmap_str* unordmapTrans, cmap_ssv* unordmapSview) +{ + csmap_str_clear(mapTrans); + csmap_ssv_clear(mapSview); + cmap_str_clear(unordmapTrans); + cmap_ssv_clear(unordmapSview); + + size_t n = 0; + c_foreach (i, cvec_str, *vs) + { + csmap_str_insert(mapTrans, cstr_clone(*i.ref), n); + csmap_ssv_insert(mapSview, cstr_clone(*i.ref), n); + cmap_str_insert(unordmapTrans, cstr_clone(*i.ref), n); + cmap_ssv_insert(unordmapSview, cstr_clone(*i.ref), n); + ++n; + } +} + +void benchmark( + const cvec_str* vec_string, + const cvec_sv* vec_stringview, + const csmap_str* mapTrans, + const csmap_ssv* mapSview, + const cmap_str* unordmapTrans, + const cmap_ssv* unordmapSview); + +//const size_t MAX_LOOP = 1000000; +const size_t MAX_LOOP = 2000; + +int main() +{ + c_auto (cvec_str, vec_string) + c_auto (cvec_sv, vec_stringview) + c_auto (csmap_str, mapTrans) + c_auto (csmap_ssv, mapSview) + c_auto (cmap_str, unordmapTrans) + c_auto (cmap_ssv, unordmapSview) + { + std::cout << "Short String Benchmark" << std::endl; + std::cout << "======================" << std::endl; + + initShortStringVec(&vec_string, &vec_stringview); + initMaps(&vec_string, &mapTrans, &mapSview, + &unordmapTrans, &unordmapSview); + + for (int i=0; i<3; ++i) + benchmark( + &vec_string, + &vec_stringview, + &mapTrans, + &mapSview, + &unordmapTrans, + &unordmapSview); + + std::cout << "Long String Benchmark" << std::endl; + std::cout << "=====================" << std::endl; + + initLongStringVec(&vec_string, &vec_stringview); + initMaps(&vec_string, &mapTrans, &mapSview, + &unordmapTrans, &unordmapSview); + for (int i=0; i<3; ++i) + benchmark( + &vec_string, + &vec_stringview, + &mapTrans, + &mapSview, + &unordmapTrans, + &unordmapSview); + } + return 0; +} + +void benchmark( + const cvec_str* vec_string, + const cvec_sv* vec_stringview, + const csmap_str* mapTrans, + const csmap_ssv* mapSview, + const cmap_str* unordmapTrans, + const cmap_ssv* unordmapSview) +{ + size_t grandtotal = 0; + + size_t total = 0; + + timer stopwatch; + total = 0; + stopwatch.start("Trans Map with char*"); + for (size_t i = 0; i < MAX_LOOP; ++i) + { + c_foreach (j, cvec_str, *vec_string) + { + const csmap_str_value* v = csmap_str_get(mapTrans, cstr_str(j.ref)); + if (v) + total += v->second; + } + } + grandtotal += total; + stopwatch.stop(); + + total = 0; + stopwatch.start("Trans Map with string_view"); + for (size_t i = 0; i < MAX_LOOP; ++i) + { + c_foreach (j, cvec_sv, *vec_stringview) + { + const csmap_ssv_value* v = csmap_ssv_get(mapSview, *j.ref); + if (v) + total += v->second; + } + } + grandtotal += total; + stopwatch.stop(); + + total = 0; + stopwatch.start("Trans Unord Map with char*"); + for (size_t i = 0; i < MAX_LOOP; ++i) + { + c_foreach (j, cvec_str, *vec_string) + { + const cmap_str_value* v = cmap_str_get(unordmapTrans, cstr_str(j.ref)); + if (v) + total += v->second; + } + } + grandtotal += total; + stopwatch.stop(); + + total = 0; + stopwatch.start("Trans Unord Map with string_view"); + for (size_t i = 0; i < MAX_LOOP; ++i) + { + c_foreach (j, cvec_sv, *vec_stringview) + { + const cmap_ssv_value* v = cmap_ssv_get(unordmapSview, *j.ref); + if (v) + total += v->second; + } + } + grandtotal += total; + stopwatch.stop(); + + std::cout << "grandtotal:" << grandtotal << " <--- Ignore this\n" << std::endl; + +} diff --git a/benchmarks/misc/string_bench_STD.cpp b/benchmarks/misc/string_bench_STD.cpp new file mode 100644 index 00000000..595ab632 --- /dev/null +++ b/benchmarks/misc/string_bench_STD.cpp @@ -0,0 +1,370 @@ +// https://www.codeproject.com/Tips/5255442/Cplusplus14-20-Heterogeneous-Lookup-Benchmark +// https://github.com/shaovoon/cpp_hetero_lookup_bench +// Requires c++20, e.g. g++ -std=c++20 + +#include <iostream> +#include <iomanip> +#include <chrono> +#include <string> +#include <string_view> +#include <vector> +#include <map> +#include <unordered_map> +#include <stc/cstr.h> + +std::vector<std::string> read_file(const char* name) +{ + std::vector<std::string> data; + c_auto (cstr, line) + c_autovar (FILE* f = fopen(name, "r"), fclose(f)) + while (cstr_getline(&line, f)) + data.emplace_back(cstr_str(&line)); + return data; +} + +class timer +{ +public: + timer() = default; + void start(const std::string& text_) + { + text = text_; + begin = std::chrono::high_resolution_clock::now(); + } + void stop() + { + auto end = std::chrono::high_resolution_clock::now(); + auto dur = end - begin; + auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(dur).count(); + std::cout << std::setw(32) << text << " timing:" << std::setw(5) << ms << "ms" << std::endl; + } + +private: + std::string text; + std::chrono::high_resolution_clock::time_point begin; +}; + +void initShortStringVec(std::vector<std::string>& vs, std::vector<std::string_view>& vsv) +{ + vs.clear(); + vsv.clear(); + + vs = read_file("names.txt"); +/* + vs.push_back("Susan"); + vs.push_back("Jason"); + vs.push_back("Lily"); + vs.push_back("Michael"); + vs.push_back("Mary"); + + vs.push_back("Jerry"); + vs.push_back("Jenny"); + vs.push_back("Klaus"); + vs.push_back("Celine"); + vs.push_back("Kenny"); + + vs.push_back("Kelly"); + vs.push_back("Jackson"); + vs.push_back("Mandy"); + vs.push_back("Terry"); + vs.push_back("Sandy"); + + vs.push_back("Billy"); + vs.push_back("Cindy"); + vs.push_back("Phil"); + vs.push_back("Lindy"); + vs.push_back("David"); +*/ + size_t num = 0; + for (size_t i = 0; i < vs.size(); ++i) + { + vsv.push_back(vs.at(i)); + num += vs.at(i).size(); + } + std::cout << "num strings: " << vsv.size() << std::endl; + std::cout << "avg str len: " << num / (float)vsv.size() << std::endl; +} + +void initLongStringVec(std::vector<std::string>& vs, std::vector<std::string_view>& vsv) +{ + vs.clear(); + vsv.clear(); + + vs = read_file("names.txt"); + for (size_t i = 1; i < vs.size(); ++i) { + vs[i] += vs[i]; + vs[i] += vs[i]; + vs[i] += vs[i]; + } +/* + vs.push_back("Susan Susan Susan Susan Susan Susan"); + vs.push_back("Jason Jason Jason Jason Jason Jason"); + vs.push_back("Lily Lily Lily Lily Lily Lily"); + vs.push_back("Michael Michael Michael Michael Michael Michael"); + vs.push_back("Mary Mary Mary Mary Mary Mary"); + + vs.push_back("Jerry Jerry Jerry Jerry Jerry Jerry"); + vs.push_back("Jenny Jenny Jenny Jenny Jenny Jenny"); + vs.push_back("Klaus Klaus Klaus Klaus Klaus Klaus"); + vs.push_back("Celine Celine Celine Celine Celine Celine"); + vs.push_back("Kenny Kenny Kenny Kenny Kenny Kenny"); + + vs.push_back("Kelly Kelly Kelly Kelly Kelly Kelly"); + vs.push_back("Jackson Jackson Jackson Jackson Jackson Jackson"); + vs.push_back("Mandy Mandy Mandy Mandy Mandy Mandy"); + vs.push_back("Terry Terry Terry Terry Terry Terry"); + vs.push_back("Sandy Sandy Sandy Sandy Sandy Sandy"); + + vs.push_back("Billy Billy Billy Billy Billy Billy"); + vs.push_back("Cindy Cindy Cindy Cindy Cindy Cindy"); + vs.push_back("Phil Phil Phil Phil Phil Phil"); + vs.push_back("Lindy Lindy Lindy Lindy Lindy Lindy"); + vs.push_back("David David David David David David"); +*/ + size_t num = 0; + for (size_t i = 0; i < vs.size(); ++i) + { + vsv.push_back(vs.at(i)); + num += vs.at(i).size(); + } + std::cout << "num strings: " << vsv.size() << std::endl; + std::cout << "avg str len: " << num / (float)vsv.size() << std::endl; +} + +void initMapNormal(const std::vector<std::string>& vs, std::map<std::string, size_t>& mapNormal) +{ + mapNormal.clear(); + for (size_t i = 0; i < vs.size(); ++i) + { + mapNormal.insert(std::make_pair(vs.at(i), i)); + } +} + +void initMapTrans(const std::vector<std::string>& vs, std::map<std::string, size_t, std::less<> >& mapTrans) +{ + mapTrans.clear(); + for (size_t i = 0; i < vs.size(); ++i) + { + mapTrans.insert(std::make_pair(vs.at(i), i)); + } +} + +struct MyEqual : public std::equal_to<> +{ + using is_transparent = void; +}; + +struct string_hash { + using is_transparent = void; + using key_equal = std::equal_to<>; // Pred to use + using hash_type = std::hash<std::string_view>; // just a helper local type + size_t operator()(std::string_view txt) const { return hash_type{}(txt); } + size_t operator()(const std::string& txt) const { return hash_type{}(txt); } + size_t operator()(const char* txt) const { return hash_type{}(txt); } +}; + +void initUnorderedMapNormal(const std::vector<std::string>& vs, std::unordered_map<std::string, size_t>& unordmapNormal) +{ + unordmapNormal.clear(); + for (size_t i = 0; i < vs.size(); ++i) + { + unordmapNormal.insert(std::make_pair(vs.at(i), i)); + } +} + +void initUnorderedMapTrans(const std::vector<std::string>& vs, std::unordered_map<std::string, size_t, string_hash, MyEqual>& unordmapTrans) +{ + unordmapTrans.clear(); + for (size_t i = 0; i < vs.size(); ++i) + { + unordmapTrans.insert(std::make_pair(vs.at(i), i)); + } +} + +void benchmark( + const std::vector<std::string>& vec_shortstr, + const std::vector<std::string_view>& vec_shortstrview, + const std::map<std::string, size_t>& mapNormal, + const std::map<std::string, size_t, std::less<> >& mapTrans, + const std::unordered_map<std::string, size_t>& unordmapNormal, + const std::unordered_map<std::string, size_t, string_hash, MyEqual>& unordmapTrans); + +//const size_t MAX_LOOP = 1000000; +const size_t MAX_LOOP = 2000; + +int main() +{ + std::vector<std::string> vec_shortstr; + std::vector<std::string_view> vec_shortstrview; + + std::map<std::string, size_t> mapNormal; + std::map<std::string, size_t, std::less<> > mapTrans; + initShortStringVec(vec_shortstr, vec_shortstrview); + initMapNormal(vec_shortstr, mapNormal); + initMapTrans(vec_shortstr, mapTrans); + + std::unordered_map<std::string, size_t> unordmapNormal; + std::unordered_map<std::string, size_t, string_hash, MyEqual> unordmapTrans; + initUnorderedMapNormal(vec_shortstr, unordmapNormal); + initUnorderedMapTrans(vec_shortstr, unordmapTrans); + + std::cout << "Short String Benchmark" << std::endl; + std::cout << "======================" << std::endl; + + for (int i=0; i<3; ++i) benchmark( + vec_shortstr, + vec_shortstrview, + mapNormal, + mapTrans, + unordmapNormal, + unordmapTrans); + + std::cout << "Long String Benchmark" << std::endl; + std::cout << "=====================" << std::endl; + + initLongStringVec(vec_shortstr, vec_shortstrview); + initMapNormal(vec_shortstr, mapNormal); + initMapTrans(vec_shortstr, mapTrans); + + initUnorderedMapNormal(vec_shortstr, unordmapNormal); + initUnorderedMapTrans(vec_shortstr, unordmapTrans); + + for (int i=0; i<3; ++i) benchmark( + vec_shortstr, + vec_shortstrview, + mapNormal, + mapTrans, + unordmapNormal, + unordmapTrans); + + return 0; +} + +void benchmark( + const std::vector<std::string>& vec_shortstr, + const std::vector<std::string_view>& vec_shortstrview, + const std::map<std::string, size_t>& mapNormal, + const std::map<std::string, size_t, std::less<> >& mapTrans, + const std::unordered_map<std::string, size_t>& unordmapNormal, + const std::unordered_map<std::string, size_t, string_hash, MyEqual>& unordmapTrans) +{ + size_t grandtotal = 0; + size_t total = 0; + timer stopwatch; +/* + total = 0; + stopwatch.start("Normal Map with string"); + for (size_t i = 0; i < MAX_LOOP; ++i) + { + for (size_t j = 0; j < vec_shortstr.size(); ++j) + { + const auto& it = mapNormal.find(vec_shortstr[j]); + if(it!=mapNormal.cend()) + total += it->second; + } + } + grandtotal += total; + stopwatch.stop(); + + total = 0; + stopwatch.start("Normal Map with char*"); + for (size_t i = 0; i < MAX_LOOP; ++i) + { + for (size_t j = 0; j < vec_shortstr.size(); ++j) + { + const auto& it = mapNormal.find(vec_shortstr[j].c_str()); + if (it != mapNormal.cend()) + total += it->second; + } + } + grandtotal += total; + stopwatch.stop(); +*/ + total = 0; + stopwatch.start("Trans Map with char*"); + for (size_t i = 0; i < MAX_LOOP; ++i) + { + for (size_t j = 0; j < vec_shortstr.size(); ++j) + { + const auto& it = mapTrans.find(vec_shortstr[j].c_str()); + if (it != mapTrans.cend()) + total += it->second; + } + } + grandtotal += total; + stopwatch.stop(); + + total = 0; + stopwatch.start("Trans Map with string_view"); + for (size_t i = 0; i < MAX_LOOP; ++i) + { + for (size_t j = 0; j < vec_shortstrview.size(); ++j) + { + const auto& it = mapTrans.find(vec_shortstrview[j]); + if (it != mapTrans.cend()) + total += it->second; + } + } + grandtotal += total; + stopwatch.stop(); +/* + total = 0; + stopwatch.start("Normal Unord Map with string"); + for (size_t i = 0; i < MAX_LOOP; ++i) + { + for (size_t j = 0; j < vec_shortstr.size(); ++j) + { + const auto& it = unordmapNormal.find(vec_shortstr[j]); + if (it != unordmapNormal.cend()) + total += it->second; + } + } + grandtotal += total; + stopwatch.stop(); + + total = 0; + stopwatch.start("Normal Unord Map with char*"); + for (size_t i = 0; i < MAX_LOOP; ++i) + { + for (size_t j = 0; j < vec_shortstr.size(); ++j) + { + const auto& it = unordmapNormal.find(vec_shortstr[j].c_str()); + if (it != unordmapNormal.cend()) + total += it->second; + } + } + grandtotal += total; + stopwatch.stop(); +*/ + total = 0; + stopwatch.start("Trans Unord Map with char*"); + for (size_t i = 0; i < MAX_LOOP; ++i) + { + for (size_t j = 0; j < vec_shortstr.size(); ++j) + { + const auto& it = unordmapTrans.find(vec_shortstr[j].c_str()); + if (it != unordmapTrans.cend()) + total += it->second; + } + } + grandtotal += total; + stopwatch.stop(); + + total = 0; + stopwatch.start("Trans Unord Map with string_view"); + for (size_t i = 0; i < MAX_LOOP; ++i) + { + for (size_t j = 0; j < vec_shortstrview.size(); ++j) + { + const auto& it = unordmapTrans.find(vec_shortstrview[j]); + if (it != unordmapTrans.cend()) + total += it->second; + } + } + grandtotal += total; + + stopwatch.stop(); + + std::cout << "grandtotal:" << grandtotal << " <--- Ignore this\n" << std::endl; + +} diff --git a/docs/cstr_api.md b/docs/cstr_api.md index 4f7c689e..85a872fe 100644 --- a/docs/cstr_api.md +++ b/docs/cstr_api.md @@ -22,6 +22,7 @@ cstr cstr_from_n(const char* str, size_t n); // constru cstr cstr_with_capacity(size_t cap); cstr cstr_with_size(size_t len, char fill); // repeat fill len times cstr cstr_from_fmt(const char* fmt, ...); // printf() formatting +cstr cstr_from_replace_all_sv(csview sv, csview find, csview repl); cstr cstr_clone(cstr s); cstr* cstr_take(cstr* self, cstr s); // take the constructed or moved string diff --git a/docs/csview_api.md b/docs/csview_api.md index a472194f..5211e2f6 100644 --- a/docs/csview_api.md +++ b/docs/csview_api.md @@ -76,7 +76,7 @@ uint32_t utf8_decode(uint32_t *state, uint32_t *codep, const uint32_t byt #### Extended cstr methods ```c cstr cstr_from_sv(csview sv); // construct cstr from csview -csview cstr_to_sv(const cstr* self); // convert to csview from const cstr* +csview cstr_sv(const cstr* self); // convert to csview from const cstr* cstr cstr_from_replace_all_sv(csview sv, csview find, csview replace); csview cstr_substr(const cstr* s, intptr_t pos, size_t n); // negative pos count from end diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 56dd501e..1c19bde7 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -112,27 +112,24 @@ typedef const char* crawstr; #define _c_ROTL(x, k) (x << (k) | x >> (8*sizeof(x) - (k)))
-STC_INLINE uint64_t c_strhash(const char *s) {
- int c; uint64_t h = *s++;
- if (h) while ((c = *s++)) h = (h << 10) - h + c;
- return _c_ROTL(h, 26) ^ h;
-}
-
STC_INLINE uint64_t c_default_hash(const void* key, size_t len) {
- uint64_t u8, h = 1;
+ uint64_t u8, h = 1; size_t n = len >> 3;
uint32_t u4;
const uint8_t *x = (const uint8_t*) key;
- for (size_t n = len >> 3; n--; )
- memcpy(&u8, x, 8), x += 8, h += u8*0xc6a4a7935bd1e99d;
+ while (n--)
+ memcpy(&u8, x, 8), x += 8, h += (h << 10) ^ (u8*0xc6a4a7935bd1e99d);
switch (len &= 7) {
- case 0: return h;
- case 4: memcpy(&u4, x, 4); return h + u4*0xc6a4a7935bd1e99d;
+ case 0: return h;
+ case 4: memcpy(&u4, x, 4); return h + u4*0xc6a4a7935bd1e99d;
}
h += *x++;
while (--len) h = (h << 10) - h + *x++;
return _c_ROTL(h, 26) ^ h;
}
+STC_INLINE uint64_t c_strhash(const char *s)
+ { return c_default_hash(s, strlen(s)); }
+
STC_INLINE char* c_strnstrn(const char *s, const char *needle, size_t slen, const size_t nlen) {
if (!nlen) return (char *)s;
if (nlen > slen) return NULL;
diff --git a/include/stc/cstr.h b/include/stc/cstr.h index 9c6568f7..b669b6d5 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -87,12 +87,17 @@ STC_API void cstr_erase_n(cstr* self, size_t pos, size_t n); STC_API cstr cstr_from_fmt(const char* fmt, ...);
STC_API int cstr_printf(cstr* self, const char* fmt, ...);
STC_API void cstr_replace_all(cstr* self, const char* find, const char* repl);
+STC_API cstr cstr_from_replace_all_sv(csview sv, csview find, csview repl);
STC_INLINE cstr_rep_t cstr_rep(cstr* s) {
return cstr_is_long(s)
? c_make(cstr_rep_t){s->lon.data, cstr_l_size(s), cstr_l_cap(s)}
: c_make(cstr_rep_t){s->sml.data, cstr_s_size(s), cstr_s_cap};
}
+STC_INLINE csview cstr_sv(const cstr* s) {
+ return cstr_is_long(s) ? c_make(csview){s->lon.data, cstr_l_size(s)}
+ : c_make(csview){s->sml.data, cstr_s_size(s)};
+}
STC_INLINE cstr cstr_init(void)
{ return cstr_null; }
@@ -132,8 +137,8 @@ STC_INLINE cstr cstr_move(cstr* self) { }
STC_INLINE cstr cstr_clone(cstr s) {
- cstr_rep_t r = cstr_rep(&s);
- return cstr_from_n(r.data, r.size);
+ csview sv = cstr_sv(&s);
+ return cstr_from_n(sv.str, sv.size);
}
STC_INLINE void cstr_drop(cstr* self) {
@@ -169,17 +174,19 @@ STC_INLINE size_t cstr_length(cstr s) STC_INLINE size_t cstr_capacity(cstr s)
{ return cstr_is_long(&s) ? cstr_l_cap(&s) : cstr_s_cap; }
+STC_INLINE int cstr_cmp(const cstr* s1, const cstr* s2)
+ { return strcmp(cstr_str(s1), cstr_str(s2)); }
+
+STC_INLINE bool cstr_eq(const cstr* s1, const cstr* s2) {
+ csview x = cstr_sv(s1), y = cstr_sv(s2);
+ return x.size == y.size && !memcmp(x.str, y.str, x.size);
+}
+
STC_INLINE bool cstr_equals(cstr s1, const char* str)
{ return strcmp(cstr_str(&s1), str) == 0; }
STC_INLINE bool cstr_equals_s(cstr s1, cstr s2)
- { return strcmp(cstr_str(&s1), cstr_str(&s2)) == 0; }
-
-STC_INLINE bool cstr_eq(const cstr* s1, const cstr* s2)
- { return strcmp(cstr_str(s1), cstr_str(s2)) == 0; }
-
-STC_INLINE int cstr_cmp(const cstr* s1, const cstr* s2)
- { return strcmp(cstr_str(s1), cstr_str(s2)); }
+ { return cstr_cmp(&s1, &s2) == 0; }
STC_INLINE size_t cstr_find(cstr s, const char* needle) {
const char *str = cstr_str(&s), *res = strstr(str, needle);
@@ -205,8 +212,8 @@ STC_INLINE bool cstr_starts_with_s(cstr s, cstr sub) { return cstr_starts_with(s, cstr_str(&sub)); }
STC_INLINE bool cstr_ends_with(cstr s, const char* sub) {
- cstr_rep_t r = cstr_rep(&s); size_t n = strlen(sub);
- return n <= r.size && memcmp(r.data + r.size - n, sub, n) == 0;
+ csview sv = cstr_sv(&s); size_t n = strlen(sub);
+ return n <= sv.size && memcmp(sv.str + sv.size - n, sub, n) == 0;
}
STC_INLINE bool cstr_ends_with_s(cstr s, cstr sub)
@@ -216,16 +223,16 @@ STC_INLINE void cstr_assign(cstr* self, const char* str) { cstr_assign_n(self, str, strlen(str)); }
STC_INLINE void cstr_copy(cstr* self, cstr s) {
- cstr_rep_t r = cstr_rep(&s);
- cstr_assign_n(self, r.data, r.size);
+ csview sv = cstr_sv(&s);
+ cstr_assign_n(self, sv.str, sv.size);
}
STC_INLINE void cstr_append(cstr* self, const char* str)
{ cstr_append_n(self, str, strlen(str)); }
STC_INLINE void cstr_append_s(cstr* self, cstr s) {
- cstr_rep_t r = cstr_rep(&s);
- cstr_append_n(self, r.data, r.size);
+ csview sv = cstr_sv(&s);
+ cstr_append_n(self, sv.str, sv.size);
}
STC_INLINE void cstr_replace_n(cstr* self, size_t pos, size_t len, const char* str, size_t n) {
@@ -237,8 +244,8 @@ STC_INLINE void cstr_replace(cstr* self, size_t pos, size_t len, const char* str { cstr_replace_n(self, pos, len, str, strlen(str)); }
STC_INLINE void cstr_replace_s(cstr* self, size_t pos, size_t len, cstr s) {
- cstr_rep_t r = cstr_rep(&s);
- cstr_replace_n(self, pos, len, r.data, r.size);
+ csview sv = cstr_sv(&s);
+ cstr_replace_n(self, pos, len, sv.str, sv.size);
}
STC_INLINE void cstr_insert_n(cstr* self, size_t pos, const char* str, size_t n)
@@ -248,18 +255,17 @@ STC_INLINE void cstr_insert(cstr* self, size_t pos, const char* str) { cstr_replace_n(self, pos, 0, str, strlen(str)); }
STC_INLINE void cstr_insert_s(cstr* self, size_t pos, cstr s) {
- cstr_rep_t r = cstr_rep(&s);
- cstr_replace_n(self, pos, 0, r.data, r.size);
+ csview sv = cstr_sv(&s);
+ cstr_replace_n(self, pos, 0, sv.str, sv.size);
}
STC_INLINE bool cstr_getline(cstr *self, FILE *fp)
{ return cstr_getdelim(self, '\n', fp); }
-/* container adaptor functions: */
-#define cstr_cmp(xp, yp) strcmp(cstr_str(xp), cstr_str(yp))
-#define cstr_eq(xp, yp) (!cstr_cmp(xp, yp))
-STC_INLINE uint64_t cstr_hash(const cstr *self, size_t dummylen)
- { return c_default_hash(cstr_str(self), cstr_size(*self)); }
+STC_INLINE uint64_t cstr_hash(const cstr *self, size_t dummylen) {
+ csview sv = cstr_sv(self);
+ return c_default_hash(sv.str, sv.size);
+}
/* -------------------------- IMPLEMENTATION ------------------------- */
#if defined(_i_implement)
@@ -332,11 +338,11 @@ STC_DEF void cstr_resize(cstr* self, const size_t size, const char value) { }
STC_DEF size_t cstr_find_n(cstr s, const char* needle, const size_t pos, const size_t nmax) {
- cstr_rep_t r = cstr_rep(&s);
+ csview sv = cstr_sv(&s);
const size_t nlen = (size_t) strlen(needle);
- if (pos > r.size) return cstr_npos;
- char* res = c_strnstrn(r.data + pos, needle, r.size, nmax < nlen ? nmax : nlen);
- return res ? res - r.data : cstr_npos;
+ if (pos > sv.size) return cstr_npos;
+ char* res = c_strnstrn(sv.str + pos, needle, sv.size, nmax < nlen ? nmax : nlen);
+ return res ? res - sv.str : cstr_npos;
}
STC_DEF cstr* cstr_assign_n(cstr* self, const char* str, const size_t n) {
@@ -401,9 +407,15 @@ cstr_from_replace_all(const char* str, const size_t str_len, STC_DEF void
cstr_replace_all(cstr* self, const char* find, const char* repl) {
- cstr_rep_t r = cstr_rep(self);
- cstr_take(self, cstr_from_replace_all(r.data, r.size, find, strlen(find),
- repl, strlen(repl)));
+ csview sv = cstr_sv(self);
+ cstr_take(self, cstr_from_replace_all(sv.str, sv.size, find, strlen(find),
+ repl, strlen(repl)));
+}
+
+STC_DEF cstr
+cstr_from_replace_all_sv(csview sv, csview find, csview repl) {
+ return cstr_from_replace_all(sv.str, sv.size, find.str, find.size,
+ repl.str, repl.size);
}
STC_DEF void cstr_erase_n(cstr* self, const size_t pos, size_t n) {
diff --git a/include/stc/csview.h b/include/stc/csview.h index 59e853ca..be430a79 100644 --- a/include/stc/csview.h +++ b/include/stc/csview.h @@ -94,11 +94,6 @@ STC_INLINE csview csview_from_s(const cstr* self) STC_INLINE cstr cstr_from_sv(csview sv)
{ return cstr_from_n(sv.str, sv.size); }
-/*STC_INLINE cstr cstr_from_replace_all_sv(csview sv, csview find, csview repl)
- { return cstr_from_replace_all(sv.str, sv.size, find.str, find.size,
- repl.str, repl.size); }*/
-STC_INLINE csview cstr_to_sv(const cstr* self)
- { return c_make(csview){cstr_str(self), cstr_size(*self)}; }
STC_INLINE csview cstr_substr(const cstr* self, intptr_t pos, size_t n)
{ return csview_substr(csview_from_s(self), pos, n); }
STC_INLINE csview cstr_slice(const cstr* self, intptr_t p1, intptr_t p2)
@@ -127,12 +122,12 @@ STC_INLINE bool cstr_ends_with_sv(cstr s, csview sub) #endif
/* ---- Container helper functions ---- */
-STC_INLINE int csview_cmp(const csview* x, const csview* y) {
- const size_t m = x->size < y->size ? x->size : y->size;
- const int c = memcmp(x->str, y->str, m);
- return c ? c : x->size - y->size;
- }
-#define csview_eq(xp, yp) (!csview_cmp(xp, yp))
+STC_INLINE int csview_cmp(const csview* x, const csview* y)
+ { return strcmp(x->str, y->str); }
+
+STC_INLINE bool csview_eq(const csview* x, const csview* y)
+ { return x->size == y->size && !memcmp(x->str, y->str, x->size); }
+
STC_INLINE uint64_t csview_hash(const csview *self, size_t sz)
{ return c_default_hash(self->str, self->size); }
diff --git a/include/stc/template.h b/include/stc/template.h index 48881edf..659f6a72 100644 --- a/include/stc/template.h +++ b/include/stc/template.h @@ -106,7 +106,8 @@ #define i_key_bind cstr
#define i_keyraw csview
#define i_keyfrom cstr_from_sv
- #define i_keyto cstr_to_sv
+ #define i_keyto cstr_sv
+ #define i_eq csview_eq
#ifndef i_tag
#define i_tag ssv
#endif
@@ -197,7 +198,7 @@ #define i_val cstr
#define i_valraw csview
#define i_valfrom cstr_from_sv
- #define i_valto cstr_to_sv
+ #define i_valto cstr_sv
#define i_valdrop cstr_drop
#elif defined i_val_arcbox
#define i_val_bind i_val_arcbox
|
