michael@0: /* michael@0: ****************************************************************************** michael@0: * Copyright (C) 1999-2010, International Business Machines Corporation and * michael@0: * others. All Rights Reserved. * michael@0: ****************************************************************************** michael@0: */ michael@0: michael@0: #include "uvectr64.h" michael@0: #include "cmemory.h" michael@0: #include "putilimp.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: michael@0: UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UVector64) michael@0: michael@0: UVector64::UVector64(UErrorCode &status) : michael@0: count(0), michael@0: capacity(0), michael@0: maxCapacity(0), michael@0: elements(NULL) michael@0: { michael@0: _init(DEFAULT_CAPACITY, status); michael@0: } michael@0: michael@0: UVector64::UVector64(int32_t initialCapacity, UErrorCode &status) : michael@0: count(0), michael@0: capacity(0), michael@0: maxCapacity(0), michael@0: elements(0) michael@0: { michael@0: _init(initialCapacity, status); michael@0: } michael@0: michael@0: michael@0: michael@0: void UVector64::_init(int32_t initialCapacity, UErrorCode &status) { michael@0: // Fix bogus initialCapacity values; avoid malloc(0) michael@0: if (initialCapacity < 1) { michael@0: initialCapacity = DEFAULT_CAPACITY; michael@0: } michael@0: if (maxCapacity>0 && maxCapacity (int32_t)(INT32_MAX / sizeof(int64_t))) { michael@0: initialCapacity = uprv_min(DEFAULT_CAPACITY, maxCapacity); michael@0: } michael@0: elements = (int64_t *)uprv_malloc(sizeof(int64_t)*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: UVector64::~UVector64() { 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: */ michael@0: void UVector64::assign(const UVector64& other, UErrorCode &ec) { michael@0: if (ensureCapacity(other.count, ec)) { michael@0: setSize(other.count); michael@0: for (int32_t i=0; iindex; --i) { michael@0: elements[i] = elements[i-1]; michael@0: } michael@0: elements[index] = elem; michael@0: ++count; michael@0: } michael@0: /* else index out of range */ michael@0: } michael@0: michael@0: void UVector64::removeAllElements(void) { michael@0: count = 0; michael@0: } michael@0: michael@0: UBool UVector64::expandCapacity(int32_t minimumCapacity, UErrorCode &status) { michael@0: if (minimumCapacity < 0) { michael@0: status = U_ILLEGAL_ARGUMENT_ERROR; michael@0: return FALSE; michael@0: } michael@0: if (capacity >= minimumCapacity) { michael@0: return TRUE; michael@0: } michael@0: if (maxCapacity>0 && minimumCapacity>maxCapacity) { michael@0: status = U_BUFFER_OVERFLOW_ERROR; michael@0: return FALSE; michael@0: } michael@0: if (capacity > (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 (maxCapacity > 0 && newCap > maxCapacity) { michael@0: newCap = maxCapacity; michael@0: } michael@0: if (newCap > (int32_t)(INT32_MAX / sizeof(int64_t))) { // integer overflow check michael@0: // We keep the original memory contents on bad minimumCapacity/maxCapacity. michael@0: status = U_ILLEGAL_ARGUMENT_ERROR; michael@0: return FALSE; michael@0: } michael@0: int64_t* newElems = (int64_t *)uprv_realloc(elements, sizeof(int64_t)*newCap); michael@0: if (newElems == NULL) { michael@0: // We keep the original contents on the memory failure on realloc. michael@0: status = U_MEMORY_ALLOCATION_ERROR; michael@0: return FALSE; michael@0: } michael@0: elements = newElems; michael@0: capacity = newCap; michael@0: return TRUE; michael@0: } michael@0: michael@0: void UVector64::setMaxCapacity(int32_t limit) { michael@0: U_ASSERT(limit >= 0); michael@0: if (limit < 0) { michael@0: limit = 0; michael@0: } michael@0: if (limit > (int32_t)(INT32_MAX / sizeof(int64_t))) { // integer overflow check for realloc michael@0: // Something is very wrong, don't realloc, leave capacity and maxCapacity unchanged michael@0: return; michael@0: } michael@0: maxCapacity = limit; michael@0: if (capacity <= maxCapacity || maxCapacity == 0) { michael@0: // Current capacity is within the new limit. michael@0: return; michael@0: } michael@0: michael@0: // New maximum capacity is smaller than the current size. michael@0: // Realloc the storage to the new, smaller size. michael@0: int64_t* newElems = (int64_t *)uprv_realloc(elements, sizeof(int64_t)*maxCapacity); michael@0: if (newElems == NULL) { michael@0: // Realloc to smaller failed. michael@0: // Just keep what we had. No need to call it a failure. michael@0: return; michael@0: } michael@0: elements = newElems; michael@0: capacity = maxCapacity; michael@0: if (count > capacity) { michael@0: count = capacity; michael@0: } 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 UVector64::setSize(int32_t newSize) { michael@0: int32_t i; michael@0: if (newSize < 0) { michael@0: return; michael@0: } michael@0: if (newSize > count) { michael@0: UErrorCode ec = U_ZERO_ERROR; michael@0: if (!ensureCapacity(newSize, ec)) { michael@0: return; michael@0: } michael@0: for (i=count; i