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