diff options
Diffstat (limited to 'thirdparty/icu4c/common/uvector.cpp')
-rw-r--r-- | thirdparty/icu4c/common/uvector.cpp | 228 |
1 files changed, 133 insertions, 95 deletions
diff --git a/thirdparty/icu4c/common/uvector.cpp b/thirdparty/icu4c/common/uvector.cpp index 9c7e74c6d5..4da8b864e1 100644 --- a/thirdparty/icu4c/common/uvector.cpp +++ b/thirdparty/icu4c/common/uvector.cpp @@ -17,59 +17,34 @@ U_NAMESPACE_BEGIN -#define DEFAULT_CAPACITY 8 +constexpr int32_t DEFAULT_CAPACITY = 8; /* * Constants for hinting whether a key is an integer * or a pointer. If a hint bit is zero, then the associated * token is assumed to be an integer. This is needed for iSeries */ -#define HINT_KEY_POINTER (1) -#define HINT_KEY_INTEGER (0) +constexpr int8_t HINT_KEY_POINTER = 1; +constexpr int8_t HINT_KEY_INTEGER = 0; UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UVector) UVector::UVector(UErrorCode &status) : - count(0), - capacity(0), - elements(0), - deleter(0), - comparer(0) -{ - _init(DEFAULT_CAPACITY, status); + UVector(nullptr, nullptr, DEFAULT_CAPACITY, status) { } UVector::UVector(int32_t initialCapacity, UErrorCode &status) : - count(0), - capacity(0), - elements(0), - deleter(0), - comparer(0) -{ - _init(initialCapacity, status); + UVector(nullptr, nullptr, initialCapacity, status) { } UVector::UVector(UObjectDeleter *d, UElementsAreEqual *c, UErrorCode &status) : - count(0), - capacity(0), - elements(0), - deleter(d), - comparer(c) -{ - _init(DEFAULT_CAPACITY, status); + UVector(d, c, DEFAULT_CAPACITY, status) { } UVector::UVector(UObjectDeleter *d, UElementsAreEqual *c, int32_t initialCapacity, UErrorCode &status) : - count(0), - capacity(0), - elements(0), deleter(d), comparer(c) { - _init(initialCapacity, status); -} - -void UVector::_init(int32_t initialCapacity, UErrorCode &status) { if (U_FAILURE(status)) { return; } @@ -78,7 +53,7 @@ void UVector::_init(int32_t initialCapacity, UErrorCode &status) { initialCapacity = DEFAULT_CAPACITY; } elements = (UElement *)uprv_malloc(sizeof(UElement)*initialCapacity); - if (elements == 0) { + if (elements == nullptr) { status = U_MEMORY_ALLOCATION_ERROR; } else { capacity = initialCapacity; @@ -88,7 +63,7 @@ void UVector::_init(int32_t initialCapacity, UErrorCode &status) { UVector::~UVector() { removeAllElements(); uprv_free(elements); - elements = 0; + elements = nullptr; } /** @@ -100,7 +75,7 @@ void UVector::assign(const UVector& other, UElementAssigner *assign, UErrorCode setSize(other.count, ec); if (U_SUCCESS(ec)) { for (int32_t i=0; i<other.count; ++i) { - if (elements[i].pointer != 0 && deleter != 0) { + if (elements[i].pointer != nullptr && deleter != nullptr) { (*deleter)(elements[i].pointer); } (*assign)(&elements[i], &other.elements[i]); @@ -110,29 +85,47 @@ void UVector::assign(const UVector& other, UElementAssigner *assign, UErrorCode } // This only does something sensible if this object has a non-null comparer -UBool UVector::operator==(const UVector& other) { - int32_t i; - if (count != other.count) return FALSE; - if (comparer != NULL) { +bool UVector::operator==(const UVector& other) const { + U_ASSERT(comparer != nullptr); + if (count != other.count) return false; + if (comparer != nullptr) { // Compare using this object's comparer - for (i=0; i<count; ++i) { + for (int32_t i=0; i<count; ++i) { if (!(*comparer)(elements[i], other.elements[i])) { - return FALSE; + return false; } } } - return TRUE; + return true; +} + +// TODO: delete this function once all call sites have been migrated to the +// new addElement(). +void UVector::addElementX(void* obj, UErrorCode &status) { + if (ensureCapacityX(count + 1, status)) { + elements[count++].pointer = obj; + } } void UVector::addElement(void* obj, UErrorCode &status) { + U_ASSERT(deleter == nullptr); if (ensureCapacity(count + 1, status)) { elements[count++].pointer = obj; } } +void UVector::adoptElement(void* obj, UErrorCode &status) { + U_ASSERT(deleter != nullptr); + if (ensureCapacity(count + 1, status)) { + elements[count++].pointer = obj; + } else { + (*deleter)(obj); + } +} void UVector::addElement(int32_t elem, UErrorCode &status) { + U_ASSERT(deleter == nullptr); // Usage error. Mixing up ints and pointers. if (ensureCapacity(count + 1, status)) { - elements[count].pointer = NULL; // Pointers may be bigger than ints. + elements[count].pointer = nullptr; // Pointers may be bigger than ints. elements[count].integer = elem; count++; } @@ -140,49 +133,61 @@ void UVector::addElement(int32_t elem, UErrorCode &status) { void UVector::setElementAt(void* obj, int32_t index) { if (0 <= index && index < count) { - if (elements[index].pointer != 0 && deleter != 0) { + if (elements[index].pointer != nullptr && deleter != nullptr) { (*deleter)(elements[index].pointer); } elements[index].pointer = obj; + } else { + /* index out of range */ + if (deleter != nullptr) { + (*deleter)(obj); + } } - /* else index out of range */ } void UVector::setElementAt(int32_t elem, int32_t index) { + U_ASSERT(deleter == nullptr); // Usage error. Mixing up ints and pointers. if (0 <= index && index < count) { - if (elements[index].pointer != 0 && deleter != 0) { - // TODO: this should be an error. mixing up ints and pointers. - (*deleter)(elements[index].pointer); - } - elements[index].pointer = NULL; + elements[index].pointer = nullptr; elements[index].integer = elem; } /* else index out of range */ } void UVector::insertElementAt(void* obj, int32_t index, UErrorCode &status) { - // must have 0 <= index <= count - if (0 <= index && index <= count && ensureCapacity(count + 1, status)) { - for (int32_t i=count; i>index; --i) { - elements[i] = elements[i-1]; + if (ensureCapacity(count + 1, status)) { + if (0 <= index && index <= count) { + for (int32_t i=count; i>index; --i) { + elements[i] = elements[i-1]; + } + elements[index].pointer = obj; + ++count; + } else { + /* index out of range */ + status = U_ILLEGAL_ARGUMENT_ERROR; } - elements[index].pointer = obj; - ++count; } - /* else index out of range */ + if (U_FAILURE(status) && deleter != nullptr) { + (*deleter)(obj); + } } void UVector::insertElementAt(int32_t elem, int32_t index, UErrorCode &status) { + U_ASSERT(deleter == nullptr); // Usage error. Mixing up ints and pointers. // must have 0 <= index <= count - if (0 <= index && index <= count && ensureCapacity(count + 1, status)) { - for (int32_t i=count; i>index; --i) { - elements[i] = elements[i-1]; + if (ensureCapacity(count + 1, status)) { + if (0 <= index && index <= count) { + for (int32_t i=count; i>index; --i) { + elements[i] = elements[i-1]; + } + elements[index].pointer = nullptr; + elements[index].integer = elem; + ++count; + } else { + /* index out of range */ + status = U_ILLEGAL_ARGUMENT_ERROR; } - elements[index].pointer = NULL; - elements[index].integer = elem; - ++count; } - /* else index out of range */ } void* UVector::elementAt(int32_t index) const { @@ -237,7 +242,7 @@ UBool UVector::retainAll(const UVector& other) { void UVector::removeElementAt(int32_t index) { void* e = orphanElementAt(index); - if (e != 0 && deleter != 0) { + if (e != nullptr && deleter != nullptr) { (*deleter)(e); } } @@ -252,9 +257,9 @@ UBool UVector::removeElement(void* obj) { } void UVector::removeAllElements(void) { - if (deleter != 0) { + if (deleter != nullptr) { for (int32_t i=0; i<count; ++i) { - if (elements[i].pointer != 0) { + if (elements[i].pointer != nullptr) { (*deleter)(elements[i].pointer); } } @@ -268,7 +273,7 @@ UBool UVector::equals(const UVector &other) const { if (this->count != other.count) { return FALSE; } - if (comparer == 0) { + if (comparer == nullptr) { for (i=0; i<count; i++) { if (elements[i].pointer != other.elements[i].pointer) { return FALSE; @@ -300,17 +305,15 @@ int32_t UVector::indexOf(int32_t obj, int32_t startIndex) const { return indexOf(key, startIndex, HINT_KEY_INTEGER); } -// This only works if this object has a non-null comparer int32_t UVector::indexOf(UElement key, int32_t startIndex, int8_t hint) const { - int32_t i; - if (comparer != 0) { - for (i=startIndex; i<count; ++i) { + if (comparer != nullptr) { + for (int32_t i=startIndex; i<count; ++i) { if ((*comparer)(key, elements[i])) { return i; } } } else { - for (i=startIndex; i<count; ++i) { + for (int32_t i=startIndex; i<count; ++i) { /* Pointers are not always the same size as ints so to perform * a valid comparison we need to know whether we are being * provided an int or a pointer. */ @@ -328,8 +331,8 @@ int32_t UVector::indexOf(UElement key, int32_t startIndex, int8_t hint) const { return -1; } -UBool UVector::ensureCapacity(int32_t minimumCapacity, UErrorCode &status) { - if (minimumCapacity < 0) { +UBool UVector::ensureCapacityX(int32_t minimumCapacity, UErrorCode &status) { + if (minimumCapacity < 0) { status = U_ILLEGAL_ARGUMENT_ERROR; return FALSE; } @@ -348,7 +351,7 @@ UBool UVector::ensureCapacity(int32_t minimumCapacity, UErrorCode &status) { return FALSE; } UElement* newElems = (UElement *)uprv_realloc(elements, sizeof(UElement)*newCap); - if (newElems == NULL) { + if (newElems == nullptr) { // We keep the original contents on the memory failure on realloc or bad minimumCapacity. status = U_MEMORY_ALLOCATION_ERROR; return FALSE; @@ -359,30 +362,60 @@ UBool UVector::ensureCapacity(int32_t minimumCapacity, UErrorCode &status) { return TRUE; } + +UBool UVector::ensureCapacity(int32_t minimumCapacity, UErrorCode &status) { + if (U_FAILURE(status)) { + return false; + } + if (minimumCapacity < 0) { + status = U_ILLEGAL_ARGUMENT_ERROR; + return false; + } + if (capacity < minimumCapacity) { + if (capacity > (INT32_MAX - 1) / 2) { // integer overflow check + status = U_ILLEGAL_ARGUMENT_ERROR; + return false; + } + int32_t newCap = capacity * 2; + if (newCap < minimumCapacity) { + newCap = minimumCapacity; + } + if (newCap > (int32_t)(INT32_MAX / sizeof(UElement))) { // integer overflow check + // We keep the original memory contents on bad minimumCapacity. + status = U_ILLEGAL_ARGUMENT_ERROR; + return false; + } + UElement* newElems = (UElement *)uprv_realloc(elements, sizeof(UElement)*newCap); + if (newElems == nullptr) { + // We keep the original contents on the memory failure on realloc or bad minimumCapacity. + status = U_MEMORY_ALLOCATION_ERROR; + return false; + } + elements = newElems; + capacity = newCap; + } + return true; +} /** * Change the size of this vector as follows: If newSize is smaller, * then truncate the array, possibly deleting held elements for i >= * newSize. If newSize is larger, grow the array, filling in new - * slots with NULL. + * slots with nullptr. */ void UVector::setSize(int32_t newSize, UErrorCode &status) { - int32_t i; - if (newSize < 0) { + if (!ensureCapacity(newSize, status)) { return; } if (newSize > count) { - if (!ensureCapacity(newSize, status)) { - return; - } UElement empty; - empty.pointer = NULL; + empty.pointer = nullptr; empty.integer = 0; - for (i=count; i<newSize; ++i) { + for (int32_t i=count; i<newSize; ++i) { elements[i] = empty; } } else { /* Most efficient to count down */ - for (i=count-1; i>=newSize; --i) { + for (int32_t i=count-1; i>=newSize; --i) { removeElementAt(i); } } @@ -422,7 +455,7 @@ UElementsAreEqual *UVector::setComparer(UElementsAreEqual *d) { * then 0 is returned and the vector is unchanged. */ void* UVector::orphanElementAt(int32_t index) { - void* e = 0; + void* e = nullptr; if (0 <= index && index < count) { e = elements[index].pointer; for (int32_t i=index; i<count-1; ++i) { @@ -451,7 +484,8 @@ void UVector::sortedInsert(void* obj, UElementComparator *compare, UErrorCode& e * be sorted already. */ void UVector::sortedInsert(int32_t obj, UElementComparator *compare, UErrorCode& ec) { - UElement e; + U_ASSERT(deleter == nullptr); + UElement e {}; e.integer = obj; sortedInsert(e, compare, ec); } @@ -463,10 +497,16 @@ void UVector::sortedInsert(UElement e, UElementComparator *compare, UErrorCode& // tok && tok < b, where there is a 'virtual' elements[-1] always // less than tok and a 'virtual' elements[count] always greater // than tok. + if (!ensureCapacity(count + 1, ec)) { + if (deleter != nullptr) { + (*deleter)(e.pointer); + } + return; + } int32_t min = 0, max = count; while (min != max) { int32_t probe = (min + max) / 2; - int8_t c = (*compare)(elements[probe], e); + int32_t c = (*compare)(elements[probe], e); if (c > 0) { max = probe; } else { @@ -474,13 +514,11 @@ void UVector::sortedInsert(UElement e, UElementComparator *compare, UErrorCode& min = probe + 1; } } - if (ensureCapacity(count + 1, ec)) { - for (int32_t i=count; i>min; --i) { - elements[i] = elements[i-1]; - } - elements[min] = e; - ++count; + for (int32_t i=count; i>min; --i) { + elements[i] = elements[i-1]; } + elements[min] = e; + ++count; } /** @@ -526,7 +564,7 @@ sortiComparator(const void * /*context */, const void *left, const void *right) void UVector::sorti(UErrorCode &ec) { if (U_SUCCESS(ec)) { uprv_sortArray(elements, count, sizeof(UElement), - sortiComparator, NULL, FALSE, &ec); + sortiComparator, nullptr, FALSE, &ec); } } @@ -539,7 +577,7 @@ void UVector::sorti(UErrorCode &ec) { * required by uprv_sortArray(). This is handled by passing the * the UVector sort function pointer via the context pointer to a * sortArray() comparator function, which can then call back to - * the original user functtion. + * the original user function. * * An additional twist is that it's not safe to pass a pointer-to-function * as a (void *) data pointer, so instead we pass a (data) pointer to a |