/*---------------------------------------------------------------------------* * ArrayListImpl.c * * * * Copyright 2007, 2008 Nuance Communciations, Inc. * * * * 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 "ArrayList.h" #include "ArrayListImpl.h" #include "pmemory.h" #define MTAG NULL #define INITIAL_CAPACITY 16 ESR_ReturnCode ArrayListCreateWithCapacity(ArrayList **self, size_t minCapacity) { ArrayListImpl* impl; if (self == NULL) return ESR_INVALID_ARGUMENT; impl = NEW(ArrayListImpl, MTAG); if (impl == NULL) return ESR_OUT_OF_MEMORY; impl->Interface.add = &ArrayList_Add; impl->Interface.insertAt = &ArrayList_InsertAt; impl->Interface.contains = &ArrayList_Contains; impl->Interface.destroy = &ArrayList_Destroy; impl->Interface.get = &ArrayList_Get; impl->Interface.getSize = &ArrayList_GetSize; impl->Interface.remove = &ArrayList_Remove; impl->Interface.removeAtIndex = &ArrayList_RemoveAtIndex; impl->Interface.removeAll = &ArrayList_RemoveAll; impl->Interface.set = &ArrayList_Set; impl->Interface.toStaticArray = NULL; /* Not implemented */ impl->Interface.clone = &ArrayList_Clone; impl->contents = MALLOC(minCapacity * sizeof(void*), MTAG); if (impl->contents == NULL) { FREE(impl); return ESR_OUT_OF_MEMORY; } impl->capacity = minCapacity; impl->minCapacity = minCapacity; impl->size = 0; *self = (ArrayList*) impl; return ESR_SUCCESS; } ESR_ReturnCode ArrayListCreate(ArrayList** self) { return ArrayListCreateWithCapacity(self, INITIAL_CAPACITY); } static ESR_ReturnCode ArrayList_Insert_Internal(ArrayListImpl *impl, size_t index, void *element) { size_t i; if (impl->size >= impl->capacity) { /* enlarge buffer */ size_t newCapacity = impl->capacity * 2; void** temp = REALLOC(impl->contents, newCapacity * sizeof(void*)); if (temp == NULL) return ESR_OUT_OF_MEMORY; impl->contents = temp; impl->capacity = newCapacity; } for (i = impl->size; i > index; --i) impl->contents[i] = impl->contents[i - 1]; ++impl->size; impl->contents[index] = element; return ESR_SUCCESS; } ESR_ReturnCode ArrayList_Add(ArrayList* self, void* element) { ArrayListImpl *impl = (ArrayListImpl *) self; return ArrayList_Insert_Internal(impl, impl->size, element); } ESR_ReturnCode ArrayList_InsertAt(ArrayList *self, size_t index, void *element) { ArrayListImpl *impl = (ArrayListImpl *) self; if (index > impl->size) return ESR_ARGUMENT_OUT_OF_BOUNDS; return ArrayList_Insert_Internal(impl, index, element); } static ESR_ReturnCode ArrayList_Remove_Internal(ArrayListImpl *impl, size_t i) { --impl->size; while (i < impl->size) { impl->contents[i] = impl->contents[i+1]; ++i; } if (impl->capacity > impl->minCapacity && impl->size <= impl->capacity / 4) { void** temp; size_t newCapacity = impl->capacity / 2; /* shrink buffer */ if ((temp = REALLOC(impl->contents, newCapacity * sizeof(void*))) == NULL) return ESR_OUT_OF_MEMORY; impl->contents = temp; impl->capacity = newCapacity; } return ESR_SUCCESS; } ESR_ReturnCode ArrayList_Remove(ArrayList* self, const void* element) { ArrayListImpl* impl = (ArrayListImpl*) self; size_t i; /* Remove element */ for (i = 0; i < impl->size; ++i) { if (impl->contents[i] == element) return ArrayList_Remove_Internal(impl, i); } return ESR_NO_MATCH_ERROR; } ESR_ReturnCode ArrayList_RemoveAtIndex(ArrayList* self, size_t index) { ArrayListImpl* impl = (ArrayListImpl*) self; if (index >= impl->size) return ESR_ARGUMENT_OUT_OF_BOUNDS; return ArrayList_Remove_Internal(impl, index); } ESR_ReturnCode ArrayList_RemoveAll(ArrayList* self) { ArrayListImpl* impl = (ArrayListImpl*) self; impl->size = 0; return ESR_SUCCESS; } ESR_ReturnCode ArrayList_Contains(ArrayList* self, const void* element, ESR_BOOL* exists) { ArrayListImpl* impl = (ArrayListImpl*) self; size_t i; for (i = 0; i < impl->size; ++i) { if (impl->contents[i] == element) { *exists = ESR_TRUE; return ESR_SUCCESS; } } *exists = ESR_FALSE; return ESR_SUCCESS; } ESR_ReturnCode ArrayList_Get(ArrayList* self, size_t index, void** element) { ArrayListImpl* impl = (ArrayListImpl*) self; if (index >= impl->size) return ESR_ARGUMENT_OUT_OF_BOUNDS; *element = impl->contents[index]; return ESR_SUCCESS; } ESR_ReturnCode ArrayList_Set(ArrayList* self, size_t index, void* element) { ArrayListImpl* impl = (ArrayListImpl*) self; if (index >= impl->size) return ESR_ARGUMENT_OUT_OF_BOUNDS; impl->contents[index] = element; return ESR_SUCCESS; } ESR_ReturnCode ArrayList_GetSize(ArrayList* self, size_t* size) { ArrayListImpl* impl = (ArrayListImpl*) self; *size = impl->size; return ESR_SUCCESS; } ESR_ReturnCode ArrayList_Clone(ArrayList* self, ArrayList* clone) { size_t size, i; void* element; ESR_ReturnCode rc; CHK(rc, clone->removeAll(clone)); CHK(rc, self->getSize(self, &size)); for (i = 0; i < size; ++i) { CHK(rc, self->get(self, i, &element)); CHK(rc, clone->add(clone, element)); } return ESR_SUCCESS; CLEANUP: return rc; } ESR_ReturnCode ArrayList_Destroy(ArrayList* self) { ArrayListImpl* impl = (ArrayListImpl*) self; FREE(impl->contents); FREE(self); return ESR_SUCCESS; }