|  | /* | 
|  | * Copyright (C) 2007 The Android Open Source Project | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | * you may not use this file except in compliance with the License. | 
|  | * You may obtain a copy of the License at | 
|  | * | 
|  | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | * See the License for the specific language governing permissions and | 
|  | * limitations under the License. | 
|  | */ | 
|  |  | 
|  | #include <cutils/array.h> | 
|  | #include <assert.h> | 
|  | #include <stdlib.h> | 
|  | #include <string.h> | 
|  | #include <limits.h> | 
|  |  | 
|  | #define INITIAL_CAPACITY (4) | 
|  | #define MAX_CAPACITY     ((int)(UINT_MAX/sizeof(void*))) | 
|  |  | 
|  | struct Array { | 
|  | void** contents; | 
|  | int size; | 
|  | int capacity; | 
|  | }; | 
|  |  | 
|  | Array* arrayCreate() { | 
|  | return calloc(1, sizeof(struct Array)); | 
|  | } | 
|  |  | 
|  | void arrayFree(Array* array) { | 
|  | assert(array != NULL); | 
|  |  | 
|  | // Free internal array. | 
|  | free(array->contents); | 
|  |  | 
|  | // Free the Array itself. | 
|  | free(array); | 
|  | } | 
|  |  | 
|  | /** Returns 0 if successful, < 0 otherwise.. */ | 
|  | static int ensureCapacity(Array* array, int capacity) { | 
|  | int oldCapacity = array->capacity; | 
|  | if (capacity > oldCapacity) { | 
|  | int newCapacity = (oldCapacity == 0) ? INITIAL_CAPACITY : oldCapacity; | 
|  |  | 
|  | // Ensure we're not doing something nasty | 
|  | if (capacity > MAX_CAPACITY) | 
|  | return -1; | 
|  |  | 
|  | // Keep doubling capacity until we surpass necessary capacity. | 
|  | while (newCapacity < capacity) { | 
|  | int  newCap = newCapacity*2; | 
|  | // Handle integer overflows | 
|  | if (newCap < newCapacity || newCap > MAX_CAPACITY) { | 
|  | newCap = MAX_CAPACITY; | 
|  | } | 
|  | newCapacity = newCap; | 
|  | } | 
|  |  | 
|  | // Should not happen, but better be safe than sorry | 
|  | if (newCapacity < 0 || newCapacity > MAX_CAPACITY) | 
|  | return -1; | 
|  |  | 
|  | void** newContents; | 
|  | if (array->contents == NULL) { | 
|  | // Allocate new array. | 
|  | newContents = malloc(newCapacity * sizeof(void*)); | 
|  | if (newContents == NULL) { | 
|  | return -1; | 
|  | } | 
|  | } else { | 
|  | // Expand existing array. | 
|  | newContents = realloc(array->contents, sizeof(void*) * newCapacity); | 
|  | if (newContents == NULL) { | 
|  | return -1; | 
|  | } | 
|  | } | 
|  |  | 
|  | array->capacity = newCapacity; | 
|  | array->contents = newContents; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int arrayAdd(Array* array, void* pointer) { | 
|  | assert(array != NULL); | 
|  | int size = array->size; | 
|  | int result = ensureCapacity(array, size + 1); | 
|  | if (result < 0) { | 
|  | return result; | 
|  | } | 
|  | array->contents[size] = pointer; | 
|  | array->size++; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static inline void checkBounds(Array* array, int index) { | 
|  | assert(array != NULL); | 
|  | assert(index < array->size); | 
|  | assert(index >= 0); | 
|  | } | 
|  |  | 
|  | void* arrayGet(Array* array, int index) { | 
|  | checkBounds(array, index); | 
|  | return array->contents[index]; | 
|  | } | 
|  |  | 
|  | void* arrayRemove(Array* array, int index) { | 
|  | checkBounds(array, index); | 
|  |  | 
|  | void* pointer = array->contents[index]; | 
|  |  | 
|  | int newSize = array->size - 1; | 
|  |  | 
|  | // Shift entries left. | 
|  | if (index != newSize) { | 
|  | memmove(array->contents + index, array->contents + index + 1, | 
|  | (sizeof(void*)) * (newSize - index)); | 
|  | } | 
|  |  | 
|  | array->size = newSize; | 
|  |  | 
|  | return pointer; | 
|  | } | 
|  |  | 
|  | void* arraySet(Array* array, int index, void* pointer) { | 
|  | checkBounds(array, index); | 
|  | void* old = array->contents[index]; | 
|  | array->contents[index] = pointer; | 
|  | return old; | 
|  | } | 
|  |  | 
|  | int arraySetSize(Array* array, int newSize) { | 
|  | assert(array != NULL); | 
|  | assert(newSize >= 0); | 
|  |  | 
|  | int oldSize = array->size; | 
|  |  | 
|  | if (newSize > oldSize) { | 
|  | // Expand. | 
|  | int result = ensureCapacity(array, newSize); | 
|  | if (result < 0) { | 
|  | return result; | 
|  | } | 
|  |  | 
|  | // Zero out new entries. | 
|  | memset(array->contents + sizeof(void*) * oldSize, 0, | 
|  | sizeof(void*) * (newSize - oldSize)); | 
|  | } | 
|  |  | 
|  | array->size = newSize; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int arraySize(Array* array) { | 
|  | assert(array != NULL); | 
|  | return array->size; | 
|  | } | 
|  |  | 
|  | const void** arrayUnwrap(Array* array) { | 
|  | return (const void**)array->contents; | 
|  | } |