summaryrefslogtreecommitdiffhomepage
path: root/docs/carc_api.md
blob: cc6c9c32e0e4dd7d329af189dd3c5bf8b081d98f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# STC [carc](../include/stc/carc.h): Atomic Reference Counted Smart Pointer

**carc** is a smart pointer that retains shared ownership of an object through a pointer.
Several **carc** objects may own the same object. The object is destroyed and its memory
deallocated when the last remaining **carc** owning the object is destroyed with *carc_X_drop()*;

The object is destroyed using *carc_X_drop()*. A **carc** may also own no objects, in which 
case it is called empty. The *carc_X_cmp()*, *carc_X_drop()* methods are defined based on
the `i_cmp` and `i_valdrop` macros specified. Use *carc_X_clone(p)* when sharing ownership of
the pointed-to object. 

All **carc** functions can be called by multiple threads on different instances of **carc** without
additional synchronization even if these instances are copies and share ownership of the same object.
**carc** uses thread-safe atomic reference counting, through the *carc_X_clone()* and *carc_X_drop()* methods.

When declaring a container with shared pointers, define `i_valboxed` with the carc type, see example.

See similar c++ class [std::shared_ptr](https://en.cppreference.com/w/cpp/memory/shared_ptr) for a functional reference, or Rust [std::sync::Arc](https://doc.rust-lang.org/std/sync/struct.Arc.html) / [std::rc::Rc](https://doc.rust-lang.org/std/rc/struct.Rc.html).

## Header file and declaration

```c
#define i_type            // full typename of the carc
#define i_val             // value: REQUIRED

#define i_valraw          // convertion "raw" type - defaults to i_val
#define i_valto           // convertion func i_val* => i_valraw: REQUIRED IF i_valraw defined.
#define i_valfrom         // convertion func i_valraw => i_val
      
#define i_opt c_no_atomic // Non-atomic reference counting, like Rust Rc.
#define i_tag             // alternative typename: carc_{i_tag}. i_tag defaults to i_val
#include <stc/carc.h>
```
`X` should be replaced by the value of `i_tag` in all of the following documentation.

## Methods
```c
carc_X      carc_X_init();                                     // empty shared pointer
carc_X      carc_X_from(i_valraw raw);                         // create an carc from raw type (available if i_valraw defined by user).
carc_X      carc_X_from_ptr(i_val* p);                         // create an carc from raw pointer. Takes ownership of p.
carc_X      carc_X_make(i_val val);                            // create an carc from constructed val object. Faster than from_ptr().

carc_X      carc_X_clone(carc_X other);                        // return other with increased use count
carc_X      carc_X_move(carc_X* self);                         // transfer ownership to receiver; self becomes NULL
void        carc_X_take(carc_X* self, carc_X unowned);         // take ownership of unowned.
void        carc_X_assign(carc_X* self, carc_X other);         // shared assign (increases use count)

void        carc_X_drop(carc_X* self);                         // destruct (decrease use count, free at 0)
long        carc_X_use_count(const carc_X* self);    

void        carc_X_reset(carc_X* self);    
void        carc_X_reset_to(carc_X* self, i_val* p);           // assign new carc from ptr. Takes ownership of p.

uint64_t    carc_X_hash(const carc_X* x);                      // hash value
int         carc_X_cmp(const carc_X* x, const carc_X* y);      // compares pointer addresses if no `i_cmp` is specified.
                                                               // is defined. Otherwise uses 'i_cmp' or default cmp.
bool        carc_X_eq(const carc_X* x, const carc_X* y);       // carc_X_cmp() == 0

// functions on pointed to objects.

uint64_t    carc_X_value_hash(const i_val* x);
int         carc_X_value_cmp(const i_val* x, const i_val* y);
bool        carc_X_value_eq(const i_val* x, const i_val* y);
```

## Types and constants

| Type name         | Type definition                                   | Used to represent...   |
|:------------------|:--------------------------------------------------|:-----------------------|
| `carc_NULL`       | `{NULL, NULL}`                                    | Init nullptr const     |
| `carc_X`          | `struct { carc_X_value* get; long* use_count; }`  | The carc type          |
| `carc_X_value`    | `i_val`                                           | The carc element type  |
| `carc_X_raw`      | `i_valraw`                                        | Convertion type        |

## Example

```c
// Create two stacks with carcs to maps.
// Demonstrate sharing and cloning of maps.
// Show elements dropped.
#include <stc/cstr.h>

#define i_type Map
#define i_key_str // i_key: cstr, i_keydrop: cstr_drop, etc..
#define i_val int // year
// override cstr_drop(p) by defining i_keydrop:
#define i_keydrop(p) (printf("  drop name: %s\n", cstr_str(p)), cstr_drop(p))
#include <stc/csmap.h>

#define i_type Arc // (atomic) ref. counted pointer
#define i_val Map
#define i_valdrop(p) (printf("drop Arc:\n"), Map_drop(p))
#include <stc/carc.h>

#define i_type Stack
#define i_valboxed Arc // Note: use i_valboxed for carc or cbox value types
#include <stc/cstack.h>

int main()
{
    c_auto (Stack, s1, s2) // RAII
    {
        // POPULATE s1 with shared pointers to Map:
        Map *map;

        map = Stack_push(&s1, Arc_make(Map_init()))->get; // push empty map to s1.
        c_forlist (i, Map_raw, { {"Joey", 1990}, {"Mary", 1995}, {"Joanna", 1992} }) {
            Map_emplace(map, c_PAIR(i.ref)); // populate it.
        }

        map = Stack_push(&s1, Arc_make(Map_init()))->get;
        c_forlist (i, Map_raw, { {"Rosanna", 2001}, {"Brad", 1999}, {"Jack", 1980} }) {
            Map_emplace(map, c_PAIR(i.ref));
        }

        // POPULATE s2:
        map = Stack_push(&s2, Arc_make(Map_init()))->get;
        c_forlist (i, Map_raw, { {"Steve", 1979}, {"Rick", 1974}, {"Tracy", 2003} }) {
            Map_emplace(map, c_PAIR(i.ref));
        }
        
        // Share two Maps from s1 with s2 by cloning(=sharing) the carcs:
        Stack_push(&s2, Arc_clone(s1.data[0]));
        Stack_push(&s2, Arc_clone(s1.data[1]));
        
        // Deep-copy (does not share) a Map from s1 to s2.
        // s2 will contain two shared and two unshared maps.
        map = Stack_push(&s2, Arc_from(Map_clone(*s1.data[1].get)))->get;
        
        // Add one more element to the cloned map:
        Map_emplace_or_assign(map, "Cloned", 2022);

        // Add one more element to the shared map:
        Map_emplace_or_assign(s1.data[1].get, "Shared", 2022);

        puts("S1");
        c_foreach (i, Stack, s1) {
            c_forpair (name, year, Map, *i.ref->get)
                printf("  %s:%d", cstr_str(_.name), *_.year);
            puts("");
        }

        puts("S2");
        c_foreach (i, Stack, s2) {
            c_forpair (name, year, Map, *i.ref->get)
                printf("  %s:%d", cstr_str(_.name), *_.year);
            puts("");
        }
        puts("");
    }
}
```
Output:
```
S1
  Joanna:1992  Joey:1990  Mary:1995
  Brad:1999  Jack:1980  Rosanna:2001  Shared:2022
S2
  Rick:1974  Steve:1979  Tracy:2003
  Joanna:1992  Joey:1990  Mary:1995
  Brad:1999  Jack:1980  Rosanna:2001  Shared:2022
  Brad:1999  Cloned:2022  Jack:1980  Rosanna:2001

drop Arc:
  drop name: Rick
  drop name: Tracy
  drop name: Steve
drop Arc:
  drop name: Cloned
  drop name: Brad
  drop name: Rosanna
  drop name: Jack
drop Arc:
  drop name: Brad
  drop name: Shared
  drop name: Rosanna
  drop name: Jack
drop Arc:
  drop name: Joanna
  drop name: Mary
  drop name: Joey
```