michael@0: /* michael@0: ****************************************************************************** michael@0: * Copyright (C) 1999-2013, International Business Machines Corporation and michael@0: * others. All Rights Reserved. michael@0: ****************************************************************************** michael@0: * Date Name Description michael@0: * 10/22/99 alan Creation. michael@0: ********************************************************************** michael@0: */ michael@0: michael@0: #include "uvector.h" michael@0: #include "cmemory.h" michael@0: #include "uarrsort.h" michael@0: #include "uelement.h" michael@0: michael@0: U_NAMESPACE_BEGIN michael@0: michael@0: #define DEFAULT_CAPACITY 8 michael@0: michael@0: /* michael@0: * Constants for hinting whether a key is an integer michael@0: * or a pointer. If a hint bit is zero, then the associated michael@0: * token is assumed to be an integer. This is needed for iSeries michael@0: */ michael@0: #define HINT_KEY_POINTER (1) michael@0: #define HINT_KEY_INTEGER (0) michael@0: michael@0: UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UVector) michael@0: michael@0: UVector::UVector(UErrorCode &status) : michael@0: count(0), michael@0: capacity(0), michael@0: elements(0), michael@0: deleter(0), michael@0: comparer(0) michael@0: { michael@0: _init(DEFAULT_CAPACITY, status); michael@0: } michael@0: michael@0: UVector::UVector(int32_t initialCapacity, UErrorCode &status) : michael@0: count(0), michael@0: capacity(0), michael@0: elements(0), michael@0: deleter(0), michael@0: comparer(0) michael@0: { michael@0: _init(initialCapacity, status); michael@0: } michael@0: michael@0: UVector::UVector(UObjectDeleter *d, UElementsAreEqual *c, UErrorCode &status) : michael@0: count(0), michael@0: capacity(0), michael@0: elements(0), michael@0: deleter(d), michael@0: comparer(c) michael@0: { michael@0: _init(DEFAULT_CAPACITY, status); michael@0: } michael@0: michael@0: UVector::UVector(UObjectDeleter *d, UElementsAreEqual *c, int32_t initialCapacity, UErrorCode &status) : michael@0: count(0), michael@0: capacity(0), michael@0: elements(0), michael@0: deleter(d), michael@0: comparer(c) michael@0: { michael@0: _init(initialCapacity, status); michael@0: } michael@0: michael@0: void UVector::_init(int32_t initialCapacity, UErrorCode &status) { michael@0: if (U_FAILURE(status)) { michael@0: return; michael@0: } michael@0: // Fix bogus initialCapacity values; avoid malloc(0) and integer overflow michael@0: if ((initialCapacity < 1) || (initialCapacity > (int32_t)(INT32_MAX / sizeof(UElement)))) { michael@0: initialCapacity = DEFAULT_CAPACITY; michael@0: } michael@0: elements = (UElement *)uprv_malloc(sizeof(UElement)*initialCapacity); michael@0: if (elements == 0) { michael@0: status = U_MEMORY_ALLOCATION_ERROR; michael@0: } else { michael@0: capacity = initialCapacity; michael@0: } michael@0: } michael@0: michael@0: UVector::~UVector() { michael@0: removeAllElements(); michael@0: uprv_free(elements); michael@0: elements = 0; michael@0: } michael@0: michael@0: /** michael@0: * Assign this object to another (make this a copy of 'other'). michael@0: * Use the 'assign' function to assign each element. michael@0: */ michael@0: void UVector::assign(const UVector& other, UElementAssigner *assign, UErrorCode &ec) { michael@0: if (ensureCapacity(other.count, ec)) { michael@0: setSize(other.count, ec); michael@0: if (U_SUCCESS(ec)) { michael@0: for (int32_t i=0; iindex; --i) { michael@0: elements[i] = elements[i-1]; michael@0: } michael@0: elements[index].pointer = obj; michael@0: ++count; michael@0: } michael@0: /* else index out of range */ michael@0: } michael@0: michael@0: void UVector::insertElementAt(int32_t elem, int32_t index, UErrorCode &status) { michael@0: // must have 0 <= index <= count michael@0: if (0 <= index && index <= count && ensureCapacity(count + 1, status)) { michael@0: for (int32_t i=count; i>index; --i) { michael@0: elements[i] = elements[i-1]; michael@0: } michael@0: elements[index].pointer = NULL; michael@0: elements[index].integer = elem; michael@0: ++count; michael@0: } michael@0: /* else index out of range */ michael@0: } michael@0: michael@0: void* UVector::elementAt(int32_t index) const { michael@0: return (0 <= index && index < count) ? elements[index].pointer : 0; michael@0: } michael@0: michael@0: int32_t UVector::elementAti(int32_t index) const { michael@0: return (0 <= index && index < count) ? elements[index].integer : 0; michael@0: } michael@0: michael@0: UBool UVector::containsAll(const UVector& other) const { michael@0: for (int32_t i=0; i= 0) { michael@0: return FALSE; michael@0: } michael@0: } michael@0: return TRUE; michael@0: } michael@0: michael@0: UBool UVector::removeAll(const UVector& other) { michael@0: UBool changed = FALSE; michael@0: for (int32_t i=0; i= 0) { michael@0: removeElementAt(j); michael@0: changed = TRUE; michael@0: } michael@0: } michael@0: return changed; michael@0: } michael@0: michael@0: UBool UVector::retainAll(const UVector& other) { michael@0: UBool changed = FALSE; michael@0: for (int32_t j=size()-1; j>=0; --j) { michael@0: int32_t i = other.indexOf(elements[j]); michael@0: if (i < 0) { michael@0: removeElementAt(j); michael@0: changed = TRUE; michael@0: } michael@0: } michael@0: return changed; michael@0: } michael@0: michael@0: void UVector::removeElementAt(int32_t index) { michael@0: void* e = orphanElementAt(index); michael@0: if (e != 0 && deleter != 0) { michael@0: (*deleter)(e); michael@0: } michael@0: } michael@0: michael@0: UBool UVector::removeElement(void* obj) { michael@0: int32_t i = indexOf(obj); michael@0: if (i >= 0) { michael@0: removeElementAt(i); michael@0: return TRUE; michael@0: } michael@0: return FALSE; michael@0: } michael@0: michael@0: void UVector::removeAllElements(void) { michael@0: if (deleter != 0) { michael@0: for (int32_t i=0; icount != other.count) { michael@0: return FALSE; michael@0: } michael@0: if (comparer == 0) { michael@0: for (i=0; i (INT32_MAX - 1) / 2) { // integer overflow check michael@0: status = U_ILLEGAL_ARGUMENT_ERROR; michael@0: return FALSE; michael@0: } michael@0: int32_t newCap = capacity * 2; michael@0: if (newCap < minimumCapacity) { michael@0: newCap = minimumCapacity; michael@0: } michael@0: if (newCap > (int32_t)(INT32_MAX / sizeof(UElement))) { // integer overflow check michael@0: // We keep the original memory contents on bad minimumCapacity. michael@0: status = U_ILLEGAL_ARGUMENT_ERROR; michael@0: return FALSE; michael@0: } michael@0: UElement* newElems = (UElement *)uprv_realloc(elements, sizeof(UElement)*newCap); michael@0: if (newElems == NULL) { michael@0: // We keep the original contents on the memory failure on realloc or bad minimumCapacity. michael@0: status = U_MEMORY_ALLOCATION_ERROR; michael@0: return FALSE; michael@0: } michael@0: elements = newElems; michael@0: capacity = newCap; michael@0: } michael@0: return TRUE; michael@0: } michael@0: michael@0: /** michael@0: * Change the size of this vector as follows: If newSize is smaller, michael@0: * then truncate the array, possibly deleting held elements for i >= michael@0: * newSize. If newSize is larger, grow the array, filling in new michael@0: * slots with NULL. michael@0: */ michael@0: void UVector::setSize(int32_t newSize, UErrorCode &status) { michael@0: int32_t i; michael@0: if (newSize < 0) { michael@0: return; michael@0: } michael@0: if (newSize > count) { michael@0: if (!ensureCapacity(newSize, status)) { michael@0: return; michael@0: } michael@0: UElement empty; michael@0: empty.pointer = NULL; michael@0: empty.integer = 0; michael@0: for (i=count; i=newSize; --i) { michael@0: removeElementAt(i); michael@0: } michael@0: } michael@0: count = newSize; michael@0: } michael@0: michael@0: /** michael@0: * Fill in the given array with all elements of this vector. michael@0: */ michael@0: void** UVector::toArray(void** result) const { michael@0: void** a = result; michael@0: for (int i=0; i 0) { michael@0: max = probe; michael@0: } else { michael@0: // assert(c <= 0); michael@0: min = probe + 1; michael@0: } michael@0: } michael@0: if (ensureCapacity(count + 1, ec)) { michael@0: for (int32_t i=count; i>min; --i) { michael@0: elements[i] = elements[i-1]; michael@0: } michael@0: elements[min] = e; michael@0: ++count; michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Array sort comparator function. michael@0: * Used from UVector::sort() michael@0: * Conforms to function signature required for uprv_sortArray(). michael@0: * This function is essentially just a wrapper, to make a michael@0: * UVector style comparator function usable with uprv_sortArray(). michael@0: * michael@0: * The context pointer to this function is a pointer back michael@0: * (with some extra indirection) to the user supplied comparator. michael@0: * michael@0: */ michael@0: static int32_t U_CALLCONV michael@0: sortComparator(const void *context, const void *left, const void *right) { michael@0: UElementComparator *compare = *static_cast(context); michael@0: UElement e1 = *static_cast(left); michael@0: UElement e2 = *static_cast(right); michael@0: int32_t result = (*compare)(e1, e2); michael@0: return result; michael@0: } michael@0: michael@0: michael@0: /** michael@0: * Array sort comparison function for use from UVector::sorti() michael@0: * Compares int32_t vector elements. michael@0: */ michael@0: static int32_t U_CALLCONV michael@0: sortiComparator(const void * /*context */, const void *left, const void *right) { michael@0: const UElement *e1 = static_cast(left); michael@0: const UElement *e2 = static_cast(right); michael@0: int32_t result = e1->integer < e2->integer? -1 : michael@0: e1->integer == e2->integer? 0 : 1; michael@0: return result; michael@0: } michael@0: michael@0: /** michael@0: * Sort the vector, assuming it constains ints. michael@0: * (A more general sort would take a comparison function, but it's michael@0: * not clear whether UVector's UElementComparator or michael@0: * UComparator from uprv_sortAray would be more appropriate.) michael@0: */ michael@0: void UVector::sorti(UErrorCode &ec) { michael@0: if (U_SUCCESS(ec)) { michael@0: uprv_sortArray(elements, count, sizeof(UElement), michael@0: sortiComparator, NULL, FALSE, &ec); michael@0: } michael@0: } michael@0: michael@0: michael@0: /** michael@0: * Sort with a user supplied comparator. michael@0: * michael@0: * The comparator function handling is confusing because the function type michael@0: * for UVector (as defined for sortedInsert()) is different from the signature michael@0: * required by uprv_sortArray(). This is handled by passing the michael@0: * the UVector sort function pointer via the context pointer to a michael@0: * sortArray() comparator function, which can then call back to michael@0: * the original user functtion. michael@0: * michael@0: * An additional twist is that it's not safe to pass a pointer-to-function michael@0: * as a (void *) data pointer, so instead we pass a (data) pointer to a michael@0: * pointer-to-function variable. michael@0: */ michael@0: void UVector::sort(UElementComparator *compare, UErrorCode &ec) { michael@0: if (U_SUCCESS(ec)) { michael@0: uprv_sortArray(elements, count, sizeof(UElement), michael@0: sortComparator, &compare, FALSE, &ec); michael@0: } michael@0: } michael@0: michael@0: michael@0: /** michael@0: * Stable sort with a user supplied comparator of type UComparator. michael@0: */ michael@0: void UVector::sortWithUComparator(UComparator *compare, const void *context, UErrorCode &ec) { michael@0: if (U_SUCCESS(ec)) { michael@0: uprv_sortArray(elements, count, sizeof(UElement), michael@0: compare, context, TRUE, &ec); michael@0: } michael@0: } michael@0: michael@0: U_NAMESPACE_END michael@0: