summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorTyge Løvset <[email protected]>2022-04-24 13:31:11 +0200
committerTyge Løvset <[email protected]>2022-04-24 13:31:11 +0200
commit6d8406e66c029d4c672bb7531aabec7eb1d079d8 (patch)
tree4bd1e513a04000d3e4140857fcae032f05abeba0
parent2b74b8a880d48232892ca84ac29efacd66905cd4 (diff)
downloadSTC-modified-6d8406e66c029d4c672bb7531aabec7eb1d079d8.tar.gz
STC-modified-6d8406e66c029d4c672bb7531aabec7eb1d079d8.zip
Created VERSION 3.5. See News section in docs for changes.
-rw-r--r--README.md13
-rw-r--r--benchmarks/misc/sso_bench.c52
-rw-r--r--benchmarks/misc/sso_bench.cpp (renamed from benchmarks/misc/sso_bench2.cpp)17
-rw-r--r--benchmarks/misc/string_bench.c153
-rw-r--r--benchmarks/misc/string_bench.cpp199
-rw-r--r--benchmarks/misc/string_bench_STC.cpp298
-rw-r--r--benchmarks/misc/string_bench_STD.cpp370
-rw-r--r--docs/cstr_api.md1
-rw-r--r--docs/csview_api.md2
-rw-r--r--include/stc/ccommon.h19
-rw-r--r--include/stc/cstr.h74
-rw-r--r--include/stc/csview.h17
-rw-r--r--include/stc/template.h5
13 files changed, 746 insertions, 474 deletions
diff --git a/README.md b/README.md
index 754f58f4..8bc3e7fa 100644
--- a/README.md
+++ b/README.md
@@ -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