Coverage Report

Created: 2026-03-12 06:42

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
35
#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
36
#include <stdio.h>
37
#endif
38
39
#if U_DEBUG
40
41
/*
42
 * The C++ standard requires that the source pointer for memcpy() & memmove()
43
 * is valid, not NULL, and not at the end of an allocated memory block.
44
 * In debug mode, we read one byte from the source point to verify that it's
45
 * a valid, readable pointer.
46
 */
47
48
U_CAPI void uprv_checkValidMemory(const void *p, size_t n);
49
50
#define uprv_memcpy(dst, src, size) ( \
51
    uprv_checkValidMemory(src, 1), \
52
    U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size))
53
#define uprv_memmove(dst, src, size) ( \
54
    uprv_checkValidMemory(src, 1), \
55
    U_STANDARD_CPP_NAMESPACE memmove(dst, src, size))
56
57
#else
58
59
32.6M
#define uprv_memcpy(dst, src, size) U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size)
60
31.4k
#define uprv_memmove(dst, src, size) U_STANDARD_CPP_NAMESPACE memmove(dst, src, size)
61
62
#endif  /* U_DEBUG */
63
64
/**
65
 * \def UPRV_LENGTHOF
66
 * Convenience macro to determine the length of a fixed array at compile-time.
67
 * @param array A fixed length array
68
 * @return The length of the array, in elements
69
 * @internal
70
 */
71
2.29M
#define UPRV_LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
72
1.51M
#define uprv_memset(buffer, mark, size) U_STANDARD_CPP_NAMESPACE memset(buffer, mark, size)
73
0
#define uprv_memcmp(buffer1, buffer2, size) U_STANDARD_CPP_NAMESPACE memcmp(buffer1, buffer2,size)
74
75
U_CAPI void * U_EXPORT2
76
uprv_malloc(size_t s) U_MALLOC_ATTR U_ALLOC_SIZE_ATTR(1);
77
78
U_CAPI void * U_EXPORT2
79
uprv_realloc(void *mem, size_t size) U_ALLOC_SIZE_ATTR(2);
80
81
U_CAPI void U_EXPORT2
82
uprv_free(void *mem);
83
84
U_CAPI void * U_EXPORT2
85
uprv_calloc(size_t num, size_t size) U_MALLOC_ATTR U_ALLOC_SIZE_ATTR2(1,2);
86
87
/**
88
 * This should align the memory properly on any machine.
89
 * This is very useful for the safeClone functions.
90
 */
91
typedef union {
92
    long    t1;
93
    double  t2;
94
    void   *t3;
95
} UAlignedMemory;
96
97
/**
98
 * Get the least significant bits of a pointer (a memory address).
99
 * For example, with a mask of 3, the macro gets the 2 least significant bits,
100
 * which will be 0 if the pointer is 32-bit (4-byte) aligned.
101
 *
102
 * ptrdiff_t is the most appropriate integer type to cast to.
103
 * size_t should work too, since on most (or all?) platforms it has the same
104
 * width as ptrdiff_t.
105
 */
106
0
#define U_POINTER_MASK_LSB(ptr, mask) (((ptrdiff_t)(char *)(ptr)) & (mask))
107
108
/**
109
 * Get the amount of bytes that a pointer is off by from
110
 * the previous UAlignedMemory-aligned pointer.
111
 */
112
0
#define U_ALIGNMENT_OFFSET(ptr) U_POINTER_MASK_LSB(ptr, sizeof(UAlignedMemory) - 1)
113
114
/**
115
 * Get the amount of bytes to add to a pointer
116
 * in order to get the next UAlignedMemory-aligned address.
117
 */
118
0
#define U_ALIGNMENT_OFFSET_UP(ptr) (sizeof(UAlignedMemory) - U_ALIGNMENT_OFFSET(ptr))
119
120
/**
121
  *  Heap clean up function, called from u_cleanup()
122
  *    Clears any user heap functions from u_setMemoryFunctions()
123
  *    Does NOT deallocate any remaining allocated memory.
124
  */
125
U_CFUNC UBool 
126
cmemory_cleanup(void);
127
128
/**
129
 * A function called by <TT>uhash_remove</TT>,
130
 * <TT>uhash_close</TT>, or <TT>uhash_put</TT> to delete
131
 * an existing key or value.
132
 * @param obj A key or value stored in a hashtable
133
 * @see uprv_deleteUObject
134
 */
135
typedef void U_CALLCONV UObjectDeleter(void* obj);
136
137
/**
138
 * Deleter for UObject instances.
139
 * Works for all subclasses of UObject because it has a virtual destructor.
140
 */
141
U_CAPI void U_EXPORT2
142
uprv_deleteUObject(void *obj);
143
144
#ifdef __cplusplus
145
146
U_NAMESPACE_BEGIN
147
148
/**
149
 * "Smart pointer" class, deletes memory via uprv_free().
150
 * For most methods see the LocalPointerBase base class.
151
 * Adds operator[] for array item access.
152
 *
153
 * @see LocalPointerBase
154
 */
155
template<typename T>
156
class LocalMemory : public LocalPointerBase<T> {
157
public:
158
    using LocalPointerBase<T>::operator*;
159
    using LocalPointerBase<T>::operator->;
160
    /**
161
     * Constructor takes ownership.
162
     * @param p simple pointer to an array of T items that is adopted
163
     */
164
0
    explicit LocalMemory(T *p=NULL) : LocalPointerBase<T>(p) {}
165
    /**
166
     * Move constructor, leaves src with isNull().
167
     * @param src source smart pointer
168
     */
169
    LocalMemory(LocalMemory<T> &&src) U_NOEXCEPT : LocalPointerBase<T>(src.ptr) {
170
        src.ptr=NULL;
171
    }
172
    /**
173
     * Destructor deletes the memory it owns.
174
     */
175
0
    ~LocalMemory() {
176
0
        uprv_free(LocalPointerBase<T>::ptr);
177
0
    }
178
    /**
179
     * Move assignment operator, leaves src with isNull().
180
     * The behavior is undefined if *this and src are the same object.
181
     * @param src source smart pointer
182
     * @return *this
183
     */
184
    LocalMemory<T> &operator=(LocalMemory<T> &&src) U_NOEXCEPT {
185
        return moveFrom(src);
186
    }
187
    /**
188
     * Move assignment, leaves src with isNull().
189
     * The behavior is undefined if *this and src are the same object.
190
     *
191
     * Can be called explicitly, does not need C++11 support.
192
     * @param src source smart pointer
193
     * @return *this
194
     */
195
    LocalMemory<T> &moveFrom(LocalMemory<T> &src) U_NOEXCEPT {
196
        delete[] LocalPointerBase<T>::ptr;
197
        LocalPointerBase<T>::ptr=src.ptr;
198
        src.ptr=NULL;
199
        return *this;
200
    }
201
    /**
202
     * Swap pointers.
203
     * @param other other smart pointer
204
     */
205
    void swap(LocalMemory<T> &other) U_NOEXCEPT {
206
        T *temp=LocalPointerBase<T>::ptr;
207
        LocalPointerBase<T>::ptr=other.ptr;
208
        other.ptr=temp;
209
    }
210
    /**
211
     * Non-member LocalMemory swap function.
212
     * @param p1 will get p2's pointer
213
     * @param p2 will get p1's pointer
214
     */
215
    friend inline void swap(LocalMemory<T> &p1, LocalMemory<T> &p2) U_NOEXCEPT {
216
        p1.swap(p2);
217
    }
218
    /**
219
     * Deletes the array it owns,
220
     * and adopts (takes ownership of) the one passed in.
221
     * @param p simple pointer to an array of T items that is adopted
222
     */
223
    void adoptInstead(T *p) {
224
        uprv_free(LocalPointerBase<T>::ptr);
225
        LocalPointerBase<T>::ptr=p;
226
    }
227
    /**
228
     * Deletes the array it owns, allocates a new one and reset its bytes to 0.
229
     * Returns the new array pointer.
230
     * If the allocation fails, then the current array is unchanged and
231
     * this method returns NULL.
232
     * @param newCapacity must be >0
233
     * @return the allocated array pointer, or NULL if the allocation failed
234
     */
235
    inline T *allocateInsteadAndReset(int32_t newCapacity=1);
236
    /**
237
     * Deletes the array it owns and allocates a new one, copying length T items.
238
     * Returns the new array pointer.
239
     * If the allocation fails, then the current array is unchanged and
240
     * this method returns NULL.
241
     * @param newCapacity must be >0
242
     * @param length number of T items to be copied from the old array to the new one;
243
     *               must be no more than the capacity of the old array,
244
     *               which the caller must track because the LocalMemory does not track it
245
     * @return the allocated array pointer, or NULL if the allocation failed
246
     */
247
    inline T *allocateInsteadAndCopy(int32_t newCapacity=1, int32_t length=0);
248
    /**
249
     * Array item access (writable).
250
     * No index bounds check.
251
     * @param i array index
252
     * @return reference to the array item
253
     */
254
0
    T &operator[](ptrdiff_t i) const { return LocalPointerBase<T>::ptr[i]; }
255
};
256
257
template<typename T>
258
0
inline T *LocalMemory<T>::allocateInsteadAndReset(int32_t newCapacity) {
259
0
    if(newCapacity>0) {
260
0
        T *p=(T *)uprv_malloc(newCapacity*sizeof(T));
261
0
        if(p!=NULL) {
262
0
            uprv_memset(p, 0, newCapacity*sizeof(T));
263
0
            uprv_free(LocalPointerBase<T>::ptr);
264
0
            LocalPointerBase<T>::ptr=p;
265
0
        }
266
0
        return p;
267
0
    } else {
268
0
        return NULL;
269
0
    }
270
0
}
271
272
273
template<typename T>
274
inline T *LocalMemory<T>::allocateInsteadAndCopy(int32_t newCapacity, int32_t length) {
275
    if(newCapacity>0) {
276
        T *p=(T *)uprv_malloc(newCapacity*sizeof(T));
277
        if(p!=NULL) {
278
            if(length>0) {
279
                if(length>newCapacity) {
280
                    length=newCapacity;
281
                }
282
                uprv_memcpy(p, LocalPointerBase<T>::ptr, (size_t)length*sizeof(T));
283
            }
284
            uprv_free(LocalPointerBase<T>::ptr);
285
            LocalPointerBase<T>::ptr=p;
286
        }
287
        return p;
288
    } else {
289
        return NULL;
290
    }
291
}
292
293
/**
294
 * Simple array/buffer management class using uprv_malloc() and uprv_free().
295
 * Provides an internal array with fixed capacity. Can alias another array
296
 * or allocate one.
297
 *
298
 * The array address is properly aligned for type T. It might not be properly
299
 * aligned for types larger than T (or larger than the largest subtype of T).
300
 *
301
 * Unlike LocalMemory and LocalArray, this class never adopts
302
 * (takes ownership of) another array.
303
 */
304
template<typename T, int32_t stackCapacity>
305
class MaybeStackArray {
306
public:
307
    /**
308
     * Default constructor initializes with internal T[stackCapacity] buffer.
309
     */
310
707
    MaybeStackArray() : ptr(stackArray), capacity(stackCapacity), needToRelease(FALSE) {}
icu_60::MaybeStackArray<char, 40>::MaybeStackArray()
Line
Count
Source
310
707
    MaybeStackArray() : ptr(stackArray), capacity(stackCapacity), needToRelease(FALSE) {}
Unexecuted instantiation: icu_60::MaybeStackArray<_acceptLangItem, 4>::MaybeStackArray()
311
    /**
312
     * Automatically allocates the heap array if the argument is larger than the stack capacity.
313
     * Intended for use when an approximate capacity is known at compile time but the true
314
     * capacity is not known until runtime.
315
     */
316
0
    MaybeStackArray(int32_t newCapacity) : MaybeStackArray() {
317
0
        if (capacity < newCapacity) { resize(newCapacity); }
318
0
    };
319
    /**
320
     * Destructor deletes the array (if owned).
321
     */
322
707
    ~MaybeStackArray() { releaseArray(); }
icu_60::MaybeStackArray<char, 40>::~MaybeStackArray()
Line
Count
Source
322
707
    ~MaybeStackArray() { releaseArray(); }
Unexecuted instantiation: icu_60::MaybeStackArray<_acceptLangItem, 4>::~MaybeStackArray()
323
    /**
324
     * Returns the array capacity (number of T items).
325
     * @return array capacity
326
     */
327
1.94k
    int32_t getCapacity() const { return capacity; }
icu_60::MaybeStackArray<char, 40>::getCapacity() const
Line
Count
Source
327
1.94k
    int32_t getCapacity() const { return capacity; }
Unexecuted instantiation: icu_60::MaybeStackArray<_acceptLangItem, 4>::getCapacity() const
328
    /**
329
     * Access without ownership change.
330
     * @return the array pointer
331
     */
332
6.08k
    T *getAlias() const { return ptr; }
icu_60::MaybeStackArray<char, 40>::getAlias() const
Line
Count
Source
332
6.08k
    T *getAlias() const { return ptr; }
Unexecuted instantiation: icu_60::MaybeStackArray<_acceptLangItem, 4>::getAlias() const
333
    /**
334
     * Returns the array limit. Simple convenience method.
335
     * @return getAlias()+getCapacity()
336
     */
337
0
    T *getArrayLimit() const { return getAlias()+capacity; }
338
    // No "operator T *() const" because that can make
339
    // expressions like mbs[index] ambiguous for some compilers.
340
    /**
341
     * Array item access (const).
342
     * No index bounds check.
343
     * @param i array index
344
     * @return reference to the array item
345
     */
346
0
    const T &operator[](ptrdiff_t i) const { return ptr[i]; }
347
    /**
348
     * Array item access (writable).
349
     * No index bounds check.
350
     * @param i array index
351
     * @return reference to the array item
352
     */
353
2.99k
    T &operator[](ptrdiff_t i) { return ptr[i]; }
icu_60::MaybeStackArray<char, 40>::operator[](long)
Line
Count
Source
353
2.99k
    T &operator[](ptrdiff_t i) { return ptr[i]; }
Unexecuted instantiation: icu_60::MaybeStackArray<_acceptLangItem, 4>::operator[](long)
354
    /**
355
     * Deletes the array (if owned) and aliases another one, no transfer of ownership.
356
     * If the arguments are illegal, then the current array is unchanged.
357
     * @param otherArray must not be NULL
358
     * @param otherCapacity must be >0
359
     */
360
0
    void aliasInstead(T *otherArray, int32_t otherCapacity) {
361
0
        if(otherArray!=NULL && otherCapacity>0) {
362
0
            releaseArray();
363
0
            ptr=otherArray;
364
0
            capacity=otherCapacity;
365
0
            needToRelease=FALSE;
366
0
        }
367
0
    }
368
    /**
369
     * Deletes the array (if owned) and allocates a new one, copying length T items.
370
     * Returns the new array pointer.
371
     * If the allocation fails, then the current array is unchanged and
372
     * this method returns NULL.
373
     * @param newCapacity can be less than or greater than the current capacity;
374
     *                    must be >0
375
     * @param length number of T items to be copied from the old array to the new one
376
     * @return the allocated array pointer, or NULL if the allocation failed
377
     */
378
    inline T *resize(int32_t newCapacity, int32_t length=0);
379
    /**
380
     * Gives up ownership of the array if owned, or else clones it,
381
     * copying length T items; resets itself to the internal stack array.
382
     * Returns NULL if the allocation failed.
383
     * @param length number of T items to copy when cloning,
384
     *        and capacity of the clone when cloning
385
     * @param resultCapacity will be set to the returned array's capacity (output-only)
386
     * @return the array pointer;
387
     *         caller becomes responsible for deleting the array
388
     */
389
    inline T *orphanOrClone(int32_t length, int32_t &resultCapacity);
390
private:
391
    T *ptr;
392
    int32_t capacity;
393
    UBool needToRelease;
394
    T stackArray[stackCapacity];
395
711
    void releaseArray() {
396
711
        if(needToRelease) {
397
4
            uprv_free(ptr);
398
4
        }
399
711
    }
icu_60::MaybeStackArray<char, 40>::releaseArray()
Line
Count
Source
395
711
    void releaseArray() {
396
711
        if(needToRelease) {
397
4
            uprv_free(ptr);
398
4
        }
399
711
    }
Unexecuted instantiation: icu_60::MaybeStackArray<_acceptLangItem, 4>::releaseArray()
400
    /* No comparison operators with other MaybeStackArray's. */
401
0
    bool operator==(const MaybeStackArray & /*other*/) {return FALSE;}
402
0
    bool operator!=(const MaybeStackArray & /*other*/) {return TRUE;}
403
    /* No ownership transfer: No copy constructor, no assignment operator. */
404
0
    MaybeStackArray(const MaybeStackArray & /*other*/) {}
405
0
    void operator=(const MaybeStackArray & /*other*/) {}
406
407
    // No heap allocation. Use only on the stack.
408
    //   (Declaring these functions private triggers a cascade of problems:
409
    //      MSVC insists on exporting an instantiation of MaybeStackArray, which
410
    //      requires that all functions be defined.
411
    //      An empty implementation of new() is rejected, it must return a value.
412
    //      Returning NULL is rejected by gcc for operator new.
413
    //      The expedient thing is just not to override operator new.
414
    //      While relatively pointless, heap allocated instances will function.
415
    // static void * U_EXPORT2 operator new(size_t size); 
416
    // static void * U_EXPORT2 operator new[](size_t size);
417
#if U_HAVE_PLACEMENT_NEW
418
    // static void * U_EXPORT2 operator new(size_t, void *ptr);
419
#endif
420
};
421
422
template<typename T, int32_t stackCapacity>
423
4
inline T *MaybeStackArray<T, stackCapacity>::resize(int32_t newCapacity, int32_t length) {
424
4
    if(newCapacity>0) {
425
#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
426
      ::fprintf(::stderr,"MaybeStacArray (resize) alloc %d * %lu\n", newCapacity,sizeof(T));
427
#endif
428
4
        T *p=(T *)uprv_malloc(newCapacity*sizeof(T));
429
4
        if(p!=NULL) {
430
4
            if(length>0) {
431
4
                if(length>capacity) {
432
0
                    length=capacity;
433
0
                }
434
4
                if(length>newCapacity) {
435
0
                    length=newCapacity;
436
0
                }
437
4
                uprv_memcpy(p, ptr, (size_t)length*sizeof(T));
438
4
            }
439
4
            releaseArray();
440
4
            ptr=p;
441
4
            capacity=newCapacity;
442
4
            needToRelease=TRUE;
443
4
        }
444
4
        return p;
445
4
    } else {
446
0
        return NULL;
447
0
    }
448
4
}
icu_60::MaybeStackArray<char, 40>::resize(int, int)
Line
Count
Source
423
4
inline T *MaybeStackArray<T, stackCapacity>::resize(int32_t newCapacity, int32_t length) {
424
4
    if(newCapacity>0) {
425
#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
426
      ::fprintf(::stderr,"MaybeStacArray (resize) alloc %d * %lu\n", newCapacity,sizeof(T));
427
#endif
428
4
        T *p=(T *)uprv_malloc(newCapacity*sizeof(T));
429
4
        if(p!=NULL) {
430
4
            if(length>0) {
431
4
                if(length>capacity) {
432
0
                    length=capacity;
433
0
                }
434
4
                if(length>newCapacity) {
435
0
                    length=newCapacity;
436
0
                }
437
4
                uprv_memcpy(p, ptr, (size_t)length*sizeof(T));
438
4
            }
439
4
            releaseArray();
440
4
            ptr=p;
441
4
            capacity=newCapacity;
442
4
            needToRelease=TRUE;
443
4
        }
444
4
        return p;
445
4
    } else {
446
        return NULL;
447
0
    }
448
4
}
Unexecuted instantiation: icu_60::MaybeStackArray<_acceptLangItem, 4>::resize(int, int)
449
450
template<typename T, int32_t stackCapacity>
451
0
inline T *MaybeStackArray<T, stackCapacity>::orphanOrClone(int32_t length, int32_t &resultCapacity) {
452
0
    T *p;
453
0
    if(needToRelease) {
454
0
        p=ptr;
455
0
    } else if(length<=0) {
456
0
        return NULL;
457
0
    } else {
458
0
        if(length>capacity) {
459
0
            length=capacity;
460
0
        }
461
0
        p=(T *)uprv_malloc(length*sizeof(T));
462
#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
463
      ::fprintf(::stderr,"MaybeStacArray (orphan) alloc %d * %lu\n", length,sizeof(T));
464
#endif
465
0
        if(p==NULL) {
466
0
            return NULL;
467
0
        }
468
0
        uprv_memcpy(p, ptr, (size_t)length*sizeof(T));
469
0
    }
470
0
    resultCapacity=length;
471
0
    ptr=stackArray;
472
0
    capacity=stackCapacity;
473
0
    needToRelease=FALSE;
474
0
    return p;
475
0
}
476
477
/**
478
 * Variant of MaybeStackArray that allocates a header struct and an array
479
 * in one contiguous memory block, using uprv_malloc() and uprv_free().
480
 * Provides internal memory with fixed array capacity. Can alias another memory
481
 * block or allocate one.
482
 * The stackCapacity is the number of T items in the internal memory,
483
 * not counting the H header.
484
 * Unlike LocalMemory and LocalArray, this class never adopts
485
 * (takes ownership of) another memory block.
486
 */
487
template<typename H, typename T, int32_t stackCapacity>
488
class MaybeStackHeaderAndArray {
489
public:
490
    /**
491
     * Default constructor initializes with internal H+T[stackCapacity] buffer.
492
     */
493
    MaybeStackHeaderAndArray() : ptr(&stackHeader), capacity(stackCapacity), needToRelease(FALSE) {}
494
    /**
495
     * Destructor deletes the memory (if owned).
496
     */
497
    ~MaybeStackHeaderAndArray() { releaseMemory(); }
498
    /**
499
     * Returns the array capacity (number of T items).
500
     * @return array capacity
501
     */
502
    int32_t getCapacity() const { return capacity; }
503
    /**
504
     * Access without ownership change.
505
     * @return the header pointer
506
     */
507
    H *getAlias() const { return ptr; }
508
    /**
509
     * Returns the array start.
510
     * @return array start, same address as getAlias()+1
511
     */
512
    T *getArrayStart() const { return reinterpret_cast<T *>(getAlias()+1); }
513
    /**
514
     * Returns the array limit.
515
     * @return array limit
516
     */
517
    T *getArrayLimit() const { return getArrayStart()+capacity; }
518
    /**
519
     * Access without ownership change. Same as getAlias().
520
     * A class instance can be used directly in expressions that take a T *.
521
     * @return the header pointer
522
     */
523
    operator H *() const { return ptr; }
524
    /**
525
     * Array item access (writable).
526
     * No index bounds check.
527
     * @param i array index
528
     * @return reference to the array item
529
     */
530
    T &operator[](ptrdiff_t i) { return getArrayStart()[i]; }
531
    /**
532
     * Deletes the memory block (if owned) and aliases another one, no transfer of ownership.
533
     * If the arguments are illegal, then the current memory is unchanged.
534
     * @param otherArray must not be NULL
535
     * @param otherCapacity must be >0
536
     */
537
    void aliasInstead(H *otherMemory, int32_t otherCapacity) {
538
        if(otherMemory!=NULL && otherCapacity>0) {
539
            releaseMemory();
540
            ptr=otherMemory;
541
            capacity=otherCapacity;
542
            needToRelease=FALSE;
543
        }
544
    }
545
    /**
546
     * Deletes the memory block (if owned) and allocates a new one,
547
     * copying the header and length T array items.
548
     * Returns the new header pointer.
549
     * If the allocation fails, then the current memory is unchanged and
550
     * this method returns NULL.
551
     * @param newCapacity can be less than or greater than the current capacity;
552
     *                    must be >0
553
     * @param length number of T items to be copied from the old array to the new one
554
     * @return the allocated pointer, or NULL if the allocation failed
555
     */
556
    inline H *resize(int32_t newCapacity, int32_t length=0);
557
    /**
558
     * Gives up ownership of the memory if owned, or else clones it,
559
     * copying the header and length T array items; resets itself to the internal memory.
560
     * Returns NULL if the allocation failed.
561
     * @param length number of T items to copy when cloning,
562
     *        and array capacity of the clone when cloning
563
     * @param resultCapacity will be set to the returned array's capacity (output-only)
564
     * @return the header pointer;
565
     *         caller becomes responsible for deleting the array
566
     */
567
    inline H *orphanOrClone(int32_t length, int32_t &resultCapacity);
568
private:
569
    H *ptr;
570
    int32_t capacity;
571
    UBool needToRelease;
572
    // stackHeader must precede stackArray immediately.
573
    H stackHeader;
574
    T stackArray[stackCapacity];
575
    void releaseMemory() {
576
        if(needToRelease) {
577
            uprv_free(ptr);
578
        }
579
    }
580
    /* No comparison operators with other MaybeStackHeaderAndArray's. */
581
    bool operator==(const MaybeStackHeaderAndArray & /*other*/) {return FALSE;}
582
    bool operator!=(const MaybeStackHeaderAndArray & /*other*/) {return TRUE;}
583
    /* No ownership transfer: No copy constructor, no assignment operator. */
584
    MaybeStackHeaderAndArray(const MaybeStackHeaderAndArray & /*other*/) {}
585
    void operator=(const MaybeStackHeaderAndArray & /*other*/) {}
586
587
    // No heap allocation. Use only on the stack.
588
    //   (Declaring these functions private triggers a cascade of problems;
589
    //    see the MaybeStackArray class for details.)
590
    // static void * U_EXPORT2 operator new(size_t size); 
591
    // static void * U_EXPORT2 operator new[](size_t size);
592
#if U_HAVE_PLACEMENT_NEW
593
    // static void * U_EXPORT2 operator new(size_t, void *ptr);
594
#endif
595
};
596
597
template<typename H, typename T, int32_t stackCapacity>
598
inline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::resize(int32_t newCapacity,
599
                                                                int32_t length) {
600
    if(newCapacity>=0) {
601
#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
602
      ::fprintf(::stderr,"MaybeStackHeaderAndArray alloc %d + %d * %ul\n", sizeof(H),newCapacity,sizeof(T));
603
#endif
604
        H *p=(H *)uprv_malloc(sizeof(H)+newCapacity*sizeof(T));
605
        if(p!=NULL) {
606
            if(length<0) {
607
                length=0;
608
            } else if(length>0) {
609
                if(length>capacity) {
610
                    length=capacity;
611
                }
612
                if(length>newCapacity) {
613
                    length=newCapacity;
614
                }
615
            }
616
            uprv_memcpy(p, ptr, sizeof(H)+(size_t)length*sizeof(T));
617
            releaseMemory();
618
            ptr=p;
619
            capacity=newCapacity;
620
            needToRelease=TRUE;
621
        }
622
        return p;
623
    } else {
624
        return NULL;
625
    }
626
}
627
628
template<typename H, typename T, int32_t stackCapacity>
629
inline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::orphanOrClone(int32_t length,
630
                                                                       int32_t &resultCapacity) {
631
    H *p;
632
    if(needToRelease) {
633
        p=ptr;
634
    } else {
635
        if(length<0) {
636
            length=0;
637
        } else if(length>capacity) {
638
            length=capacity;
639
        }
640
#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
641
      ::fprintf(::stderr,"MaybeStackHeaderAndArray (orphan) alloc %ul + %d * %lu\n", sizeof(H),length,sizeof(T));
642
#endif
643
        p=(H *)uprv_malloc(sizeof(H)+length*sizeof(T));
644
        if(p==NULL) {
645
            return NULL;
646
        }
647
        uprv_memcpy(p, ptr, sizeof(H)+(size_t)length*sizeof(T));
648
    }
649
    resultCapacity=length;
650
    ptr=&stackHeader;
651
    capacity=stackCapacity;
652
    needToRelease=FALSE;
653
    return p;
654
}
655
656
U_NAMESPACE_END
657
658
#endif  /* __cplusplus */
659
#endif  /* CMEMORY_H */