array.cc revision b2a292b5d8df2f359c38b0787bc01181225a9bc9
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 30struct 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 38static bool grow(array_t *array); 39 40static const size_t INTERNAL_ELEMENTS = 16; 41 42array_t *array_new(size_t element_size) { 43 assert(element_size > 0); 44 45 array_t *array = static_cast<array_t *>(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 53void 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 63void *array_ptr(const array_t *array) { 64 return array_at(array, 0); 65} 66 67void *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 73size_t array_length(const array_t *array) { 74 assert(array != NULL); 75 return array->length; 76} 77 78bool array_append_value(array_t *array, uint32_t value) { 79 return array_append_ptr(array, &value); 80} 81 82bool 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 96static 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 = static_cast<uint8_t *>(new_data); 108 array->capacity = new_capacity; 109 return true; 110} 111