diff options
| author | Tyge Løvset <[email protected]> | 2021-05-18 10:08:35 +0200 |
|---|---|---|
| committer | Tyge Løvset <[email protected]> | 2021-05-18 10:08:35 +0200 |
| commit | ccc45a1dc249160364aa12b3cfecc9844d6760ff (patch) | |
| tree | 0519dbbf45cabb8869a11219ba64d9ef034759fa | |
| parent | 60a127bb9a7180d4d30c2b7186456cc1226e812a (diff) | |
| download | STC-modified-ccc45a1dc249160364aa12b3cfecc9844d6760ff.tar.gz STC-modified-ccc45a1dc249160364aa12b3cfecc9844d6760ff.zip | |
Added new file: csview: String View
| -rw-r--r-- | README.md | 1 | ||||
| -rw-r--r-- | docs/csview_api.md | 155 | ||||
| -rw-r--r-- | examples/svmap.c | 38 | ||||
| -rw-r--r-- | stc/csview.h | 157 |
4 files changed, 351 insertions, 0 deletions
@@ -25,6 +25,7 @@ the multi-map/set variants: - [***csset*** - **std::set** sorted set alike type](docs/csset_api.md)
- [***cstack*** - **std::stack** alike (adapter) type](docs/cstack_api.md)
- [***cstr*** - **std::string** alike type](docs/cstr_api.md)
+- [***csview*** - **std::string_view** alike type](docs/csview_api.md)
- [***cvec*** - **std::vector** alike type](docs/cvec_api.md)
Others:
diff --git a/docs/csview_api.md b/docs/csview_api.md new file mode 100644 index 00000000..4098114c --- /dev/null +++ b/docs/csview_api.md @@ -0,0 +1,155 @@ +# STC [csview](../stc/csview.h): String View + + +The type **csview** is a string view and can refer to a constant contiguous sequence of char-elements with the first +element of the sequence at position zero. The implementation holds two members: a pointer to constant char and a size. + +**csview** is an efficient replacent for `const char*`. It never allocates memory, and therefore need not be destructed. +Its lifetime is limited by the source string storage. It keeps the length of the string, and does not call *strlen()* +when passing it around. It is faster when using`csview` as convertion type (raw) than `const char*` in associative +containers with cstr keys. E.g. prefer `using_cmap_svkey()` over `using_cmap_strkey()`. + +See the c++ class [std::basic_string_view](https://en.cppreference.com/w/cpp/string/basic_string_view) for a functional +description. + +## Header file + +All csview definitions and prototypes are available by including a single header file. + +```c +#include <stc/csview.h> +``` +## Methods + +```c +csview csview_new(const char literal_only[]); // csview from literal, no strlen() +csview c_sv(const char literal_only[]); // shorthand for csview_new() +csview csview_from(const char* str); // construct +csview csview_from_n(const char* str, size_t n); // construct +csview csview_from_s(cstr s); // construct +csview csview_substr(csview sv, size_t pos, size_t n); + +size_t csview_size(csview sv); +size_t csview_length(csview sv); +bool csview_empty(csview sv); + +void csview_clear(csview* self); + +bool csview_equals(csview sv, csview sv2); +size_t csview_find(csview sv, csview needle); +bool csview_contains(csview sv, csview needle); +bool csview_begins_with(csview sv, csview sub); +bool csview_ends_with(csview sv, csview sub); + +const char* csview_front(const csview* self); +const char* csview_back(const csview* self); + +csview_iter_t csview_begin(const csview* self); +csview_iter_t csview_end(const csview* self); +void csview_next(csview_iter_t* it); +``` +#### Extended cstr methods +```c +cstr cstr_from_v(csview sv); +csview cstr_to_v(const cstr* self); +cstr* cstr_assign_v(cstr* self, csview sv); +cstr* cstr_append_v(cstr* self, csview sv); +void cstr_insert_v(cstr* self, size_t pos, csview sv); +void cstr_replace_v(cstr* self, size_t pos, size_t len, csview sv); + +bool cstr_equals_v(cstr s, csview sv); +size_t cstr_find_v(cstr s, csview needle); +bool cstr_contains_v(cstr s, csview needle); +bool cstr_begins_with_v(cstr s, csview sub); +bool cstr_ends_with_v(cstr s, csview sub); +``` +#### Helper methods +```c +int csview_compare_ref(const csview* x, const csview* y); +bool csview_equals_ref(const csview* x, const csview* y); +uint64_t csview_hash_ref(const csview* x, size_t ignored); +``` +## Types + +| Type name | Type definition | Used to represent... | +|:------------------|:------------------------------------------|:-------------------------| +| `csview` | `struct { const char *str; size_t size }` | The string view type | +| `csview_value_t` | `char` | The string element type | +| `csview_iter_t` | `struct { csview_value_t *ref; }` | csview iterator | + +## Constants and macros + +| Name | Value | +|:------------------|:------------------| +| `csview_null` | csview null value | + +## Container adaptors +``` +using_cvec_sv() +using_cdeq_sv() +using_clist_sv() + +using_csmap_svkey(X, Mapped) +using_csmap_svkey(X, Mapped, mappedDel) +using_csmap_svkey(X, Mapped, mappedDel, mappedClone) +using_csmap_svkey(X, Mapped, mappedDel, mappedFromRaw, mappedToRaw, RawMapped) +using_csmap_sv() +using_csset_sv() + +using_cmap_svkey(X, Mapped) +using_cmap_svkey(X, Mapped, mappedDel) +using_cmap_svkey(X, Mapped, mappedDel, mappedClone) +using_cmap_svkey(X, Mapped, mappedDel, mappedFromRaw, mappedToRaw, RawMapped) +using_cmap_sv() +using_cset_sv() +``` + +## Example +```c +#include <stc/cmap.h> + +using_cmap_svkey(si, int); // cmap<cstr, int> with csview as convertion type +using_cvec_sv(); // cvec<cstr> with csview as convertion type + +int main() +{ + csview text = c_sv("A long and winded literal string"); + printf("%s\nLength: %zu\n\n", text.str, text.size); + + c_var (cvec_sv, vec, { + c_sv("Element 1"), + c_sv("Element 2"), + c_sv("Element 3") + }); + cvec_sv_push_back(&vec, cstr_new("Second last element")); + cvec_sv_emplace_back(&vec, c_sv("Last element")); // converts from csview to cstr + + c_foreach (i, cvec_sv, vec) + printf("%s\n", i.ref->str); + + c_var (cmap_si, map, { + {c_sv("hello"), 100}, + {c_sv("world"), 200} + }); + cmap_si_emplace(&map, c_sv("gone mad"), 300); + + cmap_si_value_t* v = cmap_si_get(&map, c_sv("world")); + printf("\n%s: %d\n", v->first.str, v->second); + + cmap_si_del(&map); + cvec_sv_del(&vec); +} +``` +Output: +``` +A long and winded literal string +Length: 32 + +Great +Fantastic +Sensational +Second last element +Last element + +world: 200 +``` diff --git a/examples/svmap.c b/examples/svmap.c new file mode 100644 index 00000000..f4bcc311 --- /dev/null +++ b/examples/svmap.c @@ -0,0 +1,38 @@ +#include <stc/csview.h>
+#include <stc/cmap.h>
+#include <stdio.h>
+
+// cmap<cstr, int> with csview as convertion key-type (raw):
+using_cmap_svkey(si, int);
+
+int main() {
+ csview fox = c_sv("The quick brown fox jumps over the lazy dog.");
+ printf("\"%s\", length=%zu\n", fox.str, fox.size);
+
+ cmap_si frequencies = cmap_si_init();
+
+ // Non-emplace: cstr element API
+ cmap_si_insert(&frequencies, cstr_new("thousand"), 1000);
+ cmap_si_insert_or_assign(&frequencies, cstr_new("thousand"), 2000); // update; same as put()
+ cmap_si_insert(&frequencies, cstr_new("thousand"), 3000); // ignored
+
+ // Emplace: csview element API
+ const char* key = "hundred";
+ cmap_si_emplace(&frequencies, c_sv("hundred"), 300); // c_sv() shorthand for csview_new()
+ cmap_si_emplace(&frequencies, csview_from_n(key, 4), 400); // insert "hund"
+ cmap_si_emplace_or_assign(&frequencies, csview_from(key), 500); // update
+ cmap_si_emplace(&frequencies, c_sv("hundred"), 600); // ignored, already inserted
+
+ // Lookup always uses "raw" type API, i.e. csview here.
+ printf("at(\"hundred\"): %d\n", *cmap_si_at(&frequencies, c_sv("hundred")));
+
+ c_foreach (i, cmap_si, frequencies)
+ printf("%s: %d\n", i.ref->first.str, i.ref->second);
+
+ /* Output: */
+ // "The quick brown fox jumps over the lazy dog.", length=44
+ // at("hundred"): 500
+ // hund: 400
+ // hundred: 500
+ // thousand: 2000
+}
\ No newline at end of file diff --git a/stc/csview.h b/stc/csview.h new file mode 100644 index 00000000..a24bac26 --- /dev/null +++ b/stc/csview.h @@ -0,0 +1,157 @@ +/* MIT License
+ *
+ * Copyright (c) 2021 Tyge Løvset, NORCE, www.norceresearch.no
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef CSVIEW_H_INCLUDED
+#define CSVIEW_H_INCLUDED
+
+#include "cstr.h"
+
+typedef struct { const char* str; size_t size; } csview;
+typedef struct { const char *ref; } csview_iter_t;
+typedef char csview_value_t;
+#define csview_null c_make(csview){"", 0}
+
+#define csview_new(literal) \
+ c_make(csview){literal, sizeof c_make(strlit_t){literal} - 1}
+#define c_sv(literal) \
+ csview_new(literal)
+STC_INLINE csview csview_from(const char* str)
+ { return c_make(csview){str, strlen(str)}; }
+STC_INLINE csview csview_from_n(const char* str, size_t n)
+ { return c_make(csview){str, n}; }
+STC_INLINE csview csview_from_v(csview sv, size_t pos)
+ { sv.str += pos, sv.size -= pos; return sv; }
+STC_INLINE csview csview_from_s(cstr s)
+ { return c_make(csview){s.str, _cstr_rep(&s)->size}; }
+STC_INLINE csview csview_substr(csview sv, size_t pos, size_t n)
+ { sv.str += pos, sv.size = n; return sv; }
+
+STC_INLINE size_t csview_size(csview sv) { return sv.size; }
+STC_INLINE size_t csview_length(csview sv) { return sv.size; }
+STC_INLINE bool csview_empty(csview sv) { return sv.size == 0; }
+STC_INLINE void csview_clear(csview* self) { *self = csview_null; }
+STC_INLINE const char* csview_front(const csview* self) { return self->str; }
+STC_INLINE const char* csview_back(const csview* self) { return self->str + self->size - 1; }
+
+STC_INLINE size_t csview_find(csview sv, csview needle)
+ { char* res = c_strnstrn(sv.str, needle.str, sv.size, needle.size);
+ return res ? res - sv.str : cstr_npos; }
+STC_INLINE bool csview_equals(csview sv, csview sv2)
+ { return sv.size == sv2.size && !memcmp(sv.str, sv2.str, sv.size); }
+STC_INLINE bool csview_contains(csview sv, csview sub)
+ { return c_strnstrn(sv.str, sub.str, sv.size, sub.size) != NULL; }
+STC_INLINE bool csview_begins_with(csview sv, csview sub)
+ { if (sub.size > sv.size) return false;
+ return !memcmp(sv.str, sub.str, sub.size); }
+STC_INLINE bool csview_ends_with(csview sv, csview sub)
+ { if (sub.size > sv.size) return false;
+ return !memcmp(sv.str + sv.size - sub.size, sub.str, sub.size); }
+STC_INLINE csview_iter_t csview_begin(const csview* self)
+ { return c_make(csview_iter_t){self->str}; }
+STC_INLINE csview_iter_t csview_end(const csview* self)
+ { return c_make(csview_iter_t){self->str + self->size}; }
+STC_INLINE void csview_next(csview_iter_t* it) { ++it->ref; }
+
+/* cstr interaction with csview: */
+
+STC_INLINE cstr cstr_from_v(csview sv)
+ { return cstr_from_n(sv.str, sv.size); }
+STC_INLINE csview cstr_to_v(const cstr* self)
+ { return c_make(csview){self->str, _cstr_rep(self)->size}; }
+STC_INLINE cstr* cstr_assign_v(cstr* self, csview sv)
+ { return cstr_assign_n(self, sv.str, sv.size); }
+STC_INLINE cstr* cstr_append_v(cstr* self, csview sv)
+ { return cstr_append_n(self, sv.str, sv.size); }
+STC_INLINE void cstr_insert_v(cstr* self, size_t pos, csview sv)
+ { cstr_replace_n(self, pos, 0, sv.str, sv.size); }
+STC_INLINE void cstr_replace_v(cstr* self, size_t pos, size_t len, csview sv)
+ { cstr_replace_n(self, pos, len, sv.str, sv.size); }
+STC_INLINE size_t cstr_find_v(cstr s, csview needle)
+ { char* res = c_strnstrn(s.str, needle.str, cstr_size(s), needle.size);
+ return res ? res - s.str : cstr_npos; }
+STC_INLINE bool cstr_equals_v(cstr s, csview sv)
+ { return sv.size == cstr_size(s) && !memcmp(s.str, sv.str, sv.size); }
+STC_INLINE bool cstr_contains_v(cstr s, csview sub)
+ { return c_strnstrn(s.str, sub.str, cstr_size(s), sub.size) != NULL; }
+STC_INLINE bool cstr_begins_with_v(cstr s, csview sub)
+ { if (sub.size > cstr_size(s)) return false;
+ return !memcmp(s.str, sub.str, sub.size); }
+STC_INLINE bool cstr_ends_with_v(cstr s, csview sub)
+ { if (sub.size > cstr_size(s)) return false;
+ return !memcmp(s.str + cstr_size(s) - sub.size, sub.str, sub.size); }
+
+
+/* ---- Adaptor functions ---- */
+
+#define csview_compare_ref(xp, yp) strcmp((xp)->str, (yp)->str)
+STC_INLINE bool csview_equals_ref(const csview* a, const csview* b)
+ { return a->size == b->size && !memcmp(a->str, b->str, a->size); }
+#define csview_hash_ref(xp, none) c_default_hash((xp)->str, (xp)->size)
+
+/* ---- Containers ---- */
+
+#define using_cvec_sv() \
+ using_cvec(sv, cstr, csview_compare_ref, cstr_del, cstr_from_v, cstr_to_v, csview)
+#define using_cdeq_sv() \
+ using_cdeq(sv, cstr, csview_compare_ref, cstr_del, cstr_from_v, cstr_to_v, csview)
+#define using_clist_sv() \
+ using_clist(sv, cstr, csview_compare_ref, cstr_del, cstr_from_v, cstr_to_v, csview)
+
+
+#define using_csmap_svkey(...) c_MACRO_OVERLOAD(using_csmap_svkey, __VA_ARGS__)
+
+#define using_csmap_svkey_2(X, Mapped) \
+ using_csmap_svkey_4(X, Mapped, c_default_del, c_default_fromraw)
+#define using_csmap_svkey_3(X, Mapped, mappedDel) \
+ using_csmap_svkey_4(X, Mapped, mappedDel, c_no_clone)
+#define using_csmap_svkey_4(X, Mapped, mappedDel, mappedClone) \
+ using_csmap_svkey_6(X, Mapped, mappedDel, mappedClone, c_default_toraw, Mapped)
+#define using_csmap_svkey_6(X, Mapped, mappedDel, mappedFromRaw, mappedToRaw, RawMapped) \
+ _c_using_aatree(csmap_##X, csmap_, cstr, Mapped, csview_compare_ref, \
+ mappedDel, mappedFromRaw, mappedToRaw, RawMapped, \
+ cstr_del, cstr_from_v, cstr_to_v, csview)
+#define using_csmap_sv() \
+ using_csmap_svkey_6(sv, cstr, cstr_del, cstr_from_v, cstr_to_v, csview)
+#define using_csset_sv() \
+ _c_using_aatree(csset_sv, csset_, cstr, cstr, csview_compare_ref, \
+ @@, @@, @@, void, cstr_del, cstr_from_v, cstr_to_v, csview)
+
+
+#define using_cmap_svkey(...) c_MACRO_OVERLOAD(using_cmap_svkey, __VA_ARGS__)
+
+#define using_cmap_svkey_2(X, Mapped) \
+ using_cmap_svkey_4(X, Mapped, c_default_del, c_default_fromraw)
+#define using_cmap_svkey_3(X, Mapped, mappedDel) \
+ using_cmap_svkey_4(X, Mapped, mappedDel, c_no_clone)
+#define using_cmap_svkey_4(X, Mapped, mappedDel, mappedClone) \
+ using_cmap_svkey_6(X, Mapped, mappedDel, mappedClone, c_default_toraw, Mapped)
+#define using_cmap_svkey_6(X, Mapped, mappedDel, mappedFromRaw, mappedToRaw, RawMapped) \
+ _c_using_chash(cmap_##X, cmap_, cstr, Mapped, csview_equals_ref, csview_hash_ref, \
+ mappedDel, mappedFromRaw, mappedToRaw, RawMapped, \
+ cstr_del, cstr_from_v, cstr_to_v, csview)
+#define using_cmap_sv() \
+ using_cmap_svkey_6(sv, cstr, cstr_del, cstr_from_v, cstr_to_v, csview)
+#define using_cset_sv() \
+ _c_using_chash(cset_sv, cset_, cstr, cstr, csview_equals_ref, csview_hash_ref, \
+ @@, @@, @@, void, cstr_del, cstr_from_v, cstr_to_v, csview)
+
+#endif
\ No newline at end of file |
