Coverage Report

Created: 2021-08-22 09:07

/src/skia/third_party/externals/icu/source/common/cmemory.h
Line
Count
Source (jump to first uncovered line)
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
1.80M
#define uprv_memcpy(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \
43
1.76M
    /* Suppress warnings about addresses that will never be NULL */ \
44
1.76M
    _Pragma("clang diagnostic push") \
45
1.76M
    _Pragma("clang diagnostic ignored \"-Waddress\"") \
46
1.76M
    U_ASSERT(dst != NULL); \
47
1.76M
    U_ASSERT(src != NULL); \
48
1.76M
    _Pragma("clang diagnostic pop") \
49
1.67M
    U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size); \
50
1.76M
} UPRV_BLOCK_MACRO_END
51
104k
#define uprv_memmove(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \
52
104k
    /* Suppress warnings about addresses that will never be NULL */ \
53
104k
    _Pragma("clang diagnostic push") \
54
104k
    _Pragma("clang diagnostic ignored \"-Waddress\"") \
55
104k
    U_ASSERT(dst != NULL); \
56
104k
    U_ASSERT(src != NULL); \
57
104k
    _Pragma("clang diagnostic pop") \
58
16.9k
    U_STANDARD_CPP_NAMESPACE memmove(dst, src, size); \
59
104k
} 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
332k
#define UPRV_LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
100
994k
#define uprv_memset(buffer, mark, size) U_STANDARD_CPP_NAMESPACE memset(buffer, mark, size)
101
6
#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
39.5k
#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
4
#define STATIC_NEW(type) [] () { \
145
4
    alignas(type) static char storage[sizeof(type)]; \
146
4
    return new(storage) type();} ()
umutex.cpp:icu::umtx_init()::$_0::operator()() const
Line
Count
Source
144
2
#define STATIC_NEW(type) [] () { \
145
2
    alignas(type) static char storage[sizeof(type)]; \
146
2
    return new(storage) type();} ()
umutex.cpp:icu::umtx_init()::$_1::operator()() const
Line
Count
Source
144
2
#define STATIC_NEW(type) [] () { \
145
2
    alignas(type) static char storage[sizeof(type)]; \
146
2
    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=NULL) : LocalPointerBase<T>(p) {}
Unexecuted instantiation: icu::LocalMemory<UKeywordsContext>::LocalMemory(UKeywordsContext*)
Unexecuted instantiation: icu::LocalMemory<UEnumeration>::LocalMemory(UEnumeration*)
Unexecuted instantiation: icu::LocalMemory<int>::LocalMemory(int*)
Unexecuted instantiation: icu::LocalMemory<char const*>::LocalMemory(char const**)
196
    /**
197
     * Move constructor, leaves src with isNull().
198
     * @param src source smart pointer
199
     */
200
    LocalMemory(LocalMemory<T> &&src) U_NOEXCEPT : LocalPointerBase<T>(src.ptr) {
201
        src.ptr=NULL;
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::LocalMemory<UKeywordsContext>::~LocalMemory()
Unexecuted instantiation: icu::LocalMemory<UEnumeration>::~LocalMemory()
Unexecuted instantiation: icu::LocalMemory<int>::~LocalMemory()
Unexecuted instantiation: icu::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) U_NOEXCEPT {
216
        uprv_free(LocalPointerBase<T>::ptr);
217
        LocalPointerBase<T>::ptr=src.ptr;
218
        src.ptr=NULL;
219
        return *this;
220
    }
221
    /**
222
     * Swap pointers.
223
     * @param other other smart pointer
224
     */
225
    void swap(LocalMemory<T> &other) U_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) U_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::LocalMemory<UKeywordsContext>::adoptInstead(UKeywordsContext*)
Unexecuted instantiation: icu::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 NULL.
252
     * @param newCapacity must be >0
253
     * @return the allocated array pointer, or NULL 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 NULL.
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 NULL 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::LocalMemory<int>::operator[](long) const
Unexecuted instantiation: icu::LocalMemory<char const*>::operator[](long) const
275
};
276
277
template<typename T>
278
0
inline T *LocalMemory<T>::allocateInsteadAndReset(int32_t newCapacity) {
279
0
    if(newCapacity>0) {
280
0
        T *p=(T *)uprv_malloc(newCapacity*sizeof(T));
281
0
        if(p!=NULL) {
282
0
            uprv_memset(p, 0, newCapacity*sizeof(T));
283
0
            uprv_free(LocalPointerBase<T>::ptr);
284
0
            LocalPointerBase<T>::ptr=p;
285
0
        }
286
0
        return p;
287
0
    } else {
288
0
        return NULL;
289
0
    }
290
0
}
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!=NULL) {
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 NULL;
310
0
    }
311
0
}
Unexecuted instantiation: icu::LocalMemory<char const*>::allocateInsteadAndCopy(int, int)
Unexecuted instantiation: icu::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) U_NOEXCEPT = delete;
336
    static void* U_EXPORT2 operator new[](size_t) U_NOEXCEPT = delete;
337
#if U_HAVE_PLACEMENT_NEW
338
    static void* U_EXPORT2 operator new(size_t, void*) U_NOEXCEPT = delete;
339
#endif
340
341
    /**
342
     * Default constructor initializes with internal T[stackCapacity] buffer.
343
     */
344
427k
    MaybeStackArray() : ptr(stackArray), capacity(stackCapacity), needToRelease(false) {}
icu::MaybeStackArray<char, 40>::MaybeStackArray()
Line
Count
Source
344
427k
    MaybeStackArray() : ptr(stackArray), capacity(stackCapacity), needToRelease(false) {}
Unexecuted instantiation: icu::MaybeStackArray<icu::CharString*, 8>::MaybeStackArray()
Unexecuted instantiation: icu::MaybeStackArray<LocExtKeyData*, 8>::MaybeStackArray()
Unexecuted instantiation: icu::MaybeStackArray<LocExtType*, 8>::MaybeStackArray()
Unexecuted instantiation: icu::MaybeStackArray<AttributeListEntry*, 8>::MaybeStackArray()
Unexecuted instantiation: icu::MaybeStackArray<ExtensionListEntry*, 8>::MaybeStackArray()
Unexecuted instantiation: icu::MaybeStackArray<void*, 16>::MaybeStackArray()
Unexecuted instantiation: icu::MaybeStackArray<max_align_t, 7>::MaybeStackArray()
Unexecuted instantiation: icu::MaybeStackArray<max_align_t, 14>::MaybeStackArray()
345
    /**
346
     * Automatically allocates the heap array if the argument is larger than the stack capacity.
347
     * Intended for use when an approximate capacity is known at compile time but the true
348
     * capacity is not known until runtime.
349
     */
350
0
    MaybeStackArray(int32_t newCapacity, UErrorCode status) : MaybeStackArray() {
351
0
        if (U_FAILURE(status)) {
352
0
            return;
353
0
        }
354
0
        if (capacity < newCapacity) {
355
0
            if (resize(newCapacity) == nullptr) {
356
0
                status = U_MEMORY_ALLOCATION_ERROR;
357
0
            }
358
0
        }
359
0
    }
360
    /**
361
     * Destructor deletes the array (if owned).
362
     */
363
427k
    ~MaybeStackArray() { releaseArray(); }
icu::MaybeStackArray<char, 40>::~MaybeStackArray()
Line
Count
Source
363
427k
    ~MaybeStackArray() { releaseArray(); }
Unexecuted instantiation: icu::MaybeStackArray<LocExtKeyData*, 8>::~MaybeStackArray()
Unexecuted instantiation: icu::MaybeStackArray<LocExtType*, 8>::~MaybeStackArray()
Unexecuted instantiation: icu::MaybeStackArray<icu::CharString*, 8>::~MaybeStackArray()
Unexecuted instantiation: icu::MaybeStackArray<ExtensionListEntry*, 8>::~MaybeStackArray()
Unexecuted instantiation: icu::MaybeStackArray<AttributeListEntry*, 8>::~MaybeStackArray()
Unexecuted instantiation: icu::MaybeStackArray<void*, 16>::~MaybeStackArray()
Unexecuted instantiation: icu::MaybeStackArray<max_align_t, 7>::~MaybeStackArray()
Unexecuted instantiation: icu::MaybeStackArray<max_align_t, 14>::~MaybeStackArray()
364
    /**
365
     * Move constructor: transfers ownership or copies the stack array.
366
     */
367
    MaybeStackArray(MaybeStackArray<T, stackCapacity> &&src) U_NOEXCEPT;
368
    /**
369
     * Move assignment: transfers ownership or copies the stack array.
370
     */
371
    MaybeStackArray<T, stackCapacity> &operator=(MaybeStackArray<T, stackCapacity> &&src) U_NOEXCEPT;
372
    /**
373
     * Returns the array capacity (number of T items).
374
     * @return array capacity
375
     */
376
966k
    int32_t getCapacity() const { return capacity; }
icu::MaybeStackArray<char, 40>::getCapacity() const
Line
Count
Source
376
966k
    int32_t getCapacity() const { return capacity; }
Unexecuted instantiation: icu::MaybeStackArray<icu::CharString*, 8>::getCapacity() const
Unexecuted instantiation: icu::MaybeStackArray<LocExtType*, 8>::getCapacity() const
Unexecuted instantiation: icu::MaybeStackArray<LocExtKeyData*, 8>::getCapacity() const
Unexecuted instantiation: icu::MaybeStackArray<AttributeListEntry*, 8>::getCapacity() const
Unexecuted instantiation: icu::MaybeStackArray<ExtensionListEntry*, 8>::getCapacity() const
Unexecuted instantiation: icu::MaybeStackArray<void*, 16>::getCapacity() const
Unexecuted instantiation: icu::MaybeStackArray<max_align_t, 7>::getCapacity() const
Unexecuted instantiation: icu::MaybeStackArray<max_align_t, 14>::getCapacity() const
377
    /**
378
     * Access without ownership change.
379
     * @return the array pointer
380
     */
381
2.74M
    T *getAlias() const { return ptr; }
icu::MaybeStackArray<char, 40>::getAlias() const
Line
Count
Source
381
2.74M
    T *getAlias() const { return ptr; }
Unexecuted instantiation: icu::MaybeStackArray<void*, 16>::getAlias() const
Unexecuted instantiation: icu::MaybeStackArray<max_align_t, 7>::getAlias() const
Unexecuted instantiation: icu::MaybeStackArray<max_align_t, 14>::getAlias() const
382
    /**
383
     * Returns the array limit. Simple convenience method.
384
     * @return getAlias()+getCapacity()
385
     */
386
0
    T *getArrayLimit() const { return getAlias()+capacity; }
387
    // No "operator T *() const" because that can make
388
    // expressions like mbs[index] ambiguous for some compilers.
389
    /**
390
     * Array item access (const).
391
     * No index bounds check.
392
     * @param i array index
393
     * @return reference to the array item
394
     */
395
0
    const T &operator[](ptrdiff_t i) const { return ptr[i]; }
396
    /**
397
     * Array item access (writable).
398
     * No index bounds check.
399
     * @param i array index
400
     * @return reference to the array item
401
     */
402
1.71M
    T &operator[](ptrdiff_t i) { return ptr[i]; }
icu::MaybeStackArray<char, 40>::operator[](long)
Line
Count
Source
402
1.71M
    T &operator[](ptrdiff_t i) { return ptr[i]; }
Unexecuted instantiation: icu::MaybeStackArray<LocExtKeyData*, 8>::operator[](long)
Unexecuted instantiation: icu::MaybeStackArray<LocExtType*, 8>::operator[](long)
Unexecuted instantiation: icu::MaybeStackArray<icu::CharString*, 8>::operator[](long)
Unexecuted instantiation: icu::MaybeStackArray<AttributeListEntry*, 8>::operator[](long)
Unexecuted instantiation: icu::MaybeStackArray<ExtensionListEntry*, 8>::operator[](long)
403
    /**
404
     * Deletes the array (if owned) and aliases another one, no transfer of ownership.
405
     * If the arguments are illegal, then the current array is unchanged.
406
     * @param otherArray must not be NULL
407
     * @param otherCapacity must be >0
408
     */
409
0
    void aliasInstead(T *otherArray, int32_t otherCapacity) {
410
0
        if(otherArray!=NULL && otherCapacity>0) {
411
0
            releaseArray();
412
0
            ptr=otherArray;
413
0
            capacity=otherCapacity;
414
0
            needToRelease=false;
415
0
        }
416
0
    }
417
    /**
418
     * Deletes the array (if owned) and allocates a new one, copying length T items.
419
     * Returns the new array pointer.
420
     * If the allocation fails, then the current array is unchanged and
421
     * this method returns NULL.
422
     * @param newCapacity can be less than or greater than the current capacity;
423
     *                    must be >0
424
     * @param length number of T items to be copied from the old array to the new one
425
     * @return the allocated array pointer, or NULL if the allocation failed
426
     */
427
    inline T *resize(int32_t newCapacity, int32_t length=0);
428
    /**
429
     * Gives up ownership of the array if owned, or else clones it,
430
     * copying length T items; resets itself to the internal stack array.
431
     * Returns NULL if the allocation failed.
432
     * @param length number of T items to copy when cloning,
433
     *        and capacity of the clone when cloning
434
     * @param resultCapacity will be set to the returned array's capacity (output-only)
435
     * @return the array pointer;
436
     *         caller becomes responsible for deleting the array
437
     */
438
    inline T *orphanOrClone(int32_t length, int32_t &resultCapacity);
439
440
protected:
441
    // Resizes the array to the size of src, then copies the contents of src.
442
0
    void copyFrom(const MaybeStackArray &src, UErrorCode &status) {
443
0
        if (U_FAILURE(status)) {
444
0
            return;
445
0
        }
446
0
        if (this->resize(src.capacity, 0) == NULL) {
447
0
            status = U_MEMORY_ALLOCATION_ERROR;
448
0
            return;
449
0
        }
450
0
        uprv_memcpy(this->ptr, src.ptr, (size_t)capacity * sizeof(T));
451
0
    }
452
453
private:
454
    T *ptr;
455
    int32_t capacity;
456
    UBool needToRelease;
457
    T stackArray[stackCapacity];
458
427k
    void releaseArray() {
459
427k
        if(needToRelease) {
460
0
            uprv_free(ptr);
461
0
        }
462
427k
    }
icu::MaybeStackArray<char, 40>::releaseArray()
Line
Count
Source
458
427k
    void releaseArray() {
459
427k
        if(needToRelease) {
460
0
            uprv_free(ptr);
461
0
        }
462
427k
    }
Unexecuted instantiation: icu::MaybeStackArray<LocExtKeyData*, 8>::releaseArray()
Unexecuted instantiation: icu::MaybeStackArray<LocExtType*, 8>::releaseArray()
Unexecuted instantiation: icu::MaybeStackArray<icu::CharString*, 8>::releaseArray()
Unexecuted instantiation: icu::MaybeStackArray<AttributeListEntry*, 8>::releaseArray()
Unexecuted instantiation: icu::MaybeStackArray<ExtensionListEntry*, 8>::releaseArray()
Unexecuted instantiation: icu::MaybeStackArray<void*, 16>::releaseArray()
Unexecuted instantiation: icu::MaybeStackArray<max_align_t, 7>::releaseArray()
Unexecuted instantiation: icu::MaybeStackArray<max_align_t, 14>::releaseArray()
463
0
    void resetToStackArray() {
464
0
        ptr=stackArray;
465
0
        capacity=stackCapacity;
466
0
        needToRelease=false;
467
0
    }
468
    /* No comparison operators with other MaybeStackArray's. */
469
    bool operator==(const MaybeStackArray & /*other*/) = delete;
470
    bool operator!=(const MaybeStackArray & /*other*/) = delete;
471
    /* No ownership transfer: No copy constructor, no assignment operator. */
472
    MaybeStackArray(const MaybeStackArray & /*other*/) = delete;
473
    void operator=(const MaybeStackArray & /*other*/) = delete;
474
};
475
476
template<typename T, int32_t stackCapacity>
477
icu::MaybeStackArray<T, stackCapacity>::MaybeStackArray(
478
        MaybeStackArray <T, stackCapacity>&& src) U_NOEXCEPT
479
0
        : ptr(src.ptr), capacity(src.capacity), needToRelease(src.needToRelease) {
480
0
    if (src.ptr == src.stackArray) {
481
0
        ptr = stackArray;
482
0
        uprv_memcpy(stackArray, src.stackArray, sizeof(T) * src.capacity);
483
0
    } else {
484
0
        src.resetToStackArray();  // take ownership away from src
485
0
    }
486
0
}
487
488
template<typename T, int32_t stackCapacity>
489
inline MaybeStackArray <T, stackCapacity>&
490
0
MaybeStackArray<T, stackCapacity>::operator=(MaybeStackArray <T, stackCapacity>&& src) U_NOEXCEPT {
491
0
    releaseArray();  // in case this instance had its own memory allocated
492
0
    capacity = src.capacity;
493
0
    needToRelease = src.needToRelease;
494
0
    if (src.ptr == src.stackArray) {
495
0
        ptr = stackArray;
496
0
        uprv_memcpy(stackArray, src.stackArray, sizeof(T) * src.capacity);
497
0
    } else {
498
0
        ptr = src.ptr;
499
0
        src.resetToStackArray();  // take ownership away from src
500
0
    }
501
0
    return *this;
502
0
}
503
504
template<typename T, int32_t stackCapacity>
505
0
inline T *MaybeStackArray<T, stackCapacity>::resize(int32_t newCapacity, int32_t length) {
506
0
    if(newCapacity>0) {
507
#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
508
        ::fprintf(::stderr, "MaybeStackArray (resize) alloc %d * %lu\n", newCapacity, sizeof(T));
509
#endif
510
0
        T *p=(T *)uprv_malloc(newCapacity*sizeof(T));
511
0
        if(p!=NULL) {
512
0
            if(length>0) {
513
0
                if(length>capacity) {
514
0
                    length=capacity;
515
0
                }
516
0
                if(length>newCapacity) {
517
0
                    length=newCapacity;
518
0
                }
519
0
                uprv_memcpy(p, ptr, (size_t)length*sizeof(T));
520
0
            }
521
0
            releaseArray();
522
0
            ptr=p;
523
0
            capacity=newCapacity;
524
0
            needToRelease=true;
525
0
        }
526
0
        return p;
527
0
    } else {
528
0
        return NULL;
529
0
    }
530
0
}
Unexecuted instantiation: icu::MaybeStackArray<char, 40>::resize(int, int)
Unexecuted instantiation: icu::MaybeStackArray<icu::CharString*, 8>::resize(int, int)
Unexecuted instantiation: icu::MaybeStackArray<LocExtType*, 8>::resize(int, int)
Unexecuted instantiation: icu::MaybeStackArray<LocExtKeyData*, 8>::resize(int, int)
Unexecuted instantiation: icu::MaybeStackArray<AttributeListEntry*, 8>::resize(int, int)
Unexecuted instantiation: icu::MaybeStackArray<ExtensionListEntry*, 8>::resize(int, int)
Unexecuted instantiation: icu::MaybeStackArray<void*, 16>::resize(int, int)
Unexecuted instantiation: icu::MaybeStackArray<max_align_t, 7>::resize(int, int)
Unexecuted instantiation: icu::MaybeStackArray<max_align_t, 14>::resize(int, int)
531
532
template<typename T, int32_t stackCapacity>
533
0
inline T *MaybeStackArray<T, stackCapacity>::orphanOrClone(int32_t length, int32_t &resultCapacity) {
534
0
    T *p;
535
0
    if(needToRelease) {
536
0
        p=ptr;
537
0
    } else if(length<=0) {
538
0
        return NULL;
539
0
    } else {
540
0
        if(length>capacity) {
541
0
            length=capacity;
542
0
        }
543
0
        p=(T *)uprv_malloc(length*sizeof(T));
544
#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
545
      ::fprintf(::stderr,"MaybeStacArray (orphan) alloc %d * %lu\n", length,sizeof(T));
546
#endif
547
0
        if(p==NULL) {
548
0
            return NULL;
549
0
        }
550
0
        uprv_memcpy(p, ptr, (size_t)length*sizeof(T));
551
0
    }
552
0
    resultCapacity=length;
553
0
    resetToStackArray();
554
0
    return p;
555
0
}
556
557
/**
558
 * Variant of MaybeStackArray that allocates a header struct and an array
559
 * in one contiguous memory block, using uprv_malloc() and uprv_free().
560
 * Provides internal memory with fixed array capacity. Can alias another memory
561
 * block or allocate one.
562
 * The stackCapacity is the number of T items in the internal memory,
563
 * not counting the H header.
564
 * Unlike LocalMemory and LocalArray, this class never adopts
565
 * (takes ownership of) another memory block.
566
 */
567
template<typename H, typename T, int32_t stackCapacity>
568
class MaybeStackHeaderAndArray {
569
public:
570
    // No heap allocation. Use only on the stack.
571
    static void* U_EXPORT2 operator new(size_t) U_NOEXCEPT = delete;
572
    static void* U_EXPORT2 operator new[](size_t) U_NOEXCEPT = delete;
573
#if U_HAVE_PLACEMENT_NEW
574
    static void* U_EXPORT2 operator new(size_t, void*) U_NOEXCEPT = delete;
575
#endif
576
577
    /**
578
     * Default constructor initializes with internal H+T[stackCapacity] buffer.
579
     */
580
    MaybeStackHeaderAndArray() : ptr(&stackHeader), capacity(stackCapacity), needToRelease(false) {}
581
    /**
582
     * Destructor deletes the memory (if owned).
583
     */
584
    ~MaybeStackHeaderAndArray() { releaseMemory(); }
585
    /**
586
     * Returns the array capacity (number of T items).
587
     * @return array capacity
588
     */
589
    int32_t getCapacity() const { return capacity; }
590
    /**
591
     * Access without ownership change.
592
     * @return the header pointer
593
     */
594
    H *getAlias() const { return ptr; }
595
    /**
596
     * Returns the array start.
597
     * @return array start, same address as getAlias()+1
598
     */
599
    T *getArrayStart() const { return reinterpret_cast<T *>(getAlias()+1); }
600
    /**
601
     * Returns the array limit.
602
     * @return array limit
603
     */
604
    T *getArrayLimit() const { return getArrayStart()+capacity; }
605
    /**
606
     * Access without ownership change. Same as getAlias().
607
     * A class instance can be used directly in expressions that take a T *.
608
     * @return the header pointer
609
     */
610
    operator H *() const { return ptr; }
611
    /**
612
     * Array item access (writable).
613
     * No index bounds check.
614
     * @param i array index
615
     * @return reference to the array item
616
     */
617
    T &operator[](ptrdiff_t i) { return getArrayStart()[i]; }
618
    /**
619
     * Deletes the memory block (if owned) and aliases another one, no transfer of ownership.
620
     * If the arguments are illegal, then the current memory is unchanged.
621
     * @param otherArray must not be NULL
622
     * @param otherCapacity must be >0
623
     */
624
    void aliasInstead(H *otherMemory, int32_t otherCapacity) {
625
        if(otherMemory!=NULL && otherCapacity>0) {
626
            releaseMemory();
627
            ptr=otherMemory;
628
            capacity=otherCapacity;
629
            needToRelease=false;
630
        }
631
    }
632
    /**
633
     * Deletes the memory block (if owned) and allocates a new one,
634
     * copying the header and length T array items.
635
     * Returns the new header pointer.
636
     * If the allocation fails, then the current memory is unchanged and
637
     * this method returns NULL.
638
     * @param newCapacity can be less than or greater than the current capacity;
639
     *                    must be >0
640
     * @param length number of T items to be copied from the old array to the new one
641
     * @return the allocated pointer, or NULL if the allocation failed
642
     */
643
    inline H *resize(int32_t newCapacity, int32_t length=0);
644
    /**
645
     * Gives up ownership of the memory if owned, or else clones it,
646
     * copying the header and length T array items; resets itself to the internal memory.
647
     * Returns NULL if the allocation failed.
648
     * @param length number of T items to copy when cloning,
649
     *        and array capacity of the clone when cloning
650
     * @param resultCapacity will be set to the returned array's capacity (output-only)
651
     * @return the header pointer;
652
     *         caller becomes responsible for deleting the array
653
     */
654
    inline H *orphanOrClone(int32_t length, int32_t &resultCapacity);
655
private:
656
    H *ptr;
657
    int32_t capacity;
658
    UBool needToRelease;
659
    // stackHeader must precede stackArray immediately.
660
    H stackHeader;
661
    T stackArray[stackCapacity];
662
    void releaseMemory() {
663
        if(needToRelease) {
664
            uprv_free(ptr);
665
        }
666
    }
667
    /* No comparison operators with other MaybeStackHeaderAndArray's. */
668
    bool operator==(const MaybeStackHeaderAndArray & /*other*/) {return false;}
669
    bool operator!=(const MaybeStackHeaderAndArray & /*other*/) {return true;}
670
    /* No ownership transfer: No copy constructor, no assignment operator. */
671
    MaybeStackHeaderAndArray(const MaybeStackHeaderAndArray & /*other*/) {}
672
    void operator=(const MaybeStackHeaderAndArray & /*other*/) {}
673
};
674
675
template<typename H, typename T, int32_t stackCapacity>
676
inline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::resize(int32_t newCapacity,
677
                                                                int32_t length) {
678
    if(newCapacity>=0) {
679
#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
680
      ::fprintf(::stderr,"MaybeStackHeaderAndArray alloc %d + %d * %ul\n", sizeof(H),newCapacity,sizeof(T));
681
#endif
682
        H *p=(H *)uprv_malloc(sizeof(H)+newCapacity*sizeof(T));
683
        if(p!=NULL) {
684
            if(length<0) {
685
                length=0;
686
            } else if(length>0) {
687
                if(length>capacity) {
688
                    length=capacity;
689
                }
690
                if(length>newCapacity) {
691
                    length=newCapacity;
692
                }
693
            }
694
            uprv_memcpy(p, ptr, sizeof(H)+(size_t)length*sizeof(T));
695
            releaseMemory();
696
            ptr=p;
697
            capacity=newCapacity;
698
            needToRelease=true;
699
        }
700
        return p;
701
    } else {
702
        return NULL;
703
    }
704
}
705
706
template<typename H, typename T, int32_t stackCapacity>
707
inline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::orphanOrClone(int32_t length,
708
                                                                       int32_t &resultCapacity) {
709
    H *p;
710
    if(needToRelease) {
711
        p=ptr;
712
    } else {
713
        if(length<0) {
714
            length=0;
715
        } else if(length>capacity) {
716
            length=capacity;
717
        }
718
#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
719
      ::fprintf(::stderr,"MaybeStackHeaderAndArray (orphan) alloc %ul + %d * %lu\n", sizeof(H),length,sizeof(T));
720
#endif
721
        p=(H *)uprv_malloc(sizeof(H)+length*sizeof(T));
722
        if(p==NULL) {
723
            return NULL;
724
        }
725
        uprv_memcpy(p, ptr, sizeof(H)+(size_t)length*sizeof(T));
726
    }
727
    resultCapacity=length;
728
    ptr=&stackHeader;
729
    capacity=stackCapacity;
730
    needToRelease=false;
731
    return p;
732
}
733
734
/**
735
 * A simple memory management class that creates new heap allocated objects (of
736
 * any class that has a public constructor), keeps track of them and eventually
737
 * deletes them all in its own destructor.
738
 *
739
 * A typical use-case would be code like this:
740
 *
741
 *     MemoryPool<MyType> pool;
742
 *
743
 *     MyType* o1 = pool.create();
744
 *     if (o1 != nullptr) {
745
 *         foo(o1);
746
 *     }
747
 *
748
 *     MyType* o2 = pool.create(1, 2, 3);
749
 *     if (o2 != nullptr) {
750
 *         bar(o2);
751
 *     }
752
 *
753
 *     // MemoryPool will take care of deleting the MyType objects.
754
 *
755
 * It doesn't do anything more than that, and is intentionally kept minimalist.
756
 */
757
template<typename T, int32_t stackCapacity = 8>
758
class MemoryPool : public UMemory {
759
public:
760
0
    MemoryPool() : fCount(0), fPool() {}
Unexecuted instantiation: icu::MemoryPool<icu::CharString, 8>::MemoryPool()
Unexecuted instantiation: icu::MemoryPool<LocExtKeyData, 8>::MemoryPool()
Unexecuted instantiation: icu::MemoryPool<LocExtType, 8>::MemoryPool()
Unexecuted instantiation: icu::MemoryPool<AttributeListEntry, 8>::MemoryPool()
Unexecuted instantiation: icu::MemoryPool<ExtensionListEntry, 8>::MemoryPool()
761
762
0
    ~MemoryPool() {
763
0
        for (int32_t i = 0; i < fCount; ++i) {
764
0
            delete fPool[i];
765
0
        }
766
0
    }
Unexecuted instantiation: icu::MemoryPool<LocExtKeyData, 8>::~MemoryPool()
Unexecuted instantiation: icu::MemoryPool<LocExtType, 8>::~MemoryPool()
Unexecuted instantiation: icu::MemoryPool<icu::CharString, 8>::~MemoryPool()
Unexecuted instantiation: icu::MemoryPool<ExtensionListEntry, 8>::~MemoryPool()
Unexecuted instantiation: icu::MemoryPool<AttributeListEntry, 8>::~MemoryPool()
767
768
    MemoryPool(const MemoryPool&) = delete;
769
    MemoryPool& operator=(const MemoryPool&) = delete;
770
771
    MemoryPool(MemoryPool&& other) U_NOEXCEPT : fCount(other.fCount),
772
                                                fPool(std::move(other.fPool)) {
773
        other.fCount = 0;
774
    }
775
776
    MemoryPool& operator=(MemoryPool&& other) U_NOEXCEPT {
777
        // Since `this` may contain instances that need to be deleted, we can't
778
        // just throw them away and replace them with `other`. The normal way of
779
        // dealing with this in C++ is to swap `this` and `other`, rather than
780
        // simply overwrite: the destruction of `other` can then take care of
781
        // running MemoryPool::~MemoryPool() over the still-to-be-deallocated
782
        // instances.
783
        std::swap(fCount, other.fCount);
784
        std::swap(fPool, other.fPool);
785
        return *this;
786
    }
787
788
    /**
789
     * Creates a new object of typename T, by forwarding any and all arguments
790
     * to the typename T constructor.
791
     *
792
     * @param args Arguments to be forwarded to the typename T constructor.
793
     * @return A pointer to the newly created object, or nullptr on error.
794
     */
795
    template<typename... Args>
796
0
    T* create(Args&&... args) {
797
0
        int32_t capacity = fPool.getCapacity();
798
0
        if (fCount == capacity &&
799
0
            fPool.resize(capacity == stackCapacity ? 4 * capacity : 2 * capacity,
800
0
                         capacity) == nullptr) {
801
0
            return nullptr;
802
0
        }
803
0
        return fPool[fCount++] = new T(std::forward<Args>(args)...);
804
0
    }
Unexecuted instantiation: icu::CharString* icu::MemoryPool<icu::CharString, 8>::create<>()
Unexecuted instantiation: icu::CharString* icu::MemoryPool<icu::CharString, 8>::create<char const*&, UErrorCode&>(char const*&, UErrorCode&)
Unexecuted instantiation: LocExtType* icu::MemoryPool<LocExtType, 8>::create<>()
Unexecuted instantiation: LocExtKeyData* icu::MemoryPool<LocExtKeyData, 8>::create<>()
Unexecuted instantiation: AttributeListEntry* icu::MemoryPool<AttributeListEntry, 8>::create<>()
Unexecuted instantiation: icu::CharString* icu::MemoryPool<icu::CharString, 8>::create<char (&) [100], int&, UErrorCode&>(char (&) [100], int&, UErrorCode&)
Unexecuted instantiation: icu::CharString* icu::MemoryPool<icu::CharString, 8>::create<icu::CharString&, UErrorCode&>(icu::CharString&, UErrorCode&)
Unexecuted instantiation: icu::CharString* icu::MemoryPool<icu::CharString, 8>::create<char*, int&, UErrorCode&>(char*&&, int&, UErrorCode&)
Unexecuted instantiation: ExtensionListEntry* icu::MemoryPool<ExtensionListEntry, 8>::create<>()
Unexecuted instantiation: icu::CharString* icu::MemoryPool<icu::CharString, 8>::create<char (&) [3], int&, UErrorCode&>(char (&) [3], int&, UErrorCode&)
Unexecuted instantiation: icu::CharString* icu::MemoryPool<icu::CharString, 8>::create<char (&) [128], int&, UErrorCode&>(char (&) [128], int&, UErrorCode&)
805
806
    template <typename... Args>
807
    T* createAndCheckErrorCode(UErrorCode &status, Args &&... args) {
808
        if (U_FAILURE(status)) {
809
            return nullptr;
810
        }
811
        T *pointer = this->create(args...);
812
        if (U_SUCCESS(status) && pointer == nullptr) {
813
            status = U_MEMORY_ALLOCATION_ERROR;
814
        }
815
        return pointer;
816
    }
817
818
    /**
819
     * @return Number of elements that have been allocated.
820
     */
821
    int32_t count() const {
822
        return fCount;
823
    }
824
825
protected:
826
    int32_t fCount;
827
    MaybeStackArray<T*, stackCapacity> fPool;
828
};
829
830
/**
831
 * An internal Vector-like implementation based on MemoryPool.
832
 *
833
 * Heap-allocates each element and stores pointers.
834
 *
835
 * To append an item to the vector, use emplaceBack.
836
 *
837
 *     MaybeStackVector<MyType> vector;
838
 *     MyType* element = vector.emplaceBack();
839
 *     if (!element) {
840
 *         status = U_MEMORY_ALLOCATION_ERROR;
841
 *     }
842
 *     // do stuff with element
843
 *
844
 * To loop over the vector, use a for loop with indices:
845
 *
846
 *     for (int32_t i = 0; i < vector.length(); i++) {
847
 *         MyType* element = vector[i];
848
 *     }
849
 */
850
template<typename T, int32_t stackCapacity = 8>
851
class MaybeStackVector : protected MemoryPool<T, stackCapacity> {
852
public:
853
    template<typename... Args>
854
    T* emplaceBack(Args&&... args) {
855
        return this->create(args...);
856
    }
857
858
    template <typename... Args>
859
    T *emplaceBackAndCheckErrorCode(UErrorCode &status, Args &&... args) {
860
        return this->createAndCheckErrorCode(status, args...);
861
    }
862
863
    int32_t length() const {
864
        return this->fCount;
865
    }
866
867
    T** getAlias() {
868
        return this->fPool.getAlias();
869
    }
870
871
    const T *const *getAlias() const {
872
        return this->fPool.getAlias();
873
    }
874
875
    /**
876
     * Array item access (read-only).
877
     * No index bounds check.
878
     * @param i array index
879
     * @return reference to the array item
880
     */
881
    const T* operator[](ptrdiff_t i) const {
882
        return this->fPool[i];
883
    }
884
885
    /**
886
     * Array item access (writable).
887
     * No index bounds check.
888
     * @param i array index
889
     * @return reference to the array item
890
     */
891
    T* operator[](ptrdiff_t i) {
892
        return this->fPool[i];
893
    }
894
};
895
896
897
U_NAMESPACE_END
898
899
#endif  /* __cplusplus */
900
#endif  /* CMEMORY_H */