From 48eb33996632d99f917e7c4432c2891b5bf29c54 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 30 Mar 2021 16:44:07 +0200 Subject: Removed the cptr raw pointer. Only keep csptr: shared_ptr. Renamed cptr.h to csptr.h. --- README.md | 4 +- docs/cptr_api.md | 256 ------------------------------------------------------ docs/csptr_api.md | 190 ++++++++++++++++++++++++++++++++++++++++ examples/prime.c | 12 +-- stc/cptr.h | 213 --------------------------------------------- stc/csptr.h | 151 ++++++++++++++++++++++++++++++++ 6 files changed, 349 insertions(+), 477 deletions(-) delete mode 100644 docs/cptr_api.md create mode 100644 docs/csptr_api.md delete mode 100644 stc/cptr.h create mode 100644 stc/csptr.h diff --git a/README.md b/README.md index 35d46238..d27771d7 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ It is a compact, header-only library with the all the major "standard" data cont - [***clist*** - **std::forward_list** alike type](docs/clist_api.md) - [***cmap*** - **std::unordered_map** alike type](docs/cmap_api.md) - [***cpque*** - **std::priority_queue** alike (adapter) type](docs/cpque_api.md) -- [***cptr*** - **std::shared_ptr** alike support](docs/cptr_api.md) +- [***csptr*** - **std::shared_ptr** alike support](docs/csptr_api.md) - [***cqueue*** - **std::queue** alike (adapter) type](docs/cqueue_api.md) - [***cset*** - **std::unordered_set** alike type](docs/cset_api.md) - [***csmap*** - **std::map** sorted map alike type](docs/csmap_api.md) @@ -32,7 +32,7 @@ Highlights ---------- - **User friendly** - Just include the headers and you are good. The API and functionality is very close to c++ STL, and is fully listed in the docs. The ***using***-declaration instantiates the container type to use. You may pass *optional* arguments to it for customization of element- *comparison*, *destruction*, *cloning*, *conversion types*, and more. - **Unparalleled performance** - The containers are about equal and often much faster than the c++ STL containers. -- **Fully memory managed** - All containers will destruct keys/values via destructor passed as macro parameters to the ***using***-declaration. Also, smart-pointers are supported and can be stored in containers, see ***csptr***. +- **Fully memory managed** - All containers will destruct keys/values via destructor passed as macro parameters to the ***using***-declaration. Also, shared pointers are supported and can be stored in containers, see ***csptr***. - **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 using six different containers is *27 kb in size* compiled with TinyC. diff --git a/docs/cptr_api.md b/docs/cptr_api.md deleted file mode 100644 index 3583bc62..00000000 --- a/docs/cptr_api.md +++ /dev/null @@ -1,256 +0,0 @@ -# STC [cptr](../stc/cptr.h): Smart Pointers - -**cptr** (managed raw pointer) and **csptr** (shared pointer) enables memory managed pointers in containers. - -The pointed-to elements are automatically destructed and deleted when the container is destructed. **csptr** elements are only deleted if there are no other shared references to the element. **csptr** uses thread-safe atomic use-count, through the *csptr_X_clone()* and *csptr_X_del()* methods. - - See the c++ classes [std::shared_ptr](https://en.cppreference.com/w/cpp/memory/shared_ptr) for a functional reference. - -## Header file and declaration - -```c -#include - -using_cptr(X, Value); -using_cptr(X, Value, valueCompare); -using_cptr(X, Value, valueCompare, valueDel); - -using_csptr(X, Value); -using_csptr(X, Value, valueCompare); -using_csptr(X, Value, valueCompare, valueDel); -``` -The macro `using_cptr()` must be instantiated in the global scope. `X` is a type tag name and will -affect the names of all cptr types and methods. E.g. declaring `using_cptr(v4, Vec4);`, -`X` should be replaced by `v4` in all of the following documentation. - -## Methods - -The *del()* and *compare()* methods are defined based on the arguments passed to the **using**-macro. For **csptr**, use *csptr_X_clone(p)* when sharing ownership of the pointed-to object. See examples below. - -### Managed raw pointer -```c -cptr_X cptr_X_init(void); -cptr_X cptr_X_clone(cptr_X ptr); -void cptr_X_reset(cptr_X* self, cptr_X_value_t* ptr); -void cptr_X_del(cptr_X* self); // destructor -int cptr_X_compare(cptr_X* x, cptr_X* y); -``` -### Shared pointer -```c -csptr_X csptr_X_from(csptr_X_value_t* ptr); -csptr_X csptr_X_make(csptr_X_value_t val); -void csptr_X_reset(csptr_X* self, csptr_X_value_t* ptr); -csptr_X csptr_X_clone(csptr_X sptr); // share the pointer (increase use count) -void csptr_X_del(csptr_X* self); // destructor: decrease use count, destroy if 0 -int csptr_X_compare(csptr_X* x, csptr_X* y); -``` - -## Types - -| Type name | Type definition | Used to represent... | -|:-------------------|:----------------------|:------------------------| -| `cptr_X` | `cptr_X_value_t *` | The cptr type | -| `cptr_X_value_t` | `Value` | The cptr element type | - - -| Type name | Type definition | Used to represent... | -|:--------------------|:--------------------------------------------------------------|:-------------------------| -| `csptr_X` | `struct { csptr_X_value_t* get; atomic_count_t* use_count; }` | The csptr type | -| `csptr_X_value_t` | `Value` | The csptr element type | -| `atomic_count_t` | `long` | The reference counter | - -## Example - -Managed raw pointers (cptr) in a cvec. -```c -#include -#include -#include - -typedef struct { cstr name, last; } Person; - -Person* Person_make(Person* p, const char* name, const char* last) { - p->name = cstr_from(name), p->last = cstr_from(last); - return p; -} -void Person_del(Person* p) { - printf("Destroy: %s %s\n", p->name.str, p->last.str); - c_del(cstr, &p->name, &p->last); -} -// declare managed pointer and cvec with pointers -using_cptr(pe, Person, c_no_compare, Person_del); -using_cvec(pe, Person*, c_no_compare, cptr_pe_del, c_no_clone); - -int main() { - cvec_pe vec = cvec_pe_init(); - cvec_pe_push_back(&vec, Person_make(c_new(Person), "John", "Smiths")); - cvec_pe_push_back(&vec, Person_make(c_new(Person), "Jane", "Doe")); - - c_foreach (i, cvec_pe, vec) - printf("%s %s\n", (*i.ref)->name.str, (*i.ref)->last.str); - cvec_pe_del(&vec); -} -``` -Output: -``` -John Smiths -Jane Doe -Destroy: John Smiths -Destroy: Jane Doe -``` -### Example 2 - -Simple shared pointer (csptr) usage. -```c -#include -#include - -typedef struct { cstr name, last; } Person; - -Person* Person_make(Person* p, const char* name, const char* last) { - p->name = cstr_from(name), p->last = cstr_from(last); - return p; -} -void Person_del(Person* p) { - printf("Destroy: %s %s\n", p->name.str, p->last.str); - c_del(cstr, &p->name, &p->last); -} - -using_csptr(pe, Person, c_no_compare, Person_del); - -int main() { - csptr_pe p = csptr_pe_from(Person_make(c_new(Person), "John", "Smiths")); - csptr_pe q = csptr_pe_clone(p); // means: share the pointer - - printf("Person: %s %s. uses: %zu\n", p.get->name.str, p.get->last.str, *p.use_count); - csptr_pe_del(&p); - - printf("Last man standing: %s %s. uses: %zu\n", q.get->name.str, q.get->last.str, *q.use_count); - csptr_pe_del(&q); -} -``` -Output: -``` -Person: John Smiths. uses: 2 -Last man standing: John Smiths. uses: 1 -Destroy: John Smiths -``` - -### Example 3 - -Advanced: Three different ways to store Person in vectors: 1) `cvec`, 2) `cvec`, and 3) `cvec>`. -```c -#include -#include -#include - -typedef struct { cstr name, last; } Person; - -Person* Person_make(Person* p, const char* name, const char* last) { - p->name = cstr_from(name), p->last = cstr_from(last); - return p; -} -int Person_compare(const Person* p, const Person* q) { - int cmp = strcmp(p->name.str, q->name.str); - return cmp == 0 ? strcmp(p->last.str, q->last.str) : cmp; -} -void Person_del(Person* p) { - printf("del: %s\n", p->name.str); - c_del(cstr, &p->name, &p->last); -} - -// 1. cvec of Person struct; emplace and cloning disabled. -using_cvec(pe, Person, Person_compare, Person_del, c_no_clone); - -// 2. cvec of raw/owned pointers to Person; emplace and cloning disabled. -using_cptr(pe, Person, Person_compare, Person_del); -using_cvec(pp, Person*, cptr_pe_compare, cptr_pe_del, c_no_clone); - -// 3. cvec of shared-ptr to Person - with emplace_back() and cloning cvec ENABLED. -using_csptr(pe, Person, Person_compare, Person_del); -using_cvec(ps, csptr_pe, csptr_pe_compare, csptr_pe_del, csptr_pe_clone); - -const char* names[] = { - "Joe", "Jordan", - "Annie", "Aniston", - "Jane", "Jacobs" -}; - -int main() { - cvec_pe vec1 = cvec_pe_init(); - cvec_pp vec2 = cvec_pp_init(); - cvec_ps vec3 = cvec_ps_init(); - - for (int i = 0; i < 6; i += 2) { - Person tmp; - cvec_pe_push_back(&vec1, *Person_make(&tmp, names[i], names[i+1])); - cvec_pp_push_back(&vec2, Person_make(c_new(Person), names[i], names[i+1])); - cvec_ps_push_back(&vec3, csptr_pe_from(Person_make(c_new(Person), names[i], names[i+1]))); - } - puts("1. Sorted vec1 of Person:"); - cvec_pe_sort(&vec1); - c_foreach (i, cvec_pe, vec1) - printf(" %s %s\n", i.ref->name.str, i.ref->last.str); - - puts("\n2. Sorted vec2 of pointer to Person:"); - cvec_pp_sort(&vec2); - c_foreach (i, cvec_pp, vec2) - printf(" %s %s\n", (*i.ref)->name.str, (*i.ref)->last.str); - - // Append a shared copy of vec3.data[0]. Will only be destructed once! - cvec_ps_emplace_back(&vec3, vec3.data[0]); - //cvec_ps_push_back(&vec3, csptr_pe_clone(vec3.data[0])); // alternativ - puts("\n3. Sorted vec3 of shared-pointer to Person:"); - cvec_ps_sort(&vec3); - c_foreach (i, cvec_ps, vec3) - printf(" %s %s\n", i.ref->get->name.str, i.ref->get->last.str); - - // Share vec3.data[1] with elem1 variable. - csptr_pe elem1 = csptr_pe_clone(vec3.data[1]); - - puts("\nDestroy vec1:"); - cvec_pe_del(&vec1); - puts("\nDestroy vec2:"); - cvec_pp_del(&vec2); - puts("\nDestroy vec3:"); - cvec_ps_del(&vec3); - - puts("\nDestroy elem1:"); - csptr_pe_del(&elem1); -} -``` -Output: -``` -1. Sorted vec1 of Person: - Annie Aniston - Jane Jacobs - Joe Jordan - -2. Sorted vec2 of pointer to Person: - Annie Aniston - Jane Jacobs - Joe Jordan - -3. Sorted vec3 of shared-pointer to Person: - Annie Aniston - Jane Jacobs - Joe Jordan - Joe Jordan - -Destroy vec1: -del: Annie -del: Jane -del: Joe - -Destroy vec2: -del: Annie -del: Jane -del: Joe - -Destroy vec3: -del: Annie -del: Joe - -Destroy elem1: -del: Jane -``` diff --git a/docs/csptr_api.md b/docs/csptr_api.md new file mode 100644 index 00000000..9669d97b --- /dev/null +++ b/docs/csptr_api.md @@ -0,0 +1,190 @@ +# STC [csptr](../stc/csptr.h): Shared Pointers + +**csptr** is a smart pointer that retains shared ownership of an object through a pointer. +Several **csptr** objects may own the same object. The object is destroyed and its memory +deallocated when either of the following happens: + +- the last remaining **csptr** owning the object is destroyed with *csptr_X_del()*; +- the last remaining **csptr** owning the object is assigned another pointer via *csptr_X_clone()*, *csptr_X_move()* or by *csptr_X_reset()*. + +The object is destroyed using *csptr_X_del()* or a custom deleter that is supplied to **csptr** +in the using-statement. + +A **csptr** may also own no objects, in which case it is called empty. + +All **csptr** functions can be called by multiple threads on different instances of **csptr** without +additional synchronization even if these instances are copies and share ownership of the same object. +**csptr** uses thread-safe atomic reference counting, through the *csptr_X_clone()* and *csptr_X_del()* methods. + +See the c++ classes [std::shared_ptr](https://en.cppreference.com/w/cpp/memory/shared_ptr) for a functional reference. + +## Header file and declaration + +```c +#include + +using_csptr(X, Value); +using_csptr(X, Value, valueCompare); +using_csptr(X, Value, valueCompare, valueDel); +``` +The macro `using_csptr()` must be instantiated in the global scope. `X` is a type tag name and will affect the names of all csptr types and methods. E.g. declaring `using_csptr(v4, Vec4)`, `X` should be replaced by `v4` in all of the following documentation. + +## Methods + +Use *csptr_X_clone(p)* when sharing ownership of the pointed-to object. See examples below. + +The *csptr_X_compare()*, *csptr_X_equals()* and *csptr_X_del()* methods are defined based on the *valeCompare* and *valueDel* arguments passed to the **using**-macro. + +```c +csptr_X csptr_X_from(csptr_X_value_t* ptr); // constructor +csptr_X csptr_X_make(csptr_X_value_t val); // make_shared +void csptr_X_reset(csptr_X* self); +void csptr_X_reset_to(csptr_X* self, csptr_X_value_t* ptr); + +csptr_X csptr_X_clone(csptr_X sptr); // share the pointer (increase use count) +void csptr_X_move(csptr_X* self); // transfer ownership instead of sharing. +void csptr_X_del(csptr_X* self); // destructor: decrease use count, destroy at 0 + +int csptr_X_compare(csptr_X* x, csptr_X* y); +bool csptr_X_equals(csptr_X* x, csptr_X* y); +``` + +## Types + +| Type name | Type definition | Used to represent... | +|:--------------------|:--------------------------------------------------------------|:-------------------------| +| `csptr_X` | `struct { csptr_X_value_t* get; atomic_count_t* use_count; }` | The csptr type | +| `csptr_X_value_t` | `Value` | The csptr element type | +| `atomic_count_t` | `long` | The reference counter | + +## Example + +```c +#include +#include + +typedef struct { cstr name, last; } Person; + +Person* Person_make(Person* p, const char* name, const char* last) { + p->name = cstr_from(name), p->last = cstr_from(last); + return p; +} +void Person_del(Person* p) { + printf("Destroy: %s %s\n", p->name.str, p->last.str); + c_del(cstr, &p->name, &p->last); +} + +using_csptr(pe, Person, c_no_compare, Person_del); + +int main() { + csptr_pe p = csptr_pe_from(Person_make(c_new(Person), "John", "Smiths")); + csptr_pe q = csptr_pe_clone(p); // means: share the pointer + + printf("Person: %s %s. uses: %zu\n", p.get->name.str, p.get->last.str, *p.use_count); + csptr_pe_del(&p); + + printf("Last man standing: %s %s. uses: %zu\n", q.get->name.str, q.get->last.str, *q.use_count); + csptr_pe_del(&q); +} +``` +Output: +``` +Person: John Smiths. uses: 2 +Last man standing: John Smiths. uses: 1 +Destroy: John Smiths +``` + +### Example 2 + +Advanced: Two different ways to store Person in vectors: 1) `cvec`, 2) `cvec< csptr >`. +```c +#include +#include +#include + +typedef struct { cstr name, last; } Person; + +Person* Person_make(Person* p, const char* name, const char* last) { + p->name = cstr_from(name), p->last = cstr_from(last); + return p; +} +int Person_compare(const Person* p, const Person* q) { + int cmp = strcmp(p->name.str, q->name.str); + return cmp == 0 ? strcmp(p->last.str, q->last.str) : cmp; +} +void Person_del(Person* p) { + printf("del: %s\n", p->name.str); + c_del(cstr, &p->name, &p->last); +} + +// 1. cvec of Person struct; emplace and cloning disabled. +using_cvec(pe, Person, Person_compare, Person_del, c_no_clone); + +// 2. cvec of shared-ptr to Person - with emplace_back() and cloning cvec ENABLED. +using_csptr(pe, Person, Person_compare, Person_del); +using_cvec(ps, csptr_pe, csptr_pe_compare, csptr_pe_del, csptr_pe_clone); + +const char* names[] = { + "Joe", "Jordan", + "Annie", "Aniston", + "Jane", "Jacobs" +}; + +int main() { + cvec_pe vec1 = cvec_pe_init(); + cvec_ps vec2 = cvec_ps_init(); + + for (int i = 0; i < 6; i += 2) { + Person tmp; + cvec_pe_push_back(&vec1, *Person_make(&tmp, names[i], names[i+1])); + cvec_ps_push_back(&vec2, csptr_pe_from(Person_make(c_new(Person), names[i], names[i+1]))); + } + puts("1. Sorted vec1 of Person:"); + cvec_pe_sort(&vec1); + c_foreach (i, cvec_pe, vec1) + printf(" %s %s\n", i.ref->name.str, i.ref->last.str); + + // Append a shared copy of vec2.data[0]. Will only be destructed once! + cvec_ps_emplace_back(&vec2, vec2.data[0]); // emplace will internally call csptr_ps_clone()! + puts("\n2. Sorted vec2 of shared-pointer to Person:"); + cvec_ps_sort(&vec2); + c_foreach (i, cvec_ps, vec2) + printf(" %s %s\n", i.ref->get->name.str, i.ref->get->last.str); + + // Share vec2.data[1] with elem1 variable. + csptr_pe elem1 = csptr_pe_clone(vec2.data[1]); + + puts("\nDestroy vec1:"); + cvec_pe_del(&vec1); + puts("\nDestroy vec2:"); + cvec_ps_del(&vec2); + + puts("\nDestroy elem1:"); + csptr_pe_del(&elem1); +} +``` +Output: +``` +1. Sorted vec1 of Person: + Annie Aniston + Jane Jacobs + Joe Jordan + +2. Sorted vec2 of shared-pointer to Person: + Annie Aniston + Jane Jacobs + Joe Jordan + Joe Jordan + +Destroy vec1: +del: Annie +del: Jane +del: Joe + +Destroy vec2: +del: Annie +del: Joe + +Destroy elem1: +del: Jane +``` diff --git a/examples/prime.c b/examples/prime.c index 39418c49..5c6b5065 100644 --- a/examples/prime.c +++ b/examples/prime.c @@ -5,11 +5,11 @@ cbits sieveOfEratosthenes(size_t n) { - cbits bits = cbits_with_size(n>>1, true); - size_t q = (size_t) sqrt(n); - - for (size_t i = 3; i <= q; i += 2) { - for (size_t j = i; j < n; j += 2) { + cbits bits = cbits_with_size(n/2 + 1, true); + size_t q = (size_t) sqrt(n) + 1; + for (size_t i = 3; i < q; i += 2) { + size_t j = i; + for (; j < n; j += 2) { if (cbits_test(bits, j>>1)) { i = j; break; @@ -23,7 +23,7 @@ cbits sieveOfEratosthenes(size_t n) int main(void) { - size_t n = 100000000; + size_t n = 1000000000; printf("computing prime numbers up to %zu\n", n); clock_t t1 = clock(); diff --git a/stc/cptr.h b/stc/cptr.h deleted file mode 100644 index 0cb51841..00000000 --- a/stc/cptr.h +++ /dev/null @@ -1,213 +0,0 @@ -/* 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 CPTR_H_INCLUDED -#define CPTR_H_INCLUDED - -/* cptr: std::unique_ptr -like type */ -/* -#include -#include -#include - -typedef struct { cstr name, last; } Person; - -Person* Person_make(Person* p, const char* name, const char* last) { - p->name = cstr_from(name), p->last = cstr_from(last); - return p; -} -void Person_del(Person* p) { - printf("del: %s\n", p->name.str); - c_del(cstr, &p->name, &p->last); -} -int Person_compare(const Person* p, const Person* q) { - int cmp = strcmp(p->name.str, q->name.str); - return cmp == 0 ? strcmp(p->last.str, q->last.str) : cmp; -} - -using_cptr(pe, Person, Person_compare, Person_del); -using_cvec(pe, Person*, cptr_pe_compare, cptr_pe_del, c_no_clone); - -int main() { - cvec_pe vec = cvec_pe_init(); - cvec_pe_push_back(&vec, Person_make(c_new(Person), "John", "Smiths")); - cvec_pe_push_back(&vec, Person_make(c_new(Person), "Jane", "Doe")); - - c_foreach (i, cvec_pe, vec) - printf("%s %s\n", (*i.ref)->name.str, (*i.ref)->last.str); - cvec_pe_del(&vec); -} -*/ -#include "ccommon.h" - -#define using_cptr(...) c_MACRO_OVERLOAD(using_cptr, __VA_ARGS__) - -#define using_cptr_2(X, Value) \ - using_cptr_3(X, Value, c_default_compare) - -#define using_cptr_3(X, Value, valueCompare) \ - using_cptr_4(X, Value, valueCompare, c_trivial_del) - -#define using_cptr_4(X, Value, valueCompare, valueDel) \ - typedef Value cptr_##X##_value_t; \ - typedef cptr_##X##_value_t *cptr_##X; \ -\ - STC_INLINE void \ - cptr_##X##_del(cptr_##X* self) { \ - valueDel(*self); \ - c_free(*self); \ - } \ -\ - STC_INLINE void \ - cptr_##X##_reset(cptr_##X* self, cptr_##X##_value_t* p) { \ - cptr_##X##_del(self); \ - *self = p; \ - } \ -\ - STC_INLINE int \ - cptr_##X##_compare(cptr_##X* x, cptr_##X* y) { \ - return valueCompare(*x, *y); \ - } \ - STC_INLINE int \ - cptr_##X##_equals(cptr_##X* x, cptr_##X* y) { \ - return valueCompare(*x, *y) == 0; \ - } \ - typedef cptr_##X cptr_##X##_t - - - -/* csptr: std::shared_ptr -like type: - -#include -#include - -typedef struct { cstr name, last; } Person; - -Person* Person_make(Person* p, const char* name, const char* last) { - p->name = cstr_from(name), p->last = cstr_from(last); - return p; -} -void Person_del(Person* p) { - printf("del: %s\n", p->name.str); - c_del(cstr, &p->name, &p->last); -} - -using_csptr(pe, Person, c_no_compare, Person_del); - -int main() { - csptr_pe p = csptr_pe_from(Person_make(c_new(Person), "John", "Smiths")); - csptr_pe q = csptr_pe_clone(p); // share the pointer - - printf("%s %s. uses: %zu\n", q.get->name.str, q.get->last.str, *q.use_count); - c_del(csptr_pe, &p, &q); -} -*/ -typedef long atomic_count_t; -#if defined(__GNUC__) || defined(__clang__) - STC_INLINE void atomic_increment(atomic_count_t* pw) {__atomic_add_fetch(pw, 1, __ATOMIC_SEQ_CST);} - STC_INLINE atomic_count_t atomic_decrement(atomic_count_t* pw) {return __atomic_sub_fetch(pw, 1, __ATOMIC_SEQ_CST);} -#elif defined(_MSC_VER) - #include - STC_INLINE void atomic_increment(atomic_count_t* pw) {_InterlockedIncrement(pw);} - STC_INLINE atomic_count_t atomic_decrement(atomic_count_t* pw) {return _InterlockedDecrement(pw);} -#elif defined(__i386__) || defined(__x86_64__) - STC_INLINE void atomic_increment(atomic_count_t* pw) { - __asm__ ( - "lock\n\t" - "incl %0": - "=m"( *pw ): // ++*pw // output (%0) - "m"( *pw ): // input (%1) - "cc" // clobbers - ); - } - STC_INLINE atomic_count_t atomic_decrement(atomic_count_t* pw) { - int r; - __asm__ __volatile__ ( - "lock\n\t" - "xadd %1, %0": - "=m"( *pw ), "=r"( r ): // int r = *pw; // outputs (%0, %1) - "m"( *pw ), "1"( -1 ): // *pw += -1; // inputs (%2, %3 == %1) - "memory", "cc" // clobbers - ); - return r - 1; - } -#endif - -#define using_csptr(...) c_MACRO_OVERLOAD(using_csptr, __VA_ARGS__) - -#define using_csptr_2(X, Value) \ - using_csptr_3(X, Value, c_default_compare) - -#define using_csptr_3(X, Value, valueCompare) \ - using_csptr_4(X, Value, valueCompare, c_trivial_del) - -#define using_csptr_4(X, Value, valueCompare, valueDel) \ - typedef Value csptr_##X##_value_t; \ - typedef struct { csptr_##X##_value_t* get; atomic_count_t* use_count; } csptr_##X; \ -\ - STC_INLINE csptr_##X \ - csptr_##X##_from(csptr_##X##_value_t* p) { \ - csptr_##X ptr = {p}; \ - if (p) *(ptr.use_count = c_new_1(atomic_count_t)) = 1; \ - return ptr; \ - } \ - STC_INLINE csptr_##X \ - csptr_##X##_make(csptr_##X##_value_t val) { \ - csptr_##X ptr = {c_new_1(csptr_##X##_value_t), c_new_1(atomic_count_t)}; \ - *ptr.get = val, *ptr.use_count = 1; return ptr; \ - } \ - STC_INLINE csptr_##X \ - csptr_##X##_clone(csptr_##X ptr) { \ - if (ptr.use_count) atomic_increment(ptr.use_count); \ - return ptr; \ - } \ - STC_INLINE csptr_##X \ - csptr_##X##_move(csptr_##X* self) { \ - csptr_##X x = *self; self->use_count = NULL; \ - return x; \ - } \ -\ - STC_INLINE void \ - csptr_##X##_del(csptr_##X* self) { \ - if (self->use_count && atomic_decrement(self->use_count) == 0) { \ - c_free(self->use_count); \ - valueDel(self->get); \ - c_free(self->get); \ - } \ - } \ - STC_INLINE void \ - csptr_##X##_reset(csptr_##X* self, csptr_##X##_value_t* p) { \ - csptr_##X##_del(self); \ - *self = csptr_##X##_from(p); \ - } \ -\ - STC_INLINE int \ - csptr_##X##_compare(csptr_##X* x, csptr_##X* y) { \ - return valueCompare(x->get, y->get); \ - } \ - STC_INLINE int \ - csptr_##X##_equals(csptr_##X* x, csptr_##X* y) { \ - return valueCompare(x->get, y->get) == 0; \ - } \ - typedef csptr_##X csptr_##X##_t - -#endif diff --git a/stc/csptr.h b/stc/csptr.h new file mode 100644 index 00000000..feb89b5a --- /dev/null +++ b/stc/csptr.h @@ -0,0 +1,151 @@ +/* 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 CSPTR_H_INCLUDED +#define CSPTR_H_INCLUDED + +#include "ccommon.h" + +/* csptr: std::shared_ptr -like type: + +#include +#include + +typedef struct { cstr name, last; } Person; + +Person* Person_make(Person* p, const char* name, const char* last) { + p->name = cstr_from(name), p->last = cstr_from(last); + return p; +} +void Person_del(Person* p) { + printf("del: %s\n", p->name.str); + c_del(cstr, &p->name, &p->last); +} + +using_csptr(pe, Person, c_no_compare, Person_del); + +int main() { + csptr_pe p = csptr_pe_from(Person_make(c_new(Person), "John", "Smiths")); + csptr_pe q = csptr_pe_clone(p); // share the pointer + + printf("%s %s. uses: %zu\n", q.get->name.str, q.get->last.str, *q.use_count); + c_del(csptr_pe, &p, &q); +} +*/ +typedef long atomic_count_t; +#if defined(__GNUC__) || defined(__clang__) + STC_INLINE void atomic_increment(atomic_count_t* pw) {__atomic_add_fetch(pw, 1, __ATOMIC_SEQ_CST);} + STC_INLINE atomic_count_t atomic_decrement(atomic_count_t* pw) {return __atomic_sub_fetch(pw, 1, __ATOMIC_SEQ_CST);} +#elif defined(_MSC_VER) + #include + STC_INLINE void atomic_increment(atomic_count_t* pw) {_InterlockedIncrement(pw);} + STC_INLINE atomic_count_t atomic_decrement(atomic_count_t* pw) {return _InterlockedDecrement(pw);} +#elif defined(__i386__) || defined(__x86_64__) + STC_INLINE void atomic_increment(atomic_count_t* pw) { + __asm__ ( + "lock\n\t" + "incl %0": + "=m"( *pw ): // ++*pw // output (%0) + "m"( *pw ): // input (%1) + "cc" // clobbers + ); + } + STC_INLINE atomic_count_t atomic_decrement(atomic_count_t* pw) { + int r; + __asm__ __volatile__ ( + "lock\n\t" + "xadd %1, %0": + "=m"( *pw ), "=r"( r ): // int r = *pw; // outputs (%0, %1) + "m"( *pw ), "1"( -1 ): // *pw += -1; // inputs (%2, %3 == %1) + "memory", "cc" // clobbers + ); + return r - 1; + } +#endif + +#define csptr_null {NULL, NULL} + +#define using_csptr(...) c_MACRO_OVERLOAD(using_csptr, __VA_ARGS__) + +#define using_csptr_2(X, Value) \ + using_csptr_3(X, Value, c_default_compare) + +#define using_csptr_3(X, Value, valueCompare) \ + using_csptr_4(X, Value, valueCompare, c_trivial_del) + +#define using_csptr_4(X, Value, valueCompare, valueDel) \ + typedef Value csptr_##X##_value_t; \ + typedef struct { csptr_##X##_value_t* get; atomic_count_t* use_count; } csptr_##X; \ +\ + STC_INLINE csptr_##X \ + csptr_##X##_from(csptr_##X##_value_t* p) { \ + csptr_##X ptr = {p}; \ + if (p) *(ptr.use_count = c_new_1(atomic_count_t)) = 1; \ + return ptr; \ + } \ + STC_INLINE csptr_##X \ + csptr_##X##_make(csptr_##X##_value_t val) { \ + csptr_##X ptr = {c_new_1(csptr_##X##_value_t), c_new_1(atomic_count_t)}; \ + *ptr.get = val, *ptr.use_count = 1; return ptr; \ + } \ + STC_INLINE csptr_##X \ + csptr_##X##_clone(csptr_##X ptr) { \ + if (ptr.use_count) atomic_increment(ptr.use_count); \ + return ptr; \ + } \ + STC_INLINE csptr_##X \ + csptr_##X##_move(csptr_##X* self) { \ + csptr_##X ptr = *self; \ + self->get = NULL, self->use_count = NULL; \ + return ptr; \ + } \ +\ + STC_INLINE void \ + csptr_##X##_del(csptr_##X* self) { \ + if (self->use_count && atomic_decrement(self->use_count) == 0) { \ + c_free(self->use_count); \ + valueDel(self->get); \ + c_free(self->get); \ + } \ + } \ + STC_INLINE void \ + csptr_##X##_reset(csptr_##X* self) { \ + csptr_##X##_del(self); \ + self->use_count = NULL, self->get = NULL; \ + } \ + STC_INLINE void \ + csptr_##X##_reset_to(csptr_##X* self, csptr_##X##_value_t* p) { \ + csptr_##X##_del(self); \ + *self = csptr_##X##_from(p); \ + } \ +\ + STC_INLINE int \ + csptr_##X##_compare(csptr_##X* x, csptr_##X* y) { \ + return valueCompare(x->get, y->get); \ + } \ + STC_INLINE bool \ + csptr_##X##_equals(csptr_##X* x, csptr_##X* y) { \ + return valueCompare(x->get, y->get) == 0; \ + } \ + typedef csptr_##X csptr_##X##_t + +#endif -- cgit v1.2.3