1 /****************************************************************************** 2 * 3 * Copyright (C) 2014 Google, Inc. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at: 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 ******************************************************************************/ 18 19 #define LOG_TAG "bt_osi_array" 20 21 #include "osi/include/array.h" 22 23 #include <assert.h> 24 #include <stdlib.h> 25 #include <string.h> 26 27 #include "osi/include/allocator.h" 28 #include "osi/include/log.h" 29 30 struct array_t { 31 size_t element_size; 32 size_t length; 33 size_t capacity; 34 uint8_t *data; 35 uint8_t internal_storage[]; 36 }; 37 38 static bool grow(array_t *array); 39 40 static const size_t INTERNAL_ELEMENTS = 16; 41 42 array_t *array_new(size_t element_size) { 43 assert(element_size > 0); 44 45 array_t *array = osi_calloc(sizeof(array_t) + element_size * INTERNAL_ELEMENTS); 46 47 array->element_size = element_size; 48 array->capacity = INTERNAL_ELEMENTS; 49 array->data = array->internal_storage; 50 return array; 51 } 52 53 void array_free(array_t *array) { 54 if (!array) 55 return; 56 57 if (array->data != array->internal_storage) 58 free(array->data); 59 60 osi_free(array); 61 } 62 63 void *array_ptr(const array_t *array) { 64 return array_at(array, 0); 65 } 66 67 void *array_at(const array_t *array, size_t index) { 68 assert(array != NULL); 69 assert(index < array->length); 70 return array->data + (index * array->element_size); 71 } 72 73 size_t array_length(const array_t *array) { 74 assert(array != NULL); 75 return array->length; 76 } 77 78 bool array_append_value(array_t *array, uint32_t value) { 79 return array_append_ptr(array, &value); 80 } 81 82 bool array_append_ptr(array_t *array, void *data) { 83 assert(array != NULL); 84 assert(data != NULL); 85 86 if (array->length == array->capacity && !grow(array)) { 87 LOG_ERROR(LOG_TAG, "%s unable to grow array past current capacity of %zu elements of size %zu.", __func__, array->capacity, array->element_size); 88 return false; 89 } 90 91 ++array->length; 92 memcpy(array_at(array, array->length - 1), data, array->element_size); 93 return true; 94 } 95 96 static bool grow(array_t *array) { 97 const size_t new_capacity = array->capacity + (array->capacity / 2); 98 const bool is_moving = (array->data == array->internal_storage); 99 100 void *new_data = realloc(is_moving ? NULL : array->data, new_capacity * array->element_size); 101 if (!new_data) 102 return false; 103 104 if (is_moving) 105 memcpy(new_data, array->internal_storage, array->length * array->element_size); 106 107 array->data = new_data; 108 array->capacity = new_capacity; 109 return true; 110 } 111