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 <base/logging.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 CHECK(element_size > 0); 44 45 array_t* array = static_cast<array_t*>( 46 osi_calloc(sizeof(array_t) + element_size * INTERNAL_ELEMENTS)); 47 48 array->element_size = element_size; 49 array->capacity = INTERNAL_ELEMENTS; 50 array->data = array->internal_storage; 51 return array; 52 } 53 54 void array_free(array_t* array) { 55 if (!array) return; 56 57 if (array->data != array->internal_storage) free(array->data); 58 59 osi_free(array); 60 } 61 62 void* array_ptr(const array_t* array) { return array_at(array, 0); } 63 64 void* array_at(const array_t* array, size_t index) { 65 CHECK(array != NULL); 66 CHECK(index < array->length); 67 return array->data + (index * array->element_size); 68 } 69 70 size_t array_length(const array_t* array) { 71 CHECK(array != NULL); 72 return array->length; 73 } 74 75 bool array_append_value(array_t* array, uint32_t value) { 76 return array_append_ptr(array, &value); 77 } 78 79 bool array_append_ptr(array_t* array, void* data) { 80 CHECK(array != NULL); 81 CHECK(data != NULL); 82 83 if (array->length == array->capacity && !grow(array)) { 84 LOG_ERROR(LOG_TAG, 85 "%s unable to grow array past current capacity of %zu elements " 86 "of size %zu.", 87 __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, 101 new_capacity * array->element_size); 102 if (!new_data) return false; 103 104 if (is_moving) 105 memcpy(new_data, array->internal_storage, 106 array->length * array->element_size); 107 108 array->data = static_cast<uint8_t*>(new_data); 109 array->capacity = new_capacity; 110 return true; 111 } 112