diff options
Diffstat (limited to 'examples/crash_course.c')
| -rw-r--r-- | examples/crash_course.c | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/examples/crash_course.c b/examples/crash_course.c new file mode 100644 index 000000000000..4bd9f9379d26 --- /dev/null +++ b/examples/crash_course.c @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2014-2020 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include "cbor.h" + +// Part 1: Begin +void item_examples() { + // A cbor_item_t can contain any CBOR data type + cbor_item_t* float_item = cbor_build_float4(3.14f); + cbor_item_t* string_item = cbor_build_string("Hello World!"); + cbor_item_t* array_item = cbor_new_indefinite_array(); + + // They can be inspected + assert(cbor_is_float(float_item)); + assert(cbor_typeof(string_item) == CBOR_TYPE_STRING); + assert(cbor_array_is_indefinite(array_item)); + assert(cbor_array_size(array_item) == 0); + + // The data can be accessed + assert(cbor_float_get_float4(float_item) == 3.14f); + assert(memcmp(cbor_string_handle(string_item), "Hello World!", + cbor_string_length(string_item)) == 0); + + // And they can be modified + assert(cbor_array_push(array_item, float_item)); + assert(cbor_array_push(array_item, string_item)); + assert(cbor_array_size(array_item) == 2); + + // At the end of their lifetime, items must be freed + cbor_decref(&float_item); + cbor_decref(&string_item); + cbor_decref(&array_item); +} +// Part 1: End + +// Part 2: Begin +void encode_decode() { + cbor_item_t* item = cbor_build_uint8(42); + + // Serialize the item to a buffer (it will be allocated by libcbor) + unsigned char* buffer; + size_t buffer_size; + cbor_serialize_alloc(item, &buffer, &buffer_size); + assert(buffer_size == 2); + assert(buffer[0] == 0x18); // Encoding byte for uint8 + assert(buffer[1] == 42); // The value itself + + // And deserialize bytes back to an item + struct cbor_load_result result; + cbor_item_t* decoded_item = cbor_load(buffer, buffer_size, &result); + assert(result.error.code == CBOR_ERR_NONE); + assert(cbor_isa_uint(decoded_item)); + assert(cbor_get_uint8(decoded_item) == 42); + + // Free the allocated buffer and items + free(buffer); + cbor_decref(&decoded_item); + cbor_decref(&item); +} +// Part 2: End + +// Part 3: Begin +void reference_counting() { + // cbor_item_t is a reference counted pointer under the hood + cbor_item_t* item = cbor_build_uint8(42); + + // Reference count starts at 1 + assert(cbor_refcount(item) == 1); + + // Most operations have reference semantics + cbor_item_t* array_item = cbor_new_definite_array(1); + assert(cbor_array_push(array_item, item)); + assert(cbor_refcount(item) == 2); // item and array_item reference it + cbor_item_t* first_array_element = cbor_array_get(array_item, 0); + assert(first_array_element == item); // same item under the hood + assert(cbor_refcount(item) == + 3); // and now first_array_element also points to it + + // To release the reference, use cbor_decref + cbor_decref(&first_array_element); + + // When reference count reaches 0, the item is freed + assert(cbor_refcount(array_item) == 1); + cbor_decref(&array_item); + assert(array_item == NULL); + assert(cbor_refcount(item) == 1); + + // Be careful, loops leak memory! + + // Deep copy copies the whole item tree + cbor_item_t* item_copy = cbor_copy(item); + assert(cbor_refcount(item) == 1); + assert(cbor_refcount(item_copy) == 1); + assert(item_copy != item); + cbor_decref(&item); + cbor_decref(&item_copy); +} +// Part 3: End + +// Part 4: Begin +void moving_values() { + { + // Move the "42" into an array. + cbor_item_t* array_item = cbor_new_definite_array(1); + // The line below leaks memory! + assert(cbor_array_push(array_item, cbor_build_uint8(42))); + cbor_item_t* first_array_element = cbor_array_get(array_item, 0); + assert(cbor_refcount(first_array_element) == 3); // Should be 2! + cbor_decref(&first_array_element); + cbor_decref(&array_item); + assert(cbor_refcount(first_array_element) == 1); // Shouldn't exist! + // Clean up + cbor_decref(&first_array_element); + } + + { + // A correct way to move values is to decref them in the caller scope. + cbor_item_t* array_item = cbor_new_definite_array(1); + cbor_item_t* item = cbor_build_uint8(42); + assert(cbor_array_push(array_item, item)); + assert(cbor_refcount(item) == 2); + // "Give up" the item + cbor_decref(&item); + cbor_decref(&array_item); + // item is a dangling pointer at this point + } + + { + // cbor_move avoids the need to decref and the dangling pointer + cbor_item_t* array_item = cbor_new_definite_array(1); + assert(cbor_array_push(array_item, cbor_move(cbor_build_uint8(42)))); + cbor_item_t* first_array_element = cbor_array_get(array_item, 0); + assert(cbor_refcount(first_array_element) == 2); + cbor_decref(&first_array_element); + cbor_decref(&array_item); + } +} +// Part 4: End + +// Part 5: Begin +// Refcount can be managed in conjunction with ownership +static cbor_item_t* global_item = NULL; + +// This function takes shared ownership of the item +void borrow_item(cbor_item_t* item) { + global_item = item; + // Mark the extra reference + cbor_incref(item); +} + +void return_item() { + cbor_decref(&global_item); + global_item = NULL; +} + +void reference_ownership() { + cbor_item_t* item = cbor_build_uint8(42); + + // Lend the item + borrow_item(item); + assert(cbor_refcount(item) == 2); + cbor_decref(&item); + + // Release the shared ownership. return_item will deallocate the item. + return_item(); +} +// Part 5: End + +int main(void) { + item_examples(); + encode_decode(); + reference_counting(); + moving_values(); + reference_ownership(); + return 0; +} |
