]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/common/uvector.cpp
ICU-59173.0.1.tar.gz
[apple/icu.git] / icuSources / common / uvector.cpp
index 8da159924fcd79ba2ff860f4885e9690c14c7c64..cf19edf646fb0a2618cb5198c431dcb313d1e0aa 100644 (file)
@@ -1,7 +1,9 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
 /*
 ******************************************************************************
-* Copyright (C) 1999-2001, International Business Machines Corporation and   *
-* others. All Rights Reserved.                                               *
+* Copyright (C) 1999-2013, International Business Machines Corporation and
+* others. All Rights Reserved.
 ******************************************************************************
 *   Date        Name        Description
 *   10/22/99    alan        Creation.
 
 #include "uvector.h"
 #include "cmemory.h"
+#include "uarrsort.h"
+#include "uelement.h"
 
 U_NAMESPACE_BEGIN
 
-#define DEFUALT_CAPACITY 8
+#define DEFAULT_CAPACITY 8
 
 /*
  * Constants for hinting whether a key is an integer
@@ -23,7 +27,7 @@ U_NAMESPACE_BEGIN
 #define HINT_KEY_POINTER   (1)
 #define HINT_KEY_INTEGER   (0)
  
-const char UVector::fgClassID=0;
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UVector)
 
 UVector::UVector(UErrorCode &status) :
     count(0),
@@ -32,7 +36,7 @@ UVector::UVector(UErrorCode &status) :
     deleter(0),
     comparer(0)
 {
-    _init(DEFUALT_CAPACITY, status);
+    _init(DEFAULT_CAPACITY, status);
 }
 
 UVector::UVector(int32_t initialCapacity, UErrorCode &status) :
@@ -45,17 +49,17 @@ UVector::UVector(int32_t initialCapacity, UErrorCode &status) :
     _init(initialCapacity, status);
 }
 
-UVector::UVector(UObjectDeleter *d, UKeyComparator *c, UErrorCode &status) :
+UVector::UVector(UObjectDeleter *d, UElementsAreEqual *c, UErrorCode &status) :
     count(0),
     capacity(0),
     elements(0),
     deleter(d),
     comparer(c)
 {
-    _init(DEFUALT_CAPACITY, status);
+    _init(DEFAULT_CAPACITY, status);
 }
 
-UVector::UVector(UObjectDeleter *d, UKeyComparator *c, int32_t initialCapacity, UErrorCode &status) :
+UVector::UVector(UObjectDeleter *d, UElementsAreEqual *c, int32_t initialCapacity, UErrorCode &status) :
     count(0),
     capacity(0),
     elements(0),
@@ -66,11 +70,14 @@ UVector::UVector(UObjectDeleter *d, UKeyComparator *c, int32_t initialCapacity,
 }
 
 void UVector::_init(int32_t initialCapacity, UErrorCode &status) {
-    // Fix bogus initialCapacity values; avoid malloc(0)
-    if (initialCapacity < 1) {
-        initialCapacity = DEFUALT_CAPACITY;
+    if (U_FAILURE(status)) {
+        return;
+    }
+    // Fix bogus initialCapacity values; avoid malloc(0) and integer overflow
+    if ((initialCapacity < 1) || (initialCapacity > (int32_t)(INT32_MAX / sizeof(UElement)))) {
+        initialCapacity = DEFAULT_CAPACITY;
     }
-    elements = (UHashTok *)uprv_malloc(sizeof(UHashTok)*initialCapacity);
+    elements = (UElement *)uprv_malloc(sizeof(UElement)*initialCapacity);
     if (elements == 0) {
         status = U_MEMORY_ALLOCATION_ERROR;
     } else {
@@ -88,14 +95,16 @@ UVector::~UVector() {
  * Assign this object to another (make this a copy of 'other').
  * Use the 'assign' function to assign each element.
  */
-void UVector::assign(const UVector& other, UTokenAssigner *assign, UErrorCode &ec) {
+void UVector::assign(const UVector& other, UElementAssigner *assign, UErrorCode &ec) {
     if (ensureCapacity(other.count, ec)) {
-        setSize(other.count);
-        for (int32_t i=0; i<other.count; ++i) {
-            if (elements[i].pointer != 0 && deleter != 0) {
-                (*deleter)(elements[i].pointer);
+        setSize(other.count, ec);
+        if (U_SUCCESS(ec)) {
+            for (int32_t i=0; i<other.count; ++i) {
+                if (elements[i].pointer != 0 && deleter != 0) {
+                    (*deleter)(elements[i].pointer);
+                }
+                (*assign)(&elements[i], &other.elements[i]);
             }
-            (*assign)(&elements[i], &other.elements[i]);
         }
     }
 }
@@ -266,7 +275,7 @@ UBool   UVector::equals(const UVector &other) const {
             }
         }
     } else {
-        UHashTok key;
+        UElement key;
         for (i=0; i<count; i++) {
             key.pointer = &other.elements[i];
             if (!(*comparer)(key, elements[i])) {
@@ -280,19 +289,19 @@ UBool   UVector::equals(const UVector &other) const {
 
 
 int32_t UVector::indexOf(void* obj, int32_t startIndex) const {
-    UHashTok key;
+    UElement key;
     key.pointer = obj;
     return indexOf(key, startIndex, HINT_KEY_POINTER);
 }
 
 int32_t UVector::indexOf(int32_t obj, int32_t startIndex) const {
-    UHashTok key;
+    UElement key;
     key.integer = obj;
     return indexOf(key, startIndex, HINT_KEY_INTEGER);
 }
 
 // This only works if this object has a non-null comparer
-int32_t UVector::indexOf(UHashTok key, int32_t startIndex, int8_t hint) const {
+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) {
@@ -320,24 +329,34 @@ int32_t UVector::indexOf(UHashTok key, int32_t startIndex, int8_t hint) const {
 }
 
 UBool UVector::ensureCapacity(int32_t minimumCapacity, UErrorCode &status) {
-    if (capacity >= minimumCapacity) {
-        return TRUE;
-    } else {
+       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;
         }
-        UHashTok* newElems = (UHashTok *)uprv_malloc(sizeof(UHashTok)*newCap);
-        if (newElems == 0) {
+        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 == NULL) {
+            // We keep the original contents on the memory failure on realloc or bad minimumCapacity.
             status = U_MEMORY_ALLOCATION_ERROR;
             return FALSE;
         }
-        uprv_memcpy(newElems, elements, sizeof(elements[0]) * count);
-        uprv_free(elements);
         elements = newElems;
         capacity = newCap;
-        return TRUE;
     }
+    return TRUE;
 }
 
 /**
@@ -346,17 +365,16 @@ UBool UVector::ensureCapacity(int32_t minimumCapacity, UErrorCode &status) {
  * newSize.  If newSize is larger, grow the array, filling in new
  * slots with NULL.
  */
-void UVector::setSize(int32_t newSize) {
+void UVector::setSize(int32_t newSize, UErrorCode &status) {
     int32_t i;
     if (newSize < 0) {
         return;
     }
     if (newSize > count) {
-        UErrorCode ec = U_ZERO_ERROR;
-        if (!ensureCapacity(newSize, ec)) {
+        if (!ensureCapacity(newSize, status)) {
             return;
         }
-        UHashTok empty;
+        UElement empty;
         empty.pointer = NULL;
         empty.integer = 0;
         for (i=count; i<newSize; ++i) {
@@ -388,8 +406,8 @@ UObjectDeleter *UVector::setDeleter(UObjectDeleter *d) {
     return old;
 }
 
-UKeyComparator *UVector::setComparer(UKeyComparator *d) {
-    UKeyComparator *old = comparer;
+UElementsAreEqual *UVector::setComparer(UElementsAreEqual *d) {
+    UElementsAreEqual *old = comparer;
     comparer = d;
     return old;
 }
@@ -421,10 +439,10 @@ void* UVector::orphanElementAt(int32_t index) {
  * as defined by 'compare'.  The current elements are assumed to
  * be sorted already.
  */
-void UVector::sortedInsert(void* obj, USortComparator *compare, UErrorCode& ec) {
-    UHashTok tok;
-    tok.pointer = obj;
-    sortedInsert(tok, compare, ec);
+void UVector::sortedInsert(void* obj, UElementComparator *compare, UErrorCode& ec) {
+    UElement e;
+    e.pointer = obj;
+    sortedInsert(e, compare, ec);
 }
 
 /**
@@ -432,14 +450,14 @@ void UVector::sortedInsert(void* obj, USortComparator *compare, UErrorCode& ec)
  * as defined by 'compare'.  The current elements are assumed to
  * be sorted already.
  */
-void UVector::sortedInsert(int32_t obj, USortComparator *compare, UErrorCode& ec) {
-    UHashTok tok;
-    tok.integer = obj;
-    sortedInsert(tok, compare, ec);
+void UVector::sortedInsert(int32_t obj, UElementComparator *compare, UErrorCode& ec) {
+    UElement e;
+    e.integer = obj;
+    sortedInsert(e, compare, ec);
 }
 
 // ASSUME elements[] IS CURRENTLY SORTED
-void UVector::sortedInsert(UHashTok tok, USortComparator *compare, UErrorCode& ec) {
+void UVector::sortedInsert(UElement e, UElementComparator *compare, UErrorCode& ec) {
     // Perform a binary search for the location to insert tok at.  Tok
     // will be inserted between two elements a and b such that a <=
     // tok && tok < b, where there is a 'virtual' elements[-1] always
@@ -448,7 +466,7 @@ void UVector::sortedInsert(UHashTok tok, USortComparator *compare, UErrorCode& e
     int32_t min = 0, max = count;
     while (min != max) {
         int32_t probe = (min + max) / 2;
-        int8_t c = (*compare)(elements[probe], tok);
+        int8_t c = (*compare)(elements[probe], e);
         if (c > 0) {
             max = probe;
         } else {
@@ -460,56 +478,89 @@ void UVector::sortedInsert(UHashTok tok, USortComparator *compare, UErrorCode& e
         for (int32_t i=count; i>min; --i) {
             elements[i] = elements[i-1];
         }
-        elements[min] = tok;
+        elements[min] = e;
         ++count;
     }
 }
 
-const char UStack::fgClassID=0;
-
-UStack::UStack(UErrorCode &status) :
-    UVector(status)
-{
-}
-
-UStack::UStack(int32_t initialCapacity, UErrorCode &status) :
-    UVector(initialCapacity, status)
-{
+/**
+  *  Array sort comparator function.
+  *  Used from UVector::sort()
+  *  Conforms to function signature required for uprv_sortArray().
+  *  This function is essentially just a wrapper, to make a
+  *  UVector style comparator function usable with uprv_sortArray().
+  *
+  *  The context pointer to this function is a pointer back
+  *  (with some extra indirection) to the user supplied comparator.
+  *  
+  */
+static int32_t U_CALLCONV
+sortComparator(const void *context, const void *left, const void *right) {
+    UElementComparator *compare = *static_cast<UElementComparator * const *>(context);
+    UElement e1 = *static_cast<const UElement *>(left);
+    UElement e2 = *static_cast<const UElement *>(right);
+    int32_t result = (*compare)(e1, e2);
+    return result;
 }
 
-UStack::UStack(UObjectDeleter *d, UKeyComparator *c, UErrorCode &status) :
-    UVector(d, c, status)
-{
-}
 
-UStack::UStack(UObjectDeleter *d, UKeyComparator *c, int32_t initialCapacity, UErrorCode &status) :
-    UVector(d, c, initialCapacity, status)
-{
+/**
+  *  Array sort comparison function for use from UVector::sorti()
+  *  Compares int32_t vector elements.
+  */
+static int32_t U_CALLCONV
+sortiComparator(const void * /*context */, const void *left, const void *right) {
+    const UElement *e1 = static_cast<const UElement *>(left);
+    const UElement *e2 = static_cast<const UElement *>(right);
+    int32_t result = e1->integer < e2->integer? -1 :
+                     e1->integer == e2->integer? 0 : 1;
+    return result;
 }
 
-void* UStack::pop(void) {
-    int32_t n = size() - 1;
-    void* result = 0;
-    if (n >= 0) {
-        result = elementAt(n);
-        removeElementAt(n);
+/**
+  * Sort the vector, assuming it constains ints.
+  *     (A more general sort would take a comparison function, but it's
+  *     not clear whether UVector's UElementComparator or
+  *     UComparator from uprv_sortAray would be more appropriate.)
+  */
+void UVector::sorti(UErrorCode &ec) {
+    if (U_SUCCESS(ec)) {
+        uprv_sortArray(elements, count, sizeof(UElement),
+                       sortiComparator, NULL,  FALSE, &ec);
     }
-    return result;
 }
 
-int32_t UStack::popi(void) {
-    int32_t n = size() - 1;
-    int32_t result = 0;
-    if (n >= 0) {
-        result = elementAti(n);
-        removeElementAt(n);
+
+/**
+ *  Sort with a user supplied comparator.
+ *
+ *    The comparator function handling is confusing because the function type
+ *    for UVector  (as defined for sortedInsert()) is different from the signature
+ *    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.
+ *
+ *    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
+ *    pointer-to-function variable.
+ */
+void UVector::sort(UElementComparator *compare, UErrorCode &ec) {
+    if (U_SUCCESS(ec)) {
+        uprv_sortArray(elements, count, sizeof(UElement),
+                       sortComparator, &compare, FALSE, &ec);
     }
-    return result;
 }
 
-int32_t UStack::search(void* obj) const {
-    int32_t i = indexOf(obj);
-    return (i >= 0) ? size() - i : i;
+
+/**
+ *  Stable sort with a user supplied comparator of type UComparator.
+ */
+void UVector::sortWithUComparator(UComparator *compare, const void *context, UErrorCode &ec) {
+    if (U_SUCCESS(ec)) {
+        uprv_sortArray(elements, count, sizeof(UElement),
+                       compare, context, TRUE, &ec);
+    }
 }
 
 U_NAMESPACE_END