File: | out/../deps/icu-small/source/common/cmemory.h |
Warning: | line 274, column 40 Returning null reference |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | ||||
25 | U_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> | |||
33 | static 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 | */ | |||
52 | static 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 | */ | |||
61 | class 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 | */ | |||
123 | UStringSet::~UStringSet() {} | |||
124 | ||||
125 | /* ----------------------------------------------------------- */ | |||
126 | ||||
127 | ||||
128 | /* Filtered Break constants */ | |||
129 | static const int32_t kPARTIAL = (1<<0); //< partial - need to run through forward trie | |||
130 | static const int32_t kMATCH = (1<<1); //< exact match - skip this one. | |||
131 | static const int32_t kSuppressInReverse = (1<<0); | |||
132 | static const int32_t kAddToForward = (1<<1); | |||
133 | static const UChar kFULLSTOP = 0x002E; // '.' | |||
134 | ||||
135 | /** | |||
136 | * Shared data for SimpleFilteredSentenceBreakIterator | |||
137 | */ | |||
138 | class SimpleFilteredSentenceBreakData : public UMemory { | |||
139 | public: | |||
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 | ||||
160 | private: | |||
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 | ||||
168 | SimpleFilteredSentenceBreakData::~SimpleFilteredSentenceBreakData() {} | |||
169 | ||||
170 | /** | |||
171 | * Concrete implementation | |||
172 | */ | |||
173 | class SimpleFilteredSentenceBreakIterator : public BreakIterator { | |||
174 | public: | |||
175 | SimpleFilteredSentenceBreakIterator(BreakIterator *adopt, UCharsTrie *forwards, UCharsTrie *backwards, UErrorCode &status); | |||
176 | SimpleFilteredSentenceBreakIterator(const SimpleFilteredSentenceBreakIterator& other); | |||
177 | virtual ~SimpleFilteredSentenceBreakIterator(); | |||
178 | private: | |||
179 | SimpleFilteredSentenceBreakData *fData; | |||
180 | LocalPointer<BreakIterator> fDelegate; | |||
181 | LocalUTextPointer fText; | |||
182 | ||||
183 | /* -- subclass interface -- */ | |||
184 | public: | |||
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 | ||||
220 | private: | |||
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 | ||||
253 | SimpleFilteredSentenceBreakIterator::SimpleFilteredSentenceBreakIterator(const SimpleFilteredSentenceBreakIterator& other) | |||
254 | : BreakIterator(other), fData(other.fData->incr()), fDelegate(other.fDelegate->clone()) | |||
255 | { | |||
256 | } | |||
257 | ||||
258 | ||||
259 | SimpleFilteredSentenceBreakIterator::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 | ||||
273 | SimpleFilteredSentenceBreakIterator::~SimpleFilteredSentenceBreakIterator() { | |||
274 | fData = fData->decr(); | |||
275 | } | |||
276 | ||||
277 | void SimpleFilteredSentenceBreakIterator::resetState(UErrorCode &status) { | |||
278 | fText.adoptInstead(fDelegate->getUText(fText.orphan(), status)); | |||
279 | } | |||
280 | ||||
281 | SimpleFilteredSentenceBreakIterator::EFBMatchResult | |||
282 | SimpleFilteredSentenceBreakIterator::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. | |||
365 | int32_t | |||
366 | SimpleFilteredSentenceBreakIterator::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 | ||||
395 | int32_t | |||
396 | SimpleFilteredSentenceBreakIterator::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 | ||||
425 | int32_t | |||
426 | SimpleFilteredSentenceBreakIterator::next() { | |||
427 | return internalNext(fDelegate->next()); | |||
428 | } | |||
429 | ||||
430 | int32_t | |||
431 | SimpleFilteredSentenceBreakIterator::first(void) { | |||
432 | // Don't suppress a break opportunity at the beginning of text. | |||
433 | return fDelegate->first(); | |||
434 | } | |||
435 | ||||
436 | int32_t | |||
437 | SimpleFilteredSentenceBreakIterator::preceding(int32_t offset) { | |||
438 | return internalPrev(fDelegate->preceding(offset)); | |||
439 | } | |||
440 | ||||
441 | int32_t | |||
442 | SimpleFilteredSentenceBreakIterator::previous(void) { | |||
443 | return internalPrev(fDelegate->previous()); | |||
444 | } | |||
445 | ||||
446 | UBool 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 | ||||
465 | int32_t | |||
466 | SimpleFilteredSentenceBreakIterator::next(int32_t offset) { | |||
467 | return internalNext(fDelegate->next(offset)); | |||
468 | } | |||
469 | ||||
470 | int32_t | |||
471 | SimpleFilteredSentenceBreakIterator::following(int32_t offset) { | |||
472 | return internalNext(fDelegate->following(offset)); | |||
473 | } | |||
474 | ||||
475 | int32_t | |||
476 | SimpleFilteredSentenceBreakIterator::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 | */ | |||
485 | class U_COMMON_API SimpleFilteredBreakIteratorBuilder : public FilteredBreakIteratorBuilder { | |||
486 | public: | |||
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; | |||
493 | private: | |||
494 | UStringSet fSet; | |||
495 | }; | |||
496 | ||||
497 | SimpleFilteredBreakIteratorBuilder::~SimpleFilteredBreakIteratorBuilder() | |||
498 | { | |||
499 | } | |||
500 | ||||
501 | SimpleFilteredBreakIteratorBuilder::SimpleFilteredBreakIteratorBuilder(UErrorCode &status) | |||
502 | : fSet(status) | |||
503 | { | |||
504 | } | |||
505 | ||||
506 | SimpleFilteredBreakIteratorBuilder::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 | ||||
559 | UBool | |||
560 | SimpleFilteredBreakIteratorBuilder::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 | ||||
567 | UBool | |||
568 | SimpleFilteredBreakIteratorBuilder::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 | */ | |||
582 | static inline UnicodeString* newUnicodeStringArray(size_t count) { | |||
583 | return new UnicodeString[count ? count : 1]; | |||
584 | } | |||
585 | ||||
586 | BreakIterator * | |||
587 | SimpleFilteredBreakIteratorBuilder::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)) { | |||
| ||||
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; | |||
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; | |||
613 | i<fSet.size(); | |||
614 | i++) { | |||
615 | const UnicodeString *abbr = fSet.getStringAt(i); | |||
616 | if(abbr) { | |||
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 | |||
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 | ||||
709 | FilteredBreakIteratorBuilder::FilteredBreakIteratorBuilder() { | |||
710 | } | |||
711 | ||||
712 | FilteredBreakIteratorBuilder::~FilteredBreakIteratorBuilder() { | |||
713 | } | |||
714 | ||||
715 | FilteredBreakIteratorBuilder * | |||
716 | FilteredBreakIteratorBuilder::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 | ||||
722 | FilteredBreakIteratorBuilder * | |||
723 | FilteredBreakIteratorBuilder::createInstance(UErrorCode &status) { | |||
724 | return createEmptyInstance(status); | |||
725 | } | |||
726 | ||||
727 | FilteredBreakIteratorBuilder * | |||
728 | FilteredBreakIteratorBuilder::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 | ||||
734 | U_NAMESPACE_END} | |||
735 | ||||
736 | #endif //#if !UCONFIG_NO_BREAK_ITERATION && !UCONFIG_NO_FILTERED_BREAK_ITERATION |
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 | ||||
104 | U_CAPIextern "C" void * U_EXPORT2 | |||
105 | uprv_mallocuprv_malloc_71(size_t s) U_MALLOC_ATTR__attribute__ ((__malloc__)) U_ALLOC_SIZE_ATTR(1)__attribute__ ((alloc_size(1))); | |||
106 | ||||
107 | U_CAPIextern "C" void * U_EXPORT2 | |||
108 | uprv_reallocuprv_realloc_71(void *mem, size_t size) U_ALLOC_SIZE_ATTR(2)__attribute__ ((alloc_size(2))); | |||
109 | ||||
110 | U_CAPIextern "C" void U_EXPORT2 | |||
111 | uprv_freeuprv_free_71(void *mem); | |||
112 | ||||
113 | U_CAPIextern "C" void * U_EXPORT2 | |||
114 | uprv_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 | */ | |||
153 | U_CFUNCextern "C" UBool | |||
154 | cmemory_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 | */ | |||
163 | typedef void U_CALLCONV UObjectDeleter(void* obj); | |||
164 | ||||
165 | /** | |||
166 | * Deleter for UObject instances. | |||
167 | * Works for all subclasses of UObject because it has a virtual destructor. | |||
168 | */ | |||
169 | U_CAPIextern "C" void U_EXPORT2 | |||
170 | uprv_deleteUObjectuprv_deleteUObject_71(void *obj); | |||
171 | ||||
172 | #ifdef __cplusplus201703L | |||
173 | ||||
174 | #include <utility> | |||
175 | #include "unicode/uobject.h" | |||
176 | ||||
177 | U_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 | */ | |||
186 | template<typename T> | |||
187 | class LocalMemory : public LocalPointerBase<T> { | |||
188 | public: | |||
189 | using LocalPointerBase<T>::operator*; | |||
190 | using LocalPointerBase<T>::operator->; | |||
191 | /** | |||
192 | * Constructor takes ownership. | |||
193 | * @param p simple pointer to an array of T items that is adopted | |||
194 | */ | |||
195 | explicit LocalMemory(T *p=NULL__null) : LocalPointerBase<T>(p) {} | |||
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]; } | |||
| ||||
275 | }; | |||
276 | ||||
277 | template<typename T> | |||
278 | inline 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 | ||||
293 | template<typename T> | |||
294 | inline 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 | */ | |||
331 | template<typename T, int32_t stackCapacity> | |||
332 | class MaybeStackArray { | |||
333 | public: | |||
334 | // No heap allocation. Use only on the stack. | |||
335 | static void* U_EXPORT2 operator new(size_t) U_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 | ||||
440 | protected: | |||
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 | ||||
453 | private: | |||
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 | ||||
476 | template<typename T, int32_t stackCapacity> | |||
477 | icu::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 | ||||
488 | template<typename T, int32_t stackCapacity> | |||
489 | inline MaybeStackArray <T, stackCapacity>& | |||
490 | MaybeStackArray<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 | ||||
504 | template<typename T, int32_t stackCapacity> | |||
505 | inline 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 | ||||
532 | template<typename T, int32_t stackCapacity> | |||
533 | inline 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 | */ | |||
567 | template<typename H, typename T, int32_t stackCapacity> | |||
568 | class MaybeStackHeaderAndArray { | |||
569 | public: | |||
570 | // No heap allocation. Use only on the stack. | |||
571 | static void* U_EXPORT2 operator new(size_t) U_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); | |||
655 | private: | |||
656 | H *ptr; | |||
657 | int32_t capacity; | |||
658 | UBool needToRelease; | |||
659 | // stackHeader must precede stackArray immediately. | |||
660 | H stackHeader; | |||
661 | T stackArray[stackCapacity]; | |||
662 | void releaseMemory() { | |||
663 | if(needToRelease) { | |||
664 | uprv_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 | ||||
675 | template<typename H, typename T, int32_t stackCapacity> | |||
676 | inline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::resize(int32_t newCapacity, | |||
677 | int32_t length) { | |||
678 | if(newCapacity>=0) { | |||
679 | #if U_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 | ||||
706 | template<typename H, typename T, int32_t stackCapacity> | |||
707 | inline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::orphanOrClone(int32_t length, | |||
708 | int32_t &resultCapacity) { | |||
709 | H *p; | |||
710 | if(needToRelease) { | |||
711 | p=ptr; | |||
712 | } else { | |||
713 | if(length<0) { | |||
714 | length=0; | |||
715 | } else if(length>capacity) { | |||
716 | length=capacity; | |||
717 | } | |||
718 | #if U_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 | */ | |||
757 | template<typename T, int32_t stackCapacity = 8> | |||
758 | class MemoryPool : public UMemory { | |||
759 | public: | |||
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 | ||||
825 | protected: | |||
826 | int32_t fCount; | |||
827 | MaybeStackArray<T*, stackCapacity> fPool; | |||
828 | }; | |||
829 | ||||
830 | /** | |||
831 | * An internal Vector-like implementation based on MemoryPool. | |||
832 | * | |||
833 | * Heap-allocates each element and stores pointers. | |||
834 | * | |||
835 | * To append an item to the vector, use emplaceBack. | |||
836 | * | |||
837 | * MaybeStackVector<MyType> vector; | |||
838 | * MyType* element = vector.emplaceBack(); | |||
839 | * if (!element) { | |||
840 | * status = U_MEMORY_ALLOCATION_ERROR; | |||
841 | * } | |||
842 | * // do stuff with element | |||
843 | * | |||
844 | * To loop over the vector, use a for loop with indices: | |||
845 | * | |||
846 | * for (int32_t i = 0; i < vector.length(); i++) { | |||
847 | * MyType* element = vector[i]; | |||
848 | * } | |||
849 | */ | |||
850 | template<typename T, int32_t stackCapacity = 8> | |||
851 | class MaybeStackVector : protected MemoryPool<T, stackCapacity> { | |||
852 | public: | |||
853 | template<typename... Args> | |||
854 | T* emplaceBack(Args&&... args) { | |||
855 | return this->create(args...); | |||
856 | } | |||
857 | ||||
858 | template <typename... Args> | |||
859 | T *emplaceBackAndCheckErrorCode(UErrorCode &status, Args &&... args) { | |||
860 | return this->createAndCheckErrorCode(status, args...); | |||
861 | } | |||
862 | ||||
863 | int32_t length() const { | |||
864 | return this->fCount; | |||
865 | } | |||
866 | ||||
867 | T** getAlias() { | |||
868 | return this->fPool.getAlias(); | |||
869 | } | |||
870 | ||||
871 | const T *const *getAlias() const { | |||
872 | return this->fPool.getAlias(); | |||
873 | } | |||
874 | ||||
875 | /** | |||
876 | * Array item access (read-only). | |||
877 | * No index bounds check. | |||
878 | * @param i array index | |||
879 | * @return reference to the array item | |||
880 | */ | |||
881 | const T* operator[](ptrdiff_t i) const { | |||
882 | return this->fPool[i]; | |||
883 | } | |||
884 | ||||
885 | /** | |||
886 | * Array item access (writable). | |||
887 | * No index bounds check. | |||
888 | * @param i array index | |||
889 | * @return reference to the array item | |||
890 | */ | |||
891 | T* operator[](ptrdiff_t i) { | |||
892 | return this->fPool[i]; | |||
893 | } | |||
894 | }; | |||
895 | ||||
896 | ||||
897 | U_NAMESPACE_END} | |||
898 | ||||
899 | #endif /* __cplusplus */ | |||
900 | #endif /* CMEMORY_H */ |
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 | |
47 | U_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 | */ |
67 | template<typename T> |
68 | class LocalPointerBase { |
69 | public: |
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) {} |
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 | } |
157 | protected: |
158 | /** |
159 | * Actual pointer. |
160 | * @internal |
161 | */ |
162 | T *ptr; |
163 | private: |
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 | */ |
190 | template<typename T> |
191 | class LocalPointer : public LocalPointerBase<T> { |
192 | public: |
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 | */ |
365 | template<typename T> |
366 | class LocalArray : public LocalPointerBase<T> { |
367 | public: |
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 | |
592 | U_NAMESPACE_END} |
593 | |
594 | #endif /* U_SHOW_CPLUSPLUS_API */ |
595 | #endif /* __LOCALPOINTER_H__ */ |