Skip to content

Latest commit

 

History

History
191 lines (149 loc) · 6.55 KB

File metadata and controls

191 lines (149 loc) · 6.55 KB

STC csptr: 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 for a functional reference.

Header file and declaration

#include <stc/csptr.h>

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.

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_with(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 and constants

Type name Type definition Used to represent...
csptr_null {NULL, NULL} Init nullptr const
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

#include <stc/csptr.h>
#include <stc/cstr.h>

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<Person>, 2) cvec< csptr<Person> >.

#include <stc/csptr.h>
#include <stc/cstr.h>
#include <stc/cvec.h>

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