/src/libcbor/src/cbor/maps.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2014-2020 Pavel Kalvoda <me@pavelkalvoda.com> |
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 "maps.h" |
9 | | #include "internal/memory_utils.h" |
10 | | |
11 | 8.44M | size_t cbor_map_size(const cbor_item_t *item) { |
12 | 8.44M | CBOR_ASSERT(cbor_isa_map(item)); |
13 | 8.44M | return item->metadata.map_metadata.end_ptr; |
14 | 8.44M | } |
15 | | |
16 | 0 | size_t cbor_map_allocated(const cbor_item_t *item) { |
17 | 0 | CBOR_ASSERT(cbor_isa_map(item)); |
18 | 0 | return item->metadata.map_metadata.allocated; |
19 | 0 | } |
20 | | |
21 | 5.87M | cbor_item_t *cbor_new_definite_map(size_t size) { |
22 | 5.87M | cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t)); |
23 | 5.87M | _CBOR_NOTNULL(item); |
24 | | |
25 | 5.87M | *item = (cbor_item_t){ |
26 | 5.87M | .refcount = 1, |
27 | 5.87M | .type = CBOR_TYPE_MAP, |
28 | 5.87M | .metadata = {.map_metadata = {.allocated = size, |
29 | 5.87M | .type = _CBOR_METADATA_DEFINITE, |
30 | 5.87M | .end_ptr = 0}}, |
31 | 5.87M | .data = _cbor_alloc_multiple(sizeof(struct cbor_pair), size)}; |
32 | 5.87M | _CBOR_DEPENDENT_NOTNULL(item, item->data); |
33 | | |
34 | 5.87M | return item; |
35 | 5.87M | } |
36 | | |
37 | 1.27M | cbor_item_t *cbor_new_indefinite_map(void) { |
38 | 1.27M | cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t)); |
39 | 1.27M | _CBOR_NOTNULL(item); |
40 | | |
41 | 1.27M | *item = (cbor_item_t){ |
42 | 1.27M | .refcount = 1, |
43 | 1.27M | .type = CBOR_TYPE_MAP, |
44 | 1.27M | .metadata = {.map_metadata = {.allocated = 0, |
45 | 1.27M | .type = _CBOR_METADATA_INDEFINITE, |
46 | 1.27M | .end_ptr = 0}}, |
47 | 1.27M | .data = NULL}; |
48 | | |
49 | 1.27M | return item; |
50 | 1.27M | } |
51 | | |
52 | 2.56M | bool _cbor_map_add_key(cbor_item_t *item, cbor_item_t *key) { |
53 | 2.56M | CBOR_ASSERT(cbor_isa_map(item)); |
54 | 2.56M | struct _cbor_map_metadata *metadata = |
55 | 2.56M | (struct _cbor_map_metadata *)&item->metadata; |
56 | 2.56M | if (cbor_map_is_definite(item)) { |
57 | 420k | struct cbor_pair *data = cbor_map_handle(item); |
58 | 420k | if (metadata->end_ptr >= metadata->allocated) { |
59 | | /* Don't realloc definite preallocated map */ |
60 | 0 | return false; |
61 | 0 | } |
62 | | |
63 | 420k | data[metadata->end_ptr].key = key; |
64 | 420k | data[metadata->end_ptr++].value = NULL; |
65 | 2.14M | } else { |
66 | 2.14M | if (metadata->end_ptr >= metadata->allocated) { |
67 | | /* Exponential realloc */ |
68 | | // Check for overflows first |
69 | 1.31M | if (!_cbor_safe_to_multiply(CBOR_BUFFER_GROWTH, metadata->allocated)) { |
70 | 0 | return false; |
71 | 0 | } |
72 | | |
73 | 1.31M | size_t new_allocation = metadata->allocated == 0 |
74 | 1.31M | ? 1 |
75 | 1.31M | : CBOR_BUFFER_GROWTH * metadata->allocated; |
76 | | |
77 | 1.31M | unsigned char *new_data = _cbor_realloc_multiple( |
78 | 1.31M | item->data, sizeof(struct cbor_pair), new_allocation); |
79 | | |
80 | 1.31M | if (new_data == NULL) { |
81 | 2 | return false; |
82 | 2 | } |
83 | | |
84 | 1.31M | item->data = new_data; |
85 | 1.31M | metadata->allocated = new_allocation; |
86 | 1.31M | } |
87 | 2.14M | struct cbor_pair *data = cbor_map_handle(item); |
88 | 2.14M | data[metadata->end_ptr].key = key; |
89 | 2.14M | data[metadata->end_ptr++].value = NULL; |
90 | 2.14M | } |
91 | 2.56M | cbor_incref(key); |
92 | 2.56M | return true; |
93 | 2.56M | } |
94 | | |
95 | 2.56M | bool _cbor_map_add_value(cbor_item_t *item, cbor_item_t *value) { |
96 | 2.56M | CBOR_ASSERT(cbor_isa_map(item)); |
97 | 2.56M | cbor_incref(value); |
98 | 2.56M | cbor_map_handle(item)[ |
99 | | /* Move one back since we are assuming _add_key (which increased the ptr) |
100 | | * was the previous operation on this object */ |
101 | 2.56M | item->metadata.map_metadata.end_ptr - 1] |
102 | 2.56M | .value = value; |
103 | 2.56M | return true; |
104 | 2.56M | } |
105 | | |
106 | | // TODO: Add a more convenient API like add(item, key, val) |
107 | 1.29M | bool cbor_map_add(cbor_item_t *item, struct cbor_pair pair) { |
108 | 1.29M | CBOR_ASSERT(cbor_isa_map(item)); |
109 | 1.29M | if (!_cbor_map_add_key(item, pair.key)) return false; |
110 | 1.29M | return _cbor_map_add_value(item, pair.value); |
111 | 1.29M | } |
112 | | |
113 | 8.29M | bool cbor_map_is_definite(const cbor_item_t *item) { |
114 | 8.29M | CBOR_ASSERT(cbor_isa_map(item)); |
115 | 8.29M | return item->metadata.map_metadata.type == _CBOR_METADATA_DEFINITE; |
116 | 8.29M | } |
117 | | |
118 | 23.8k | bool cbor_map_is_indefinite(const cbor_item_t *item) { |
119 | 23.8k | return !cbor_map_is_definite(item); |
120 | 23.8k | } |
121 | | |
122 | 19.3M | struct cbor_pair *cbor_map_handle(const cbor_item_t *item) { |
123 | 19.3M | CBOR_ASSERT(cbor_isa_map(item)); |
124 | 19.3M | return (struct cbor_pair *)item->data; |
125 | 19.3M | } |