diff options
| -rw-r--r-- | .gitattributes | 2 | ||||
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | README.md | 107 | ||||
| -rw-r--r-- | docs/cstr_api.md | 2 | ||||
| -rw-r--r-- | include/stc/algo/filter.h | 28 | ||||
| -rw-r--r-- | include/stc/cstack.h | 5 | ||||
| -rw-r--r-- | misc/examples/demos.c | 30 | ||||
| -rw-r--r-- | misc/examples/mapmap.c | 18 | ||||
| -rw-r--r-- | misc/examples/multimap.c | 31 | ||||
| -rw-r--r-- | misc/examples/sort.c | 48 | ||||
| -rw-r--r-- | misc/examples/utf8replace_c.c | 23 | ||||
| -rw-r--r-- | misc/examples/utf8replace_rs.rs | 11 | ||||
| -rw-r--r-- | misc/include/c11/fmt.h (renamed from misc/include/fmt.h) | 37 | ||||
| -rw-r--r-- | misc/include/old/carr2.h (renamed from include/stc/carr2.h) | 8 | ||||
| -rw-r--r-- | misc/include/old/carr3.h (renamed from include/stc/carr3.h) | 8 | ||||
| -rw-r--r-- | misc/include/old/csmap.h (renamed from misc/include/alt/csmap.h) | 0 | ||||
| -rw-r--r-- | misc/include/old/cstr.h (renamed from misc/include/alt/cstr.h) | 0 | ||||
| -rw-r--r-- | misc/include/old/new_arr.c (renamed from misc/examples/new_arr.c) | 6 | ||||
| -rw-r--r-- | misc/include/stctest.h | 203 |
19 files changed, 215 insertions, 354 deletions
diff --git a/.gitattributes b/.gitattributes index 66fdcd56..489a12a4 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,3 @@ -benchmarks/external/* linguist-vendored
+misc/benchmarks/external/* linguist-vendored
*.h linguist-language=C
*.c linguist-language=C
@@ -1,6 +1,6 @@ # Folders stuff/* -benchmarks/external/* +misc/benchmarks/external/* # Prerequisites *.d @@ -3,7 +3,7 @@ STC - Smart Template Containers for C ===================================== -News: Version 4.0 Release Candidate 3 (Sep 2022) +News: Version 4.1 Beta (Dec 2022) ------------------------------------------------ - [See detailed changes for version 4](#version-4). @@ -44,8 +44,8 @@ Containers Others ------ -- [***ccommon*** - Generic algorithms and macros](docs/ccommon_api.md) -- [***cregex*** - Regular expression parser (extended from Rob Pike's regexp9)](docs/cregex_api.md) +- [***ccommon*** - Generic safe macros and algorithms](docs/ccommon_api.md) +- [***cregex*** - Regular expressions (extended from Rob Pike's regexp9)](docs/cregex_api.md) - [***crandom*** - A novel very fast *PRNG* named **stc64**](docs/crandom_api.md) - [***coption*** - getopt() alike command line args parser](docs/coption_api.md) @@ -63,26 +63,26 @@ Highlights - **Compiles with C++ and C99** - C code can be compiled with C++ (container element types must be POD). - **Container prefix and forward declaration** - Templated containers may have user defined prefix, e.g. myvec_push_back(). They may also be forward declared without including the full API/implementation. See documentation below. -Three standout features of STC are -1. the centralized analysis of template arguments: It assigns good defaults to non-specified templates. +Three standout features of STC +1. ***Centralized analysis of template arguments***. Assigns good defaults to non-specified templates. You may specify a number of "standard" template arguments for each container, but as minimum only one is required (two for maps). In the latter case, STC assumes the elements are basic types. For more complex types, additional template arguments must be defined. -2. the general "heterogeneous lookup"-like feature: Allows specification of an alternative type to use +2. ***General "heterogeneous lookup"-like feature***. Allows specification of an alternative type to use for lookup in containers. E.g. for containers with string type (**cstr**) elements, `const char*` is used as lookup type. It will then use the input `const char*` directly when comparing with the string data in the container. This avoids the construction of a new `cstr` (which possible allocates memory) for the lookup. Finally, destruction of the lookup key (i.e. string literal) after usage is not needed (or allowed), which is convenient in C. The alternative lookup type may also be used for adding entries into containers by using the *emplace*-functions. E.g. `MyCStrVec_emplace_back(&vec, "Hello")`, which further simplifies usage of STC. -3. the design of iterators: All container can be iterated the same way, and uses the +3. ***Standardized container iterators***. All container can be iterated the same way, and uses the same element access syntax. E.g. `c_FOREACH (it, IntContainer, container) printf(" %d", *it.ref);` will work for every type of container defined as `IntContainer` with `int` elements. Also the form `c_FOREACH (it, IntContainer, it1, it2)` may be used to iterate from `it1` up to `it2`. Performance ----------- - + Benchmark notes: - The barchart shows average test times over three platforms: Mingw64 10.30, Win-Clang 12, VC19. CPU: Ryzen 7 2700X CPU @4Ghz. @@ -99,11 +99,12 @@ The usage of the containers is similar to the c++ standard containers in STL, so are familiar with them. All containers are generic/templated, except for **cstr** and **cbits**. No casting is used, so containers are type-safe like templates in c++. A basic usage example: ```c -#define i_type FVec // if not defined, vector type would be cvec_float -#define i_val float // container value type -#include <stc/cvec.h> // defines the FVec type +#define i_type FVec // Container type name; if not defined, it would be cvec_float +#define i_val float // Container element type +#include <stc/cvec.h> -int main(void) { +int main(void) +{ FVec vec = FVec_init(); FVec_push_back(&vec, 10.f); FVec_push_back(&vec, 20.f); @@ -112,7 +113,7 @@ int main(void) { for (size_t i = 0; i < FVec_size(vec); ++i) printf(" %g", vec.data[i]); - FVec_drop(&vec); // free memory + FVec_drop(&vec); // cleanup memory } ``` Below is an alternative way to write this code with STC. It uses three @@ -120,15 +121,17 @@ macros: `c_AUTO`, `c_FORLIST`, and `c_FOREACH`. These macro not only simplifies the code, but more importantly makes it less prone to errors, while maintaining readability: ```c -int main() { - c_AUTO (FVec, vec) // RAII: init + free at one location in the code. +int main() +{ + c_AUTO (FVec, vec) // RAII: define vec, init() and drop() all-in-one syntax. { - c_FORLIST (i, float, {10.f, 20.f, 30.f}) // use array literals. - FVec_push(&vec, *i.ref); // alias for push_back. + c_FORLIST (i, float, {10.f, 20.f, 30.f}) // Iterate a list of floats. + FVec_push(&vec, *i.ref); // All containers have push() method. - c_FOREACH (i, FVec, vec) // works for all containers. - printf(" %g", *i.ref); - } + c_FOREACH (i, FVec, vec) // Iterate elements of the container. + printf(" %g", *i.ref); // i.ref is a pointer to the current element. + + } // vec is auto cleaned up at end of scope } ``` For struct element types, an `i_cmp` compare function is required (uses `<` and `==` by default, @@ -160,11 +163,7 @@ With six different containers: #include <stc/ccommon.h> struct Point { float x, y; }; - -int Point_cmp(const struct Point* a, const struct Point* b) { - int cmp = c_default_cmp(&a->x, &b->x); - return cmp ? cmp : c_default_cmp(&a->y, &b->y); -} +int Point_cmp(const struct Point* a, const struct Point* b); #define i_key int #include <stc/cset.h> // cset_int: unordered set @@ -187,8 +186,14 @@ int Point_cmp(const struct Point* a, const struct Point* b) { #define i_val int #include <stc/csmap.h> // csmap_int: sorted map int => int -int main(void) { - /* define six containers with automatic call of init and drop (destruction after scope exit) */ +int Point_cmp(const struct Point* a, const struct Point* b) { + int cmp = c_default_cmp(&a->x, &b->x); + return cmp ? cmp : c_default_cmp(&a->y, &b->y); +} + +int main(void) +{ + /* Define six containers with automatic call of init and drop (destruction after scope exit) */ c_AUTO (cset_int, set) c_AUTO (cvec_pnt, vec) c_AUTO (cdeq_int, deq) @@ -200,40 +205,58 @@ int main(void) { struct Point pts[4] = { {10, 1}, {20, 2}, {30, 3}, {40, 4} }; int pairs[4][2] = { {20, 2}, {10, 1}, {30, 3}, {40, 4} }; - /* add some elements to each container */ + /* Add some elements to each container */ for (int i = 0; i < 4; ++i) { cset_int_insert(&set, nums[i]); cvec_pnt_push(&vec, pts[i]); cdeq_int_push_back(&deq, nums[i]); clist_int_push_back(&lst, nums[i]); - cstack_int_push(&set, nums[i]); + cstack_int_push(&stk, nums[i]); csmap_int_insert(&map, pairs[i][0], pairs[i][1]); } - /* find an element in each container (except cstack) */ + /* Find an element in each container (except cstack) */ cset_int_iter i1 = cset_int_find(&set, 20); cvec_pnt_iter i2 = cvec_pnt_find(&vec, (struct Point){20, 2}); cdeq_int_iter i3 = cdeq_int_find(&deq, 20); clist_int_iter i4 = clist_int_find(&lst, 20); csmap_int_iter i5 = csmap_int_find(&map, 20); - printf("\nFound: %d, (%g, %g), %d, %d, [%d: %d]\n", *i1.ref, i2.ref->x, i2.ref->y, - *i3.ref, *i4.ref, - i5.ref->first, i5.ref->second); - /* erase the elements found */ + + printf("\nFound: %d, (%g, %g), %d, %d, [%d: %d]\n", + *i1.ref, i2.ref->x, i2.ref->y, *i3.ref, + *i4.ref, i5.ref->first, i5.ref->second); + + /* Erase the elements found */ cset_int_erase_at(&set, i1); cvec_pnt_erase_at(&vec, i2); cdeq_int_erase_at(&deq, i3); clist_int_erase_at(&lst, i4); csmap_int_erase_at(&map, i5); - printf("After erasing elements found:"); - printf("\n set:"); c_FOREACH (i, cset_int, set) printf(" %d", *i.ref); - printf("\n vec:"); c_FOREACH (i, cvec_pnt, vec) printf(" (%g, %g)", i.ref->x, i.ref->y); - printf("\n deq:"); c_FOREACH (i, cdeq_int, deq) printf(" %d", *i.ref); - printf("\n lst:"); c_FOREACH (i, clist_int, lst) printf(" %d", *i.ref); - printf("\n stk:"); c_FOREACH (i, cstack_int, stk) printf(" %d", *i.ref); - printf("\n map:"); c_FOREACH (i, csmap_int, map) printf(" [%d: %d]", i.ref->first, - i.ref->second); + printf("After erasing the elements found:"); + printf("\n set:"); + c_FOREACH (i, cset_int, set) + printf(" %d", *i.ref); + + printf("\n vec:"); + c_FOREACH (i, cvec_pnt, vec) + printf(" (%g, %g)", i.ref->x, i.ref->y); + + printf("\n deq:"); + c_FOREACH (i, cdeq_int, deq) + printf(" %d", *i.ref); + + printf("\n lst:"); + c_FOREACH (i, clist_int, lst) + printf(" %d", *i.ref); + + printf("\n stk:"); + c_FOREACH (i, cstack_int, stk) + printf(" %d", *i.ref); + + printf("\n map:"); + c_FOREACH (i, csmap_int, map) + printf(" [%d: %d]", i.ref->first, i.ref->second); } } ``` diff --git a/docs/cstr_api.md b/docs/cstr_api.md index 0ee8b2cb..4f895549 100644 --- a/docs/cstr_api.md +++ b/docs/cstr_api.md @@ -76,8 +76,8 @@ void cstr_replace_at_sv(cstr* self, size_t pos, size_t len, const csview void cstr_replace_at_s(cstr* self, size_t pos, size_t len, cstr repl); bool cstr_equals(const cstr* self, const char* str); -bool cstr_equals_s(const cstr* self, cstr s); bool cstr_equals_sv(const cstr* self, csview sv); +bool cstr_equals_s(const cstr* self, cstr s); size_t cstr_find(const cstr* self, const char* search); size_t cstr_find_at(const cstr* self, size_t pos, const char* search); // search from pos diff --git a/include/stc/algo/filter.h b/include/stc/algo/filter.h index 486568f2..10aeb7e7 100644 --- a/include/stc/algo/filter.h +++ b/include/stc/algo/filter.h @@ -23,24 +23,26 @@ /* #include <stdio.h> #define i_val int -#define i_capacity 10 #include <stc/cstack.h> #include <stc/algo/filter.h> int main() { - cstack_int stk = cstack_INITIALIZER(int, {1, 2, 3, 4, 5, 6, 7, 8, 9}); - - c_foreach (i, cstack_int, stk) - printf(" %d", *i.ref); - puts(""); - - c_forfilter (i, cstack_int, stk - , c_flt_skipwhile(i, *i.ref < 3) - && (*i.ref & 1) == 0 // even only - , c_flt_take(i, 2)) // break after 2 - printf(" %d", *i.ref); - puts(""); + c_WITH (cstack_int stk = {0}, cstack_int_drop(&stk)) { + c_FORLIST (i, int, {1, 2, 3, 4, 5, 6, 7, 8, 9}) + cstack_int_push(&stk, i); + + c_FOREACH (i, cstack_int, stk) + printf(" %d", *i.ref); + puts(""); + + c_FORFILTER (i, cstack_int, stk + , c_flt_skipwhile(i, *i.ref < 3) + && (*i.ref & 1) == 0 // even only + , c_flt_take(i, 2)) // break after 2 + printf(" %d", *i.ref); + puts(""); + } } */ #ifndef STC_FILTER_H_INCLUDED diff --git a/include/stc/cstack.h b/include/stc/cstack.h index e4b64848..5e87cf9f 100644 --- a/include/stc/cstack.h +++ b/include/stc/cstack.h @@ -52,9 +52,6 @@ STC_INLINE _cx_self _cx_memb(_init)(void) { } #ifdef i_capacity -#define cstack_INITIALIZER(T, ...) \ - {.data=__VA_ARGS__, ._len=sizeof((T[])__VA_ARGS__)/sizeof(T)} - STC_INLINE void _cx_memb(_create)(_cx_self* self) { self->_len = 0; } #else @@ -71,7 +68,7 @@ STC_INLINE _cx_self _cx_memb(_with_size)(size_t size, i_key null) { while (size) out.data[--size] = null; return out; } -#endif +#endif // i_capacity STC_INLINE void _cx_memb(_clear)(_cx_self* self) { _cx_value *p = self->data + self->_len; diff --git a/misc/examples/demos.c b/misc/examples/demos.c index 4a9fac89..4455b840 100644 --- a/misc/examples/demos.c +++ b/misc/examples/demos.c @@ -185,35 +185,6 @@ void mapdemo3() cmap_str_drop(&table); // frees key and value cstrs, and hash table. } -#define i_val float -#define i_tag f -#include <stc/carr3.h> - -void arraydemo1() -{ - printf("\nARRAYDEMO1\n"); - c_WITH (carr3_f arr3 = carr3_f_with_size(30, 20, 10, 0.0f), - carr3_f_drop(&arr3)) - { - arr3.data[5][4][3] = 10.2f; - float **arr2 = arr3.data[5]; - float *arr1 = arr3.data[5][4]; - - printf("arr3: %" c_ZU ": (%" c_ZU ", %" c_ZU ", %" c_ZU ") = %" c_ZU "\n", sizeof(arr3), - arr3.xdim, arr3.ydim, arr3.zdim, carr3_f_size(&arr3)); - - printf("%g\n", arr1[3]); // = 10.2 - printf("%g\n", arr2[4][3]); // = 10.2 - printf("%g\n", arr3.data[5][4][3]); // = 10.2 - - float x = 0.0; - c_FOREACH (i, carr3_f, arr3) - *i.ref = ++x; - printf("%g\n", arr3.data[29][19][9]); // = 6000 - } -} - - int main() { stringdemo1(); @@ -224,5 +195,4 @@ int main() mapdemo1(); mapdemo2(); mapdemo3(); - arraydemo1(); } diff --git a/misc/examples/mapmap.c b/misc/examples/mapmap.c index c361233b..d5fe9c81 100644 --- a/misc/examples/mapmap.c +++ b/misc/examples/mapmap.c @@ -4,18 +4,24 @@ // People: std::map<std::string, std::string> #define i_type People -#define i_key_str -#define i_val_str +#define i_key_str // name +#define i_val_str // email #define i_keydrop(p) (printf("kdrop: %s\n", cstr_str(p)), cstr_drop(p)) // override #include <stc/csmap.h> // Departments: std::map<std::string, People> #define i_type Departments -#define i_key_str +#define i_key_str // dep. name #define i_valclass People -// Shorthand for: +// i_key_str implies: +// #define i_tag str +// #define i_key cstr +// #define i_keyclone cstr_clone +// #define i_keydrop cstr_drop +// #define i_cmp cstr_cmp +// #define i_hash cstr_hash +// i_valclass implies: // #define i_val People -// #define i_cmp People_cmp // #define i_valclone People_clone // #define i_valdrop People_drop #include <stc/csmap.h> @@ -23,7 +29,7 @@ void add(Departments* deps, const char* name, const char* email, const char* dep) { - People *people = &Departments_insert(deps, cstr_from(dep), People_init()).ref->second; + People *people = &Departments_emplace(deps, dep, People_init()).ref->second; People_emplace_or_assign(people, name, email); } diff --git a/misc/examples/multimap.c b/misc/examples/multimap.c index 8797c24e..ba0bf71b 100644 --- a/misc/examples/multimap.c +++ b/misc/examples/multimap.c @@ -32,14 +32,14 @@ struct OlympicsData { int year; const char *city, *country, *date; } ol_data[] = {1924, "Chamonix", "France", "January 25 - February 5"}, }; -typedef struct { int year; cstr city, date; } OlympicLocation; +typedef struct { int year; cstr city, date; } OlympicLoc; -int OlympicLocation_cmp(const OlympicLocation* a, const OlympicLocation* b); -OlympicLocation OlympicLocation_clone(OlympicLocation loc); -void OlympicLocation_drop(OlympicLocation* self); +int OlympicLoc_cmp(const OlympicLoc* a, const OlympicLoc* b); +OlympicLoc OlympicLoc_clone(OlympicLoc loc); +void OlympicLoc_drop(OlympicLoc* self); -// Create a clist<OlympicLocation>, can be sorted by year. -#define i_valclass OlympicLocation // binds _cmp, _clone and _drop. +// Create a clist<OlympicLoc>, can be sorted by year. +#define i_valclass OlympicLoc // binds _cmp, _clone and _drop. #define i_tag OL #define i_extern // define _clist_mergesort() #include <stc/clist.h> @@ -50,19 +50,22 @@ void OlympicLocation_drop(OlympicLocation* self); #define i_tag OL #include <stc/csmap.h> -int OlympicLocation_cmp(const OlympicLocation* a, const OlympicLocation* b) { +int OlympicLoc_cmp(const OlympicLoc* a, const OlympicLoc* b) { return a->year - b->year; } -OlympicLocation OlympicLocation_clone(OlympicLocation loc) { +OlympicLoc OlympicLoc_clone(OlympicLoc loc) { loc.city = cstr_clone(loc.city); loc.date = cstr_clone(loc.date); return loc; } -void OlympicLocation_drop(OlympicLocation* self) { - c_DROP(cstr, &self->city, &self->date); + +void OlympicLoc_drop(OlympicLoc* self) { + cstr_drop(&self->city); + cstr_drop(&self->date); } + int main() { // Define the multimap with destructor defered to when block is completed. @@ -73,12 +76,12 @@ int main() for (size_t i = 0; i < c_ARRAYLEN(ol_data); ++i) { struct OlympicsData* d = &ol_data[i]; - OlympicLocation loc = {.year = d->year, - .city = cstr_from(d->city), - .date = cstr_from(d->date)}; + OlympicLoc loc = {.year = d->year, + .city = cstr_from(d->city), + .date = cstr_from(d->date)}; // Insert an empty list for each new country, and append the entry to the list. // If country already exist in map, its list is returned from the insert function. - clist_OL* list = &csmap_OL_insert(&multimap, cstr_from(d->country), empty).ref->second; + clist_OL* list = &csmap_OL_emplace(&multimap, d->country, empty).ref->second; clist_OL_push_back(list, loc); } // Sort locations by year for each country. diff --git a/misc/examples/sort.c b/misc/examples/sort.c new file mode 100644 index 00000000..65ae7359 --- /dev/null +++ b/misc/examples/sort.c @@ -0,0 +1,48 @@ +#include <stdio.h> +#include <time.h> +#include <stdlib.h> +#define i_val int +#include <stc/crandom.h> +#include <stc/algo/csort.h> +#ifdef __cplusplus +#include <algorithm> +#endif + + +int testsort(csortval_int *a, size_t size, const char *desc) { + clock_t t = clock(); +#ifdef __cplusplus + printf("std::sort: "); + std::sort(a, a + size); +#else + printf("csort: "); + csort_int(a, size); +#endif + t = clock() - t; + + printf("%s: %d elements sorted in %.3fms\n", + desc, (int)size, t*1000.0/CLOCKS_PER_SEC); + return 0; +} + +int main(int argc, char *argv[]) { + size_t i, size = argc > 1 ? strtoull(argv[1], NULL, 0) : 10000000; + csortval_int *a = (csortval_int*)malloc(sizeof(*a) * size); + if (a == NULL) return -1; + + for (i = 0; i < size; i++) + a[i] = crandom() & ((1U << 28) - 1); + testsort(a, size, "random"); + for (i = 0; i < 20; i++) printf(" %d", a[i]); + puts(""); + + testsort(a, size, "sorted"); + + for (i = 0; i < size; i++) a[i] = size - i; + testsort(a, size, "reverse sorted"); + + for (i = 0; i < size; i++) a[i] = 126735; + testsort(a, size, "constant"); + + free(a); +} diff --git a/misc/examples/utf8replace_c.c b/misc/examples/utf8replace_c.c index 3645bd0a..2d8d1921 100644 --- a/misc/examples/utf8replace_c.c +++ b/misc/examples/utf8replace_c.c @@ -1,23 +1,26 @@ -#define i_extern // add utf8 dependencies #include <stc/cstr.h> -#include <stc/csview.h> int main() { - c_AUTO (cstr, hello, upper) { + c_AUTO (cstr, hello, str) { hello = cstr_lit("hell😀 w😀rld"); printf("%s\n", cstr_str(&hello)); /* replace second smiley at utf8 codepoint pos 7 */ - cstr_u8_replace_at(&hello, cstr_u8_to_pos(&hello, 7), 1, c_SV("🐨")); + cstr_u8_replace_at(&hello, + cstr_u8_to_pos(&hello, 7), + 1, + c_SV("🐨") + ); printf("%s\n", cstr_str(&hello)); - cstr_replace_ex(&hello, "🐨", "ø", 1); - printf("%s\n", cstr_str(&hello)); - - upper = cstr_toupper_sv(cstr_sv(&hello)); - c_FOREACH (c, cstr, hello) printf("%.*s,", c_ARGSV(c.u8.chr)); - puts(""); + + //csview sv = c_SV("If you find the time, you will find the winner"); + //str = cstr_replace_sv(sv, c_SV("find"), c_SV("match"), 0); + + str = cstr_lit("If you find the time, you will find the winner"); + cstr_replace(&str, "find", "match"); + printf("\n%s\n", cstr_str(&str)); } } diff --git a/misc/examples/utf8replace_rs.rs b/misc/examples/utf8replace_rs.rs index 717978aa..8b163b4e 100644 --- a/misc/examples/utf8replace_rs.rs +++ b/misc/examples/utf8replace_rs.rs @@ -1,12 +1,12 @@ - pub fn main() { - let mut hello = String::from("hell😀 world"); + let mut hello = String::from("hell😀 w😀rld"); println!("{}", hello); - + + /* replace second smiley at utf8 codepoint pos 7 */ hello.replace_range( hello .char_indices() - .nth(4) + .nth(7) .map(|(pos, ch)| (pos..pos + ch.len_utf8())) .unwrap(), "🐨", @@ -16,4 +16,7 @@ pub fn main() { for c in hello.chars() { print!("{},", c); } + + let str = "If you find the time, you will find the winner"; + println!("\n{}", str.replace("find", "match")); } diff --git a/misc/include/fmt.h b/misc/include/c11/fmt.h index df1fe990..d5ba3575 100644 --- a/misc/include/fmt.h +++ b/misc/include/c11/fmt.h @@ -30,12 +30,14 @@ int main() { const double pi = 3.141592653589793;
const size_t x = 1234567890;
const char* string = "Hello world";
+ const wchar_t* wstr = L"The whole";
const char z = 'z';
_Bool flag = 1;
unsigned char r = 123, g = 214, b = 90, w = 110;
char buffer[64];
fmt_print(1, "Color: ({} {} {}), {}\n", r, g, b, flag);
+ fmt_print(1, "Wide: {}, {}\n", wstr, L"wide world");
fmt_print(1, "{:10} {:10} {:10.2f}\n", 42ull, 43, pi);
fmt_print(stdout, "{:>10} {:>10} {:>10}\n", z, z, w);
fmt_print(stdout, "{:10} {:10} {:10}\n", "Hello", "Mad", "World");
@@ -72,6 +74,11 @@ int main() { #else
# define FMT_API static inline
#endif
+#if defined FMT_NDEBUG || defined NDEBUG
+# define fmt_OK(exp) (void)(exp)
+#else
+# define fmt_OK(exp) assert(exp)
+#endif
typedef struct {
char* data;
@@ -92,48 +99,48 @@ FMT_API void _fmt_bprint(fmt_buffer*, const char* fmt, ...); #define fmt_print(...) fmt_OVERLOAD(fmt_print, __VA_ARGS__)
#define fmt_print2(to, fmt) \
do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 0, fmt); \
- assert(_n == 0); _fmt_fn(to)(to, fmt); } while (0)
+ fmt_OK(_n == 0); _fmt_fn(to)(to, fmt); } while (0)
#define fmt_print3(to, fmt, c) \
do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 1, fmt, _fc(c)); \
- assert(_n == 1); _fmt_fn(to)(to, _fs, c); } while (0)
+ fmt_OK(_n == 1); _fmt_fn(to)(to, _fs, c); } while (0)
#define fmt_print4(to, fmt, c, d) \
do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 2, fmt, _fc(c), _fc(d)); \
- assert(_n == 2); _fmt_fn(to)(to, _fs, c, d); } while (0)
+ fmt_OK(_n == 2); _fmt_fn(to)(to, _fs, c, d); } while (0)
#define fmt_print5(to, fmt, c, d, e) \
do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 3, fmt, _fc(c), _fc(d), _fc(e)); \
- assert(_n == 3); _fmt_fn(to)(to, _fs, c, d, e); } while (0)
+ fmt_OK(_n == 3); _fmt_fn(to)(to, _fs, c, d, e); } while (0)
#define fmt_print6(to, fmt, c, d, e, f) \
do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 4, fmt, _fc(c), _fc(d), _fc(e), _fc(f)); \
- assert(_n == 4); _fmt_fn(to)(to, _fs, c, d, e, f); } while (0)
+ fmt_OK(_n == 4); _fmt_fn(to)(to, _fs, c, d, e, f); } while (0)
#define fmt_print7(to, fmt, c, d, e, f, g) \
do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 5, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g)); \
- assert(_n == 5); _fmt_fn(to)(to, _fs, c, d, e, f, g); } while (0)
+ fmt_OK(_n == 5); _fmt_fn(to)(to, _fs, c, d, e, f, g); } while (0)
#define fmt_print8(to, fmt, c, d, e, f, g, h) \
do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 6, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h)); \
- assert(_n == 6); _fmt_fn(to)(to, _fs, c, d, e, f, g, h); } while (0)
+ fmt_OK(_n == 6); _fmt_fn(to)(to, _fs, c, d, e, f, g, h); } while (0)
#define fmt_print9(to, fmt, c, d, e, f, g, h, i) \
do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 7, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), _fc(i)); \
- assert(_n == 7); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i); } while (0)
+ fmt_OK(_n == 7); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i); } while (0)
#define fmt_print10(to, fmt, c, d, e, f, g, h, i, j) \
do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 8, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \
_fc(i), _fc(j)); \
- assert(_n == 8); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j); } while (0)
+ fmt_OK(_n == 8); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j); } while (0)
#define fmt_print11(to, fmt, c, d, e, f, g, h, i, j, k) \
do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 9, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \
_fc(i), _fc(j), _fc(k)); \
- assert(_n == 9); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j, k); } while (0)
+ fmt_OK(_n == 9); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j, k); } while (0)
#define fmt_print12(to, fmt, c, d, e, f, g, h, i, j, k, m) \
do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 10, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \
_fc(i), _fc(j), _fc(k), _fc(m)); \
- assert(_n == 10); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j, k, m); } while (0)
+ fmt_OK(_n == 10); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j, k, m); } while (0)
#define fmt_print13(to, fmt, c, d, e, f, g, h, i, j, k, m, n) \
do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 11, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \
_fc(i), _fc(j), _fc(k), _fc(m), _fc(n)); \
- assert(_n == 11); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j, k, m, n); } while (0)
+ fmt_OK(_n == 11); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j, k, m, n); } while (0)
#define fmt_print14(to, fmt, c, d, e, f, g, h, i, j, k, m, n, o) \
do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 12, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \
_fc(i), _fc(j), _fc(k), _fc(m), _fc(n), _fc(o)); \
- assert(_n == 12); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j, k, m, n, o); } while (0)
+ fmt_OK(_n == 12); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j, k, m, n, o); } while (0)
#define _fmt_fn(x) _Generic ((x), \
FILE*: fprintf, \
@@ -164,8 +171,10 @@ FMT_API void _fmt_bprint(fmt_buffer*, const char* fmt, ...); double: "@g", \
long double: "@Lg", \
char*: "s", \
+ wchar_t*: "ls", \
void*: "p", \
const char*: "s", \
+ const wchar_t*: "ls", \
const void*: "p")
#if defined FMT_IMPLEMENT || !(defined FMT_HEADER || defined FMT_IMPLEMENT)
@@ -250,4 +259,4 @@ FMT_API int _fmt_parse(char* p, int nargs, const char *fmt, ...) { return n;
}
#endif
-#endif
\ No newline at end of file +#endif
diff --git a/include/stc/carr2.h b/misc/include/old/carr2.h index 89ae9b77..aebaec81 100644 --- a/include/stc/carr2.h +++ b/misc/include/old/carr2.h @@ -20,11 +20,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#include "ccommon.h" +#include <stc/ccommon.h> #ifndef CARR2_H_INCLUDED #define CARR2_H_INCLUDED -#include "forward.h" +#include <stc/forward.h> #include <stdlib.h> #endif /* @@ -56,7 +56,7 @@ int main() { #ifndef _i_prefix #define _i_prefix carr2_ #endif -#include "priv/template.h" +#include <stc/priv/template.h> #if !c_option(c_is_forward) _cx_deftypes(_c_carr2_types, _cx_self, i_key); #endif @@ -149,4 +149,4 @@ STC_DEF void _cx_memb(_drop)(_cx_self* self) { } #endif -#include "priv/template.h" +#include <stc/priv/template.h> diff --git a/include/stc/carr3.h b/misc/include/old/carr3.h index d167dd69..a0148992 100644 --- a/include/stc/carr3.h +++ b/misc/include/old/carr3.h @@ -20,11 +20,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#include "ccommon.h" +#include <stc/ccommon.h> #ifndef CARR3_H_INCLUDED #define CARR3_H_INCLUDED -#include "forward.h" +#include <stc/forward.h> #include <stdlib.h> #endif /* @@ -57,7 +57,7 @@ int main() { #ifndef _i_prefix #define _i_prefix carr3_ #endif -#include "priv/template.h" +#include <stc/priv/template.h> #if !c_option(c_is_forward) _cx_deftypes(_c_carr3_types, _cx_self, i_key); @@ -154,4 +154,4 @@ STC_DEF void _cx_memb(_drop)(_cx_self* self) { } #endif -#include "priv/template.h" +#include <stc/priv/template.h> diff --git a/misc/include/alt/csmap.h b/misc/include/old/csmap.h index 4b4e764c..4b4e764c 100644 --- a/misc/include/alt/csmap.h +++ b/misc/include/old/csmap.h diff --git a/misc/include/alt/cstr.h b/misc/include/old/cstr.h index 8de6c4b0..8de6c4b0 100644 --- a/misc/include/alt/cstr.h +++ b/misc/include/old/cstr.h diff --git a/misc/examples/new_arr.c b/misc/include/old/new_arr.c index 7170d14a..1006439d 100644 --- a/misc/examples/new_arr.c +++ b/misc/include/old/new_arr.c @@ -1,13 +1,13 @@ #include <stc/cstr.h> #define i_val int -#include <stc/carr2.h> +#include "carr2.h" #define i_val int -#include <stc/carr3.h> +#include "carr3.h" #define i_val_str -#include <stc/carr2.h> +#include "carr2.h" int main() { diff --git a/misc/include/stctest.h b/misc/include/stctest.h deleted file mode 100644 index 9718af7f..00000000 --- a/misc/include/stctest.h +++ /dev/null @@ -1,203 +0,0 @@ -/* MIT License
- *
- * Copyright (c) 2022 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.
- */
-
-/* stctest: A small and simple C11 unit-testing framework.
-
- Features:
- - Requires C11. Should work with any C compiler supporting _Generic.
- - No library dependencies. Not even itself. Just a header file.
- - Reports assertion failures, including expressions and line numbers.
- - ANSI color output for maximum visibility.
- - Easy to embed in apps for runtime tests (e.g. environment tests).
-
- Example:
-
- #include "stctest.h"
- #include "mylib.h"
-
- void test_sheep()
- {
- EXPECT_EQ("Sheep are cool", are_sheep_cool());
- EXPECT_EQ(4, sheep.legs);
- }
-
- void test_cheese()
- {
- EXPECT_GT(cheese.tanginess, 0);
- EXPECT_EQ("Wensleydale", cheese.name);
- }
-
- int main()
- {
- RUN_TEST(test_sheep);
- RUN_TEST(test_cheese);
- return REPORT_TESTS();
- }
- */
-
-#ifndef STCTEST_INCLUDED
-#define STCTEST_INCLUDED
-
-#include <stdio.h>
-#include <time.h>
-#include <string.h>
-#include <float.h>
-#include <stdarg.h>
-#include <inttypes.h>
-
-#define STC_FLOAT_EPSILON 1e-6
-#define STC_DOUBLE_EPSILON 1e-13
-
-
-#define EXPECT_TRUE(expr) \
- do { if (!_stctest_assert(__FILE__, __LINE__, #expr, (expr) != 0)) puts(""); } while (0)
-
-#define EXPECT_TRUE1(expr, v) \
- do { if (!_stctest_assert(__FILE__, __LINE__, #expr, (expr) != 0)) { \
- char _fmt[32]; sprintf(_fmt, " ; %%s --> %s\n", _stctest_FMT(v)); \
- printf(_fmt, #v, v); \
- }} while (0)
-
-#define EXPECT_FALSE(expr) EXPECT_TRUE(!(expr))
-#define EXPECT_FALSE1(expr, v) EXPECT_TRUE1(!(expr), v)
-
-/* NB! (char*) are compared as strings. Cast to (void*) to compare pointers only */
-#define EXPECT_EQ(a, b) _stctest_CHECK(a, ==, b, -STC_DOUBLE_EPSILON)
-#define EXPECT_NE(a, b) _stctest_CHECK(a, !=, b, -STC_DOUBLE_EPSILON)
-#define EXPECT_GT(a, b) _stctest_CHECK(a, >, b, -STC_DOUBLE_EPSILON)
-#define EXPECT_LT(a, b) _stctest_CHECK(a, <, b, -STC_DOUBLE_EPSILON)
-#define EXPECT_LE(a, b) _stctest_CHECK(a, <=, b, -STC_DOUBLE_EPSILON)
-#define EXPECT_GE(a, b) _stctest_CHECK(a, >=, b, -STC_DOUBLE_EPSILON)
-#define EXPECT_FLOAT_EQ(a, b) _stctest_CHECK((float)(a), ==, (float)(b), -STC_FLOAT_EPSILON)
-#define EXPECT_DOUBLE_EQ(a, b) _stctest_CHECK((double)(a), ==, (double)(b), -STC_DOUBLE_EPSILON)
-#define EXPECT_NEAR(a, b, abs_error) _stctest_CHECK((double)(a), ==, (double)(b), abs_error)
-
-/* Run a test() function */
-#define RUN_TEST(test, ...) do { \
- puts(#test "(" #__VA_ARGS__ "):"); \
- const int ps = _stctest_s.passes; \
- const int fs = _stctest_s.fails; \
- const clock_t _start = clock(); \
- test(__VA_ARGS__); \
- const int _sum = (clock() - _start)*1000 / CLOCKS_PER_SEC; \
- _stctest_s.total_ms += _sum; \
- printf(" passed: %d/%d. duration: %d ms\n", \
- _stctest_s.passes - ps, _stctest_s.passes + _stctest_s.fails - (ps + fs), _sum); \
-} while (0)
-
-#define REPORT_TESTS() stctest_report()
-
-/* ----------------------------------------------------------------------------- */
-
-#define _stctest_CHECK(a, OP, b, e) \
- do { if (!_stctest_assert(__FILE__, __LINE__, #a " " #OP " " #b, _stctest_CMP(a, OP, b, e))) { \
- char _fmt[32]; sprintf(_fmt, " ; %s %s %s\n", _stctest_FMT(a), #OP, _stctest_FMT(b)); \
- printf(_fmt, a, b); \
- }} while (0)
-
-#define _stctest_CMP(a, OP, b, e) _Generic((a), \
- const char*: _stctest_strcmp, char*: _stctest_strcmp, \
- double: _Generic((b), double: _stctest_dblcmp, float: _stctest_dblcmp, default: _stctest_valcmp), \
- float: _Generic((b), double: _stctest_dblcmp, float: _stctest_dblcmp, default: _stctest_valcmp), \
- default: _stctest_valcmp)((a) OP (b), #OP, a, b, (double)(e))
-
-#define _stctest_FMT(a) _Generic((a), \
- float: "%.8gf", double: "%.15g", \
- int64_t: "%" PRId64, int32_t: "%" PRId32, int16_t: "%" PRId16, int8_t: "%" PRId8, \
- uint64_t: "%" PRIu64 "u", uint32_t: "%" PRIu32 "u", uint16_t: "%" PRIu16 "u", uint8_t: "%" PRIu8 "u", \
- char*: "`%s`", const char*: "`%s`", \
- default: "%p")
-
-static int _stctest_strcmp(int res, const char* OP, ...) {
- va_list ap;
- va_start(ap, OP);
- const char* a = va_arg(ap, const char *);
- const char* b = va_arg(ap, const char *);
- va_end(ap);
- int c = strcmp(a, b);
- if (OP[0] == '<') return OP[1] == '=' ? c <= 0 : c < 0;
- if (OP[0] == '>') return OP[1] == '=' ? c >= 0 : c > 0;
- return (OP[0] == '!') ^ (c == 0);
-}
-
-// Knuth:
-static int approximately_equal(double a, double b, double epsilon) {
- double d = a - b; if (d < 0) d = -d;
- if (a < 0) a = -a; if (b < 0) b = -b;
- return d <= ((a < b ? b : a) * epsilon); // (a > b ? b : a) => essentially_equal:
-}
-
-static int _stctest_dblcmp(int res, const char* OP, ...) {
- va_list ap;
- va_start(ap, OP);
- double a = va_arg(ap, double);
- double b = va_arg(ap, double);
- double e = va_arg(ap, double);
- double c = a - b;
- va_end(ap);
- if (OP[0] == '<') return OP[1] == '=' ? c <= 0 : c < 0;
- if (OP[0] == '>') return OP[1] == '=' ? c >= 0 : c > 0;
- return (OP[0] == '!') ^ (e < 0 ? approximately_equal(a, b, -e) : (c < 0 ? -c : c) <= e);
-}
-
-static int _stctest_valcmp(int res, const char* OP, ...)
- { return res; }
-
-#define _stctest_COLOR_CODE 0x1B
-#define _stctest_COLOR_RED "[1;31m"
-#define _stctest_COLOR_GREEN "[1;32m"
-#define _stctest_COLOR_RESET "[0m"
-
-static struct stctest_s {
- int passes;
- int fails;
- const char* current_file;
- int total_ms;
-} _stctest_s = {0};
-
-static int _stctest_assert(const char* file, int line, const char* expression, int pass) {
- if (pass)
- _stctest_s.passes++;
- else {
- _stctest_s.fails++;
- printf(" failed \"%s:%d\": (%s)", file, line, expression);
- }
- _stctest_s.current_file = file;
- return pass;
-}
-
-static int stctest_report(void) {
- if (_stctest_s.fails) {
- printf("%c%sFAILED%c%s: \"%s\": (failed %d, passed %d, total %d)\n",
- _stctest_COLOR_CODE, _stctest_COLOR_RED, _stctest_COLOR_CODE, _stctest_COLOR_RESET,
- _stctest_s.current_file, _stctest_s.fails, _stctest_s.passes, _stctest_s.passes + _stctest_s.fails);
- } else {
- printf("%c%sPASSED%c%s: \"%s\": (total %d)\n",
- _stctest_COLOR_CODE, _stctest_COLOR_GREEN, _stctest_COLOR_CODE, _stctest_COLOR_RESET,
- _stctest_s.current_file, _stctest_s.passes);
- }
- printf(" duration: %d ms\n", _stctest_s.total_ms); \
- return -_stctest_s.fails;
-}
-
-#endif
|
