Home | History | Annotate | Line # | Download | only in cbor
      1 /*
      2  * Copyright (c) 2014-2019 Pavel Kalvoda <me (at) 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 "arrays.h"
      9 #include <string.h>
     10 #include "internal/memory_utils.h"
     11 
     12 size_t cbor_array_size(const cbor_item_t *item) {
     13   assert(cbor_isa_array(item));
     14   return item->metadata.array_metadata.end_ptr;
     15 }
     16 
     17 size_t cbor_array_allocated(const cbor_item_t *item) {
     18   assert(cbor_isa_array(item));
     19   return item->metadata.array_metadata.allocated;
     20 }
     21 
     22 cbor_item_t *cbor_array_get(const cbor_item_t *item, size_t index) {
     23   return cbor_incref(((cbor_item_t **)item->data)[index]);
     24 }
     25 
     26 bool cbor_array_set(cbor_item_t *item, size_t index, cbor_item_t *value) {
     27   if (index == item->metadata.array_metadata.end_ptr) {
     28     return cbor_array_push(item, value);
     29   } else if (index < item->metadata.array_metadata.end_ptr) {
     30     return cbor_array_replace(item, index, value);
     31   } else {
     32     return false;
     33   }
     34   // TODO: This is unreachable and the index checking logic above seems
     35   // suspicious -- out of bounds index is a caller error. Figure out & fix.
     36   return true;
     37 }
     38 
     39 bool cbor_array_replace(cbor_item_t *item, size_t index, cbor_item_t *value) {
     40   if (index >= item->metadata.array_metadata.end_ptr) return false;
     41   /* We cannot use cbor_array_get as that would increase the refcount */
     42   cbor_intermediate_decref(((cbor_item_t **)item->data)[index]);
     43   ((cbor_item_t **)item->data)[index] = cbor_incref(value);
     44   return true;
     45 }
     46 
     47 bool cbor_array_push(cbor_item_t *array, cbor_item_t *pushee) {
     48   assert(cbor_isa_array(array));
     49   struct _cbor_array_metadata *metadata =
     50       (struct _cbor_array_metadata *)&array->metadata;
     51   cbor_item_t **data = (cbor_item_t **)array->data;
     52   if (cbor_array_is_definite(array)) {
     53     /* Do not reallocate definite arrays */
     54     if (metadata->end_ptr >= metadata->allocated) {
     55       return false;
     56     }
     57     data[metadata->end_ptr++] = pushee;
     58   } else {
     59     /* Exponential realloc */
     60     if (metadata->end_ptr >= metadata->allocated) {
     61       // Check for overflows first
     62       // TODO: Explicitly test this
     63       if (!_cbor_safe_to_multiply(CBOR_BUFFER_GROWTH, metadata->allocated)) {
     64         return false;
     65       }
     66 
     67       size_t new_allocation = metadata->allocated == 0
     68                                   ? 1
     69                                   : CBOR_BUFFER_GROWTH * metadata->allocated;
     70 
     71       unsigned char *new_data = _cbor_realloc_multiple(
     72           array->data, sizeof(cbor_item_t *), new_allocation);
     73       if (new_data == NULL) {
     74         return false;
     75       }
     76 
     77       array->data = new_data;
     78       metadata->allocated = new_allocation;
     79     }
     80     ((cbor_item_t **)array->data)[metadata->end_ptr++] = pushee;
     81   }
     82   cbor_incref(pushee);
     83   return true;
     84 }
     85 
     86 bool cbor_array_is_definite(const cbor_item_t *item) {
     87   assert(cbor_isa_array(item));
     88   return item->metadata.array_metadata.type == _CBOR_METADATA_DEFINITE;
     89 }
     90 
     91 bool cbor_array_is_indefinite(const cbor_item_t *item) {
     92   assert(cbor_isa_array(item));
     93   return item->metadata.array_metadata.type == _CBOR_METADATA_INDEFINITE;
     94 }
     95 
     96 cbor_item_t **cbor_array_handle(const cbor_item_t *item) {
     97   assert(cbor_isa_array(item));
     98   return (cbor_item_t **)item->data;
     99 }
    100 
    101 cbor_item_t *cbor_new_definite_array(size_t size) {
    102   cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t));
    103   _CBOR_NOTNULL(item);
    104   cbor_item_t **data = _cbor_alloc_multiple(sizeof(cbor_item_t *), size);
    105   _CBOR_DEPENDENT_NOTNULL(item, data);
    106 
    107   for (size_t i = 0; i < size; i++) {
    108     data[i] = NULL;
    109   }
    110 
    111   *item = (cbor_item_t){
    112       .refcount = 1,
    113       .type = CBOR_TYPE_ARRAY,
    114       .metadata = {.array_metadata = {.type = _CBOR_METADATA_DEFINITE,
    115                                       .allocated = size,
    116                                       .end_ptr = 0}},
    117       .data = (unsigned char *)data};
    118 
    119   return item;
    120 }
    121 
    122 cbor_item_t *cbor_new_indefinite_array() {
    123   cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t));
    124   _CBOR_NOTNULL(item);
    125 
    126   *item = (cbor_item_t){
    127       .refcount = 1,
    128       .type = CBOR_TYPE_ARRAY,
    129       .metadata = {.array_metadata = {.type = _CBOR_METADATA_INDEFINITE,
    130                                       .allocated = 0,
    131                                       .end_ptr = 0}},
    132       .data = NULL /* Can be safely realloc-ed */
    133   };
    134   return item;
    135 }
    136