Coverage Report

Created: 2025-07-11 06:23

/src/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
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
5.88M
#define uprv_memcpy(dst, src, size) U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size)
60
7.50M
#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
75.8k
#define UPRV_LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
72
6.53M
#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
2
#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
#if U_HAVE_RVALUE_REFERENCES
166
    /**
167
     * Move constructor, leaves src with isNull().
168
     * @param src source smart pointer
169
     */
170
    LocalMemory(LocalMemory<T> &&src) U_NOEXCEPT : LocalPointerBase<T>(src.ptr) {
171
        src.ptr=NULL;
172
    }
173
#endif
174
    /**
175
     * Destructor deletes the memory it owns.
176
     */
177
0
    ~LocalMemory() {
178
0
        uprv_free(LocalPointerBase<T>::ptr);
179
0
    }
180
#if U_HAVE_RVALUE_REFERENCES
181
    /**
182
     * Move assignment operator, leaves src with isNull().
183
     * The behavior is undefined if *this and src are the same object.
184
     * @param src source smart pointer
185
     * @return *this
186
     */
187
    LocalMemory<T> &operator=(LocalMemory<T> &&src) U_NOEXCEPT {
188
        return moveFrom(src);
189
    }
190
#endif
191
    /**
192
     * Move assignment, leaves src with isNull().
193
     * The behavior is undefined if *this and src are the same object.
194
     *
195
     * Can be called explicitly, does not need C++11 support.
196
     * @param src source smart pointer
197
     * @return *this
198
     */
199
    LocalMemory<T> &moveFrom(LocalMemory<T> &src) U_NOEXCEPT {
200
        delete[] LocalPointerBase<T>::ptr;
201
        LocalPointerBase<T>::ptr=src.ptr;
202
        src.ptr=NULL;
203
        return *this;
204
    }
205
    /**
206
     * Swap pointers.
207
     * @param other other smart pointer
208
     */
209
    void swap(LocalMemory<T> &other) U_NOEXCEPT {
210
        T *temp=LocalPointerBase<T>::ptr;
211
        LocalPointerBase<T>::ptr=other.ptr;
212
        other.ptr=temp;
213
    }
214
    /**
215
     * Non-member LocalMemory swap function.
216
     * @param p1 will get p2's pointer
217
     * @param p2 will get p1's pointer
218
     */
219
    friend inline void swap(LocalMemory<T> &p1, LocalMemory<T> &p2) U_NOEXCEPT {
220
        p1.swap(p2);
221
    }
222
    /**
223
     * Deletes the array it owns,
224
     * and adopts (takes ownership of) the one passed in.
225
     * @param p simple pointer to an array of T items that is adopted
226
     */
227
    void adoptInstead(T *p) {
228
        uprv_free(LocalPointerBase<T>::ptr);
229
        LocalPointerBase<T>::ptr=p;
230
    }
231
    /**
232
     * Deletes the array it owns, allocates a new one and reset its bytes to 0.
233
     * Returns the new array pointer.
234
     * If the allocation fails, then the current array is unchanged and
235
     * this method returns NULL.
236
     * @param newCapacity must be >0
237
     * @return the allocated array pointer, or NULL if the allocation failed
238
     */
239
    inline T *allocateInsteadAndReset(int32_t newCapacity=1);
240
    /**
241
     * Deletes the array it owns and allocates a new one, copying length T items.
242
     * Returns the new array pointer.
243
     * If the allocation fails, then the current array is unchanged and
244
     * this method returns NULL.
245
     * @param newCapacity must be >0
246
     * @param length number of T items to be copied from the old array to the new one;
247
     *               must be no more than the capacity of the old array,
248
     *               which the caller must track because the LocalMemory does not track it
249
     * @return the allocated array pointer, or NULL if the allocation failed
250
     */
251
    inline T *allocateInsteadAndCopy(int32_t newCapacity=1, int32_t length=0);
252
    /**
253
     * Array item access (writable).
254
     * No index bounds check.
255
     * @param i array index
256
     * @return reference to the array item
257
     */
258
0
    T &operator[](ptrdiff_t i) const { return LocalPointerBase<T>::ptr[i]; }
259
};
260
261
template<typename T>
262
0
inline T *LocalMemory<T>::allocateInsteadAndReset(int32_t newCapacity) {
263
0
    if(newCapacity>0) {
264
0
        T *p=(T *)uprv_malloc(newCapacity*sizeof(T));
265
0
        if(p!=NULL) {
266
0
            uprv_memset(p, 0, newCapacity*sizeof(T));
267
0
            uprv_free(LocalPointerBase<T>::ptr);
268
0
            LocalPointerBase<T>::ptr=p;
269
0
        }
270
0
        return p;
271
0
    } else {
272
0
        return NULL;
273
0
    }
274
0
}
275
276
277
template<typename T>
278
inline T *LocalMemory<T>::allocateInsteadAndCopy(int32_t newCapacity, int32_t length) {
279
    if(newCapacity>0) {
280
        T *p=(T *)uprv_malloc(newCapacity*sizeof(T));
281
        if(p!=NULL) {
282
            if(length>0) {
283
                if(length>newCapacity) {
284
                    length=newCapacity;
285
                }
286
                uprv_memcpy(p, LocalPointerBase<T>::ptr, (size_t)length*sizeof(T));
287
            }
288
            uprv_free(LocalPointerBase<T>::ptr);
289
            LocalPointerBase<T>::ptr=p;
290
        }
291
        return p;
292
    } else {
293
        return NULL;
294
    }
295
}
296
297
/**
298
 * Simple array/buffer management class using uprv_malloc() and uprv_free().
299
 * Provides an internal array with fixed capacity. Can alias another array
300
 * or allocate one.
301
 *
302
 * The array address is properly aligned for type T. It might not be properly
303
 * aligned for types larger than T (or larger than the largest subtype of T).
304
 *
305
 * Unlike LocalMemory and LocalArray, this class never adopts
306
 * (takes ownership of) another array.
307
 */
308
template<typename T, int32_t stackCapacity>
309
class MaybeStackArray {
310
public:
311
    /**
312
     * Default constructor initializes with internal T[stackCapacity] buffer.
313
     */
314
4.47k
    MaybeStackArray() : ptr(stackArray), capacity(stackCapacity), needToRelease(FALSE) {}
icu_59::MaybeStackArray<char, 40>::MaybeStackArray()
Line
Count
Source
314
4.47k
    MaybeStackArray() : ptr(stackArray), capacity(stackCapacity), needToRelease(FALSE) {}
Unexecuted instantiation: icu_59::MaybeStackArray<_acceptLangItem, 4>::MaybeStackArray()
315
    /**
316
     * Destructor deletes the array (if owned).
317
     */
318
4.47k
    ~MaybeStackArray() { releaseArray(); }
icu_59::MaybeStackArray<char, 40>::~MaybeStackArray()
Line
Count
Source
318
4.47k
    ~MaybeStackArray() { releaseArray(); }
Unexecuted instantiation: icu_59::MaybeStackArray<_acceptLangItem, 4>::~MaybeStackArray()
319
    /**
320
     * Returns the array capacity (number of T items).
321
     * @return array capacity
322
     */
323
12.2k
    int32_t getCapacity() const { return capacity; }
icu_59::MaybeStackArray<char, 40>::getCapacity() const
Line
Count
Source
323
12.2k
    int32_t getCapacity() const { return capacity; }
Unexecuted instantiation: icu_59::MaybeStackArray<_acceptLangItem, 4>::getCapacity() const
324
    /**
325
     * Access without ownership change.
326
     * @return the array pointer
327
     */
328
38.0k
    T *getAlias() const { return ptr; }
icu_59::MaybeStackArray<char, 40>::getAlias() const
Line
Count
Source
328
38.0k
    T *getAlias() const { return ptr; }
Unexecuted instantiation: icu_59::MaybeStackArray<_acceptLangItem, 4>::getAlias() const
329
    /**
330
     * Returns the array limit. Simple convenience method.
331
     * @return getAlias()+getCapacity()
332
     */
333
0
    T *getArrayLimit() const { return getAlias()+capacity; }
334
    // No "operator T *() const" because that can make
335
    // expressions like mbs[index] ambiguous for some compilers.
336
    /**
337
     * Array item access (const).
338
     * No index bounds check.
339
     * @param i array index
340
     * @return reference to the array item
341
     */
342
0
    const T &operator[](ptrdiff_t i) const { return ptr[i]; }
343
    /**
344
     * Array item access (writable).
345
     * No index bounds check.
346
     * @param i array index
347
     * @return reference to the array item
348
     */
349
19.0k
    T &operator[](ptrdiff_t i) { return ptr[i]; }
icu_59::MaybeStackArray<char, 40>::operator[](long)
Line
Count
Source
349
19.0k
    T &operator[](ptrdiff_t i) { return ptr[i]; }
Unexecuted instantiation: icu_59::MaybeStackArray<_acceptLangItem, 4>::operator[](long)
350
    /**
351
     * Deletes the array (if owned) and aliases another one, no transfer of ownership.
352
     * If the arguments are illegal, then the current array is unchanged.
353
     * @param otherArray must not be NULL
354
     * @param otherCapacity must be >0
355
     */
356
0
    void aliasInstead(T *otherArray, int32_t otherCapacity) {
357
0
        if(otherArray!=NULL && otherCapacity>0) {
358
0
            releaseArray();
359
0
            ptr=otherArray;
360
0
            capacity=otherCapacity;
361
0
            needToRelease=FALSE;
362
0
        }
363
0
    }
364
    /**
365
     * Deletes the array (if owned) and allocates a new one, copying length T items.
366
     * Returns the new array pointer.
367
     * If the allocation fails, then the current array is unchanged and
368
     * this method returns NULL.
369
     * @param newCapacity can be less than or greater than the current capacity;
370
     *                    must be >0
371
     * @param length number of T items to be copied from the old array to the new one
372
     * @return the allocated array pointer, or NULL if the allocation failed
373
     */
374
    inline T *resize(int32_t newCapacity, int32_t length=0);
375
    /**
376
     * Gives up ownership of the array if owned, or else clones it,
377
     * copying length T items; resets itself to the internal stack array.
378
     * Returns NULL if the allocation failed.
379
     * @param length number of T items to copy when cloning,
380
     *        and capacity of the clone when cloning
381
     * @param resultCapacity will be set to the returned array's capacity (output-only)
382
     * @return the array pointer;
383
     *         caller becomes responsible for deleting the array
384
     */
385
    inline T *orphanOrClone(int32_t length, int32_t &resultCapacity);
386
private:
387
    T *ptr;
388
    int32_t capacity;
389
    UBool needToRelease;
390
    T stackArray[stackCapacity];
391
4.47k
    void releaseArray() {
392
4.47k
        if(needToRelease) {
393
0
            uprv_free(ptr);
394
0
        }
395
4.47k
    }
icu_59::MaybeStackArray<char, 40>::releaseArray()
Line
Count
Source
391
4.47k
    void releaseArray() {
392
4.47k
        if(needToRelease) {
393
0
            uprv_free(ptr);
394
0
        }
395
4.47k
    }
Unexecuted instantiation: icu_59::MaybeStackArray<_acceptLangItem, 4>::releaseArray()
396
    /* No comparison operators with other MaybeStackArray's. */
397
0
    bool operator==(const MaybeStackArray & /*other*/) {return FALSE;}
398
0
    bool operator!=(const MaybeStackArray & /*other*/) {return TRUE;}
399
    /* No ownership transfer: No copy constructor, no assignment operator. */
400
0
    MaybeStackArray(const MaybeStackArray & /*other*/) {}
401
0
    void operator=(const MaybeStackArray & /*other*/) {}
402
403
    // No heap allocation. Use only on the stack.
404
    //   (Declaring these functions private triggers a cascade of problems:
405
    //      MSVC insists on exporting an instantiation of MaybeStackArray, which
406
    //      requires that all functions be defined.
407
    //      An empty implementation of new() is rejected, it must return a value.
408
    //      Returning NULL is rejected by gcc for operator new.
409
    //      The expedient thing is just not to override operator new.
410
    //      While relatively pointless, heap allocated instances will function.
411
    // static void * U_EXPORT2 operator new(size_t size); 
412
    // static void * U_EXPORT2 operator new[](size_t size);
413
#if U_HAVE_PLACEMENT_NEW
414
    // static void * U_EXPORT2 operator new(size_t, void *ptr);
415
#endif
416
};
417
418
template<typename T, int32_t stackCapacity>
419
0
inline T *MaybeStackArray<T, stackCapacity>::resize(int32_t newCapacity, int32_t length) {
420
0
    if(newCapacity>0) {
421
#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
422
      ::fprintf(::stderr,"MaybeStacArray (resize) alloc %d * %lu\n", newCapacity,sizeof(T));
423
#endif
424
0
        T *p=(T *)uprv_malloc(newCapacity*sizeof(T));
425
0
        if(p!=NULL) {
426
0
            if(length>0) {
427
0
                if(length>capacity) {
428
0
                    length=capacity;
429
0
                }
430
0
                if(length>newCapacity) {
431
0
                    length=newCapacity;
432
0
                }
433
0
                uprv_memcpy(p, ptr, (size_t)length*sizeof(T));
434
0
            }
435
0
            releaseArray();
436
0
            ptr=p;
437
0
            capacity=newCapacity;
438
0
            needToRelease=TRUE;
439
0
        }
440
0
        return p;
441
0
    } else {
442
0
        return NULL;
443
0
    }
444
0
}
Unexecuted instantiation: icu_59::MaybeStackArray<char, 40>::resize(int, int)
Unexecuted instantiation: icu_59::MaybeStackArray<_acceptLangItem, 4>::resize(int, int)
445
446
template<typename T, int32_t stackCapacity>
447
0
inline T *MaybeStackArray<T, stackCapacity>::orphanOrClone(int32_t length, int32_t &resultCapacity) {
448
0
    T *p;
449
0
    if(needToRelease) {
450
0
        p=ptr;
451
0
    } else if(length<=0) {
452
0
        return NULL;
453
0
    } else {
454
0
        if(length>capacity) {
455
0
            length=capacity;
456
0
        }
457
0
        p=(T *)uprv_malloc(length*sizeof(T));
458
#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
459
      ::fprintf(::stderr,"MaybeStacArray (orphan) alloc %d * %lu\n", length,sizeof(T));
460
#endif
461
0
        if(p==NULL) {
462
0
            return NULL;
463
0
        }
464
0
        uprv_memcpy(p, ptr, (size_t)length*sizeof(T));
465
0
    }
466
0
    resultCapacity=length;
467
0
    ptr=stackArray;
468
0
    capacity=stackCapacity;
469
0
    needToRelease=FALSE;
470
0
    return p;
471
0
}
472
473
/**
474
 * Variant of MaybeStackArray that allocates a header struct and an array
475
 * in one contiguous memory block, using uprv_malloc() and uprv_free().
476
 * Provides internal memory with fixed array capacity. Can alias another memory
477
 * block or allocate one.
478
 * The stackCapacity is the number of T items in the internal memory,
479
 * not counting the H header.
480
 * Unlike LocalMemory and LocalArray, this class never adopts
481
 * (takes ownership of) another memory block.
482
 */
483
template<typename H, typename T, int32_t stackCapacity>
484
class MaybeStackHeaderAndArray {
485
public:
486
    /**
487
     * Default constructor initializes with internal H+T[stackCapacity] buffer.
488
     */
489
    MaybeStackHeaderAndArray() : ptr(&stackHeader), capacity(stackCapacity), needToRelease(FALSE) {}
490
    /**
491
     * Destructor deletes the memory (if owned).
492
     */
493
    ~MaybeStackHeaderAndArray() { releaseMemory(); }
494
    /**
495
     * Returns the array capacity (number of T items).
496
     * @return array capacity
497
     */
498
    int32_t getCapacity() const { return capacity; }
499
    /**
500
     * Access without ownership change.
501
     * @return the header pointer
502
     */
503
    H *getAlias() const { return ptr; }
504
    /**
505
     * Returns the array start.
506
     * @return array start, same address as getAlias()+1
507
     */
508
    T *getArrayStart() const { return reinterpret_cast<T *>(getAlias()+1); }
509
    /**
510
     * Returns the array limit.
511
     * @return array limit
512
     */
513
    T *getArrayLimit() const { return getArrayStart()+capacity; }
514
    /**
515
     * Access without ownership change. Same as getAlias().
516
     * A class instance can be used directly in expressions that take a T *.
517
     * @return the header pointer
518
     */
519
    operator H *() const { return ptr; }
520
    /**
521
     * Array item access (writable).
522
     * No index bounds check.
523
     * @param i array index
524
     * @return reference to the array item
525
     */
526
    T &operator[](ptrdiff_t i) { return getArrayStart()[i]; }
527
    /**
528
     * Deletes the memory block (if owned) and aliases another one, no transfer of ownership.
529
     * If the arguments are illegal, then the current memory is unchanged.
530
     * @param otherArray must not be NULL
531
     * @param otherCapacity must be >0
532
     */
533
    void aliasInstead(H *otherMemory, int32_t otherCapacity) {
534
        if(otherMemory!=NULL && otherCapacity>0) {
535
            releaseMemory();
536
            ptr=otherMemory;
537
            capacity=otherCapacity;
538
            needToRelease=FALSE;
539
        }
540
    }
541
    /**
542
     * Deletes the memory block (if owned) and allocates a new one,
543
     * copying the header and length T array items.
544
     * Returns the new header pointer.
545
     * If the allocation fails, then the current memory is unchanged and
546
     * this method returns NULL.
547
     * @param newCapacity can be less than or greater than the current capacity;
548
     *                    must be >0
549
     * @param length number of T items to be copied from the old array to the new one
550
     * @return the allocated pointer, or NULL if the allocation failed
551
     */
552
    inline H *resize(int32_t newCapacity, int32_t length=0);
553
    /**
554
     * Gives up ownership of the memory if owned, or else clones it,
555
     * copying the header and length T array items; resets itself to the internal memory.
556
     * Returns NULL if the allocation failed.
557
     * @param length number of T items to copy when cloning,
558
     *        and array capacity of the clone when cloning
559
     * @param resultCapacity will be set to the returned array's capacity (output-only)
560
     * @return the header pointer;
561
     *         caller becomes responsible for deleting the array
562
     */
563
    inline H *orphanOrClone(int32_t length, int32_t &resultCapacity);
564
private:
565
    H *ptr;
566
    int32_t capacity;
567
    UBool needToRelease;
568
    // stackHeader must precede stackArray immediately.
569
    H stackHeader;
570
    T stackArray[stackCapacity];
571
    void releaseMemory() {
572
        if(needToRelease) {
573
            uprv_free(ptr);
574
        }
575
    }
576
    /* No comparison operators with other MaybeStackHeaderAndArray's. */
577
    bool operator==(const MaybeStackHeaderAndArray & /*other*/) {return FALSE;}
578
    bool operator!=(const MaybeStackHeaderAndArray & /*other*/) {return TRUE;}
579
    /* No ownership transfer: No copy constructor, no assignment operator. */
580
    MaybeStackHeaderAndArray(const MaybeStackHeaderAndArray & /*other*/) {}
581
    void operator=(const MaybeStackHeaderAndArray & /*other*/) {}
582
583
    // No heap allocation. Use only on the stack.
584
    //   (Declaring these functions private triggers a cascade of problems;
585
    //    see the MaybeStackArray class for details.)
586
    // static void * U_EXPORT2 operator new(size_t size); 
587
    // static void * U_EXPORT2 operator new[](size_t size);
588
#if U_HAVE_PLACEMENT_NEW
589
    // static void * U_EXPORT2 operator new(size_t, void *ptr);
590
#endif
591
};
592
593
template<typename H, typename T, int32_t stackCapacity>
594
inline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::resize(int32_t newCapacity,
595
                                                                int32_t length) {
596
    if(newCapacity>=0) {
597
#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
598
      ::fprintf(::stderr,"MaybeStackHeaderAndArray alloc %d + %d * %ul\n", sizeof(H),newCapacity,sizeof(T));
599
#endif
600
        H *p=(H *)uprv_malloc(sizeof(H)+newCapacity*sizeof(T));
601
        if(p!=NULL) {
602
            if(length<0) {
603
                length=0;
604
            } else if(length>0) {
605
                if(length>capacity) {
606
                    length=capacity;
607
                }
608
                if(length>newCapacity) {
609
                    length=newCapacity;
610
                }
611
            }
612
            uprv_memcpy(p, ptr, sizeof(H)+(size_t)length*sizeof(T));
613
            releaseMemory();
614
            ptr=p;
615
            capacity=newCapacity;
616
            needToRelease=TRUE;
617
        }
618
        return p;
619
    } else {
620
        return NULL;
621
    }
622
}
623
624
template<typename H, typename T, int32_t stackCapacity>
625
inline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::orphanOrClone(int32_t length,
626
                                                                       int32_t &resultCapacity) {
627
    H *p;
628
    if(needToRelease) {
629
        p=ptr;
630
    } else {
631
        if(length<0) {
632
            length=0;
633
        } else if(length>capacity) {
634
            length=capacity;
635
        }
636
#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
637
      ::fprintf(::stderr,"MaybeStackHeaderAndArray (orphan) alloc %ul + %d * %lu\n", sizeof(H),length,sizeof(T));
638
#endif
639
        p=(H *)uprv_malloc(sizeof(H)+length*sizeof(T));
640
        if(p==NULL) {
641
            return NULL;
642
        }
643
        uprv_memcpy(p, ptr, sizeof(H)+(size_t)length*sizeof(T));
644
    }
645
    resultCapacity=length;
646
    ptr=&stackHeader;
647
    capacity=stackCapacity;
648
    needToRelease=FALSE;
649
    return p;
650
}
651
652
U_NAMESPACE_END
653
654
#endif  /* __cplusplus */
655
#endif  /* CMEMORY_H */