diff --git a/icu4c/source/common/unorm_it.c b/icu4c/source/common/unorm_it.c index 0a7288a41c3..5ac54762f35 100644 --- a/icu4c/source/common/unorm_it.c +++ b/icu4c/source/common/unorm_it.c @@ -55,7 +55,7 @@ struct UNormIterator { uint32_t state; /* there are UChars available before start or after limit? */ - UBool hasPrevious, hasNext; + UBool hasPrevious, hasNext, isStackAllocated; UNormalizationMode mode; @@ -548,7 +548,7 @@ static const UCharIterator unormIterator={ /* Setup functions ---------------------------------------------------------- */ U_CAPI UNormIterator * U_EXPORT2 -unorm_openIter(UErrorCode *pErrorCode) { +unorm_openIter(void *stackMem, int32_t stackMemSize, UErrorCode *pErrorCode) { UNormIterator *uni; /* argument checking */ @@ -557,14 +557,33 @@ unorm_openIter(UErrorCode *pErrorCode) { } /* allocate */ - uni=(UNormIterator *)uprv_malloc(sizeof(UNormIterator)); - if(uni==NULL) { - *pErrorCode=U_MEMORY_ALLOCATION_ERROR; - return NULL; + uni=NULL; + if(stackMem!=NULL && stackMemSize>=sizeof(UNormIterator)) { + size_t align=U_ALIGNMENT_OFFSET(stackMem); + if(align==0) { + /* already aligned */ + uni=(UNormIterator *)stackMem; + } else if((stackMemSize-=align)>=sizeof(UNormIterator)) { + /* needs alignment */ + uni=(UNormIterator *)((char *)stackMem+align); + } else { + /* does not fit */ + } + } + + if(uni!=NULL) { + uprv_memset(uni, 0, sizeof(UNormIterator)); + uni->isStackAllocated=TRUE; + } else { + uni=(UNormIterator *)uprv_malloc(sizeof(UNormIterator)); + if(uni==NULL) { + *pErrorCode=U_MEMORY_ALLOCATION_ERROR; + return NULL; + } + uprv_memset(uni, 0, sizeof(UNormIterator)); } /* initialize */ - uprv_memset(uni, 0, sizeof(UNormIterator)); uni->chars=uni->charsBuffer; uni->states=uni->statesBuffer; uni->capacity=initialCapacity; @@ -581,7 +600,9 @@ unorm_closeIter(UNormIterator *uni) { /* chars and states are allocated in the same memory block */ uprv_free(uni->states); } - uprv_free(uni); + if(!uni->isStackAllocated) { + uprv_free(uni); + } } } diff --git a/icu4c/source/common/unorm_it.h b/icu4c/source/common/unorm_it.h index e46497701cb..01e269bcad6 100644 --- a/icu4c/source/common/unorm_it.h +++ b/icu4c/source/common/unorm_it.h @@ -82,16 +82,28 @@ struct UNormIterator; typedef struct UNormIterator UNormIterator; +/** + * Size of a stack buffer to hold a UNormIterator, see the stackMem parameter + * of unorm_openIter(). + * + * @internal + */ +#define UNORM_ITER_SIZE 1024 + /** * Open a normalizing iterator. Must be closed later. * Use unorm_setIter(). * + * @param stackMem Pointer to preallocated (stack-allocated) buffer to hold + * the UNormIterator if possible; can be NULL. + * @param stackMemSize Number of bytes at stackMem; can be 0, + * or should be >= UNORM_ITER_SIZE for a non-NULL stackMem. * @param pErrorCode ICU error code * @return an allocated and pre-initialized UNormIterator * @internal */ U_CAPI UNormIterator * U_EXPORT2 -unorm_openIter(UErrorCode *pErrorCode); +unorm_openIter(void *stackMem, int32_t stackMemSize, UErrorCode *pErrorCode); /** * Close a normalizing iterator. diff --git a/icu4c/source/test/cintltst/custrtst.c b/icu4c/source/test/cintltst/custrtst.c index 21c33381930..7a3c8d82812 100644 --- a/icu4c/source/test/cintltst/custrtst.c +++ b/icu4c/source/test/cintltst/custrtst.c @@ -1696,7 +1696,7 @@ testUNormIteratorWithText(const UChar *text, int32_t textLength, int32_t middle, /* open a normalizing iterator */ errorCode=U_ZERO_ERROR; - uni=unorm_openIter(&errorCode); + uni=unorm_openIter(NULL, 0, &errorCode); if(U_FAILURE(errorCode)) { log_err("unorm_openIter() fails: %s\n", u_errorName(errorCode)); return;