Bug Summary

File:out/../deps/icu-small/source/common/cmemory.h
Warning:line 274, column 40
Returning null reference

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name filteredbrk.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/home/maurizio/node-v18.6.0/out -resource-dir /usr/local/lib/clang/16.0.0 -D V8_DEPRECATION_WARNINGS -D V8_IMMINENT_DEPRECATION_WARNINGS -D _GLIBCXX_USE_CXX11_ABI=1 -D NODE_OPENSSL_CONF_NAME=nodejs_conf -D NODE_OPENSSL_HAS_QUIC -D __STDC_FORMAT_MACROS -D OPENSSL_NO_PINSHARED -D OPENSSL_THREADS -D U_COMMON_IMPLEMENTATION=1 -D U_ATTRIBUTE_DEPRECATED= -D _CRT_SECURE_NO_DEPRECATE= -D U_STATIC_IMPLEMENTATION=1 -D UCONFIG_NO_SERVICE=1 -D U_ENABLE_DYLOAD=0 -D U_HAVE_STD_STRING=1 -D UCONFIG_NO_BREAK_ITERATION=0 -I ../deps/icu-small/source/common -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8 -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8/x86_64-redhat-linux -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8/backward -internal-isystem /usr/local/lib/clang/16.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -Wno-unused-parameter -Wno-deprecated-declarations -Wno-strict-aliasing -std=gnu++17 -fdeprecated-macro -fdebug-compilation-dir=/home/maurizio/node-v18.6.0/out -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-08-22-142216-507842-1 -x c++ ../deps/icu-small/source/common/filteredbrk.cpp

../deps/icu-small/source/common/filteredbrk.cpp

1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
3/*
4*******************************************************************************
5* Copyright (C) 2014-2015, International Business Machines Corporation and
6* others. All Rights Reserved.
7*******************************************************************************
8*/
9
10#include "unicode/utypes.h"
11#if !UCONFIG_NO_BREAK_ITERATION0 && !UCONFIG_NO_FILTERED_BREAK_ITERATION0
12
13#include "cmemory.h"
14
15#include "unicode/filteredbrk.h"
16#include "unicode/ucharstriebuilder.h"
17#include "unicode/ures.h"
18
19#include "uresimp.h" // ures_getByKeyWithFallback
20#include "ubrkimpl.h" // U_ICUDATA_BRKITR
21#include "uvector.h"
22#include "cmemory.h"
23#include "umutex.h"
24
25U_NAMESPACE_BEGINnamespace icu_71 {
26
27#ifndef FB_DEBUG0
28#define FB_DEBUG0 0
29#endif
30
31#if FB_DEBUG0
32#include <stdio.h>
33static void _fb_trace(const char *m, const UnicodeString *s, UBool b, int32_t d, const char *f, int l) {
34 char buf[2048];
35 if(s) {
36 s->extract(0,s->length(),buf,2048);
37 } else {
38 strcpy(buf,"NULL");
39 }
40 fprintf(stderrstderr,"%s:%d: %s. s='%s'(%p), b=%c, d=%d\n",
41 f, l, m, buf, (const void*)s, b?'T':'F',(int)d);
42}
43
44#define FB_TRACE(m,s,b,d) _fb_trace(m,s,b,d,__FILE__"../deps/icu-small/source/common/filteredbrk.cpp",__LINE__44)
45#else
46#define FB_TRACE(m,s,b,d)
47#endif
48
49/**
50 * Used with sortedInsert()
51 */
52static int32_t U_CALLCONV compareUnicodeString(UElement t1, UElement t2) {
53 const UnicodeString &a = *(const UnicodeString*)t1.pointer;
54 const UnicodeString &b = *(const UnicodeString*)t2.pointer;
55 return a.compare(b);
56}
57
58/**
59 * A UVector which implements a set of strings.
60 */
61class U_COMMON_API UStringSet : public UVector {
62 public:
63 UStringSet(UErrorCode &status) : UVector(uprv_deleteUObjectuprv_deleteUObject_71,
64 uhash_compareUnicodeStringuhash_compareUnicodeString_71,
65 1,
66 status) {}
67 virtual ~UStringSet();
68 /**
69 * Is this UnicodeSet contained?
70 */
71 inline UBool contains(const UnicodeString& s) {
72 return contains((void*) &s);
73 }
74 using UVector::contains;
75 /**
76 * Return the ith UnicodeString alias
77 */
78 inline const UnicodeString* getStringAt(int32_t i) const {
79 return (const UnicodeString*)elementAt(i);
80 }
81 /**
82 * Adopt the UnicodeString if not already contained.
83 * Caller no longer owns the pointer in any case.
84 * @return true if adopted successfully, false otherwise (error, or else duplicate)
85 */
86 inline UBool adopt(UnicodeString *str, UErrorCode &status) {
87 if(U_FAILURE(status) || contains(*str)) {
88 delete str;
89 return false;
90 } else {
91 sortedInsert(str, compareUnicodeString, status);
92 if(U_FAILURE(status)) {
93 return false;
94 }
95 return true;
96 }
97 }
98 /**
99 * Add by value.
100 * @return true if successfully adopted.
101 */
102 inline UBool add(const UnicodeString& str, UErrorCode &status) {
103 if(U_FAILURE(status)) return false;
104 UnicodeString *t = new UnicodeString(str);
105 if(t==NULL__null) {
106 status = U_MEMORY_ALLOCATION_ERROR; return false;
107 }
108 return adopt(t, status);
109 }
110 /**
111 * Remove this string.
112 * @return true if successfully removed, false otherwise (error, or else it wasn't there)
113 */
114 inline UBool remove(const UnicodeString &s, UErrorCode &status) {
115 if(U_FAILURE(status)) return false;
116 return removeElement((void*) &s);
117 }
118};
119
120/**
121 * Virtual, won't be inlined
122 */
123UStringSet::~UStringSet() {}
124
125/* ----------------------------------------------------------- */
126
127
128/* Filtered Break constants */
129static const int32_t kPARTIAL = (1<<0); //< partial - need to run through forward trie
130static const int32_t kMATCH = (1<<1); //< exact match - skip this one.
131static const int32_t kSuppressInReverse = (1<<0);
132static const int32_t kAddToForward = (1<<1);
133static const UChar kFULLSTOP = 0x002E; // '.'
134
135/**
136 * Shared data for SimpleFilteredSentenceBreakIterator
137 */
138class SimpleFilteredSentenceBreakData : public UMemory {
139public:
140 SimpleFilteredSentenceBreakData(UCharsTrie *forwards, UCharsTrie *backwards )
141 : fForwardsPartialTrie(forwards), fBackwardsTrie(backwards), refcount(1) { }
142 SimpleFilteredSentenceBreakData *incr() {
143 umtx_atomic_inc(&refcount);
144 return this;
145 }
146 SimpleFilteredSentenceBreakData *decr() {
147 if(umtx_atomic_dec(&refcount) <= 0) {
148 delete this;
149 }
150 return 0;
151 }
152 virtual ~SimpleFilteredSentenceBreakData();
153
154 bool hasForwardsPartialTrie() const { return fForwardsPartialTrie.isValid(); }
155 bool hasBackwardsTrie() const { return fBackwardsTrie.isValid(); }
156
157 const UCharsTrie &getForwardsPartialTrie() const { return *fForwardsPartialTrie; }
158 const UCharsTrie &getBackwardsTrie() const { return *fBackwardsTrie; }
159
160private:
161 // These tries own their data arrays.
162 // They are shared and must therefore not be modified.
163 LocalPointer<UCharsTrie> fForwardsPartialTrie; // Has ".a" for "a.M."
164 LocalPointer<UCharsTrie> fBackwardsTrie; // i.e. ".srM" for Mrs.
165 u_atomic_int32_t refcount;
166};
167
168SimpleFilteredSentenceBreakData::~SimpleFilteredSentenceBreakData() {}
169
170/**
171 * Concrete implementation
172 */
173class SimpleFilteredSentenceBreakIterator : public BreakIterator {
174public:
175 SimpleFilteredSentenceBreakIterator(BreakIterator *adopt, UCharsTrie *forwards, UCharsTrie *backwards, UErrorCode &status);
176 SimpleFilteredSentenceBreakIterator(const SimpleFilteredSentenceBreakIterator& other);
177 virtual ~SimpleFilteredSentenceBreakIterator();
178private:
179 SimpleFilteredSentenceBreakData *fData;
180 LocalPointer<BreakIterator> fDelegate;
181 LocalUTextPointer fText;
182
183 /* -- subclass interface -- */
184public:
185 /* -- cloning and other subclass stuff -- */
186 virtual BreakIterator * createBufferClone(void * /*stackBuffer*/,
187 int32_t &/*BufferSize*/,
188 UErrorCode &status) override {
189 // for now - always deep clone
190 status = U_SAFECLONE_ALLOCATED_WARNING;
191 return clone();
192 }
193 virtual SimpleFilteredSentenceBreakIterator* clone() const override { return new SimpleFilteredSentenceBreakIterator(*this); }
194 virtual UClassID getDynamicClassID(void) const override { return NULL__null; }
195 virtual bool operator==(const BreakIterator& o) const override { if(this==&o) return true; return false; }
196
197 /* -- text modifying -- */
198 virtual void setText(UText *text, UErrorCode &status) override { fDelegate->setText(text,status); }
199 virtual BreakIterator &refreshInputText(UText *input, UErrorCode &status) override { fDelegate->refreshInputText(input,status); return *this; }
200 virtual void adoptText(CharacterIterator* it) override { fDelegate->adoptText(it); }
201 virtual void setText(const UnicodeString &text) override { fDelegate->setText(text); }
202
203 /* -- other functions that are just delegated -- */
204 virtual UText *getUText(UText *fillIn, UErrorCode &status) const override { return fDelegate->getUText(fillIn,status); }
205 virtual CharacterIterator& getText(void) const override { return fDelegate->getText(); }
206
207 /* -- ITERATION -- */
208 virtual int32_t first(void) override;
209 virtual int32_t preceding(int32_t offset) override;
210 virtual int32_t previous(void) override;
211 virtual UBool isBoundary(int32_t offset) override;
212 virtual int32_t current(void) const override { return fDelegate->current(); } // we keep the delegate current, so this should be correct.
213
214 virtual int32_t next(void) override;
215
216 virtual int32_t next(int32_t n) override;
217 virtual int32_t following(int32_t offset) override;
218 virtual int32_t last(void) override;
219
220private:
221 /**
222 * Given that the fDelegate has already given its "initial" answer,
223 * find the NEXT actual (non-excepted) break.
224 * @param n initial position from delegate
225 * @return new break position or UBRK_DONE
226 */
227 int32_t internalNext(int32_t n);
228 /**
229 * Given that the fDelegate has already given its "initial" answer,
230 * find the PREV actual (non-excepted) break.
231 * @param n initial position from delegate
232 * @return new break position or UBRK_DONE
233 */
234 int32_t internalPrev(int32_t n);
235 /**
236 * set up the UText with the value of the fDelegate.
237 * Call this before calling breakExceptionAt.
238 * May be able to avoid excess calls
239 */
240 void resetState(UErrorCode &status);
241 /**
242 * Is there a match (exception) at this spot?
243 */
244 enum EFBMatchResult { kNoExceptionHere, kExceptionHere };
245 /**
246 * Determine if there is an exception at this spot
247 * @param n spot to check
248 * @return kNoExceptionHere or kExceptionHere
249 **/
250 enum EFBMatchResult breakExceptionAt(int32_t n);
251};
252
253SimpleFilteredSentenceBreakIterator::SimpleFilteredSentenceBreakIterator(const SimpleFilteredSentenceBreakIterator& other)
254 : BreakIterator(other), fData(other.fData->incr()), fDelegate(other.fDelegate->clone())
255{
256}
257
258
259SimpleFilteredSentenceBreakIterator::SimpleFilteredSentenceBreakIterator(BreakIterator *adopt, UCharsTrie *forwards, UCharsTrie *backwards, UErrorCode &status) :
260 BreakIterator(adopt->getLocale(ULOC_VALID_LOCALE,status),adopt->getLocale(ULOC_ACTUAL_LOCALE,status)),
261 fData(new SimpleFilteredSentenceBreakData(forwards, backwards)),
262 fDelegate(adopt)
263{
264 if (fData == nullptr) {
265 delete forwards;
266 delete backwards;
267 if (U_SUCCESS(status)) {
268 status = U_MEMORY_ALLOCATION_ERROR;
269 }
270 }
271}
272
273SimpleFilteredSentenceBreakIterator::~SimpleFilteredSentenceBreakIterator() {
274 fData = fData->decr();
275}
276
277void SimpleFilteredSentenceBreakIterator::resetState(UErrorCode &status) {
278 fText.adoptInstead(fDelegate->getUText(fText.orphan(), status));
279}
280
281SimpleFilteredSentenceBreakIterator::EFBMatchResult
282SimpleFilteredSentenceBreakIterator::breakExceptionAt(int32_t n) {
283 int64_t bestPosn = -1;
284 int32_t bestValue = -1;
285 // loops while 'n' points to an exception.
286 utext_setNativeIndexutext_setNativeIndex_71(fText.getAlias(), n); // from n..
287
288 //if(debug2) u_printf(" n@ %d\n", n);
289 // Assume a space is following the '.' (so we handle the case: "Mr. /Brown")
290 if(utext_previous32utext_previous32_71(fText.getAlias())==u' ') { // TODO: skip a class of chars here??
291 // TODO only do this the 1st time?
292 //if(debug2) u_printf("skipping prev: |%C| \n", (UChar)uch);
293 } else {
294 //if(debug2) u_printf("not skipping prev: |%C| \n", (UChar)uch);
295 utext_next32utext_next32_71(fText.getAlias());
296 //if(debug2) u_printf(" -> : |%C| \n", (UChar)uch);
297 }
298
299 {
300 // Do not modify the shared trie!
301 UCharsTrie iter(fData->getBackwardsTrie());
302 UChar32 uch;
303 while((uch=utext_previous32utext_previous32_71(fText.getAlias()))!=U_SENTINEL(-1)) { // more to consume backwards
304 UStringTrieResult r = iter.nextForCodePoint(uch);
305 if(USTRINGTRIE_HAS_VALUE(r)((r)>=USTRINGTRIE_FINAL_VALUE)) { // remember the best match so far
306 bestPosn = utext_getNativeIndexutext_getNativeIndex_71(fText.getAlias());
307 bestValue = iter.getValue();
308 }
309 if(!USTRINGTRIE_HAS_NEXT(r)((r)&1)) {
310 break;
311 }
312 //if(debug2) u_printf("rev< /%C/ cont?%d @%d\n", (UChar)uch, r, utext_getNativeIndex(fText.getAlias()));
313 }
314 }
315
316 //if(bestValue >= 0) {
317 //if(debug2) u_printf("rev<+/%C/+end of seq.. r=%d, bestPosn=%d, bestValue=%d\n", (UChar)uch, r, bestPosn, bestValue);
318 //}
319
320 if(bestPosn>=0) {
321 //if(debug2) u_printf("rev< /%C/ end of seq.. r=%d, bestPosn=%d, bestValue=%d\n", (UChar)uch, r, bestPosn, bestValue);
322
323 //if(USTRINGTRIE_MATCHES(r)) { // matched - so, now what?
324 //int32_t bestValue = iter.getValue();
325 ////if(debug2) u_printf("rev< /%C/ matched, skip..%d bestValue=%d\n", (UChar)uch, r, bestValue);
326
327 if(bestValue == kMATCH) { // exact match!
328 //if(debug2) u_printf(" exact backward match\n");
329 return kExceptionHere; // See if the next is another exception.
330 } else if(bestValue == kPARTIAL
331 && fData->hasForwardsPartialTrie()) { // make sure there's a forward trie
332 //if(debug2) u_printf(" partial backward match\n");
333 // We matched the "Ph." in "Ph.D." - now we need to run everything through the forwards trie
334 // to see if it matches something going forward.
335 UStringTrieResult rfwd = USTRINGTRIE_INTERMEDIATE_VALUE;
336 utext_setNativeIndexutext_setNativeIndex_71(fText.getAlias(), bestPosn); // hope that's close ..
337 //if(debug2) u_printf("Retrying at %d\n", bestPosn);
338 // Do not modify the shared trie!
339 UCharsTrie iter(fData->getForwardsPartialTrie());
340 UChar32 uch;
341 while((uch=utext_next32utext_next32_71(fText.getAlias()))!=U_SENTINEL(-1) &&
342 USTRINGTRIE_HAS_NEXT(rfwd=iter.nextForCodePoint(uch))((rfwd=iter.nextForCodePoint(uch))&1)) {
343 //if(debug2) u_printf("fwd> /%C/ cont?%d @%d\n", (UChar)uch, rfwd, utext_getNativeIndex(fText.getAlias()));
344 }
345 if(USTRINGTRIE_MATCHES(rfwd)((rfwd)!=USTRINGTRIE_NO_MATCH)) {
346 //if(debug2) u_printf("fwd> /%C/ == forward match!\n", (UChar)uch);
347 // only full matches here, nothing to check
348 // skip the next:
349 return kExceptionHere;
350 } else {
351 //if(debug2) u_printf("fwd> /%C/ no match.\n", (UChar)uch);
352 // no match (no exception) -return the 'underlying' break
353 return kNoExceptionHere;
354 }
355 } else {
356 return kNoExceptionHere; // internal error and/or no forwards trie
357 }
358 } else {
359 //if(debug2) u_printf("rev< /%C/ .. no match..%d\n", (UChar)uch, r); // no best match
360 return kNoExceptionHere; // No match - so exit. Not an exception.
361 }
362}
363
364// the workhorse single next.
365int32_t
366SimpleFilteredSentenceBreakIterator::internalNext(int32_t n) {
367 if(n == UBRK_DONE((int32_t) -1) || // at end or
368 !fData->hasBackwardsTrie()) { // .. no backwards table loaded == no exceptions
369 return n;
370 }
371 // OK, do we need to break here?
372 UErrorCode status = U_ZERO_ERROR;
373 // refresh text
374 resetState(status);
375 if(U_FAILURE(status)) return UBRK_DONE((int32_t) -1); // bail out
376 int64_t utextLen = utext_nativeLengthutext_nativeLength_71(fText.getAlias());
377
378 //if(debug2) u_printf("str, native len=%d\n", utext_nativeLength(fText.getAlias()));
379 while (n != UBRK_DONE((int32_t) -1) && n != utextLen) { // outer loop runs once per underlying break (from fDelegate).
380 SimpleFilteredSentenceBreakIterator::EFBMatchResult m = breakExceptionAt(n);
381
382 switch(m) {
383 case kExceptionHere:
384 n = fDelegate->next(); // skip this one. Find the next lowerlevel break.
385 continue;
386
387 default:
388 case kNoExceptionHere:
389 return n;
390 }
391 }
392 return n;
393}
394
395int32_t
396SimpleFilteredSentenceBreakIterator::internalPrev(int32_t n) {
397 if(n == 0 || n == UBRK_DONE((int32_t) -1) || // at end or
398 !fData->hasBackwardsTrie()) { // .. no backwards table loaded == no exceptions
399 return n;
400 }
401 // OK, do we need to break here?
402 UErrorCode status = U_ZERO_ERROR;
403 // refresh text
404 resetState(status);
405 if(U_FAILURE(status)) return UBRK_DONE((int32_t) -1); // bail out
406
407 //if(debug2) u_printf("str, native len=%d\n", utext_nativeLength(fText.getAlias()));
408 while (n != UBRK_DONE((int32_t) -1) && n != 0) { // outer loop runs once per underlying break (from fDelegate).
409 SimpleFilteredSentenceBreakIterator::EFBMatchResult m = breakExceptionAt(n);
410
411 switch(m) {
412 case kExceptionHere:
413 n = fDelegate->previous(); // skip this one. Find the next lowerlevel break.
414 continue;
415
416 default:
417 case kNoExceptionHere:
418 return n;
419 }
420 }
421 return n;
422}
423
424
425int32_t
426SimpleFilteredSentenceBreakIterator::next() {
427 return internalNext(fDelegate->next());
428}
429
430int32_t
431SimpleFilteredSentenceBreakIterator::first(void) {
432 // Don't suppress a break opportunity at the beginning of text.
433 return fDelegate->first();
434}
435
436int32_t
437SimpleFilteredSentenceBreakIterator::preceding(int32_t offset) {
438 return internalPrev(fDelegate->preceding(offset));
439}
440
441int32_t
442SimpleFilteredSentenceBreakIterator::previous(void) {
443 return internalPrev(fDelegate->previous());
444}
445
446UBool SimpleFilteredSentenceBreakIterator::isBoundary(int32_t offset) {
447 if (!fDelegate->isBoundary(offset)) return false; // no break to suppress
448
449 if (!fData->hasBackwardsTrie()) return true; // no data = no suppressions
450
451 UErrorCode status = U_ZERO_ERROR;
452 resetState(status);
453
454 SimpleFilteredSentenceBreakIterator::EFBMatchResult m = breakExceptionAt(offset);
455
456 switch(m) {
457 case kExceptionHere:
458 return false;
459 default:
460 case kNoExceptionHere:
461 return true;
462 }
463}
464
465int32_t
466SimpleFilteredSentenceBreakIterator::next(int32_t offset) {
467 return internalNext(fDelegate->next(offset));
468}
469
470int32_t
471SimpleFilteredSentenceBreakIterator::following(int32_t offset) {
472 return internalNext(fDelegate->following(offset));
473}
474
475int32_t
476SimpleFilteredSentenceBreakIterator::last(void) {
477 // Don't suppress a break opportunity at the end of text.
478 return fDelegate->last();
479}
480
481
482/**
483 * Concrete implementation of builder class.
484 */
485class U_COMMON_API SimpleFilteredBreakIteratorBuilder : public FilteredBreakIteratorBuilder {
486public:
487 virtual ~SimpleFilteredBreakIteratorBuilder();
488 SimpleFilteredBreakIteratorBuilder(const Locale &fromLocale, UErrorCode &status);
489 SimpleFilteredBreakIteratorBuilder(UErrorCode &status);
490 virtual UBool suppressBreakAfter(const UnicodeString& exception, UErrorCode& status) override;
491 virtual UBool unsuppressBreakAfter(const UnicodeString& exception, UErrorCode& status) override;
492 virtual BreakIterator *build(BreakIterator* adoptBreakIterator, UErrorCode& status) override;
493private:
494 UStringSet fSet;
495};
496
497SimpleFilteredBreakIteratorBuilder::~SimpleFilteredBreakIteratorBuilder()
498{
499}
500
501SimpleFilteredBreakIteratorBuilder::SimpleFilteredBreakIteratorBuilder(UErrorCode &status)
502 : fSet(status)
503{
504}
505
506SimpleFilteredBreakIteratorBuilder::SimpleFilteredBreakIteratorBuilder(const Locale &fromLocale, UErrorCode &status)
507 : fSet(status)
508{
509 if(U_SUCCESS(status)) {
510 UErrorCode subStatus = U_ZERO_ERROR;
511 LocalUResourceBundlePointer b(ures_openures_open_71(U_ICUDATA_BRKITR"icudt" "71" "l" "-" "brkitr", fromLocale.getBaseName(), &subStatus));
512 if (U_FAILURE(subStatus) || (subStatus == U_USING_DEFAULT_WARNING) ) {
513 status = subStatus; // copy the failing status
514#if FB_DEBUG0
515 fprintf(stderrstderr, "open BUNDLE %s : %s, %s\n", fromLocale.getBaseName(), "[exit]", u_errorNameu_errorName_71(status));
516#endif
517 return; // leaves the builder empty, if you try to use it.
518 }
519 LocalUResourceBundlePointer exceptions(ures_getByKeyWithFallbackures_getByKeyWithFallback_71(b.getAlias(), "exceptions", NULL__null, &subStatus));
520 if (U_FAILURE(subStatus) || (subStatus == U_USING_DEFAULT_WARNING) ) {
521 status = subStatus; // copy the failing status
522#if FB_DEBUG0
523 fprintf(stderrstderr, "open EXCEPTIONS %s : %s, %s\n", fromLocale.getBaseName(), "[exit]", u_errorNameu_errorName_71(status));
524#endif
525 return; // leaves the builder empty, if you try to use it.
526 }
527 LocalUResourceBundlePointer breaks(ures_getByKeyWithFallbackures_getByKeyWithFallback_71(exceptions.getAlias(), "SentenceBreak", NULL__null, &subStatus));
528
529#if FB_DEBUG0
530 {
531 UErrorCode subsub = subStatus;
532 fprintf(stderrstderr, "open SentenceBreak %s => %s, %s\n", fromLocale.getBaseName(), ures_getLocaleures_getLocale_71(breaks.getAlias(), &subsub), u_errorNameu_errorName_71(subStatus));
533 }
534#endif
535
536 if (U_FAILURE(subStatus) || (subStatus == U_USING_DEFAULT_WARNING) ) {
537 status = subStatus; // copy the failing status
538#if FB_DEBUG0
539 fprintf(stderrstderr, "open %s : %s, %s\n", fromLocale.getBaseName(), "[exit]", u_errorNameu_errorName_71(status));
540#endif
541 return; // leaves the builder empty, if you try to use it.
542 }
543
544 LocalUResourceBundlePointer strs;
545 subStatus = status; // Pick up inherited warning status now
546 do {
547 strs.adoptInstead(ures_getNextResourceures_getNextResource_71(breaks.getAlias(), strs.orphan(), &subStatus));
548 if(strs.isValid() && U_SUCCESS(subStatus)) {
549 UnicodeString str(ures_getUnicodeString(strs.getAlias(), &status));
550 suppressBreakAfter(str, status); // load the string
551 }
552 } while (strs.isValid() && U_SUCCESS(subStatus));
553 if(U_FAILURE(subStatus)&&subStatus!=U_INDEX_OUTOFBOUNDS_ERROR&&U_SUCCESS(status)) {
554 status = subStatus;
555 }
556 }
557}
558
559UBool
560SimpleFilteredBreakIteratorBuilder::suppressBreakAfter(const UnicodeString& exception, UErrorCode& status)
561{
562 UBool r = fSet.add(exception, status);
563 FB_TRACE("suppressBreakAfter",&exception,r,0);
564 return r;
565}
566
567UBool
568SimpleFilteredBreakIteratorBuilder::unsuppressBreakAfter(const UnicodeString& exception, UErrorCode& status)
569{
570 UBool r = fSet.remove(exception, status);
571 FB_TRACE("unsuppressBreakAfter",&exception,r,0);
572 return r;
573}
574
575/**
576 * Jitterbug 2974: MSVC has a bug whereby new X[0] behaves badly.
577 * Work around this.
578 *
579 * Note: "new UnicodeString[subCount]" ends up calling global operator new
580 * on MSVC2012 for some reason.
581 */
582static inline UnicodeString* newUnicodeStringArray(size_t count) {
583 return new UnicodeString[count ? count : 1];
584}
585
586BreakIterator *
587SimpleFilteredBreakIteratorBuilder::build(BreakIterator* adoptBreakIterator, UErrorCode& status) {
588 LocalPointer<BreakIterator> adopt(adoptBreakIterator);
589
590 LocalPointer<UCharsTrieBuilder> builder(new UCharsTrieBuilder(status), status);
591 LocalPointer<UCharsTrieBuilder> builder2(new UCharsTrieBuilder(status), status);
592 if(U_FAILURE(status)) {
1
Taking false branch
593 return NULL__null;
594 }
595
596 int32_t revCount = 0;
597 int32_t fwdCount = 0;
598
599 int32_t subCount = fSet.size();
600
601 UnicodeString *ustrs_ptr = newUnicodeStringArray(subCount);
602
603 LocalArray<UnicodeString> ustrs(ustrs_ptr);
604
605 LocalMemory<int> partials;
2
Passing null pointer value via 1st parameter 'p'
3
Calling default constructor for 'LocalMemory<int>'
8
Returning from default constructor for 'LocalMemory<int>'
606 partials.allocateInsteadAndReset(subCount);
607
608 LocalPointer<UCharsTrie> backwardsTrie; // i.e. ".srM" for Mrs.
609 LocalPointer<UCharsTrie> forwardsPartialTrie; // Has ".a" for "a.M."
610
611 int n=0;
612 for ( int32_t i = 0;
9
Loop condition is true. Entering loop body
613 i<fSet.size();
614 i++) {
615 const UnicodeString *abbr = fSet.getStringAt(i);
616 if(abbr) {
10
Assuming 'abbr' is non-null
11
Taking true branch
617 FB_TRACE("build",abbr,TRUE,i);
618 ustrs[n] = *abbr; // copy by value
619 FB_TRACE("ustrs[n]",&ustrs[n],TRUE,i);
620 } else {
621 FB_TRACE("build",abbr,FALSE,i);
622 status = U_MEMORY_ALLOCATION_ERROR;
623 return NULL__null;
624 }
625 partials[n] = 0; // default: not partial
12
Calling 'LocalMemory::operator[]'
626 n++;
627 }
628 // first pass - find partials.
629 for(int i=0;i<subCount;i++) {
630 int nn = ustrs[i].indexOf(kFULLSTOP); // TODO: non-'.' abbreviations
631 if(nn>-1 && (nn+1)!=ustrs[i].length()) {
632 FB_TRACE("partial",&ustrs[i],FALSE,i);
633 // is partial.
634 // is it unique?
635 int sameAs = -1;
636 for(int j=0;j<subCount;j++) {
637 if(j==i) continue;
638 if(ustrs[i].compare(0,nn+1,ustrs[j],0,nn+1)==0) {
639 FB_TRACE("prefix",&ustrs[j],FALSE,nn+1);
640 //UBool otherIsPartial = ((nn+1)!=ustrs[j].length()); // true if ustrs[j] doesn't end at nn
641 if(partials[j]==0) { // hasn't been processed yet
642 partials[j] = kSuppressInReverse | kAddToForward;
643 FB_TRACE("suppressing",&ustrs[j],FALSE,j);
644 } else if(partials[j] & kSuppressInReverse) {
645 sameAs = j; // the other entry is already in the reverse table.
646 }
647 }
648 }
649 FB_TRACE("for partial same-",&ustrs[i],FALSE,sameAs);
650 FB_TRACE(" == partial #",&ustrs[i],FALSE,partials[i]);
651 UnicodeString prefix(ustrs[i], 0, nn+1);
652 if(sameAs == -1 && partials[i] == 0) {
653 // first one - add the prefix to the reverse table.
654 prefix.reverse();
655 builder->add(prefix, kPARTIAL, status);
656 revCount++;
657 FB_TRACE("Added partial",&prefix,FALSE, i);
658 FB_TRACE(u_errorName(status),&ustrs[i],FALSE,i);
659 partials[i] = kSuppressInReverse | kAddToForward;
660 } else {
661 FB_TRACE("NOT adding partial",&prefix,FALSE, i);
662 FB_TRACE(u_errorName(status),&ustrs[i],FALSE,i);
663 }
664 }
665 }
666 for(int i=0;i<subCount;i++) {
667 if(partials[i]==0) {
668 ustrs[i].reverse();
669 builder->add(ustrs[i], kMATCH, status);
670 revCount++;
671 FB_TRACE(u_errorName(status), &ustrs[i], FALSE, i);
672 } else {
673 FB_TRACE("Adding fwd",&ustrs[i], FALSE, i);
674
675 // an optimization would be to only add the portion after the '.'
676 // for example, for "Ph.D." we store ".hP" in the reverse table. We could just store "D." in the forward,
677 // instead of "Ph.D." since we already know the "Ph." part is a match.
678 // would need the trie to be able to hold 0-length strings, though.
679 builder2->add(ustrs[i], kMATCH, status); // forward
680 fwdCount++;
681 //ustrs[i].reverse();
682 ////if(debug2) u_printf("SUPPRESS- not Added(%d): /%S/ status=%s\n",partials[i], ustrs[i].getTerminatedBuffer(), u_errorName(status));
683 }
684 }
685 FB_TRACE("AbbrCount",NULL,FALSE, subCount);
686
687 if(revCount>0) {
688 backwardsTrie.adoptInstead(builder->build(USTRINGTRIE_BUILD_FAST, status));
689 if(U_FAILURE(status)) {
690 FB_TRACE(u_errorName(status),NULL,FALSE, -1);
691 return NULL__null;
692 }
693 }
694
695 if(fwdCount>0) {
696 forwardsPartialTrie.adoptInstead(builder2->build(USTRINGTRIE_BUILD_FAST, status));
697 if(U_FAILURE(status)) {
698 FB_TRACE(u_errorName(status),NULL,FALSE, -1);
699 return NULL__null;
700 }
701 }
702
703 return new SimpleFilteredSentenceBreakIterator(adopt.orphan(), forwardsPartialTrie.orphan(), backwardsTrie.orphan(), status);
704}
705
706
707// ----------- Base class implementation
708
709FilteredBreakIteratorBuilder::FilteredBreakIteratorBuilder() {
710}
711
712FilteredBreakIteratorBuilder::~FilteredBreakIteratorBuilder() {
713}
714
715FilteredBreakIteratorBuilder *
716FilteredBreakIteratorBuilder::createInstance(const Locale& where, UErrorCode& status) {
717 if(U_FAILURE(status)) return NULL__null;
718 LocalPointer<FilteredBreakIteratorBuilder> ret(new SimpleFilteredBreakIteratorBuilder(where, status), status);
719 return (U_SUCCESS(status))? ret.orphan(): NULL__null;
720}
721
722FilteredBreakIteratorBuilder *
723FilteredBreakIteratorBuilder::createInstance(UErrorCode &status) {
724 return createEmptyInstance(status);
725}
726
727FilteredBreakIteratorBuilder *
728FilteredBreakIteratorBuilder::createEmptyInstance(UErrorCode& status) {
729 if(U_FAILURE(status)) return NULL__null;
730 LocalPointer<FilteredBreakIteratorBuilder> ret(new SimpleFilteredBreakIteratorBuilder(status), status);
731 return (U_SUCCESS(status))? ret.orphan(): NULL__null;
732}
733
734U_NAMESPACE_END}
735
736#endif //#if !UCONFIG_NO_BREAK_ITERATION && !UCONFIG_NO_FILTERED_BREAK_ITERATION

../deps/icu-small/source/common/cmemory.h

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_DEBUG0 && defined(UPRV_MALLOC_COUNT)
37#include <stdio.h>
38#endif
39
40// uprv_memcpy and uprv_memmove
41#if defined(__clang__1)
42#define uprv_memcpy(dst, src, size)do { clang diagnostic push clang diagnostic ignored "-Waddress"
(void)0; (void)0; clang diagnostic pop :: memcpy(dst, src,
size); } while (false)
UPRV_BLOCK_MACRO_BEGINdo { \
43 /* Suppress warnings about addresses that will never be NULL */ \
44 _Pragma("clang diagnostic push")clang diagnostic push \
45 _Pragma("clang diagnostic ignored \"-Waddress\"")clang diagnostic ignored "-Waddress" \
46 U_ASSERT(dst != NULL)(void)0; \
47 U_ASSERT(src != NULL)(void)0; \
48 _Pragma("clang diagnostic pop")clang diagnostic pop \
49 U_STANDARD_CPP_NAMESPACE:: memcpy(dst, src, size); \
50} UPRV_BLOCK_MACRO_ENDwhile (false)
51#define uprv_memmove(dst, src, size)do { clang diagnostic push clang diagnostic ignored "-Waddress"
(void)0; (void)0; clang diagnostic pop :: memmove(dst, src
, size); } while (false)
UPRV_BLOCK_MACRO_BEGINdo { \
52 /* Suppress warnings about addresses that will never be NULL */ \
53 _Pragma("clang diagnostic push")clang diagnostic push \
54 _Pragma("clang diagnostic ignored \"-Waddress\"")clang diagnostic ignored "-Waddress" \
55 U_ASSERT(dst != NULL)(void)0; \
56 U_ASSERT(src != NULL)(void)0; \
57 _Pragma("clang diagnostic pop")clang diagnostic pop \
58 U_STANDARD_CPP_NAMESPACE:: memmove(dst, src, size); \
59} UPRV_BLOCK_MACRO_ENDwhile (false)
60#elif defined(__GNUC__4)
61#define uprv_memcpy(dst, src, size)do { clang diagnostic push clang diagnostic ignored "-Waddress"
(void)0; (void)0; clang diagnostic pop :: memcpy(dst, src,
size); } while (false)
UPRV_BLOCK_MACRO_BEGINdo { \
62 /* Suppress warnings about addresses that will never be NULL */ \
63 _Pragma("GCC diagnostic push")GCC diagnostic push \
64 _Pragma("GCC diagnostic ignored \"-Waddress\"")GCC diagnostic ignored "-Waddress" \
65 U_ASSERT(dst != NULL)(void)0; \
66 U_ASSERT(src != NULL)(void)0; \
67 _Pragma("GCC diagnostic pop")GCC diagnostic pop \
68 U_STANDARD_CPP_NAMESPACE:: memcpy(dst, src, size); \
69} UPRV_BLOCK_MACRO_ENDwhile (false)
70#define uprv_memmove(dst, src, size)do { clang diagnostic push clang diagnostic ignored "-Waddress"
(void)0; (void)0; clang diagnostic pop :: memmove(dst, src
, size); } while (false)
UPRV_BLOCK_MACRO_BEGINdo { \
71 /* Suppress warnings about addresses that will never be NULL */ \
72 _Pragma("GCC diagnostic push")GCC diagnostic push \
73 _Pragma("GCC diagnostic ignored \"-Waddress\"")GCC diagnostic ignored "-Waddress" \
74 U_ASSERT(dst != NULL)(void)0; \
75 U_ASSERT(src != NULL)(void)0; \
76 _Pragma("GCC diagnostic pop")GCC diagnostic pop \
77 U_STANDARD_CPP_NAMESPACE:: memmove(dst, src, size); \
78} UPRV_BLOCK_MACRO_ENDwhile (false)
79#else
80#define uprv_memcpy(dst, src, size)do { clang diagnostic push clang diagnostic ignored "-Waddress"
(void)0; (void)0; clang diagnostic pop :: memcpy(dst, src,
size); } while (false)
UPRV_BLOCK_MACRO_BEGINdo { \
81 U_ASSERT(dst != NULL)(void)0; \
82 U_ASSERT(src != NULL)(void)0; \
83 U_STANDARD_CPP_NAMESPACE:: memcpy(dst, src, size); \
84} UPRV_BLOCK_MACRO_ENDwhile (false)
85#define uprv_memmove(dst, src, size)do { clang diagnostic push clang diagnostic ignored "-Waddress"
(void)0; (void)0; clang diagnostic pop :: memmove(dst, src
, size); } while (false)
UPRV_BLOCK_MACRO_BEGINdo { \
86 U_ASSERT(dst != NULL)(void)0; \
87 U_ASSERT(src != NULL)(void)0; \
88 U_STANDARD_CPP_NAMESPACE:: memmove(dst, src, size); \
89} UPRV_BLOCK_MACRO_ENDwhile (false)
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#define UPRV_LENGTHOF(array)(int32_t)(sizeof(array)/sizeof((array)[0])) (int32_t)(sizeof(array)/sizeof((array)[0]))
100#define uprv_memset(buffer, mark, size):: memset(buffer, mark, size) U_STANDARD_CPP_NAMESPACE:: memset(buffer, mark, size)
101#define uprv_memcmp(buffer1, buffer2, size):: memcmp(buffer1, buffer2,size) U_STANDARD_CPP_NAMESPACE:: memcmp(buffer1, buffer2,size)
102#define uprv_memchr(ptr, value, num):: memchr(ptr, value, num) U_STANDARD_CPP_NAMESPACE:: memchr(ptr, value, num)
103
104U_CAPIextern "C" void * U_EXPORT2
105uprv_mallocuprv_malloc_71(size_t s) U_MALLOC_ATTR__attribute__ ((__malloc__)) U_ALLOC_SIZE_ATTR(1)__attribute__ ((alloc_size(1)));
106
107U_CAPIextern "C" void * U_EXPORT2
108uprv_reallocuprv_realloc_71(void *mem, size_t size) U_ALLOC_SIZE_ATTR(2)__attribute__ ((alloc_size(2)));
109
110U_CAPIextern "C" void U_EXPORT2
111uprv_freeuprv_free_71(void *mem);
112
113U_CAPIextern "C" void * U_EXPORT2
114uprv_callocuprv_calloc_71(size_t num, size_t size) U_MALLOC_ATTR__attribute__ ((__malloc__)) U_ALLOC_SIZE_ATTR2(1,2)__attribute__ ((alloc_size(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#define U_POINTER_MASK_LSB(ptr, mask)((uintptr_t)(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#define STATIC_NEW(type)[] () { alignas(type) static char storage[sizeof(type)]; return
new(storage) type();} ()
[] () { \
145 alignas(type) static char storage[sizeof(type)]; \
146 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 */
153U_CFUNCextern "C" UBool
154cmemory_cleanupcmemory_cleanup_71(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 */
163typedef 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 */
169U_CAPIextern "C" void U_EXPORT2
170uprv_deleteUObjectuprv_deleteUObject_71(void *obj);
171
172#ifdef __cplusplus201703L
173
174#include <utility>
175#include "unicode/uobject.h"
176
177U_NAMESPACE_BEGINnamespace icu_71 {
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 */
186template<typename T>
187class LocalMemory : public LocalPointerBase<T> {
188public:
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 explicit LocalMemory(T *p=NULL__null) : LocalPointerBase<T>(p) {}
4
Passing null pointer value via 1st parameter 'p'
5
Calling default constructor for 'LocalPointerBase<int>'
7
Returning from default constructor for 'LocalPointerBase<int>'
196 /**
197 * Move constructor, leaves src with isNull().
198 * @param src source smart pointer
199 */
200 LocalMemory(LocalMemory<T> &&src) U_NOEXCEPTnoexcept : LocalPointerBase<T>(src.ptr) {
201 src.ptr=NULL__null;
202 }
203 /**
204 * Destructor deletes the memory it owns.
205 */
206 ~LocalMemory() {
207 uprv_freeuprv_free_71(LocalPointerBase<T>::ptr);
208 }
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_NOEXCEPTnoexcept {
216 uprv_freeuprv_free_71(LocalPointerBase<T>::ptr);
217 LocalPointerBase<T>::ptr=src.ptr;
218 src.ptr=NULL__null;
219 return *this;
220 }
221 /**
222 * Swap pointers.
223 * @param other other smart pointer
224 */
225 void swap(LocalMemory<T> &other) U_NOEXCEPTnoexcept {
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_NOEXCEPTnoexcept {
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 void adoptInstead(T *p) {
244 uprv_freeuprv_free_71(LocalPointerBase<T>::ptr);
245 LocalPointerBase<T>::ptr=p;
246 }
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 T &operator[](ptrdiff_t i) const { return LocalPointerBase<T>::ptr[i]; }
13
Returning null reference
275};
276
277template<typename T>
278inline T *LocalMemory<T>::allocateInsteadAndReset(int32_t newCapacity) {
279 if(newCapacity>0) {
280 T *p=(T *)uprv_mallocuprv_malloc_71(newCapacity*sizeof(T));
281 if(p!=NULL__null) {
282 uprv_memset(p, 0, newCapacity*sizeof(T)):: memset(p, 0, newCapacity*sizeof(T));
283 uprv_freeuprv_free_71(LocalPointerBase<T>::ptr);
284 LocalPointerBase<T>::ptr=p;
285 }
286 return p;
287 } else {
288 return NULL__null;
289 }
290}
291
292
293template<typename T>
294inline T *LocalMemory<T>::allocateInsteadAndCopy(int32_t newCapacity, int32_t length) {
295 if(newCapacity>0) {
296 T *p=(T *)uprv_mallocuprv_malloc_71(newCapacity*sizeof(T));
297 if(p!=NULL__null) {
298 if(length>0) {
299 if(length>newCapacity) {
300 length=newCapacity;
301 }
302 uprv_memcpy(p, LocalPointerBase<T>::ptr, (size_t)length*sizeof(T))do { clang diagnostic push clang diagnostic ignored "-Waddress"
(void)0; (void)0; clang diagnostic pop :: memcpy(p, LocalPointerBase
<T>::ptr, (size_t)length*sizeof(T)); } while (false)
;
303 }
304 uprv_freeuprv_free_71(LocalPointerBase<T>::ptr);
305 LocalPointerBase<T>::ptr=p;
306 }
307 return p;
308 } else {
309 return NULL__null;
310 }
311}
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 */
331template<typename T, int32_t stackCapacity>
332class MaybeStackArray {
333public:
334 // No heap allocation. Use only on the stack.
335 static void* U_EXPORT2 operator new(size_t) U_NOEXCEPTnoexcept = delete;
336 static void* U_EXPORT2 operator new[](size_t) U_NOEXCEPTnoexcept = delete;
337#if U_HAVE_PLACEMENT_NEW1
338 static void* U_EXPORT2 operator new(size_t, void*) U_NOEXCEPTnoexcept = delete;
339#endif
340
341 /**
342 * Default constructor initializes with internal T[stackCapacity] buffer.
343 */
344 MaybeStackArray() : ptr(stackArray), capacity(stackCapacity), needToRelease(false) {}
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 MaybeStackArray(int32_t newCapacity, UErrorCode status) : MaybeStackArray() {
351 if (U_FAILURE(status)) {
352 return;
353 }
354 if (capacity < newCapacity) {
355 if (resize(newCapacity) == nullptr) {
356 status = U_MEMORY_ALLOCATION_ERROR;
357 }
358 }
359 }
360 /**
361 * Destructor deletes the array (if owned).
362 */
363 ~MaybeStackArray() { releaseArray(); }
364 /**
365 * Move constructor: transfers ownership or copies the stack array.
366 */
367 MaybeStackArray(MaybeStackArray<T, stackCapacity> &&src) U_NOEXCEPTnoexcept;
368 /**
369 * Move assignment: transfers ownership or copies the stack array.
370 */
371 MaybeStackArray<T, stackCapacity> &operator=(MaybeStackArray<T, stackCapacity> &&src) U_NOEXCEPTnoexcept;
372 /**
373 * Returns the array capacity (number of T items).
374 * @return array capacity
375 */
376 int32_t getCapacity() const { return capacity; }
377 /**
378 * Access without ownership change.
379 * @return the array pointer
380 */
381 T *getAlias() const { return ptr; }
382 /**
383 * Returns the array limit. Simple convenience method.
384 * @return getAlias()+getCapacity()
385 */
386 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 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 T &operator[](ptrdiff_t i) { return ptr[i]; }
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 void aliasInstead(T *otherArray, int32_t otherCapacity) {
410 if(otherArray!=NULL__null && otherCapacity>0) {
411 releaseArray();
412 ptr=otherArray;
413 capacity=otherCapacity;
414 needToRelease=false;
415 }
416 }
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
440protected:
441 // Resizes the array to the size of src, then copies the contents of src.
442 void copyFrom(const MaybeStackArray &src, UErrorCode &status) {
443 if (U_FAILURE(status)) {
444 return;
445 }
446 if (this->resize(src.capacity, 0) == NULL__null) {
447 status = U_MEMORY_ALLOCATION_ERROR;
448 return;
449 }
450 uprv_memcpy(this->ptr, src.ptr, (size_t)capacity * sizeof(T))do { clang diagnostic push clang diagnostic ignored "-Waddress"
(void)0; (void)0; clang diagnostic pop :: memcpy(this->
ptr, src.ptr, (size_t)capacity * sizeof(T)); } while (false)
;
451 }
452
453private:
454 T *ptr;
455 int32_t capacity;
456 UBool needToRelease;
457 T stackArray[stackCapacity];
458 void releaseArray() {
459 if(needToRelease) {
460 uprv_freeuprv_free_71(ptr);
461 }
462 }
463 void resetToStackArray() {
464 ptr=stackArray;
465 capacity=stackCapacity;
466 needToRelease=false;
467 }
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
476template<typename T, int32_t stackCapacity>
477icu::MaybeStackArray<T, stackCapacity>::MaybeStackArray(
478 MaybeStackArray <T, stackCapacity>&& src) U_NOEXCEPTnoexcept
479 : ptr(src.ptr), capacity(src.capacity), needToRelease(src.needToRelease) {
480 if (src.ptr == src.stackArray) {
481 ptr = stackArray;
482 uprv_memcpy(stackArray, src.stackArray, sizeof(T) * src.capacity)do { clang diagnostic push clang diagnostic ignored "-Waddress"
(void)0; (void)0; clang diagnostic pop :: memcpy(stackArray
, src.stackArray, sizeof(T) * src.capacity); } while (false)
;
483 } else {
484 src.resetToStackArray(); // take ownership away from src
485 }
486}
487
488template<typename T, int32_t stackCapacity>
489inline MaybeStackArray <T, stackCapacity>&
490MaybeStackArray<T, stackCapacity>::operator=(MaybeStackArray <T, stackCapacity>&& src) U_NOEXCEPTnoexcept {
491 releaseArray(); // in case this instance had its own memory allocated
492 capacity = src.capacity;
493 needToRelease = src.needToRelease;
494 if (src.ptr == src.stackArray) {
495 ptr = stackArray;
496 uprv_memcpy(stackArray, src.stackArray, sizeof(T) * src.capacity)do { clang diagnostic push clang diagnostic ignored "-Waddress"
(void)0; (void)0; clang diagnostic pop :: memcpy(stackArray
, src.stackArray, sizeof(T) * src.capacity); } while (false)
;
497 } else {
498 ptr = src.ptr;
499 src.resetToStackArray(); // take ownership away from src
500 }
501 return *this;
502}
503
504template<typename T, int32_t stackCapacity>
505inline T *MaybeStackArray<T, stackCapacity>::resize(int32_t newCapacity, int32_t length) {
506 if(newCapacity>0) {
507#if U_DEBUG0 && defined(UPRV_MALLOC_COUNT)
508 ::fprintf(::stderrstderr, "MaybeStackArray (resize) alloc %d * %lu\n", newCapacity, sizeof(T));
509#endif
510 T *p=(T *)uprv_mallocuprv_malloc_71(newCapacity*sizeof(T));
511 if(p!=NULL__null) {
512 if(length>0) {
513 if(length>capacity) {
514 length=capacity;
515 }
516 if(length>newCapacity) {
517 length=newCapacity;
518 }
519 uprv_memcpy(p, ptr, (size_t)length*sizeof(T))do { clang diagnostic push clang diagnostic ignored "-Waddress"
(void)0; (void)0; clang diagnostic pop :: memcpy(p, ptr, (
size_t)length*sizeof(T)); } while (false)
;
520 }
521 releaseArray();
522 ptr=p;
523 capacity=newCapacity;
524 needToRelease=true;
525 }
526 return p;
527 } else {
528 return NULL__null;
529 }
530}
531
532template<typename T, int32_t stackCapacity>
533inline T *MaybeStackArray<T, stackCapacity>::orphanOrClone(int32_t length, int32_t &resultCapacity) {
534 T *p;
535 if(needToRelease) {
536 p=ptr;
537 } else if(length<=0) {
538 return NULL__null;
539 } else {
540 if(length>capacity) {
541 length=capacity;
542 }
543 p=(T *)uprv_mallocuprv_malloc_71(length*sizeof(T));
544#if U_DEBUG0 && defined(UPRV_MALLOC_COUNT)
545 ::fprintf(::stderrstderr,"MaybeStacArray (orphan) alloc %d * %lu\n", length,sizeof(T));
546#endif
547 if(p==NULL__null) {
548 return NULL__null;
549 }
550 uprv_memcpy(p, ptr, (size_t)length*sizeof(T))do { clang diagnostic push clang diagnostic ignored "-Waddress"
(void)0; (void)0; clang diagnostic pop :: memcpy(p, ptr, (
size_t)length*sizeof(T)); } while (false)
;
551 }
552 resultCapacity=length;
553 resetToStackArray();
554 return p;
555}
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 */
567template<typename H, typename T, int32_t stackCapacity>
568class MaybeStackHeaderAndArray {
569public:
570 // No heap allocation. Use only on the stack.
571 static void* U_EXPORT2 operator new(size_t) U_NOEXCEPTnoexcept = delete;
572 static void* U_EXPORT2 operator new[](size_t) U_NOEXCEPTnoexcept = delete;
573#if U_HAVE_PLACEMENT_NEW1
574 static void* U_EXPORT2 operator new(size_t, void*) U_NOEXCEPTnoexcept = 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__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);
655private:
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_freeuprv_free_71(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
675template<typename H, typename T, int32_t stackCapacity>
676inline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::resize(int32_t newCapacity,
677 int32_t length) {
678 if(newCapacity>=0) {
679#if U_DEBUG0 && defined(UPRV_MALLOC_COUNT)
680 ::fprintf(::stderrstderr,"MaybeStackHeaderAndArray alloc %d + %d * %ul\n", sizeof(H),newCapacity,sizeof(T));
681#endif
682 H *p=(H *)uprv_mallocuprv_malloc_71(sizeof(H)+newCapacity*sizeof(T));
683 if(p!=NULL__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))do { clang diagnostic push clang diagnostic ignored "-Waddress"
(void)0; (void)0; clang diagnostic pop :: memcpy(p, ptr, sizeof
(H)+(size_t)length*sizeof(T)); } while (false)
;
695 releaseMemory();
696 ptr=p;
697 capacity=newCapacity;
698 needToRelease=true;
699 }
700 return p;
701 } else {
702 return NULL__null;
703 }
704}
705
706template<typename H, typename T, int32_t stackCapacity>
707inline 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_DEBUG0 && defined(UPRV_MALLOC_COUNT)
719 ::fprintf(::stderrstderr,"MaybeStackHeaderAndArray (orphan) alloc %ul + %d * %lu\n", sizeof(H),length,sizeof(T));
720#endif
721 p=(H *)uprv_mallocuprv_malloc_71(sizeof(H)+length*sizeof(T));
722 if(p==NULL__null) {
723 return NULL__null;
724 }
725 uprv_memcpy(p, ptr, sizeof(H)+(size_t)length*sizeof(T))do { clang diagnostic push clang diagnostic ignored "-Waddress"
(void)0; (void)0; clang diagnostic pop :: memcpy(p, ptr, sizeof
(H)+(size_t)length*sizeof(T)); } while (false)
;
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 */
757template<typename T, int32_t stackCapacity = 8>
758class MemoryPool : public UMemory {
759public:
760 MemoryPool() : fCount(0), fPool() {}
761
762 ~MemoryPool() {
763 for (int32_t i = 0; i < fCount; ++i) {
764 delete fPool[i];
765 }
766 }
767
768 MemoryPool(const MemoryPool&) = delete;
769 MemoryPool& operator=(const MemoryPool&) = delete;
770
771 MemoryPool(MemoryPool&& other) U_NOEXCEPTnoexcept : fCount(other.fCount),
772 fPool(std::move(other.fPool)) {
773 other.fCount = 0;
774 }
775
776 MemoryPool& operator=(MemoryPool&& other) U_NOEXCEPTnoexcept {
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 T* create(Args&&... args) {
797 int32_t capacity = fPool.getCapacity();
798 if (fCount == capacity &&
799 fPool.resize(capacity == stackCapacity ? 4 * capacity : 2 * capacity,
800 capacity) == nullptr) {
801 return nullptr;
802 }
803 return fPool[fCount++] = new T(std::forward<Args>(args)...);
804 }
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
825protected:
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 */
850template<typename T, int32_t stackCapacity = 8>
851class MaybeStackVector : protected MemoryPool<T, stackCapacity> {
852public:
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
897U_NAMESPACE_END}
898
899#endif /* __cplusplus */
900#endif /* CMEMORY_H */

../deps/icu-small/source/common/unicode/localpointer.h

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) 2009-2016, International Business Machines
7* Corporation and others. All Rights Reserved.
8*
9*******************************************************************************
10* file name: localpointer.h
11* encoding: UTF-8
12* tab size: 8 (not used)
13* indentation:4
14*
15* created on: 2009nov13
16* created by: Markus W. Scherer
17*/
18
19#ifndef __LOCALPOINTER_H__
20#define __LOCALPOINTER_H__
21
22/**
23 * \file
24 * \brief C++ API: "Smart pointers" for use with and in ICU4C C++ code.
25 *
26 * These classes are inspired by
27 * - std::auto_ptr
28 * - boost::scoped_ptr & boost::scoped_array
29 * - Taligent Safe Pointers (TOnlyPointerTo)
30 *
31 * but none of those provide for all of the goals for ICU smart pointers:
32 * - Smart pointer owns the object and releases it when it goes out of scope.
33 * - No transfer of ownership via copy/assignment to reduce misuse. Simpler & more robust.
34 * - ICU-compatible: No exceptions.
35 * - Need to be able to orphan/release the pointer and its ownership.
36 * - Need variants for normal C++ object pointers, C++ arrays, and ICU C service objects.
37 *
38 * For details see https://icu.unicode.org/design/cpp/scoped_ptr
39 */
40
41#include "unicode/utypes.h"
42
43#if U_SHOW_CPLUSPLUS_API1
44
45#include <memory>
46
47U_NAMESPACE_BEGINnamespace icu_71 {
48
49/**
50 * "Smart pointer" base class; do not use directly: use LocalPointer etc.
51 *
52 * Base class for smart pointer classes that do not throw exceptions.
53 *
54 * Do not use this base class directly, since it does not delete its pointer.
55 * A subclass must implement methods that delete the pointer:
56 * Destructor and adoptInstead().
57 *
58 * There is no operator T *() provided because the programmer must decide
59 * whether to use getAlias() (without transfer of ownership) or orphan()
60 * (with transfer of ownership and NULLing of the pointer).
61 *
62 * @see LocalPointer
63 * @see LocalArray
64 * @see U_DEFINE_LOCAL_OPEN_POINTER
65 * @stable ICU 4.4
66 */
67template<typename T>
68class LocalPointerBase {
69public:
70 // No heap allocation. Use only on the stack.
71 static void* U_EXPORT2 operator new(size_t) = delete;
72 static void* U_EXPORT2 operator new[](size_t) = delete;
73#if U_HAVE_PLACEMENT_NEW1
74 static void* U_EXPORT2 operator new(size_t, void*) = delete;
75#endif
76
77 /**
78 * Constructor takes ownership.
79 * @param p simple pointer to an object that is adopted
80 * @stable ICU 4.4
81 */
82 explicit LocalPointerBase(T *p=NULL__null) : ptr(p) {}
6
Null pointer value stored to 'partials.ptr'
83 /**
84 * Destructor deletes the object it owns.
85 * Subclass must override: Base class does nothing.
86 * @stable ICU 4.4
87 */
88 ~LocalPointerBase() { /* delete ptr; */ }
89 /**
90 * NULL check.
91 * @return true if ==NULL
92 * @stable ICU 4.4
93 */
94 UBool isNull() const { return ptr==NULL__null; }
95 /**
96 * NULL check.
97 * @return true if !=NULL
98 * @stable ICU 4.4
99 */
100 UBool isValid() const { return ptr!=NULL__null; }
101 /**
102 * Comparison with a simple pointer, so that existing code
103 * with ==NULL need not be changed.
104 * @param other simple pointer for comparison
105 * @return true if this pointer value equals other
106 * @stable ICU 4.4
107 */
108 bool operator==(const T *other) const { return ptr==other; }
109 /**
110 * Comparison with a simple pointer, so that existing code
111 * with !=NULL need not be changed.
112 * @param other simple pointer for comparison
113 * @return true if this pointer value differs from other
114 * @stable ICU 4.4
115 */
116 bool operator!=(const T *other) const { return ptr!=other; }
117 /**
118 * Access without ownership change.
119 * @return the pointer value
120 * @stable ICU 4.4
121 */
122 T *getAlias() const { return ptr; }
123 /**
124 * Access without ownership change.
125 * @return the pointer value as a reference
126 * @stable ICU 4.4
127 */
128 T &operator*() const { return *ptr; }
129 /**
130 * Access without ownership change.
131 * @return the pointer value
132 * @stable ICU 4.4
133 */
134 T *operator->() const { return ptr; }
135 /**
136 * Gives up ownership; the internal pointer becomes NULL.
137 * @return the pointer value;
138 * caller becomes responsible for deleting the object
139 * @stable ICU 4.4
140 */
141 T *orphan() {
142 T *p=ptr;
143 ptr=NULL__null;
144 return p;
145 }
146 /**
147 * Deletes the object it owns,
148 * and adopts (takes ownership of) the one passed in.
149 * Subclass must override: Base class does not delete the object.
150 * @param p simple pointer to an object that is adopted
151 * @stable ICU 4.4
152 */
153 void adoptInstead(T *p) {
154 // delete ptr;
155 ptr=p;
156 }
157protected:
158 /**
159 * Actual pointer.
160 * @internal
161 */
162 T *ptr;
163private:
164 // No comparison operators with other LocalPointerBases.
165 bool operator==(const LocalPointerBase<T> &other);
166 bool operator!=(const LocalPointerBase<T> &other);
167 // No ownership sharing: No copy constructor, no assignment operator.
168 LocalPointerBase(const LocalPointerBase<T> &other);
169 void operator=(const LocalPointerBase<T> &other);
170};
171
172/**
173 * "Smart pointer" class, deletes objects via the standard C++ delete operator.
174 * For most methods see the LocalPointerBase base class.
175 *
176 * Usage example:
177 * \code
178 * LocalPointer<UnicodeString> s(new UnicodeString((UChar32)0x50005));
179 * int32_t length=s->length(); // 2
180 * char16_t lead=s->charAt(0); // 0xd900
181 * if(some condition) { return; } // no need to explicitly delete the pointer
182 * s.adoptInstead(new UnicodeString((char16_t)0xfffc));
183 * length=s->length(); // 1
184 * // no need to explicitly delete the pointer
185 * \endcode
186 *
187 * @see LocalPointerBase
188 * @stable ICU 4.4
189 */
190template<typename T>
191class LocalPointer : public LocalPointerBase<T> {
192public:
193 using LocalPointerBase<T>::operator*;
194 using LocalPointerBase<T>::operator->;
195 /**
196 * Constructor takes ownership.
197 * @param p simple pointer to an object that is adopted
198 * @stable ICU 4.4
199 */
200 explicit LocalPointer(T *p=NULL__null) : LocalPointerBase<T>(p) {}
201 /**
202 * Constructor takes ownership and reports an error if NULL.
203 *
204 * This constructor is intended to be used with other-class constructors
205 * that may report a failure UErrorCode,
206 * so that callers need to check only for U_FAILURE(errorCode)
207 * and not also separately for isNull().
208 *
209 * @param p simple pointer to an object that is adopted
210 * @param errorCode in/out UErrorCode, set to U_MEMORY_ALLOCATION_ERROR
211 * if p==NULL and no other failure code had been set
212 * @stable ICU 55
213 */
214 LocalPointer(T *p, UErrorCode &errorCode) : LocalPointerBase<T>(p) {
215 if(p==NULL__null && U_SUCCESS(errorCode)) {
216 errorCode=U_MEMORY_ALLOCATION_ERROR;
217 }
218 }
219 /**
220 * Move constructor, leaves src with isNull().
221 * @param src source smart pointer
222 * @stable ICU 56
223 */
224 LocalPointer(LocalPointer<T> &&src) U_NOEXCEPTnoexcept : LocalPointerBase<T>(src.ptr) {
225 src.ptr=NULL__null;
226 }
227
228 /**
229 * Constructs a LocalPointer from a C++11 std::unique_ptr.
230 * The LocalPointer steals the object owned by the std::unique_ptr.
231 *
232 * This constructor works via move semantics. If your std::unique_ptr is
233 * in a local variable, you must use std::move.
234 *
235 * @param p The std::unique_ptr from which the pointer will be stolen.
236 * @stable ICU 64
237 */
238 explicit LocalPointer(std::unique_ptr<T> &&p)
239 : LocalPointerBase<T>(p.release()) {}
240
241 /**
242 * Destructor deletes the object it owns.
243 * @stable ICU 4.4
244 */
245 ~LocalPointer() {
246 delete LocalPointerBase<T>::ptr;
247 }
248 /**
249 * Move assignment operator, leaves src with isNull().
250 * The behavior is undefined if *this and src are the same object.
251 * @param src source smart pointer
252 * @return *this
253 * @stable ICU 56
254 */
255 LocalPointer<T> &operator=(LocalPointer<T> &&src) U_NOEXCEPTnoexcept {
256 delete LocalPointerBase<T>::ptr;
257 LocalPointerBase<T>::ptr=src.ptr;
258 src.ptr=NULL__null;
259 return *this;
260 }
261
262 /**
263 * Move-assign from an std::unique_ptr to this LocalPointer.
264 * Steals the pointer from the std::unique_ptr.
265 *
266 * @param p The std::unique_ptr from which the pointer will be stolen.
267 * @return *this
268 * @stable ICU 64
269 */
270 LocalPointer<T> &operator=(std::unique_ptr<T> &&p) U_NOEXCEPTnoexcept {
271 adoptInstead(p.release());
272 return *this;
273 }
274
275 /**
276 * Swap pointers.
277 * @param other other smart pointer
278 * @stable ICU 56
279 */
280 void swap(LocalPointer<T> &other) U_NOEXCEPTnoexcept {
281 T *temp=LocalPointerBase<T>::ptr;
282 LocalPointerBase<T>::ptr=other.ptr;
283 other.ptr=temp;
284 }
285 /**
286 * Non-member LocalPointer swap function.
287 * @param p1 will get p2's pointer
288 * @param p2 will get p1's pointer
289 * @stable ICU 56
290 */
291 friend inline void swap(LocalPointer<T> &p1, LocalPointer<T> &p2) U_NOEXCEPTnoexcept {
292 p1.swap(p2);
293 }
294 /**
295 * Deletes the object it owns,
296 * and adopts (takes ownership of) the one passed in.
297 * @param p simple pointer to an object that is adopted
298 * @stable ICU 4.4
299 */
300 void adoptInstead(T *p) {
301 delete LocalPointerBase<T>::ptr;
302 LocalPointerBase<T>::ptr=p;
303 }
304 /**
305 * Deletes the object it owns,
306 * and adopts (takes ownership of) the one passed in.
307 *
308 * If U_FAILURE(errorCode), then the current object is retained and the new one deleted.
309 *
310 * If U_SUCCESS(errorCode) but the input pointer is NULL,
311 * then U_MEMORY_ALLOCATION_ERROR is set,
312 * the current object is deleted, and NULL is set.
313 *
314 * @param p simple pointer to an object that is adopted
315 * @param errorCode in/out UErrorCode, set to U_MEMORY_ALLOCATION_ERROR
316 * if p==NULL and no other failure code had been set
317 * @stable ICU 55
318 */
319 void adoptInsteadAndCheckErrorCode(T *p, UErrorCode &errorCode) {
320 if(U_SUCCESS(errorCode)) {
321 delete LocalPointerBase<T>::ptr;
322 LocalPointerBase<T>::ptr=p;
323 if(p==NULL__null) {
324 errorCode=U_MEMORY_ALLOCATION_ERROR;
325 }
326 } else {
327 delete p;
328 }
329 }
330
331 /**
332 * Conversion operator to a C++11 std::unique_ptr.
333 * Disowns the object and gives it to the returned std::unique_ptr.
334 *
335 * This operator works via move semantics. If your LocalPointer is
336 * in a local variable, you must use std::move.
337 *
338 * @return An std::unique_ptr owning the pointer previously owned by this
339 * icu::LocalPointer.
340 * @stable ICU 64
341 */
342 operator std::unique_ptr<T> () && {
343 return std::unique_ptr<T>(LocalPointerBase<T>::orphan());
344 }
345};
346
347/**
348 * "Smart pointer" class, deletes objects via the C++ array delete[] operator.
349 * For most methods see the LocalPointerBase base class.
350 * Adds operator[] for array item access.
351 *
352 * Usage example:
353 * \code
354 * LocalArray<UnicodeString> a(new UnicodeString[2]);
355 * a[0].append((char16_t)0x61);
356 * if(some condition) { return; } // no need to explicitly delete the array
357 * a.adoptInstead(new UnicodeString[4]);
358 * a[3].append((char16_t)0x62).append((char16_t)0x63).reverse();
359 * // no need to explicitly delete the array
360 * \endcode
361 *
362 * @see LocalPointerBase
363 * @stable ICU 4.4
364 */
365template<typename T>
366class LocalArray : public LocalPointerBase<T> {
367public:
368 using LocalPointerBase<T>::operator*;
369 using LocalPointerBase<T>::operator->;
370 /**
371 * Constructor takes ownership.
372 * @param p simple pointer to an array of T objects that is adopted
373 * @stable ICU 4.4
374 */
375 explicit LocalArray(T *p=NULL__null) : LocalPointerBase<T>(p) {}
376 /**
377 * Constructor takes ownership and reports an error if NULL.
378 *
379 * This constructor is intended to be used with other-class constructors
380 * that may report a failure UErrorCode,
381 * so that callers need to check only for U_FAILURE(errorCode)
382 * and not also separately for isNull().
383 *
384 * @param p simple pointer to an array of T objects that is adopted
385 * @param errorCode in/out UErrorCode, set to U_MEMORY_ALLOCATION_ERROR
386 * if p==NULL and no other failure code had been set
387 * @stable ICU 56
388 */
389 LocalArray(T *p, UErrorCode &errorCode) : LocalPointerBase<T>(p) {
390 if(p==NULL__null && U_SUCCESS(errorCode)) {
391 errorCode=U_MEMORY_ALLOCATION_ERROR;
392 }
393 }
394 /**
395 * Move constructor, leaves src with isNull().
396 * @param src source smart pointer
397 * @stable ICU 56
398 */
399 LocalArray(LocalArray<T> &&src) U_NOEXCEPTnoexcept : LocalPointerBase<T>(src.ptr) {
400 src.ptr=NULL__null;
401 }
402
403 /**
404 * Constructs a LocalArray from a C++11 std::unique_ptr of an array type.
405 * The LocalPointer steals the array owned by the std::unique_ptr.
406 *
407 * This constructor works via move semantics. If your std::unique_ptr is
408 * in a local variable, you must use std::move.
409 *
410 * @param p The std::unique_ptr from which the array will be stolen.
411 * @stable ICU 64
412 */
413 explicit LocalArray(std::unique_ptr<T[]> &&p)
414 : LocalPointerBase<T>(p.release()) {}
415
416 /**
417 * Destructor deletes the array it owns.
418 * @stable ICU 4.4
419 */
420 ~LocalArray() {
421 delete[] LocalPointerBase<T>::ptr;
422 }
423 /**
424 * Move assignment operator, leaves src with isNull().
425 * The behavior is undefined if *this and src are the same object.
426 * @param src source smart pointer
427 * @return *this
428 * @stable ICU 56
429 */
430 LocalArray<T> &operator=(LocalArray<T> &&src) U_NOEXCEPTnoexcept {
431 delete[] LocalPointerBase<T>::ptr;
432 LocalPointerBase<T>::ptr=src.ptr;
433 src.ptr=NULL__null;
434 return *this;
435 }
436
437 /**
438 * Move-assign from an std::unique_ptr to this LocalPointer.
439 * Steals the array from the std::unique_ptr.
440 *
441 * @param p The std::unique_ptr from which the array will be stolen.
442 * @return *this
443 * @stable ICU 64
444 */
445 LocalArray<T> &operator=(std::unique_ptr<T[]> &&p) U_NOEXCEPTnoexcept {
446 adoptInstead(p.release());
447 return *this;
448 }
449
450 /**
451 * Swap pointers.
452 * @param other other smart pointer
453 * @stable ICU 56
454 */
455 void swap(LocalArray<T> &other) U_NOEXCEPTnoexcept {
456 T *temp=LocalPointerBase<T>::ptr;
457 LocalPointerBase<T>::ptr=other.ptr;
458 other.ptr=temp;
459 }
460 /**
461 * Non-member LocalArray swap function.
462 * @param p1 will get p2's pointer
463 * @param p2 will get p1's pointer
464 * @stable ICU 56
465 */
466 friend inline void swap(LocalArray<T> &p1, LocalArray<T> &p2) U_NOEXCEPTnoexcept {
467 p1.swap(p2);
468 }
469 /**
470 * Deletes the array it owns,
471 * and adopts (takes ownership of) the one passed in.
472 * @param p simple pointer to an array of T objects that is adopted
473 * @stable ICU 4.4
474 */
475 void adoptInstead(T *p) {
476 delete[] LocalPointerBase<T>::ptr;
477 LocalPointerBase<T>::ptr=p;
478 }
479 /**
480 * Deletes the array it owns,
481 * and adopts (takes ownership of) the one passed in.
482 *
483 * If U_FAILURE(errorCode), then the current array is retained and the new one deleted.
484 *
485 * If U_SUCCESS(errorCode) but the input pointer is NULL,
486 * then U_MEMORY_ALLOCATION_ERROR is set,
487 * the current array is deleted, and NULL is set.
488 *
489 * @param p simple pointer to an array of T objects that is adopted
490 * @param errorCode in/out UErrorCode, set to U_MEMORY_ALLOCATION_ERROR
491 * if p==NULL and no other failure code had been set
492 * @stable ICU 56
493 */
494 void adoptInsteadAndCheckErrorCode(T *p, UErrorCode &errorCode) {
495 if(U_SUCCESS(errorCode)) {
496 delete[] LocalPointerBase<T>::ptr;
497 LocalPointerBase<T>::ptr=p;
498 if(p==NULL__null) {
499 errorCode=U_MEMORY_ALLOCATION_ERROR;
500 }
501 } else {
502 delete[] p;
503 }
504 }
505 /**
506 * Array item access (writable).
507 * No index bounds check.
508 * @param i array index
509 * @return reference to the array item
510 * @stable ICU 4.4
511 */
512 T &operator[](ptrdiff_t i) const { return LocalPointerBase<T>::ptr[i]; }
513
514 /**
515 * Conversion operator to a C++11 std::unique_ptr.
516 * Disowns the object and gives it to the returned std::unique_ptr.
517 *
518 * This operator works via move semantics. If your LocalPointer is
519 * in a local variable, you must use std::move.
520 *
521 * @return An std::unique_ptr owning the pointer previously owned by this
522 * icu::LocalPointer.
523 * @stable ICU 64
524 */
525 operator std::unique_ptr<T[]> () && {
526 return std::unique_ptr<T[]>(LocalPointerBase<T>::orphan());
527 }
528};
529
530/**
531 * \def U_DEFINE_LOCAL_OPEN_POINTER
532 * "Smart pointer" definition macro, deletes objects via the closeFunction.
533 * Defines a subclass of LocalPointerBase which works just
534 * like LocalPointer<Type> except that this subclass will use the closeFunction
535 * rather than the C++ delete operator.
536 *
537 * Usage example:
538 * \code
539 * LocalUCaseMapPointer csm(ucasemap_open(localeID, options, &errorCode));
540 * utf8OutLength=ucasemap_utf8ToLower(csm.getAlias(),
541 * utf8Out, (int32_t)sizeof(utf8Out),
542 * utf8In, utf8InLength, &errorCode);
543 * if(U_FAILURE(errorCode)) { return; } // no need to explicitly delete the UCaseMap
544 * \endcode
545 *
546 * @see LocalPointerBase
547 * @see LocalPointer
548 * @stable ICU 4.4
549 */
550#define U_DEFINE_LOCAL_OPEN_POINTER(LocalPointerClassName, Type, closeFunction)class LocalPointerClassName : public LocalPointerBase<Type
> { public: using LocalPointerBase<Type>::operator*;
using LocalPointerBase<Type>::operator->; explicit LocalPointerClassName
(Type *p=__null) : LocalPointerBase<Type>(p) {} LocalPointerClassName
(LocalPointerClassName &&src) noexcept : LocalPointerBase
<Type>(src.ptr) { src.ptr=__null; } explicit LocalPointerClassName
(std::unique_ptr<Type, decltype(&closeFunction)> &&
p) : LocalPointerBase<Type>(p.release()) {} ~LocalPointerClassName
() { if (ptr != __null) { closeFunction(ptr); } } LocalPointerClassName
&operator=(LocalPointerClassName &&src) noexcept
{ if (ptr != __null) { closeFunction(ptr); } LocalPointerBase
<Type>::ptr=src.ptr; src.ptr=__null; return *this; } LocalPointerClassName
&operator=(std::unique_ptr<Type, decltype(&closeFunction
)> &&p) { adoptInstead(p.release()); return *this;
} void swap(LocalPointerClassName &other) noexcept { Type
*temp=LocalPointerBase<Type>::ptr; LocalPointerBase<
Type>::ptr=other.ptr; other.ptr=temp; } friend inline void
swap(LocalPointerClassName &p1, LocalPointerClassName &
p2) noexcept { p1.swap(p2); } void adoptInstead(Type *p) { if
(ptr != __null) { closeFunction(ptr); } ptr=p; } operator std
::unique_ptr<Type, decltype(&closeFunction)> () &&
{ return std::unique_ptr<Type, decltype(&closeFunction
)>(LocalPointerBase<Type>::orphan(), closeFunction);
} }
\
551 class LocalPointerClassName : public LocalPointerBase<Type> { \
552 public: \
553 using LocalPointerBase<Type>::operator*; \
554 using LocalPointerBase<Type>::operator->; \
555 explicit LocalPointerClassName(Type *p=NULL__null) : LocalPointerBase<Type>(p) {} \
556 LocalPointerClassName(LocalPointerClassName &&src) U_NOEXCEPTnoexcept \
557 : LocalPointerBase<Type>(src.ptr) { \
558 src.ptr=NULL__null; \
559 } \
560 /* TODO: Be agnostic of the deleter function signature from the user-provided std::unique_ptr? */ \
561 explicit LocalPointerClassName(std::unique_ptr<Type, decltype(&closeFunction)> &&p) \
562 : LocalPointerBase<Type>(p.release()) {} \
563 ~LocalPointerClassName() { if (ptr != NULL__null) { closeFunction(ptr); } } \
564 LocalPointerClassName &operator=(LocalPointerClassName &&src) U_NOEXCEPTnoexcept { \
565 if (ptr != NULL__null) { closeFunction(ptr); } \
566 LocalPointerBase<Type>::ptr=src.ptr; \
567 src.ptr=NULL__null; \
568 return *this; \
569 } \
570 /* TODO: Be agnostic of the deleter function signature from the user-provided std::unique_ptr? */ \
571 LocalPointerClassName &operator=(std::unique_ptr<Type, decltype(&closeFunction)> &&p) { \
572 adoptInstead(p.release()); \
573 return *this; \
574 } \
575 void swap(LocalPointerClassName &other) U_NOEXCEPTnoexcept { \
576 Type *temp=LocalPointerBase<Type>::ptr; \
577 LocalPointerBase<Type>::ptr=other.ptr; \
578 other.ptr=temp; \
579 } \
580 friend inline void swap(LocalPointerClassName &p1, LocalPointerClassName &p2) U_NOEXCEPTnoexcept { \
581 p1.swap(p2); \
582 } \
583 void adoptInstead(Type *p) { \
584 if (ptr != NULL__null) { closeFunction(ptr); } \
585 ptr=p; \
586 } \
587 operator std::unique_ptr<Type, decltype(&closeFunction)> () && { \
588 return std::unique_ptr<Type, decltype(&closeFunction)>(LocalPointerBase<Type>::orphan(), closeFunction); \
589 } \
590 }
591
592U_NAMESPACE_END}
593
594#endif /* U_SHOW_CPLUSPLUS_API */
595#endif /* __LOCALPOINTER_H__ */