Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/libcbor/examples/crash_course.c
178428 views
1
/*
2
* Copyright (c) 2014-2020 Pavel Kalvoda <[email protected]>
3
*
4
* libcbor is free software; you can redistribute it and/or modify
5
* it under the terms of the MIT license. See LICENSE for details.
6
*/
7
8
#include <stdbool.h>
9
#include <stdio.h>
10
#include <string.h>
11
#include "cbor.h"
12
13
// Part 1: Begin
14
void item_examples() {
15
// A cbor_item_t can contain any CBOR data type
16
cbor_item_t* float_item = cbor_build_float4(3.14f);
17
cbor_item_t* string_item = cbor_build_string("Hello World!");
18
cbor_item_t* array_item = cbor_new_indefinite_array();
19
20
// They can be inspected
21
assert(cbor_is_float(float_item));
22
assert(cbor_typeof(string_item) == CBOR_TYPE_STRING);
23
assert(cbor_array_is_indefinite(array_item));
24
assert(cbor_array_size(array_item) == 0);
25
26
// The data can be accessed
27
assert(cbor_float_get_float4(float_item) == 3.14f);
28
assert(memcmp(cbor_string_handle(string_item), "Hello World!",
29
cbor_string_length(string_item)) == 0);
30
31
// And they can be modified
32
assert(cbor_array_push(array_item, float_item));
33
assert(cbor_array_push(array_item, string_item));
34
assert(cbor_array_size(array_item) == 2);
35
36
// At the end of their lifetime, items must be freed
37
cbor_decref(&float_item);
38
cbor_decref(&string_item);
39
cbor_decref(&array_item);
40
}
41
// Part 1: End
42
43
// Part 2: Begin
44
void encode_decode() {
45
cbor_item_t* item = cbor_build_uint8(42);
46
47
// Serialize the item to a buffer (it will be allocated by libcbor)
48
unsigned char* buffer;
49
size_t buffer_size;
50
cbor_serialize_alloc(item, &buffer, &buffer_size);
51
assert(buffer_size == 2);
52
assert(buffer[0] == 0x18); // Encoding byte for uint8
53
assert(buffer[1] == 42); // The value itself
54
55
// And deserialize bytes back to an item
56
struct cbor_load_result result;
57
cbor_item_t* decoded_item = cbor_load(buffer, buffer_size, &result);
58
assert(result.error.code == CBOR_ERR_NONE);
59
assert(cbor_isa_uint(decoded_item));
60
assert(cbor_get_uint8(decoded_item) == 42);
61
62
// Free the allocated buffer and items
63
free(buffer);
64
cbor_decref(&decoded_item);
65
cbor_decref(&item);
66
}
67
// Part 2: End
68
69
// Part 3: Begin
70
void reference_counting() {
71
// cbor_item_t is a reference counted pointer under the hood
72
cbor_item_t* item = cbor_build_uint8(42);
73
74
// Reference count starts at 1
75
assert(cbor_refcount(item) == 1);
76
77
// Most operations have reference semantics
78
cbor_item_t* array_item = cbor_new_definite_array(1);
79
assert(cbor_array_push(array_item, item));
80
assert(cbor_refcount(item) == 2); // item and array_item reference it
81
cbor_item_t* first_array_element = cbor_array_get(array_item, 0);
82
assert(first_array_element == item); // same item under the hood
83
assert(cbor_refcount(item) ==
84
3); // and now first_array_element also points to it
85
86
// To release the reference, use cbor_decref
87
cbor_decref(&first_array_element);
88
89
// When reference count reaches 0, the item is freed
90
assert(cbor_refcount(array_item) == 1);
91
cbor_decref(&array_item);
92
assert(array_item == NULL);
93
assert(cbor_refcount(item) == 1);
94
95
// Be careful, loops leak memory!
96
97
// Deep copy copies the whole item tree
98
cbor_item_t* item_copy = cbor_copy(item);
99
assert(cbor_refcount(item) == 1);
100
assert(cbor_refcount(item_copy) == 1);
101
assert(item_copy != item);
102
cbor_decref(&item);
103
cbor_decref(&item_copy);
104
}
105
// Part 3: End
106
107
// Part 4: Begin
108
void moving_values() {
109
{
110
// Move the "42" into an array.
111
cbor_item_t* array_item = cbor_new_definite_array(1);
112
// The line below leaks memory!
113
assert(cbor_array_push(array_item, cbor_build_uint8(42)));
114
cbor_item_t* first_array_element = cbor_array_get(array_item, 0);
115
assert(cbor_refcount(first_array_element) == 3); // Should be 2!
116
cbor_decref(&first_array_element);
117
cbor_decref(&array_item);
118
assert(cbor_refcount(first_array_element) == 1); // Shouldn't exist!
119
// Clean up
120
cbor_decref(&first_array_element);
121
}
122
123
{
124
// A correct way to move values is to decref them in the caller scope.
125
cbor_item_t* array_item = cbor_new_definite_array(1);
126
cbor_item_t* item = cbor_build_uint8(42);
127
assert(cbor_array_push(array_item, item));
128
assert(cbor_refcount(item) == 2);
129
// "Give up" the item
130
cbor_decref(&item);
131
cbor_decref(&array_item);
132
// item is a dangling pointer at this point
133
}
134
135
{
136
// cbor_move avoids the need to decref and the dangling pointer
137
cbor_item_t* array_item = cbor_new_definite_array(1);
138
assert(cbor_array_push(array_item, cbor_move(cbor_build_uint8(42))));
139
cbor_item_t* first_array_element = cbor_array_get(array_item, 0);
140
assert(cbor_refcount(first_array_element) == 2);
141
cbor_decref(&first_array_element);
142
cbor_decref(&array_item);
143
}
144
}
145
// Part 4: End
146
147
// Part 5: Begin
148
// Refcount can be managed in conjunction with ownership
149
static cbor_item_t* global_item = NULL;
150
151
// This function takes shared ownership of the item
152
void borrow_item(cbor_item_t* item) {
153
global_item = item;
154
// Mark the extra reference
155
cbor_incref(item);
156
}
157
158
void return_item() {
159
cbor_decref(&global_item);
160
global_item = NULL;
161
}
162
163
void reference_ownership() {
164
cbor_item_t* item = cbor_build_uint8(42);
165
166
// Lend the item
167
borrow_item(item);
168
assert(cbor_refcount(item) == 2);
169
cbor_decref(&item);
170
171
// Release the shared ownership. return_item will deallocate the item.
172
return_item();
173
}
174
// Part 5: End
175
176
int main(void) {
177
item_examples();
178
encode_decode();
179
reference_counting();
180
moving_values();
181
reference_ownership();
182
return 0;
183
}
184
185