diff options
| author | Tyge Lovset <[email protected]> | 2022-08-15 08:17:01 +0200 |
|---|---|---|
| committer | Tyge Lovset <[email protected]> | 2022-08-15 08:17:01 +0200 |
| commit | 2cfad29db0fda313873f2b4a809ff60aca897785 (patch) | |
| tree | 2af00342f8fde6f71876937fabd6852be69b5890 | |
| parent | dd6e6a60b8d1af9127f2694efc314e810b71c9b1 (diff) | |
| download | STC-modified-2cfad29db0fda313873f2b4a809ff60aca897785.tar.gz STC-modified-2cfad29db0fda313873f2b4a809ff60aca897785.zip | |
Improved docs/ex. Fix range bug when container is empty cvec/cdeq.
| -rw-r--r-- | README.md | 22 | ||||
| -rw-r--r-- | examples/music_arc.c | 11 | ||||
| -rw-r--r-- | include/stc/cdeq.h | 7 | ||||
| -rw-r--r-- | include/stc/cvec.h | 9 |
4 files changed, 29 insertions, 20 deletions
@@ -3,16 +3,16 @@ STC - Smart Template Containers for C ===================================== -News: Version 4.0 (Aug 2022) +News: Version 4.0 Release Candidate (Aug 2022) --------------------------------------- API changes summary V3.8 - V4.0: - Added **cregex** with documentation - powerful regular expressions. - Updated **cstr**, now always takes self as pointer, like all containers except csview. - Updated **cvec**, **cdeq**, changed `*_range*` function names. -- `c_with`: macro renamed from `c_autovar`, which is deprecated. Like Python **with** statement. +- `c_with`: macro renamed from `c_autovar`, which is deprecated. Like Python's **with** statement. - `c_scope`: macro renamed from `c_autoscope`, which is deprecated. -- `c_defer`: macro renamed from `c_autodefer`, which is deprecated. Like Go's, Zig's **defer**. -- `c_forrange` with 3 to 5 args swapped 1st <-> 2nd arg. +- `c_defer`: macro renamed from `c_autodefer`, which is deprecated. Like Go's and Zig's **defer**. +- `c_forrange` with 3 to 5 args: swapped 1st <-> 2nd arg. - New `c_forarray` macro to replace usages of `c_apply`, which is removed. - Added back **coption** - command line argument parsing. - [See detailed changes for version 3](#version-3). @@ -21,7 +21,7 @@ Introduction ------------ STC is a *modern*, *templated*, *user-friendly*, *type-safe*, *very fast* and *compact* container library for C99. The API is fairly similar to c++ STL, but a bit more uniform across the containers and takes -inspiration from Rust and Python too. It is an advantage to know how these containers work in other languages, like +inspiration from Rust and Python as well. It is an advantage to know how these containers work in other languages, like Java, C# or C++, but it's not required. This library allows you to manage both trivial to very complex data in a wide variety of containers @@ -68,7 +68,7 @@ Highlights - **Fully memory managed** - All containers will destruct keys/values via destructor defined as macro parameters before including the container header. Also, shared pointers are supported and can be stored in containers, see ***carc***. - **Fully type safe** - Because of templating, it avoids error-prone casting of container types and elements back and forth from the containers. - **Uniform, easy-to-learn API** - Methods to ***construct***, ***initialize***, ***iterate*** and ***destruct*** have uniform and intuitive usage across the various containers. -- **Small footprint** - Small source code and generated executables. The executable from the example below with six different containers is *22 kb in size* compiled with gcc -Os on linux. +- **Small footprint** - Small source code and generated executables. The executable from the example below with six different containers is *22 kb in size* compiled with gcc -Os -s on linux. - **Dual mode compilation** - By default it is a simple header-only library with inline and static methods only, but you can easily switch to create a traditional library with shared symbols, without changing existing source files. See the Installation section. - **No callback functions** - All passed template argument functions/macros are directly called from the implementation, no slow callbacks which requires storage. - **Compiles with C++ and C99** - C code can be compiled with C++ (container element types must be POD). @@ -80,7 +80,7 @@ You may specify a number of "standard" template arguments for each container, bu 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 -for lookup in containers. E.g. for containers with string type (**cstr**) elements, `const char*` may be used +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 @@ -340,13 +340,13 @@ Specials: - `i_key_str` - Define key type *cstr* and container i_tag = *str*. It binds type convertion from/to *const char*\*, and the ***cmp***, ***eq***, ***hash***, and ***keydrop*** functions. - `i_key_ssv` - Define key type *cstr* and container i_tag = *ssv*. It binds type convertion from/to *csview*, and its ***cmp***, ***eq***, ***hash***, and ***keydrop*** functions. - `i_key_arcbox TYPE` - Define container key type where TYPE is a smart pointer **carc** or **cbox**. NB: not to be used when defining carc/cbox types themselves. -- `i_key_bind TYPE` - General version of the two above - will auto-bind to standard named functions: *TYPE_clone*, *TYPE_drop*, *TYPE_cmp*, *TYPE_eq*, *TYPE_hash*. If `i_keyraw` is defined, *TYPE_toraw* func. is bound to `i_keyto`. Only functions required by the particular container need to be defined. E.g., only **cmap** and **cset** and smart pointers uses *TYPE_hash* and *TYPE_eq*. **cstack** does not use *TYPE_cmp*. *TYPE_clone* is not used if *#define i_opt c_no_clone* is specified. Likewise, *TYPE_cmp* is not used if *#define i_opt c_no_cmp* is specified. +- `i_key_bind TYPE` - General version of the three above - will auto-bind to standard named functions: *TYPE_clone*, *TYPE_drop*, *TYPE_cmp*, *TYPE_eq*, *TYPE_hash*. If `i_keyraw` is defined, *TYPE_toraw* function is bound to `i_keyto`. Only functions required by the particular container need to be defined. E.g., only **cmap** and **cset** and smart pointers uses *TYPE_hash* and *TYPE_eq*. **cstack** does not use *TYPE_cmp*. *TYPE_clone* is not used if *#define i_opt c_no_clone* is specified. Likewise, *TYPE_cmp* is not used if *#define i_opt c_no_cmp* is specified. - `i_val_str`, `i_val_bind`, `i_val_arcbox` - Similar rules as for ***key***. **Notes**: -- Instead of defining `i_cmp`, you may define *i_opt c_no_cmp* to disable searching and sorting functions. -- Instead of defining `i_*clone`, you may define *i_opt c_no_clone* to disable emplace and clone-functions. -- `i_keyraw RAWTYPE` - If defined along with *i_key_bind*, the two functions *TYPE TYPE_from(RAWTYPE)* and *RAWTYPE TYPE_toraw(TYPE\*)* are expected in addition to *TYPE TYPE_clone(TYPE)*. Note the signature for ***cmp***, ***eq***, ***hash*** now: *int RAWTYPE_cmp(const RAWTYPE\*, const RAWTYPE\*)*, and similar for the two others. +- Instead of defining `i_cmp`, you may define *i_opt c_no_cmp* to disable *searching and sorting* functions. +- Instead of defining `i_*clone`, you may define *i_opt c_no_clone* to disable *clone* functionality. +- For `i_key_bind`, if *i_keyraw RAWTYPE* is defined along with it, *i_keyfrom* may also be defined to enable the *emplace*-functions. Note: the signature for ***cmp***, ***eq***, and ***hash*** uses *RAWTYPE* as input. The *emplace* versus non-emplace container methods -------------------------------------------------- diff --git a/examples/music_arc.c b/examples/music_arc.c index 02470b0f..6f9c1c72 100644 --- a/examples/music_arc.c +++ b/examples/music_arc.c @@ -19,12 +19,14 @@ void Song_drop(Song* s) { c_drop(cstr, &s->artist, &s->title); } +// Define the reference counted type #define i_type SongArc #define i_val Song #define i_valdrop Song_drop #define i_cmp Song_cmp #include <stc/carc.h> +// ... and a vector of it #define i_type SongVec #define i_val_arcbox SongArc #include <stc/cvec.h> @@ -39,13 +41,18 @@ void example3() Song_from("Thalia", "Entre El Mar y Una Estrella") }) SongVec_emplace(&vec, *v); + // Share all entries in vec with vec2, except Bob Dylan. c_foreach (s, SongVec, vec) if (!cstr_equals(&s.ref->get->artist, "Bob Dylan")) - SongVec_push_back(&vec2, SongArc_clone(*s.ref)); + SongVec_push(&vec2, SongArc_clone(*s.ref)); + // Add a few more to vec2. We can use emplace when creating new entries SongVec_emplace(&vec2, Song_from("Michael Jackson", "Billie Jean")); SongVec_emplace(&vec2, Song_from("Rihanna", "Stay")); + // If we use push, we would need to construct the Arc explicitly (as in c++, make_shared): + // SongVec_push(&vec2, SongArc_from(Song_from("Rihanna", "Stay"))); + // We now have two vectors with some shared, some unique entries. c_forarray (SongVec, v, {vec, vec2}) { puts("VEC:"); c_foreach (s, SongVec, *v) @@ -53,7 +60,7 @@ void example3() cstr_str(&s.ref->get->title), *s.ref->use_count); } - } + } // because the shared elem. are ref. counted, they are only dropped once here. } int main() diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h index 4bef2f38..1d75408c 100644 --- a/include/stc/cdeq.h +++ b/include/stc/cdeq.h @@ -29,6 +29,7 @@ struct cdeq_rep { size_t size, cap; unsigned base[1]; }; #define cdeq_rep_(self) c_unchecked_container_of((self)->_base, struct cdeq_rep, base) +#define it2_ref_(it1, it2) (it1.ref && !it2.ref ? it2.end : it2.ref) #endif // CDEQ_H_INCLUDED #ifndef _i_prefix @@ -137,7 +138,7 @@ _cx_memb(_erase_at)(_cx_self* self, _cx_iter it) { } STC_INLINE _cx_iter _cx_memb(_erase_range)(_cx_self* self, _cx_iter i1, _cx_iter i2) { - return _cx_memb(_erase_range_p)(self, i1.ref, (i2.ref ? i2.ref : i2.end)); + return _cx_memb(_erase_range_p)(self, i1.ref, it2_ref_(i1, i2)); } @@ -193,7 +194,7 @@ _cx_memb(_get_mut)(_cx_self* self, _cx_raw raw) STC_INLINE void _cx_memb(_sort_range)(_cx_iter i1, _cx_iter i2, int(*cmp)(const _cx_value*, const _cx_value*)) { - qsort(i1.ref, (i2.ref ? i2.ref : i2.end) - i1.ref, sizeof *i1.ref, + qsort(i1.ref, it2_ref_(i1, i2) - i1.ref, sizeof *i1.ref, (int(*)(const void*, const void*)) cmp); } @@ -427,7 +428,7 @@ _cx_memb(_copy_range)(_cx_self* self, _cx_value* pos, STC_DEF _cx_iter _cx_memb(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) { - const _cx_value* p2 = i2.ref ? i2.ref : i2.end; + const _cx_value* p2 = it2_ref_(i1, i2); for (; i1.ref != p2; ++i1.ref) { const _cx_raw r = i_keyto(i1.ref); if (i_eq((&raw), (&r))) diff --git a/include/stc/cvec.h b/include/stc/cvec.h index c734abb6..170bf741 100644 --- a/include/stc/cvec.h +++ b/include/stc/cvec.h @@ -66,6 +66,7 @@ int main() { struct cvec_rep { size_t size, cap; unsigned data[1]; }; #define cvec_rep_(self) c_unchecked_container_of((self)->data, struct cvec_rep, data) +#define it2_ref_(it1, it2) (it1.ref && !it2.ref ? it2.end : it2.ref) #endif // CVEC_H_INCLUDED #ifndef _i_prefix @@ -181,7 +182,7 @@ _cx_memb(_erase_at)(_cx_self* self, _cx_iter it) { } STC_INLINE _cx_iter _cx_memb(_erase_range)(_cx_self* self, _cx_iter i1, _cx_iter i2) { - return _cx_memb(_erase_range_p)(self, i1.ref, (i2.ref ? i2.ref : i2.end)); + return _cx_memb(_erase_range_p)(self, i1.ref, it2_ref_(i1, i2)); } STC_INLINE const _cx_value* @@ -242,7 +243,7 @@ _cx_memb(_lower_bound)(const _cx_self* self, _cx_raw raw) { STC_INLINE void _cx_memb(_sort_range)(_cx_iter i1, _cx_iter i2, int(*cmp)(const _cx_value*, const _cx_value*)) { - qsort(i1.ref, (i2.ref ? i2.ref : i2.end) - i1.ref, sizeof(_cx_value), + qsort(i1.ref, it2_ref_(i1, i2) - i1.ref, sizeof(_cx_value), (int(*)(const void*, const void*)) cmp); } @@ -404,7 +405,7 @@ _cx_memb(_emplace_range)(_cx_self* self, _cx_value* pos, #if !c_option(c_no_cmp) STC_DEF _cx_iter _cx_memb(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) { - const _cx_value* p2 = i2.ref ? i2.ref : i2.end; + const _cx_value* p2 = it2_ref_(i1, i2); for (; i1.ref != p2; ++i1.ref) { const _cx_raw r = i_keyto(i1.ref); if (i_eq((&raw), (&r))) @@ -416,7 +417,7 @@ _cx_memb(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) { STC_DEF _cx_iter _cx_memb(_binary_search_in)(_cx_iter i1, _cx_iter i2, const _cx_raw raw, _cx_iter* lower_bound) { - const _cx_value* p2 = i2.ref ? i2.ref : i2.end; + const _cx_value* p2 = it2_ref_(i1, i2); _cx_iter mid = i1; while (i1.ref != p2) { mid.ref = i1.ref + (p2 - i1.ref)/2; |
