1/*
2******************************************************************************
3* Copyright (C) 1999-2010, International Business Machines Corporation and   *
4* others. All Rights Reserved.                                               *
5******************************************************************************
6*/
7
8#include "uvectr64.h"
9#include "cmemory.h"
10#include "putilimp.h"
11
12U_NAMESPACE_BEGIN
13
14#define DEFAULT_CAPACITY 8
15
16/*
17 * Constants for hinting whether a key is an integer
18 * or a pointer.  If a hint bit is zero, then the associated
19 * token is assumed to be an integer. This is needed for iSeries
20 */
21
22UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UVector64)
23
24UVector64::UVector64(UErrorCode &status) :
25    count(0),
26    capacity(0),
27    maxCapacity(0),
28    elements(NULL)
29{
30    _init(DEFAULT_CAPACITY, status);
31}
32
33UVector64::UVector64(int32_t initialCapacity, UErrorCode &status) :
34    count(0),
35    capacity(0),
36    maxCapacity(0),
37    elements(0)
38{
39    _init(initialCapacity, status);
40}
41
42
43
44void UVector64::_init(int32_t initialCapacity, UErrorCode &status) {
45    // Fix bogus initialCapacity values; avoid malloc(0)
46    if (initialCapacity < 1) {
47        initialCapacity = DEFAULT_CAPACITY;
48    }
49    if (maxCapacity>0 && maxCapacity<initialCapacity) {
50        initialCapacity = maxCapacity;
51    }
52    if (initialCapacity > (int32_t)(INT32_MAX / sizeof(int64_t))) {
53        initialCapacity = uprv_min(DEFAULT_CAPACITY, maxCapacity);
54    }
55    elements = (int64_t *)uprv_malloc(sizeof(int64_t)*initialCapacity);
56    if (elements == 0) {
57        status = U_MEMORY_ALLOCATION_ERROR;
58    } else {
59        capacity = initialCapacity;
60    }
61}
62
63UVector64::~UVector64() {
64    uprv_free(elements);
65    elements = 0;
66}
67
68/**
69 * Assign this object to another (make this a copy of 'other').
70 */
71void UVector64::assign(const UVector64& other, UErrorCode &ec) {
72    if (ensureCapacity(other.count, ec)) {
73        setSize(other.count);
74        for (int32_t i=0; i<other.count; ++i) {
75            elements[i] = other.elements[i];
76        }
77    }
78}
79
80
81UBool UVector64::operator==(const UVector64& other) {
82    int32_t i;
83    if (count != other.count) return FALSE;
84    for (i=0; i<count; ++i) {
85        if (elements[i] != other.elements[i]) {
86            return FALSE;
87        }
88    }
89    return TRUE;
90}
91
92
93void UVector64::setElementAt(int64_t elem, int32_t index) {
94    if (0 <= index && index < count) {
95        elements[index] = elem;
96    }
97    /* else index out of range */
98}
99
100void UVector64::insertElementAt(int64_t elem, int32_t index, UErrorCode &status) {
101    // must have 0 <= index <= count
102    if (0 <= index && index <= count && ensureCapacity(count + 1, status)) {
103        for (int32_t i=count; i>index; --i) {
104            elements[i] = elements[i-1];
105        }
106        elements[index] = elem;
107        ++count;
108    }
109    /* else index out of range */
110}
111
112void UVector64::removeAllElements(void) {
113    count = 0;
114}
115
116UBool UVector64::expandCapacity(int32_t minimumCapacity, UErrorCode &status) {
117    if (minimumCapacity < 0) {
118        status = U_ILLEGAL_ARGUMENT_ERROR;
119        return FALSE;
120    }
121    if (capacity >= minimumCapacity) {
122        return TRUE;
123    }
124    if (maxCapacity>0 && minimumCapacity>maxCapacity) {
125        status = U_BUFFER_OVERFLOW_ERROR;
126        return FALSE;
127    }
128    if (capacity > (INT32_MAX - 1) / 2) {  // integer overflow check
129        status = U_ILLEGAL_ARGUMENT_ERROR;
130        return FALSE;
131    }
132    int32_t newCap = capacity * 2;
133    if (newCap < minimumCapacity) {
134        newCap = minimumCapacity;
135    }
136    if (maxCapacity > 0 && newCap > maxCapacity) {
137        newCap = maxCapacity;
138    }
139    if (newCap > (int32_t)(INT32_MAX / sizeof(int64_t))) {  // integer overflow check
140        // We keep the original memory contents on bad minimumCapacity/maxCapacity.
141        status = U_ILLEGAL_ARGUMENT_ERROR;
142        return FALSE;
143    }
144    int64_t* newElems = (int64_t *)uprv_realloc(elements, sizeof(int64_t)*newCap);
145    if (newElems == NULL) {
146        // We keep the original contents on the memory failure on realloc.
147        status = U_MEMORY_ALLOCATION_ERROR;
148        return FALSE;
149    }
150    elements = newElems;
151    capacity = newCap;
152    return TRUE;
153}
154
155void UVector64::setMaxCapacity(int32_t limit) {
156    U_ASSERT(limit >= 0);
157    if (limit < 0) {
158        limit = 0;
159    }
160    if (limit > (int32_t)(INT32_MAX / sizeof(int64_t))) {  // integer overflow check for realloc
161        //  Something is very wrong, don't realloc, leave capacity and maxCapacity unchanged
162        return;
163    }
164    maxCapacity = limit;
165    if (capacity <= maxCapacity || maxCapacity == 0) {
166        // Current capacity is within the new limit.
167        return;
168    }
169
170    // New maximum capacity is smaller than the current size.
171    // Realloc the storage to the new, smaller size.
172    int64_t* newElems = (int64_t *)uprv_realloc(elements, sizeof(int64_t)*maxCapacity);
173    if (newElems == NULL) {
174        // Realloc to smaller failed.
175        //   Just keep what we had.  No need to call it a failure.
176        return;
177    }
178    elements = newElems;
179    capacity = maxCapacity;
180    if (count > capacity) {
181        count = capacity;
182    }
183}
184
185/**
186 * Change the size of this vector as follows: If newSize is smaller,
187 * then truncate the array, possibly deleting held elements for i >=
188 * newSize.  If newSize is larger, grow the array, filling in new
189 * slots with NULL.
190 */
191void UVector64::setSize(int32_t newSize) {
192    int32_t i;
193    if (newSize < 0) {
194        return;
195    }
196    if (newSize > count) {
197        UErrorCode ec = U_ZERO_ERROR;
198        if (!ensureCapacity(newSize, ec)) {
199            return;
200        }
201        for (i=count; i<newSize; ++i) {
202            elements[i] = 0;
203        }
204    }
205    count = newSize;
206}
207
208U_NAMESPACE_END
209
210