/*
* 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;
}