Coverage Report

Created: 2026-06-13 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/icu/source/common/cmemory.h
Line
Count
Source
1
// © 2016 and later: Unicode, Inc. and others.
2
// License & terms of use: http://www.unicode.org/copyright.html
3
/*
4
******************************************************************************
5
*
6
*   Copyright (C) 1997-2016, International Business Machines
7
*   Corporation and others.  All Rights Reserved.
8
*
9
******************************************************************************
10
*
11
* File CMEMORY.H
12
*
13
*  Contains stdlib.h/string.h memory functions
14
*
15
* @author       Bertrand A. Damiba
16
*
17
* Modification History:
18
*
19
*   Date        Name        Description
20
*   6/20/98     Bertrand    Created.
21
*  05/03/99     stephen     Changed from functions to macros.
22
*
23
******************************************************************************
24
*/
25
26
#ifndef CMEMORY_H
27
#define CMEMORY_H
28
29
#include "unicode/utypes.h"
30
31
#include <stddef.h>
32
#include <string.h>
33
#include "unicode/localpointer.h"
34
#include "uassert.h"
35
36
#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
37
#include <stdio.h>
38
#endif
39
40
// uprv_memcpy and uprv_memmove
41
#if defined(__clang__)
42
52.0M
#define uprv_memcpy(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \
43
52.0M
    /* Suppress warnings about addresses that will never be NULL */ \
44
52.0M
    _Pragma("clang diagnostic push") \
45
52.0M
    _Pragma("clang diagnostic ignored \"-Waddress\"") \
46
52.0M
    U_ASSERT(dst != NULL); \
47
52.0M
    U_ASSERT(src != NULL); \
48
52.0M
    _Pragma("clang diagnostic pop") \
49
52.0M
    U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size); \
50
52.0M
} UPRV_BLOCK_MACRO_END
51
278k
#define uprv_memmove(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \
52
278k
    /* Suppress warnings about addresses that will never be NULL */ \
53
278k
    _Pragma("clang diagnostic push") \
54
278k
    _Pragma("clang diagnostic ignored \"-Waddress\"") \
55
278k
    U_ASSERT(dst != NULL); \
56
278k
    U_ASSERT(src != NULL); \
57
278k
    _Pragma("clang diagnostic pop") \
58
278k
    U_STANDARD_CPP_NAMESPACE memmove(dst, src, size); \
59
278k
} UPRV_BLOCK_MACRO_END
60
#elif defined(__GNUC__)
61
#define uprv_memcpy(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \
62
    /* Suppress warnings about addresses that will never be NULL */ \
63
    _Pragma("GCC diagnostic push") \
64
    _Pragma("GCC diagnostic ignored \"-Waddress\"") \
65
    U_ASSERT(dst != NULL); \
66
    U_ASSERT(src != NULL); \
67
    _Pragma("GCC diagnostic pop") \
68
    U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size); \
69
} UPRV_BLOCK_MACRO_END
70
#define uprv_memmove(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \
71
    /* Suppress warnings about addresses that will never be NULL */ \
72
    _Pragma("GCC diagnostic push") \
73
    _Pragma("GCC diagnostic ignored \"-Waddress\"") \
74
    U_ASSERT(dst != NULL); \
75
    U_ASSERT(src != NULL); \
76
    _Pragma("GCC diagnostic pop") \
77
    U_STANDARD_CPP_NAMESPACE memmove(dst, src, size); \
78
} UPRV_BLOCK_MACRO_END
79
#else
80
#define uprv_memcpy(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \
81
    U_ASSERT(dst != NULL); \
82
    U_ASSERT(src != NULL); \
83
    U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size); \
84
} UPRV_BLOCK_MACRO_END
85
#define uprv_memmove(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \
86
    U_ASSERT(dst != NULL); \
87
    U_ASSERT(src != NULL); \
88
    U_STANDARD_CPP_NAMESPACE memmove(dst, src, size); \
89
} UPRV_BLOCK_MACRO_END
90
#endif
91
92
/**
93
 * \def UPRV_LENGTHOF
94
 * Convenience macro to determine the length of a fixed array at compile-time.
95
 * @param array A fixed length array
96
 * @return The length of the array, in elements
97
 * @internal
98
 */
99
22.2M
#define UPRV_LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
100
7.02M
#define uprv_memset(buffer, mark, size) U_STANDARD_CPP_NAMESPACE memset(buffer, mark, size)
101
0
#define uprv_memcmp(buffer1, buffer2, size) U_STANDARD_CPP_NAMESPACE memcmp(buffer1, buffer2,size)
102
#define uprv_memchr(ptr, value, num) U_STANDARD_CPP_NAMESPACE memchr(ptr, value, num)
103
104
U_CAPI void * U_EXPORT2
105
uprv_malloc(size_t s) U_MALLOC_ATTR U_ALLOC_SIZE_ATTR(1);
106
107
U_CAPI void * U_EXPORT2
108
uprv_realloc(void *mem, size_t size) U_ALLOC_SIZE_ATTR(2);
109
110
U_CAPI void U_EXPORT2
111
uprv_free(void *mem);
112
113
U_CAPI void * U_EXPORT2
114
uprv_calloc(size_t num, size_t size) U_MALLOC_ATTR U_ALLOC_SIZE_ATTR2(1,2);
115
116
/**
117
 * Get the least significant bits of a pointer (a memory address).
118
 * For example, with a mask of 3, the macro gets the 2 least significant bits,
119
 * which will be 0 if the pointer is 32-bit (4-byte) aligned.
120
 *
121
 * uintptr_t is the most appropriate integer type to cast to.
122
 */
123
0
#define U_POINTER_MASK_LSB(ptr, mask) ((uintptr_t)(ptr) & (mask))
124
125
/**
126
 * Create & return an instance of "type" in statically allocated storage.
127
 * e.g.
128
 *    static std::mutex *myMutex = STATIC_NEW(std::mutex);
129
 * To destroy an object created in this way, invoke the destructor explicitly, e.g.
130
 *    myMutex->~mutex();
131
 * DO NOT use delete.
132
 * DO NOT use with class UMutex, which has specific support for static instances.
133
 *
134
 * STATIC_NEW is intended for use when
135
 *   - We want a static (or global) object.
136
 *   - We don't want it to ever be destructed, or to explicitly control destruction,
137
 *     to avoid use-after-destruction problems.
138
 *   - We want to avoid an ordinary heap allocated object,
139
 *     to avoid the possibility of memory allocation failures, and
140
 *     to avoid memory leak reports, from valgrind, for example.
141
 * This is defined as a macro rather than a template function because each invocation
142
 * must define distinct static storage for the object being returned.
143
 */
144
20
#define STATIC_NEW(type) [] () { \
145
20
    alignas(type) static char storage[sizeof(type)]; \
146
20
    return new(storage) type();} ()
umutex.cpp:icu_78::umtx_init()::$_0::operator()() const
Line
Count
Source
144
10
#define STATIC_NEW(type) [] () { \
145
10
    alignas(type) static char storage[sizeof(type)]; \
146
10
    return new(storage) type();} ()
umutex.cpp:icu_78::umtx_init()::$_1::operator()() const
Line
Count
Source
144
10
#define STATIC_NEW(type) [] () { \
145
10
    alignas(type) static char storage[sizeof(type)]; \
146
10
    return new(storage) type();} ()
147
148
/**
149
  *  Heap clean up function, called from u_cleanup()
150
  *    Clears any user heap functions from u_setMemoryFunctions()
151
  *    Does NOT deallocate any remaining allocated memory.
152
  */
153
U_CFUNC UBool 
154
cmemory_cleanup(void);
155
156
/**
157
 * A function called by <TT>uhash_remove</TT>,
158
 * <TT>uhash_close</TT>, or <TT>uhash_put</TT> to delete
159
 * an existing key or value.
160
 * @param obj A key or value stored in a hashtable
161
 * @see uprv_deleteUObject
162
 */
163
typedef void U_CALLCONV UObjectDeleter(void* obj);
164
165
/**
166
 * Deleter for UObject instances.
167
 * Works for all subclasses of UObject because it has a virtual destructor.
168
 */
169
U_CAPI void U_EXPORT2
170
uprv_deleteUObject(void *obj);
171
172
#ifdef __cplusplus
173
174
#include <utility>
175
#include "unicode/uobject.h"
176
177
U_NAMESPACE_BEGIN
178
179
/**
180
 * "Smart pointer" class, deletes memory via uprv_free().
181
 * For most methods see the LocalPointerBase base class.
182
 * Adds operator[] for array item access.
183
 *
184
 * @see LocalPointerBase
185
 */
186
template<typename T>
187
class LocalMemory : public LocalPointerBase<T> {
188
public:
189
    using LocalPointerBase<T>::operator*;
190
    using LocalPointerBase<T>::operator->;
191
    /**
192
     * Constructor takes ownership.
193
     * @param p simple pointer to an array of T items that is adopted
194
     */
195
0
    explicit LocalMemory(T *p=nullptr) : LocalPointerBase<T>(p) {}
Unexecuted instantiation: icu_78::LocalMemory<UKeywordsContext>::LocalMemory(UKeywordsContext*)
Unexecuted instantiation: icu_78::LocalMemory<UEnumeration>::LocalMemory(UEnumeration*)
Unexecuted instantiation: icu_78::LocalMemory<char const*>::LocalMemory(char const**)
Unexecuted instantiation: icu_78::LocalMemory<int>::LocalMemory(int*)
196
    /**
197
     * Move constructor, leaves src with isNull().
198
     * @param src source smart pointer
199
     */
200
    LocalMemory(LocalMemory<T> &&src) noexcept : LocalPointerBase<T>(src.ptr) {
201
        src.ptr=nullptr;
202
    }
203
    /**
204
     * Destructor deletes the memory it owns.
205
     */
206
0
    ~LocalMemory() {
207
0
        uprv_free(LocalPointerBase<T>::ptr);
208
0
    }
Unexecuted instantiation: icu_78::LocalMemory<UKeywordsContext>::~LocalMemory()
Unexecuted instantiation: icu_78::LocalMemory<UEnumeration>::~LocalMemory()
Unexecuted instantiation: icu_78::LocalMemory<int>::~LocalMemory()
Unexecuted instantiation: icu_78::LocalMemory<char const*>::~LocalMemory()
209
    /**
210
     * Move assignment operator, leaves src with isNull().
211
     * The behavior is undefined if *this and src are the same object.
212
     * @param src source smart pointer
213
     * @return *this
214
     */
215
    LocalMemory<T> &operator=(LocalMemory<T> &&src) noexcept {
216
        uprv_free(LocalPointerBase<T>::ptr);
217
        LocalPointerBase<T>::ptr=src.ptr;
218
        src.ptr=nullptr;
219
        return *this;
220
    }
221
    /**
222
     * Swap pointers.
223
     * @param other other smart pointer
224
     */
225
    void swap(LocalMemory<T> &other) noexcept {
226
        T *temp=LocalPointerBase<T>::ptr;
227
        LocalPointerBase<T>::ptr=other.ptr;
228
        other.ptr=temp;
229
    }
230
    /**
231
     * Non-member LocalMemory swap function.
232
     * @param p1 will get p2's pointer
233
     * @param p2 will get p1's pointer
234
     */
235
    friend inline void swap(LocalMemory<T> &p1, LocalMemory<T> &p2) noexcept {
236
        p1.swap(p2);
237
    }
238
    /**
239
     * Deletes the array it owns,
240
     * and adopts (takes ownership of) the one passed in.
241
     * @param p simple pointer to an array of T items that is adopted
242
     */
243
0
    void adoptInstead(T *p) {
244
0
        uprv_free(LocalPointerBase<T>::ptr);
245
0
        LocalPointerBase<T>::ptr=p;
246
0
    }
Unexecuted instantiation: icu_78::LocalMemory<UKeywordsContext>::adoptInstead(UKeywordsContext*)
Unexecuted instantiation: icu_78::LocalMemory<UEnumeration>::adoptInstead(UEnumeration*)
247
    /**
248
     * Deletes the array it owns, allocates a new one and reset its bytes to 0.
249
     * Returns the new array pointer.
250
     * If the allocation fails, then the current array is unchanged and
251
     * this method returns nullptr.
252
     * @param newCapacity must be >0
253
     * @return the allocated array pointer, or nullptr if the allocation failed
254
     */
255
    inline T *allocateInsteadAndReset(int32_t newCapacity=1);
256
    /**
257
     * Deletes the array it owns and allocates a new one, copying length T items.
258
     * Returns the new array pointer.
259
     * If the allocation fails, then the current array is unchanged and
260
     * this method returns nullptr.
261
     * @param newCapacity must be >0
262
     * @param length number of T items to be copied from the old array to the new one;
263
     *               must be no more than the capacity of the old array,
264
     *               which the caller must track because the LocalMemory does not track it
265
     * @return the allocated array pointer, or nullptr if the allocation failed
266
     */
267
    inline T *allocateInsteadAndCopy(int32_t newCapacity=1, int32_t length=0);
268
    /**
269
     * Array item access (writable).
270
     * No index bounds check.
271
     * @param i array index
272
     * @return reference to the array item
273
     */
274
0
    T &operator[](ptrdiff_t i) const { return LocalPointerBase<T>::ptr[i]; }
Unexecuted instantiation: icu_78::LocalMemory<char const*>::operator[](long) const
Unexecuted instantiation: icu_78::LocalMemory<int>::operator[](long) const
275
};
276
277
template<typename T>
278
inline T *LocalMemory<T>::allocateInsteadAndReset(int32_t newCapacity) {
279
    if(newCapacity>0) {
280
        T *p=(T *)uprv_malloc(newCapacity*sizeof(T));
281
        if(p!=nullptr) {
282
            uprv_memset(p, 0, newCapacity*sizeof(T));
283
            uprv_free(LocalPointerBase<T>::ptr);
284
            LocalPointerBase<T>::ptr=p;
285
        }
286
        return p;
287
    } else {
288
        return nullptr;
289
    }
290
}
291
292
293
template<typename T>
294
0
inline T *LocalMemory<T>::allocateInsteadAndCopy(int32_t newCapacity, int32_t length) {
295
0
    if(newCapacity>0) {
296
0
        T *p=(T *)uprv_malloc(newCapacity*sizeof(T));
297
0
        if(p!=nullptr) {
298
0
            if(length>0) {
299
0
                if(length>newCapacity) {
300
0
                    length=newCapacity;
301
0
                }
302
0
                uprv_memcpy(p, LocalPointerBase<T>::ptr, (size_t)length*sizeof(T));
303
0
            }
304
0
            uprv_free(LocalPointerBase<T>::ptr);
305
0
            LocalPointerBase<T>::ptr=p;
306
0
        }
307
0
        return p;
308
0
    } else {
309
0
        return nullptr;
310
0
    }
311
0
}
Unexecuted instantiation: icu_78::LocalMemory<char const*>::allocateInsteadAndCopy(int, int)
Unexecuted instantiation: icu_78::LocalMemory<int>::allocateInsteadAndCopy(int, int)
312
313
/**
314
 * Simple array/buffer management class using uprv_malloc() and uprv_free().
315
 * Provides an internal array with fixed capacity. Can alias another array
316
 * or allocate one.
317
 *
318
 * The array address is properly aligned for type T. It might not be properly
319
 * aligned for types larger than T (or larger than the largest subtype of T).
320
 *
321
 * Unlike LocalMemory and LocalArray, this class never adopts
322
 * (takes ownership of) another array.
323
 *
324
 * WARNING: MaybeStackArray only works with primitive (plain-old data) types.
325
 * It does NOT know how to call a destructor! If you work with classes with
326
 * destructors, consider:
327
 *
328
 * - LocalArray in localpointer.h if you know the length ahead of time
329
 * - MaybeStackVector if you know the length at runtime
330
 */
331
template<typename T, int32_t stackCapacity>
332
class MaybeStackArray {
333
public:
334
    // No heap allocation. Use only on the stack.
335
    static void* U_EXPORT2 operator new(size_t) noexcept = delete;
336
    static void* U_EXPORT2 operator new[](size_t) noexcept = delete;
337
    static void* U_EXPORT2 operator new(size_t, void*) noexcept = delete;
338
339
    /**
340
     * Default constructor initializes with internal T[stackCapacity] buffer.
341
     */
342
262k
    MaybeStackArray() : ptr(stackArray), capacity(stackCapacity), needToRelease(false) {}
icu_78::MaybeStackArray<char, 40>::MaybeStackArray()
Line
Count
Source
342
787
    MaybeStackArray() : ptr(stackArray), capacity(stackCapacity), needToRelease(false) {}
icu_78::MaybeStackArray<max_align_t, 7>::MaybeStackArray()
Line
Count
Source
342
261k
    MaybeStackArray() : ptr(stackArray), capacity(stackCapacity), needToRelease(false) {}
Unexecuted instantiation: icu_78::MaybeStackArray<max_align_t, 14>::MaybeStackArray()
Unexecuted instantiation: icu_78::MaybeStackArray<icu_78::FixedString*, 8>::MaybeStackArray()
Unexecuted instantiation: icu_78::MaybeStackArray<LocExtKeyData*, 8>::MaybeStackArray()
Unexecuted instantiation: icu_78::MaybeStackArray<LocExtType*, 8>::MaybeStackArray()
Unexecuted instantiation: icu_78::MaybeStackArray<TypeAlias*, 8>::MaybeStackArray()
Unexecuted instantiation: uloc_tag.cpp:icu_78::MaybeStackArray<(anonymous namespace)::AttributeListEntry*, 8>::MaybeStackArray()
Unexecuted instantiation: uloc_tag.cpp:icu_78::MaybeStackArray<(anonymous namespace)::ExtensionListEntry*, 8>::MaybeStackArray()
Unexecuted instantiation: icu_78::MaybeStackArray<icu_78::CharString*, 8>::MaybeStackArray()
Unexecuted instantiation: icu_78::MaybeStackArray<icu_78::UnicodeString*, 8>::MaybeStackArray()
343
    /**
344
     * Automatically allocates the heap array if the argument is larger than the stack capacity.
345
     * Intended for use when an approximate capacity is known at compile time but the true
346
     * capacity is not known until runtime.
347
     */
348
    MaybeStackArray(int32_t newCapacity, UErrorCode status) : MaybeStackArray() {
349
        if (U_FAILURE(status)) {
350
            return;
351
        }
352
        if (capacity < newCapacity) {
353
            if (resize(newCapacity) == nullptr) {
354
                status = U_MEMORY_ALLOCATION_ERROR;
355
            }
356
        }
357
    }
358
    /**
359
     * Destructor deletes the array (if owned).
360
     */
361
262k
    ~MaybeStackArray() { releaseArray(); }
icu_78::MaybeStackArray<char, 40>::~MaybeStackArray()
Line
Count
Source
361
787
    ~MaybeStackArray() { releaseArray(); }
icu_78::MaybeStackArray<max_align_t, 7>::~MaybeStackArray()
Line
Count
Source
361
261k
    ~MaybeStackArray() { releaseArray(); }
Unexecuted instantiation: icu_78::MaybeStackArray<max_align_t, 14>::~MaybeStackArray()
Unexecuted instantiation: icu_78::MaybeStackArray<LocExtKeyData*, 8>::~MaybeStackArray()
Unexecuted instantiation: icu_78::MaybeStackArray<LocExtType*, 8>::~MaybeStackArray()
Unexecuted instantiation: icu_78::MaybeStackArray<TypeAlias*, 8>::~MaybeStackArray()
Unexecuted instantiation: icu_78::MaybeStackArray<icu_78::FixedString*, 8>::~MaybeStackArray()
Unexecuted instantiation: icu_78::MaybeStackArray<icu_78::CharString*, 8>::~MaybeStackArray()
Unexecuted instantiation: uloc_tag.cpp:icu_78::MaybeStackArray<(anonymous namespace)::ExtensionListEntry*, 8>::~MaybeStackArray()
Unexecuted instantiation: uloc_tag.cpp:icu_78::MaybeStackArray<(anonymous namespace)::AttributeListEntry*, 8>::~MaybeStackArray()
Unexecuted instantiation: icu_78::MaybeStackArray<icu_78::UnicodeString*, 8>::~MaybeStackArray()
362
    /**
363
     * Move constructor: transfers ownership or copies the stack array.
364
     */
365
    MaybeStackArray(MaybeStackArray<T, stackCapacity> &&src) noexcept;
366
    /**
367
     * Move assignment: transfers ownership or copies the stack array.
368
     */
369
    MaybeStackArray<T, stackCapacity> &operator=(MaybeStackArray<T, stackCapacity> &&src) noexcept;
370
    /**
371
     * Returns the array capacity (number of T items).
372
     * @return array capacity
373
     */
374
263k
    int32_t getCapacity() const { return capacity; }
icu_78::MaybeStackArray<char, 40>::getCapacity() const
Line
Count
Source
374
2.16k
    int32_t getCapacity() const { return capacity; }
icu_78::MaybeStackArray<max_align_t, 7>::getCapacity() const
Line
Count
Source
374
261k
    int32_t getCapacity() const { return capacity; }
Unexecuted instantiation: icu_78::MaybeStackArray<max_align_t, 14>::getCapacity() const
Unexecuted instantiation: icu_78::MaybeStackArray<icu_78::FixedString*, 8>::getCapacity() const
Unexecuted instantiation: icu_78::MaybeStackArray<LocExtType*, 8>::getCapacity() const
Unexecuted instantiation: icu_78::MaybeStackArray<TypeAlias*, 8>::getCapacity() const
Unexecuted instantiation: icu_78::MaybeStackArray<LocExtKeyData*, 8>::getCapacity() const
Unexecuted instantiation: uloc_tag.cpp:icu_78::MaybeStackArray<(anonymous namespace)::AttributeListEntry*, 8>::getCapacity() const
Unexecuted instantiation: icu_78::MaybeStackArray<icu_78::CharString*, 8>::getCapacity() const
Unexecuted instantiation: uloc_tag.cpp:icu_78::MaybeStackArray<(anonymous namespace)::ExtensionListEntry*, 8>::getCapacity() const
Unexecuted instantiation: icu_78::MaybeStackArray<icu_78::UnicodeString*, 8>::getCapacity() const
375
    /**
376
     * Access without ownership change.
377
     * @return the array pointer
378
     */
379
268k
    T *getAlias() const { return ptr; }
icu_78::MaybeStackArray<char, 40>::getAlias() const
Line
Count
Source
379
6.77k
    T *getAlias() const { return ptr; }
icu_78::MaybeStackArray<max_align_t, 7>::getAlias() const
Line
Count
Source
379
261k
    T *getAlias() const { return ptr; }
Unexecuted instantiation: icu_78::MaybeStackArray<max_align_t, 14>::getAlias() const
380
    /**
381
     * Returns the array limit. Simple convenience method.
382
     * @return getAlias()+getCapacity()
383
     */
384
    T *getArrayLimit() const { return getAlias()+capacity; }
385
    // No "operator T *() const" because that can make
386
    // expressions like mbs[index] ambiguous for some compilers.
387
    /**
388
     * Array item access (const).
389
     * No index bounds check.
390
     * @param i array index
391
     * @return reference to the array item
392
     */
393
0
    const T &operator[](ptrdiff_t i) const { return ptr[i]; }
394
    /**
395
     * Array item access (writable).
396
     * No index bounds check.
397
     * @param i array index
398
     * @return reference to the array item
399
     */
400
3.33k
    T &operator[](ptrdiff_t i) { return ptr[i]; }
icu_78::MaybeStackArray<char, 40>::operator[](long)
Line
Count
Source
400
3.33k
    T &operator[](ptrdiff_t i) { return ptr[i]; }
Unexecuted instantiation: icu_78::MaybeStackArray<LocExtKeyData*, 8>::operator[](long)
Unexecuted instantiation: icu_78::MaybeStackArray<LocExtType*, 8>::operator[](long)
Unexecuted instantiation: icu_78::MaybeStackArray<TypeAlias*, 8>::operator[](long)
Unexecuted instantiation: icu_78::MaybeStackArray<icu_78::FixedString*, 8>::operator[](long)
Unexecuted instantiation: uloc_tag.cpp:icu_78::MaybeStackArray<(anonymous namespace)::AttributeListEntry*, 8>::operator[](long)
Unexecuted instantiation: icu_78::MaybeStackArray<icu_78::CharString*, 8>::operator[](long)
Unexecuted instantiation: uloc_tag.cpp:icu_78::MaybeStackArray<(anonymous namespace)::ExtensionListEntry*, 8>::operator[](long)
Unexecuted instantiation: icu_78::MaybeStackArray<icu_78::UnicodeString*, 8>::operator[](long)
401
    /**
402
     * Deletes the array (if owned) and aliases another one, no transfer of ownership.
403
     * If the arguments are illegal, then the current array is unchanged.
404
     * @param otherArray must not be nullptr
405
     * @param otherCapacity must be >0
406
     */
407
    void aliasInstead(T *otherArray, int32_t otherCapacity) {
408
        if(otherArray!=nullptr && otherCapacity>0) {
409
            releaseArray();
410
            ptr=otherArray;
411
            capacity=otherCapacity;
412
            needToRelease=false;
413
        }
414
    }
415
    /**
416
     * Deletes the array (if owned) and allocates a new one, copying length T items.
417
     * Returns the new array pointer.
418
     * If the allocation fails, then the current array is unchanged and
419
     * this method returns nullptr.
420
     * @param newCapacity can be less than or greater than the current capacity;
421
     *                    must be >0
422
     * @param length number of T items to be copied from the old array to the new one
423
     * @return the allocated array pointer, or nullptr if the allocation failed
424
     */
425
    inline T *resize(int32_t newCapacity, int32_t length=0);
426
    /**
427
     * Gives up ownership of the array if owned, or else clones it,
428
     * copying length T items; resets itself to the internal stack array.
429
     * Returns nullptr if the allocation failed.
430
     * @param length number of T items to copy when cloning,
431
     *        and capacity of the clone when cloning
432
     * @param resultCapacity will be set to the returned array's capacity (output-only)
433
     * @return the array pointer;
434
     *         caller becomes responsible for deleting the array
435
     */
436
    inline T *orphanOrClone(int32_t length, int32_t &resultCapacity);
437
438
protected:
439
    // Resizes the array to the size of src, then copies the contents of src.
440
    void copyFrom(const MaybeStackArray &src, UErrorCode &status) {
441
        if (U_FAILURE(status)) {
442
            return;
443
        }
444
        if (this->resize(src.capacity, 0) == nullptr) {
445
            status = U_MEMORY_ALLOCATION_ERROR;
446
            return;
447
        }
448
        uprv_memcpy(this->ptr, src.ptr, (size_t)capacity * sizeof(T));
449
    }
450
451
private:
452
    T *ptr;
453
    int32_t capacity;
454
    UBool needToRelease;
455
    T stackArray[stackCapacity];
456
262k
    void releaseArray() {
457
262k
        if(needToRelease) {
458
4
            uprv_free(ptr);
459
4
        }
460
262k
    }
icu_78::MaybeStackArray<char, 40>::releaseArray()
Line
Count
Source
456
791
    void releaseArray() {
457
791
        if(needToRelease) {
458
4
            uprv_free(ptr);
459
4
        }
460
791
    }
icu_78::MaybeStackArray<max_align_t, 7>::releaseArray()
Line
Count
Source
456
261k
    void releaseArray() {
457
261k
        if(needToRelease) {
458
0
            uprv_free(ptr);
459
0
        }
460
261k
    }
Unexecuted instantiation: icu_78::MaybeStackArray<max_align_t, 14>::releaseArray()
Unexecuted instantiation: icu_78::MaybeStackArray<LocExtKeyData*, 8>::releaseArray()
Unexecuted instantiation: icu_78::MaybeStackArray<LocExtType*, 8>::releaseArray()
Unexecuted instantiation: icu_78::MaybeStackArray<TypeAlias*, 8>::releaseArray()
Unexecuted instantiation: icu_78::MaybeStackArray<icu_78::FixedString*, 8>::releaseArray()
Unexecuted instantiation: uloc_tag.cpp:icu_78::MaybeStackArray<(anonymous namespace)::AttributeListEntry*, 8>::releaseArray()
Unexecuted instantiation: icu_78::MaybeStackArray<icu_78::CharString*, 8>::releaseArray()
Unexecuted instantiation: uloc_tag.cpp:icu_78::MaybeStackArray<(anonymous namespace)::ExtensionListEntry*, 8>::releaseArray()
Unexecuted instantiation: icu_78::MaybeStackArray<icu_78::UnicodeString*, 8>::releaseArray()
461
0
    void resetToStackArray() {
462
0
        ptr=stackArray;
463
0
        capacity=stackCapacity;
464
0
        needToRelease=false;
465
0
    }
466
    /* No comparison operators with other MaybeStackArray's. */
467
    bool operator==(const MaybeStackArray & /*other*/) = delete;
468
    bool operator!=(const MaybeStackArray & /*other*/) = delete;
469
    /* No ownership transfer: No copy constructor, no assignment operator. */
470
    MaybeStackArray(const MaybeStackArray & /*other*/) = delete;
471
    void operator=(const MaybeStackArray & /*other*/) = delete;
472
};
473
474
template<typename T, int32_t stackCapacity>
475
icu::MaybeStackArray<T, stackCapacity>::MaybeStackArray(
476
        MaybeStackArray <T, stackCapacity>&& src) noexcept
477
0
        : ptr(src.ptr), capacity(src.capacity), needToRelease(src.needToRelease) {
478
0
    if (src.ptr == src.stackArray) {
479
0
        ptr = stackArray;
480
0
        uprv_memcpy(stackArray, src.stackArray, sizeof(T) * src.capacity);
481
0
    } else {
482
0
        src.resetToStackArray();  // take ownership away from src
483
0
    }
484
0
}
485
486
template<typename T, int32_t stackCapacity>
487
inline MaybeStackArray <T, stackCapacity>&
488
0
MaybeStackArray<T, stackCapacity>::operator=(MaybeStackArray <T, stackCapacity>&& src) noexcept {
489
0
    releaseArray();  // in case this instance had its own memory allocated
490
0
    capacity = src.capacity;
491
0
    needToRelease = src.needToRelease;
492
0
    if (src.ptr == src.stackArray) {
493
0
        ptr = stackArray;
494
0
        uprv_memcpy(stackArray, src.stackArray, sizeof(T) * src.capacity);
495
0
    } else {
496
0
        ptr = src.ptr;
497
0
        src.resetToStackArray();  // take ownership away from src
498
0
    }
499
0
    return *this;
500
0
}
501
502
template<typename T, int32_t stackCapacity>
503
4
inline T *MaybeStackArray<T, stackCapacity>::resize(int32_t newCapacity, int32_t length) {
504
4
    if(newCapacity>0) {
505
#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
506
        ::fprintf(::stderr, "MaybeStackArray (resize) alloc %d * %lu\n", newCapacity, sizeof(T));
507
#endif
508
4
        T *p=(T *)uprv_malloc(newCapacity*sizeof(T));
509
4
        if(p!=nullptr) {
510
4
            if(length>0) {
511
4
                if(length>capacity) {
512
0
                    length=capacity;
513
0
                }
514
4
                if(length>newCapacity) {
515
0
                    length=newCapacity;
516
0
                }
517
4
                uprv_memcpy(p, ptr, (size_t)length*sizeof(T));
518
4
            }
519
4
            releaseArray();
520
4
            ptr=p;
521
4
            capacity=newCapacity;
522
4
            needToRelease=true;
523
4
        }
524
4
        return p;
525
4
    } else {
526
0
        return nullptr;
527
0
    }
528
4
}
icu_78::MaybeStackArray<char, 40>::resize(int, int)
Line
Count
Source
503
4
inline T *MaybeStackArray<T, stackCapacity>::resize(int32_t newCapacity, int32_t length) {
504
4
    if(newCapacity>0) {
505
#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
506
        ::fprintf(::stderr, "MaybeStackArray (resize) alloc %d * %lu\n", newCapacity, sizeof(T));
507
#endif
508
4
        T *p=(T *)uprv_malloc(newCapacity*sizeof(T));
509
4
        if(p!=nullptr) {
510
4
            if(length>0) {
511
4
                if(length>capacity) {
512
0
                    length=capacity;
513
0
                }
514
4
                if(length>newCapacity) {
515
0
                    length=newCapacity;
516
0
                }
517
4
                uprv_memcpy(p, ptr, (size_t)length*sizeof(T));
518
4
            }
519
4
            releaseArray();
520
4
            ptr=p;
521
4
            capacity=newCapacity;
522
4
            needToRelease=true;
523
4
        }
524
4
        return p;
525
4
    } else {
526
0
        return nullptr;
527
0
    }
528
4
}
Unexecuted instantiation: icu_78::MaybeStackArray<max_align_t, 7>::resize(int, int)
Unexecuted instantiation: icu_78::MaybeStackArray<max_align_t, 14>::resize(int, int)
Unexecuted instantiation: icu_78::MaybeStackArray<icu_78::FixedString*, 8>::resize(int, int)
Unexecuted instantiation: icu_78::MaybeStackArray<LocExtType*, 8>::resize(int, int)
Unexecuted instantiation: icu_78::MaybeStackArray<TypeAlias*, 8>::resize(int, int)
Unexecuted instantiation: icu_78::MaybeStackArray<LocExtKeyData*, 8>::resize(int, int)
Unexecuted instantiation: uloc_tag.cpp:icu_78::MaybeStackArray<(anonymous namespace)::AttributeListEntry*, 8>::resize(int, int)
Unexecuted instantiation: icu_78::MaybeStackArray<icu_78::CharString*, 8>::resize(int, int)
Unexecuted instantiation: uloc_tag.cpp:icu_78::MaybeStackArray<(anonymous namespace)::ExtensionListEntry*, 8>::resize(int, int)
Unexecuted instantiation: icu_78::MaybeStackArray<icu_78::UnicodeString*, 8>::resize(int, int)
529
530
template<typename T, int32_t stackCapacity>
531
inline T *MaybeStackArray<T, stackCapacity>::orphanOrClone(int32_t length, int32_t &resultCapacity) {
532
    T *p;
533
    if(needToRelease) {
534
        p=ptr;
535
    } else if(length<=0) {
536
        return nullptr;
537
    } else {
538
        if(length>capacity) {
539
            length=capacity;
540
        }
541
        p=(T *)uprv_malloc(length*sizeof(T));
542
#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
543
      ::fprintf(::stderr,"MaybeStacArray (orphan) alloc %d * %lu\n", length,sizeof(T));
544
#endif
545
        if(p==nullptr) {
546
            return nullptr;
547
        }
548
        uprv_memcpy(p, ptr, (size_t)length*sizeof(T));
549
    }
550
    resultCapacity=length;
551
    resetToStackArray();
552
    return p;
553
}
554
555
/**
556
 * Variant of MaybeStackArray that allocates a header struct and an array
557
 * in one contiguous memory block, using uprv_malloc() and uprv_free().
558
 * Provides internal memory with fixed array capacity. Can alias another memory
559
 * block or allocate one.
560
 * The stackCapacity is the number of T items in the internal memory,
561
 * not counting the H header.
562
 * Unlike LocalMemory and LocalArray, this class never adopts
563
 * (takes ownership of) another memory block.
564
 */
565
template<typename H, typename T, int32_t stackCapacity>
566
class MaybeStackHeaderAndArray {
567
public:
568
    // No heap allocation. Use only on the stack.
569
    static void* U_EXPORT2 operator new(size_t) noexcept = delete;
570
    static void* U_EXPORT2 operator new[](size_t) noexcept = delete;
571
    static void* U_EXPORT2 operator new(size_t, void*) noexcept = delete;
572
573
    /**
574
     * Default constructor initializes with internal H+T[stackCapacity] buffer.
575
     */
576
    MaybeStackHeaderAndArray() : ptr(&stackHeader), capacity(stackCapacity), needToRelease(false) {}
577
    /**
578
     * Destructor deletes the memory (if owned).
579
     */
580
    ~MaybeStackHeaderAndArray() { releaseMemory(); }
581
    /**
582
     * Returns the array capacity (number of T items).
583
     * @return array capacity
584
     */
585
    int32_t getCapacity() const { return capacity; }
586
    /**
587
     * Access without ownership change.
588
     * @return the header pointer
589
     */
590
    H *getAlias() const { return ptr; }
591
    /**
592
     * Returns the array start.
593
     * @return array start, same address as getAlias()+1
594
     */
595
    T *getArrayStart() const { return reinterpret_cast<T *>(getAlias()+1); }
596
    /**
597
     * Returns the array limit.
598
     * @return array limit
599
     */
600
    T *getArrayLimit() const { return getArrayStart()+capacity; }
601
    /**
602
     * Access without ownership change. Same as getAlias().
603
     * A class instance can be used directly in expressions that take a T *.
604
     * @return the header pointer
605
     */
606
    operator H *() const { return ptr; }
607
    /**
608
     * Array item access (writable).
609
     * No index bounds check.
610
     * @param i array index
611
     * @return reference to the array item
612
     */
613
    T &operator[](ptrdiff_t i) { return getArrayStart()[i]; }
614
    /**
615
     * Deletes the memory block (if owned) and aliases another one, no transfer of ownership.
616
     * If the arguments are illegal, then the current memory is unchanged.
617
     * @param otherArray must not be nullptr
618
     * @param otherCapacity must be >0
619
     */
620
    void aliasInstead(H *otherMemory, int32_t otherCapacity) {
621
        if(otherMemory!=nullptr && otherCapacity>0) {
622
            releaseMemory();
623
            ptr=otherMemory;
624
            capacity=otherCapacity;
625
            needToRelease=false;
626
        }
627
    }
628
    /**
629
     * Deletes the memory block (if owned) and allocates a new one,
630
     * copying the header and length T array items.
631
     * Returns the new header pointer.
632
     * If the allocation fails, then the current memory is unchanged and
633
     * this method returns nullptr.
634
     * @param newCapacity can be less than or greater than the current capacity;
635
     *                    must be >0
636
     * @param length number of T items to be copied from the old array to the new one
637
     * @return the allocated pointer, or nullptr if the allocation failed
638
     */
639
    inline H *resize(int32_t newCapacity, int32_t length=0);
640
    /**
641
     * Gives up ownership of the memory if owned, or else clones it,
642
     * copying the header and length T array items; resets itself to the internal memory.
643
     * Returns nullptr if the allocation failed.
644
     * @param length number of T items to copy when cloning,
645
     *        and array capacity of the clone when cloning
646
     * @param resultCapacity will be set to the returned array's capacity (output-only)
647
     * @return the header pointer;
648
     *         caller becomes responsible for deleting the array
649
     */
650
    inline H *orphanOrClone(int32_t length, int32_t &resultCapacity);
651
private:
652
    H *ptr;
653
    int32_t capacity;
654
    UBool needToRelease;
655
    // stackHeader must precede stackArray immediately.
656
    H stackHeader;
657
    T stackArray[stackCapacity];
658
    void releaseMemory() {
659
        if(needToRelease) {
660
            uprv_free(ptr);
661
        }
662
    }
663
    /* No comparison operators with other MaybeStackHeaderAndArray's. */
664
    bool operator==(const MaybeStackHeaderAndArray & /*other*/) {return false;}
665
    bool operator!=(const MaybeStackHeaderAndArray & /*other*/) {return true;}
666
    /* No ownership transfer: No copy constructor, no assignment operator. */
667
    MaybeStackHeaderAndArray(const MaybeStackHeaderAndArray & /*other*/) {}
668
    void operator=(const MaybeStackHeaderAndArray & /*other*/) {}
669
};
670
671
template<typename H, typename T, int32_t stackCapacity>
672
inline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::resize(int32_t newCapacity,
673
                                                                int32_t length) {
674
    if(newCapacity>=0) {
675
#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
676
      ::fprintf(::stderr,"MaybeStackHeaderAndArray alloc %d + %d * %ul\n", sizeof(H),newCapacity,sizeof(T));
677
#endif
678
        H *p=(H *)uprv_malloc(sizeof(H)+newCapacity*sizeof(T));
679
        if(p!=nullptr) {
680
            if(length<0) {
681
                length=0;
682
            } else if(length>0) {
683
                if(length>capacity) {
684
                    length=capacity;
685
                }
686
                if(length>newCapacity) {
687
                    length=newCapacity;
688
                }
689
            }
690
            uprv_memcpy(p, ptr, sizeof(H)+(size_t)length*sizeof(T));
691
            releaseMemory();
692
            ptr=p;
693
            capacity=newCapacity;
694
            needToRelease=true;
695
        }
696
        return p;
697
    } else {
698
        return nullptr;
699
    }
700
}
701
702
template<typename H, typename T, int32_t stackCapacity>
703
inline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::orphanOrClone(int32_t length,
704
                                                                       int32_t &resultCapacity) {
705
    H *p;
706
    if(needToRelease) {
707
        p=ptr;
708
    } else {
709
        if(length<0) {
710
            length=0;
711
        } else if(length>capacity) {
712
            length=capacity;
713
        }
714
#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
715
      ::fprintf(::stderr,"MaybeStackHeaderAndArray (orphan) alloc %ul + %d * %lu\n", sizeof(H),length,sizeof(T));
716
#endif
717
        p=(H *)uprv_malloc(sizeof(H)+length*sizeof(T));
718
        if(p==nullptr) {
719
            return nullptr;
720
        }
721
        uprv_memcpy(p, ptr, sizeof(H)+(size_t)length*sizeof(T));
722
    }
723
    resultCapacity=length;
724
    ptr=&stackHeader;
725
    capacity=stackCapacity;
726
    needToRelease=false;
727
    return p;
728
}
729
730
/**
731
 * A simple memory management class that creates new heap allocated objects (of
732
 * any class that has a public constructor), keeps track of them and eventually
733
 * deletes them all in its own destructor.
734
 *
735
 * A typical use-case would be code like this:
736
 *
737
 *     MemoryPool<MyType> pool;
738
 *
739
 *     MyType* o1 = pool.create();
740
 *     if (o1 != nullptr) {
741
 *         foo(o1);
742
 *     }
743
 *
744
 *     MyType* o2 = pool.create(1, 2, 3);
745
 *     if (o2 != nullptr) {
746
 *         bar(o2);
747
 *     }
748
 *
749
 *     // MemoryPool will take care of deleting the MyType objects.
750
 *
751
 * It doesn't do anything more than that, and is intentionally kept minimalist.
752
 */
753
template<typename T, int32_t stackCapacity = 8>
754
class MemoryPool : public UMemory {
755
public:
756
0
    MemoryPool() : fCount(0), fPool() {}
Unexecuted instantiation: icu_78::MemoryPool<icu_78::FixedString, 8>::MemoryPool()
Unexecuted instantiation: icu_78::MemoryPool<LocExtKeyData, 8>::MemoryPool()
Unexecuted instantiation: icu_78::MemoryPool<LocExtType, 8>::MemoryPool()
Unexecuted instantiation: icu_78::MemoryPool<TypeAlias, 8>::MemoryPool()
Unexecuted instantiation: uloc_tag.cpp:icu_78::MemoryPool<(anonymous namespace)::AttributeListEntry, 8>::MemoryPool()
Unexecuted instantiation: uloc_tag.cpp:icu_78::MemoryPool<(anonymous namespace)::ExtensionListEntry, 8>::MemoryPool()
Unexecuted instantiation: icu_78::MemoryPool<icu_78::CharString, 8>::MemoryPool()
Unexecuted instantiation: icu_78::MemoryPool<icu_78::UnicodeString, 8>::MemoryPool()
757
758
0
    ~MemoryPool() {
759
0
        for (int32_t i = 0; i < fCount; ++i) {
760
0
            delete fPool[i];
761
0
        }
762
0
    }
Unexecuted instantiation: icu_78::MemoryPool<LocExtKeyData, 8>::~MemoryPool()
Unexecuted instantiation: icu_78::MemoryPool<LocExtType, 8>::~MemoryPool()
Unexecuted instantiation: icu_78::MemoryPool<TypeAlias, 8>::~MemoryPool()
Unexecuted instantiation: icu_78::MemoryPool<icu_78::FixedString, 8>::~MemoryPool()
Unexecuted instantiation: icu_78::MemoryPool<icu_78::CharString, 8>::~MemoryPool()
Unexecuted instantiation: uloc_tag.cpp:icu_78::MemoryPool<(anonymous namespace)::ExtensionListEntry, 8>::~MemoryPool()
Unexecuted instantiation: uloc_tag.cpp:icu_78::MemoryPool<(anonymous namespace)::AttributeListEntry, 8>::~MemoryPool()
Unexecuted instantiation: icu_78::MemoryPool<icu_78::UnicodeString, 8>::~MemoryPool()
763
764
    MemoryPool(const MemoryPool&) = delete;
765
    MemoryPool& operator=(const MemoryPool&) = delete;
766
767
    MemoryPool(MemoryPool&& other) noexcept : fCount(other.fCount),
768
                                                fPool(std::move(other.fPool)) {
769
        other.fCount = 0;
770
    }
771
772
    MemoryPool& operator=(MemoryPool&& other) noexcept {
773
        // Since `this` may contain instances that need to be deleted, we can't
774
        // just throw them away and replace them with `other`. The normal way of
775
        // dealing with this in C++ is to swap `this` and `other`, rather than
776
        // simply overwrite: the destruction of `other` can then take care of
777
        // running MemoryPool::~MemoryPool() over the still-to-be-deallocated
778
        // instances.
779
        std::swap(fCount, other.fCount);
780
        std::swap(fPool, other.fPool);
781
        return *this;
782
    }
783
784
    /**
785
     * Creates a new object of typename T, by forwarding any and all arguments
786
     * to the typename T constructor.
787
     *
788
     * @param args Arguments to be forwarded to the typename T constructor.
789
     * @return A pointer to the newly created object, or nullptr on error.
790
     */
791
    template<typename... Args>
792
0
    T* create(Args&&... args) {
793
0
        int32_t capacity = fPool.getCapacity();
794
0
        if (fCount == capacity &&
795
0
            fPool.resize(capacity == stackCapacity ? 4 * capacity : 2 * capacity,
796
0
                         capacity) == nullptr) {
797
0
            return nullptr;
798
0
        }
799
0
        return fPool[fCount++] = new T(std::forward<Args>(args)...);
800
0
    }
Unexecuted instantiation: icu_78::FixedString* icu_78::MemoryPool<icu_78::FixedString, 8>::create<>()
Unexecuted instantiation: icu_78::FixedString* icu_78::MemoryPool<icu_78::FixedString, 8>::create<std::__1::basic_string_view<char, std::__1::char_traits<char> >&>(std::__1::basic_string_view<char, std::__1::char_traits<char> >&)
Unexecuted instantiation: LocExtType* icu_78::MemoryPool<LocExtType, 8>::create<>()
Unexecuted instantiation: TypeAlias* icu_78::MemoryPool<TypeAlias, 8>::create<TypeAlias>(TypeAlias&&)
Unexecuted instantiation: LocExtKeyData* icu_78::MemoryPool<LocExtKeyData, 8>::create<>()
Unexecuted instantiation: uloc_tag.cpp:(anonymous namespace)::AttributeListEntry* icu_78::MemoryPool<(anonymous namespace)::AttributeListEntry, 8>::create<>()
Unexecuted instantiation: icu_78::CharString* icu_78::MemoryPool<icu_78::CharString, 8>::create<icu_78::CharString, UErrorCode&>(icu_78::CharString&&, UErrorCode&)
Unexecuted instantiation: icu_78::CharString* icu_78::MemoryPool<icu_78::CharString, 8>::create<icu_78::CharString&, UErrorCode&>(icu_78::CharString&, UErrorCode&)
Unexecuted instantiation: icu_78::CharString* icu_78::MemoryPool<icu_78::CharString, 8>::create<char*, int&, UErrorCode&>(char*&&, int&, UErrorCode&)
Unexecuted instantiation: uloc_tag.cpp:(anonymous namespace)::ExtensionListEntry* icu_78::MemoryPool<(anonymous namespace)::ExtensionListEntry, 8>::create<>()
Unexecuted instantiation: icu_78::CharString* icu_78::MemoryPool<icu_78::CharString, 8>::create<char const*&, int&, UErrorCode&>(char const*&, int&, UErrorCode&)
Unexecuted instantiation: icu_78::CharString* icu_78::MemoryPool<icu_78::CharString, 8>::create<>()
Unexecuted instantiation: icu_78::UnicodeString* icu_78::MemoryPool<icu_78::UnicodeString, 8>::create<icu_78::UnicodeString&>(icu_78::UnicodeString&)
801
802
    template <typename... Args>
803
    T* createAndCheckErrorCode(UErrorCode &status, Args &&... args) {
804
        if (U_FAILURE(status)) {
805
            return nullptr;
806
        }
807
        T *pointer = this->create(args...);
808
        if (U_SUCCESS(status) && pointer == nullptr) {
809
            status = U_MEMORY_ALLOCATION_ERROR;
810
        }
811
        return pointer;
812
    }
813
814
    /**
815
     * @return Number of elements that have been allocated.
816
     */
817
    int32_t count() const {
818
        return fCount;
819
    }
820
821
protected:
822
    int32_t fCount;
823
    MaybeStackArray<T*, stackCapacity> fPool;
824
};
825
826
/**
827
 * An internal Vector-like implementation based on MemoryPool.
828
 *
829
 * Heap-allocates each element and stores pointers.
830
 *
831
 * To append an item to the vector, use emplaceBack.
832
 *
833
 *     MaybeStackVector<MyType> vector;
834
 *     MyType* element = vector.emplaceBack();
835
 *     if (!element) {
836
 *         status = U_MEMORY_ALLOCATION_ERROR;
837
 *     }
838
 *     // do stuff with element
839
 *
840
 * To loop over the vector, use a for loop with indices:
841
 *
842
 *     for (int32_t i = 0; i < vector.length(); i++) {
843
 *         MyType* element = vector[i];
844
 *     }
845
 */
846
template<typename T, int32_t stackCapacity = 8>
847
class MaybeStackVector : protected MemoryPool<T, stackCapacity> {
848
public:
849
    template<typename... Args>
850
    T* emplaceBack(Args&&... args) {
851
        return this->create(args...);
852
    }
853
854
    template <typename... Args>
855
    T *emplaceBackAndCheckErrorCode(UErrorCode &status, Args &&... args) {
856
        return this->createAndCheckErrorCode(status, args...);
857
    }
858
859
    int32_t length() const {
860
        return this->fCount;
861
    }
862
863
    T** getAlias() {
864
        return this->fPool.getAlias();
865
    }
866
867
    const T *const *getAlias() const {
868
        return this->fPool.getAlias();
869
    }
870
871
    /**
872
     * Array item access (read-only).
873
     * No index bounds check.
874
     * @param i array index
875
     * @return reference to the array item
876
     */
877
    const T* operator[](ptrdiff_t i) const {
878
        return this->fPool[i];
879
    }
880
881
    /**
882
     * Array item access (writable).
883
     * No index bounds check.
884
     * @param i array index
885
     * @return reference to the array item
886
     */
887
    T* operator[](ptrdiff_t i) {
888
        return this->fPool[i];
889
    }
890
};
891
892
893
U_NAMESPACE_END
894
895
#endif  /* __cplusplus */
896
#endif  /* CMEMORY_H */