| 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__ */ |