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
11size_t cbor_map_size(const cbor_item_t *item) {
12  CBOR_ASSERT(cbor_isa_map(item));
13  return item->metadata.map_metadata.end_ptr;
14}
15
16size_t cbor_map_allocated(const cbor_item_t *item) {
17  CBOR_ASSERT(cbor_isa_map(item));
18  return item->metadata.map_metadata.allocated;
19}
20
21cbor_item_t *cbor_new_definite_map(size_t size) {
22  cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t));
23  _CBOR_NOTNULL(item);
24
25  *item = (cbor_item_t){
26      .refcount = 1,
27      .type = CBOR_TYPE_MAP,
28      .metadata = {.map_metadata = {.allocated = size,
29                                    .type = _CBOR_METADATA_DEFINITE,
30                                    .end_ptr = 0}},
31      .data = _cbor_alloc_multiple(sizeof(struct cbor_pair), size)};
32  _CBOR_DEPENDENT_NOTNULL(item, item->data);
33
34  return item;
35}
36
37cbor_item_t *cbor_new_indefinite_map(void) {
38  cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t));
39  _CBOR_NOTNULL(item);
40
41  *item = (cbor_item_t){
42      .refcount = 1,
43      .type = CBOR_TYPE_MAP,
44      .metadata = {.map_metadata = {.allocated = 0,
45                                    .type = _CBOR_METADATA_INDEFINITE,
46                                    .end_ptr = 0}},
47      .data = NULL};
48
49  return item;
50}
51
52bool _cbor_map_add_key(cbor_item_t *item, cbor_item_t *key) {
53  CBOR_ASSERT(cbor_isa_map(item));
54  struct _cbor_map_metadata *metadata =
55      (struct _cbor_map_metadata *)&item->metadata;
56  if (cbor_map_is_definite(item)) {
57    struct cbor_pair *data = cbor_map_handle(item);
58    if (metadata->end_ptr >= metadata->allocated) {
59      /* Don't realloc definite preallocated map */
60      return false;
61    }
62
63    data[metadata->end_ptr].key = key;
64    data[metadata->end_ptr++].value = NULL;
65  } else {
66    if (metadata->end_ptr >= metadata->allocated) {
67      /* Exponential realloc */
68      // Check for overflows first
69      if (!_cbor_safe_to_multiply(CBOR_BUFFER_GROWTH, metadata->allocated)) {
70        return false;
71      }
72
73      size_t new_allocation = metadata->allocated == 0
74                                  ? 1
75                                  : CBOR_BUFFER_GROWTH * metadata->allocated;
76
77      unsigned char *new_data = _cbor_realloc_multiple(
78          item->data, sizeof(struct cbor_pair), new_allocation);
79
80      if (new_data == NULL) {
81        return false;
82      }
83
84      item->data = new_data;
85      metadata->allocated = new_allocation;
86    }
87    struct cbor_pair *data = cbor_map_handle(item);
88    data[metadata->end_ptr].key = key;
89    data[metadata->end_ptr++].value = NULL;
90  }
91  cbor_incref(key);
92  return true;
93}
94
95bool _cbor_map_add_value(cbor_item_t *item, cbor_item_t *value) {
96  CBOR_ASSERT(cbor_isa_map(item));
97  cbor_incref(value);
98  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      item->metadata.map_metadata.end_ptr - 1]
102      .value = value;
103  return true;
104}
105
106// TODO: Add a more convenient API like add(item, key, val)
107bool cbor_map_add(cbor_item_t *item, struct cbor_pair pair) {
108  CBOR_ASSERT(cbor_isa_map(item));
109  if (!_cbor_map_add_key(item, pair.key)) return false;
110  return _cbor_map_add_value(item, pair.value);
111}
112
113bool cbor_map_is_definite(const cbor_item_t *item) {
114  CBOR_ASSERT(cbor_isa_map(item));
115  return item->metadata.map_metadata.type == _CBOR_METADATA_DEFINITE;
116}
117
118bool cbor_map_is_indefinite(const cbor_item_t *item) {
119  return !cbor_map_is_definite(item);
120}
121
122struct cbor_pair *cbor_map_handle(const cbor_item_t *item) {
123  CBOR_ASSERT(cbor_isa_map(item));
124  return (struct cbor_pair *)item->data;
125}
126