tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

serv.cpp (26521B)


      1 // © 2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 /**
      4 *******************************************************************************
      5 * Copyright (C) 2001-2014, International Business Machines Corporation.
      6 * All Rights Reserved.
      7 *******************************************************************************
      8 */
      9 
     10 #include "unicode/utypes.h"
     11 #include "unicode/localpointer.h"
     12 
     13 #if !UCONFIG_NO_SERVICE
     14 
     15 #include "serv.h"
     16 #include "umutex.h"
     17 
     18 #undef SERVICE_REFCOUNT
     19 
     20 // in case we use the refcount stuff
     21 
     22 U_NAMESPACE_BEGIN
     23 
     24 /*
     25 ******************************************************************
     26 */
     27 
     28 const char16_t ICUServiceKey::PREFIX_DELIMITER = 0x002F;   /* '/' */
     29 
     30 ICUServiceKey::ICUServiceKey(const UnicodeString& id) 
     31 : _id(id) {
     32 }
     33 
     34 ICUServiceKey::~ICUServiceKey() 
     35 {
     36 }
     37 
     38 const UnicodeString& 
     39 ICUServiceKey::getID() const 
     40 {
     41    return _id;
     42 }
     43 
     44 UnicodeString& 
     45 ICUServiceKey::canonicalID(UnicodeString& result) const 
     46 {
     47    return result.append(_id);
     48 }
     49 
     50 UnicodeString& 
     51 ICUServiceKey::currentID(UnicodeString& result) const 
     52 {
     53    return canonicalID(result);
     54 }
     55 
     56 UnicodeString& 
     57 ICUServiceKey::currentDescriptor(UnicodeString& result) const 
     58 {
     59    prefix(result);
     60    result.append(PREFIX_DELIMITER);
     61    return currentID(result);
     62 }
     63 
     64 UBool 
     65 ICUServiceKey::fallback() 
     66 {
     67    return false;
     68 }
     69 
     70 UBool 
     71 ICUServiceKey::isFallbackOf(const UnicodeString& id) const 
     72 {
     73    return id == _id;
     74 }
     75 
     76 UnicodeString& 
     77 ICUServiceKey::prefix(UnicodeString& result) const 
     78 {
     79    return result;
     80 }
     81 
     82 UnicodeString& 
     83 ICUServiceKey::parsePrefix(UnicodeString& result) 
     84 {
     85    int32_t n = result.indexOf(PREFIX_DELIMITER);
     86    if (n < 0) {
     87        n = 0;
     88    }
     89    result.remove(n);
     90    return result;
     91 }
     92 
     93 UnicodeString& 
     94 ICUServiceKey::parseSuffix(UnicodeString& result) 
     95 {
     96    int32_t n = result.indexOf(PREFIX_DELIMITER);
     97    if (n >= 0) {
     98        result.remove(0, n+1);
     99    }
    100    return result;
    101 }
    102 
    103 #ifdef SERVICE_DEBUG
    104 UnicodeString& 
    105 ICUServiceKey::debug(UnicodeString& result) const 
    106 {
    107    debugClass(result);
    108    result.append((UnicodeString)" id: ");
    109    result.append(_id);
    110    return result;
    111 }
    112 
    113 UnicodeString& 
    114 ICUServiceKey::debugClass(UnicodeString& result) const 
    115 {
    116    return result.append((UnicodeString)"ICUServiceKey");
    117 }
    118 #endif
    119 
    120 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ICUServiceKey)
    121 
    122 /*
    123 ******************************************************************
    124 */
    125 
    126 ICUServiceFactory::~ICUServiceFactory() {}
    127 
    128 SimpleFactory::SimpleFactory(UObject* instanceToAdopt, const UnicodeString& id, UBool visible) 
    129 : _instance(instanceToAdopt), _id(id), _visible(visible)
    130 {
    131 }
    132 
    133 SimpleFactory::~SimpleFactory() 
    134 {
    135    delete _instance;
    136 }
    137 
    138 UObject* 
    139 SimpleFactory::create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const 
    140 {
    141    if (U_SUCCESS(status)) {
    142        UnicodeString temp;
    143        if (_id == key.currentID(temp)) {
    144            return service->cloneInstance(_instance); 
    145        }
    146    }
    147    return nullptr;
    148 }
    149 
    150 void 
    151 SimpleFactory::updateVisibleIDs(Hashtable& result, UErrorCode& status) const 
    152 {
    153    if (_visible) {
    154        result.put(_id, (void*)this, status); // cast away const
    155    } else {
    156        result.remove(_id);
    157    }
    158 }
    159 
    160 UnicodeString& 
    161 SimpleFactory::getDisplayName(const UnicodeString& id, const Locale& /* locale */, UnicodeString& result) const 
    162 {
    163    if (_visible && _id == id) {
    164        result = _id;
    165    } else {
    166        result.setToBogus();
    167    }
    168    return result;
    169 }
    170 
    171 #ifdef SERVICE_DEBUG
    172 UnicodeString& 
    173 SimpleFactory::debug(UnicodeString& toAppendTo) const 
    174 {
    175    debugClass(toAppendTo);
    176    toAppendTo.append((UnicodeString)" id: ");
    177    toAppendTo.append(_id);
    178    toAppendTo.append((UnicodeString)", visible: ");
    179    toAppendTo.append(_visible ? (UnicodeString)"T" : (UnicodeString)"F");
    180    return toAppendTo;
    181 }
    182 
    183 UnicodeString& 
    184 SimpleFactory::debugClass(UnicodeString& toAppendTo) const 
    185 {
    186    return toAppendTo.append((UnicodeString)"SimpleFactory");
    187 }
    188 #endif
    189 
    190 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleFactory)
    191 
    192 /*
    193 ******************************************************************
    194 */
    195 
    196 ServiceListener::~ServiceListener() {}
    197 
    198 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ServiceListener)
    199 
    200 /*
    201 ******************************************************************
    202 */
    203 
    204 // Record the actual id for this service in the cache, so we can return it
    205 // even if we succeed later with a different id.
    206 class CacheEntry : public UMemory {
    207 private:
    208    int32_t refcount;
    209 
    210 public:
    211    UnicodeString actualDescriptor;
    212    UObject* service;
    213 
    214    /**
    215    * Releases a reference to the shared resource.
    216    */
    217    ~CacheEntry() {
    218        delete service;
    219    }
    220 
    221    CacheEntry(const UnicodeString& _actualDescriptor, UObject* _service) 
    222        : refcount(1), actualDescriptor(_actualDescriptor), service(_service) {
    223    }
    224 
    225    /**
    226    * Instantiation creates an initial reference, so don't call this
    227    * unless you're creating a new pointer to this.  Management of
    228    * that pointer will have to know how to deal with refcounts.  
    229    * Return true if the resource has not already been released.
    230    */
    231    CacheEntry* ref() {
    232        ++refcount;
    233        return this;
    234    }
    235 
    236    /**
    237    * Destructions removes a reference, so don't call this unless
    238    * you're removing pointer to this somewhere.  Management of that
    239    * pointer will have to know how to deal with refcounts.  Once
    240    * the refcount drops to zero, the resource is released.  Return
    241    * false if the resource has been released.
    242    */
    243    CacheEntry* unref() {
    244        if ((--refcount) == 0) {
    245            delete this;
    246            return nullptr;
    247        }
    248        return this;
    249    }
    250 
    251    /**
    252    * Return true if there is at least one reference to this and the
    253    * resource has not been released.
    254    */
    255    UBool isShared() const {
    256        return refcount > 1;
    257    }
    258 };
    259 
    260 // Deleter for serviceCache
    261 U_CDECL_BEGIN
    262 static void U_CALLCONV
    263 cacheDeleter(void* obj) {
    264    U_NAMESPACE_USE ((CacheEntry*)obj)->unref();
    265 }
    266 
    267 U_CDECL_END
    268 
    269 /*
    270 ******************************************************************
    271 */
    272 
    273 class DNCache : public UMemory {
    274 public:
    275    Hashtable cache;
    276    const Locale locale;
    277 
    278    DNCache(const Locale& _locale) 
    279        : cache(), locale(_locale) 
    280    {
    281        // cache.setKeyDeleter(uprv_deleteUObject);
    282    }
    283 };
    284 
    285 
    286 /*
    287 ******************************************************************
    288 */
    289 
    290 StringPair* 
    291 StringPair::create(const UnicodeString& displayName, 
    292                   const UnicodeString& id,
    293                   UErrorCode& status)
    294 {
    295    if (U_SUCCESS(status)) {
    296        StringPair* sp = new StringPair(displayName, id);
    297        if (sp == nullptr || sp->isBogus()) {
    298            status = U_MEMORY_ALLOCATION_ERROR;
    299            delete sp;
    300            return nullptr;
    301        }
    302        return sp;
    303    }
    304    return nullptr;
    305 }
    306 
    307 UBool 
    308 StringPair::isBogus() const {
    309    return displayName.isBogus() || id.isBogus();
    310 }
    311 
    312 StringPair::StringPair(const UnicodeString& _displayName, 
    313                       const UnicodeString& _id)
    314 : displayName(_displayName)
    315 , id(_id)
    316 {
    317 }
    318 
    319 U_CDECL_BEGIN
    320 static void U_CALLCONV
    321 userv_deleteStringPair(void *obj) {
    322    U_NAMESPACE_USE delete (StringPair*) obj;
    323 }
    324 U_CDECL_END
    325 
    326 /*
    327 ******************************************************************
    328 */
    329 
    330 static UMutex lock;
    331 
    332 ICUService::ICUService()
    333 : name()
    334 , timestamp(0)
    335 , factories(nullptr)
    336 , serviceCache(nullptr)
    337 , idCache(nullptr)
    338 , dnCache(nullptr)
    339 {
    340 }
    341 
    342 ICUService::ICUService(const UnicodeString& newName) 
    343 : name(newName)
    344 , timestamp(0)
    345 , factories(nullptr)
    346 , serviceCache(nullptr)
    347 , idCache(nullptr)
    348 , dnCache(nullptr)
    349 {
    350 }
    351 
    352 ICUService::~ICUService()
    353 {
    354    {
    355        Mutex mutex(&lock);
    356        clearCaches();
    357        delete factories;
    358        factories = nullptr;
    359    }
    360 }
    361 
    362 UObject* 
    363 ICUService::get(const UnicodeString& descriptor, UErrorCode& status) const 
    364 {
    365    return get(descriptor, nullptr, status);
    366 }
    367 
    368 UObject* 
    369 ICUService::get(const UnicodeString& descriptor, UnicodeString* actualReturn, UErrorCode& status) const 
    370 {
    371    UObject* result = nullptr;
    372    ICUServiceKey* key = createKey(&descriptor, status);
    373    if (key) {
    374        result = getKey(*key, actualReturn, status);
    375        delete key;
    376    }
    377    return result;
    378 }
    379 
    380 UObject* 
    381 ICUService::getKey(ICUServiceKey& key, UErrorCode& status) const 
    382 {
    383    return getKey(key, nullptr, status);
    384 }
    385 
    386 // this is a vector that subclasses of ICUService can override to further customize the result object
    387 // before returning it.  All other public get functions should call this one.
    388 
    389 UObject* 
    390 ICUService::getKey(ICUServiceKey& key, UnicodeString* actualReturn, UErrorCode& status) const 
    391 {
    392    return getKey(key, actualReturn, nullptr, status);
    393 }
    394 
    395 // make it possible to call reentrantly on systems that don't have reentrant mutexes.
    396 // we can use this simple approach since we know the situation where we're calling
    397 // reentrantly even without knowing the thread.
    398 class XMutex : public UMemory {
    399 public:
    400    inline XMutex(UMutex *mutex, UBool reentering) 
    401        : fMutex(mutex)
    402        , fActive(!reentering) 
    403    {
    404        if (fActive) umtx_lock(fMutex);
    405    }
    406    inline ~XMutex() {
    407        if (fActive) umtx_unlock(fMutex);
    408    }
    409 
    410 private:
    411    UMutex  *fMutex;
    412    UBool fActive;
    413 };
    414 
    415 // called only by factories, treat as private
    416 UObject* 
    417 ICUService::getKey(ICUServiceKey& key, UnicodeString* actualReturn, const ICUServiceFactory* factory, UErrorCode& status) const 
    418 {
    419    if (U_FAILURE(status)) {
    420        return nullptr;
    421    }
    422 
    423    if (isDefault()) {
    424        return handleDefault(key, actualReturn, status);
    425    }
    426 
    427    ICUService* ncthis = const_cast<ICUService*>(this); // cast away semantic const
    428 
    429    CacheEntry* result = nullptr;
    430    {
    431        // The factory list can't be modified until we're done, 
    432        // otherwise we might update the cache with an invalid result.
    433        // The cache has to stay in synch with the factory list.
    434        // ICU doesn't have monitors so we can't use rw locks, so 
    435        // we single-thread everything using this service, for now.
    436 
    437        // if factory is not null, we're calling from within the mutex,
    438        // and since some unix machines don't have reentrant mutexes we
    439        // need to make sure not to try to lock it again.
    440        XMutex mutex(&lock, factory != nullptr);
    441 
    442        if (serviceCache == nullptr) {
    443            ncthis->serviceCache = new Hashtable(status);
    444            if (ncthis->serviceCache == nullptr) {
    445                status = U_MEMORY_ALLOCATION_ERROR;
    446                return nullptr;
    447            }
    448            if (U_FAILURE(status)) {
    449                delete serviceCache;
    450                return nullptr;
    451            }
    452            serviceCache->setValueDeleter(cacheDeleter);
    453        }
    454 
    455        UnicodeString currentDescriptor;
    456        LocalPointer<UVector> cacheDescriptorList;
    457        UBool putInCache = false;
    458 
    459        int32_t startIndex = 0;
    460        int32_t limit = factories->size();
    461        UBool cacheResult = true;
    462 
    463        if (factory != nullptr) {
    464            for (int32_t i = 0; i < limit; ++i) {
    465                if (factory == static_cast<const ICUServiceFactory*>(factories->elementAt(i))) {
    466                    startIndex = i + 1;
    467                    break;
    468                }
    469            }
    470            if (startIndex == 0) {
    471                // throw new InternalError("Factory " + factory + "not registered with service: " + this);
    472                status = U_ILLEGAL_ARGUMENT_ERROR;
    473                return nullptr;
    474            }
    475            cacheResult = false;
    476        }
    477 
    478        do {
    479            currentDescriptor.remove();
    480            key.currentDescriptor(currentDescriptor);
    481            result = static_cast<CacheEntry*>(serviceCache->get(currentDescriptor));
    482            if (result != nullptr) {
    483                break;
    484            }
    485 
    486            // first test of cache failed, so we'll have to update
    487            // the cache if we eventually succeed-- that is, if we're 
    488            // going to update the cache at all.
    489            putInCache = true;
    490 
    491            int32_t index = startIndex;
    492            while (index < limit) {
    493                ICUServiceFactory* f = static_cast<ICUServiceFactory*>(factories->elementAt(index++));
    494                LocalPointer<UObject> service(f->create(key, this, status));
    495                if (U_FAILURE(status)) {
    496                    return nullptr;
    497                }
    498                if (service.isValid()) {
    499                    result = new CacheEntry(currentDescriptor, service.getAlias());
    500                    if (result == nullptr) {
    501                        status = U_MEMORY_ALLOCATION_ERROR;
    502                        return nullptr;
    503                    }
    504                    service.orphan(); // result now owns service.
    505 
    506                    goto outerEnd;
    507                }
    508            }
    509 
    510            // prepare to load the cache with all additional ids that 
    511            // will resolve to result, assuming we'll succeed.  We
    512            // don't want to keep querying on an id that's going to
    513            // fallback to the one that succeeded, we want to hit the
    514            // cache the first time next goaround.
    515            if (cacheDescriptorList.isNull()) {
    516                cacheDescriptorList.adoptInsteadAndCheckErrorCode(new UVector(uprv_deleteUObject, nullptr, 5, status), status);
    517                if (U_FAILURE(status)) {
    518                    return nullptr;
    519                }
    520            }
    521 
    522            LocalPointer<UnicodeString> idToCache(new UnicodeString(currentDescriptor), status);
    523            if (U_FAILURE(status)) {
    524                return nullptr;
    525            }
    526            if (idToCache->isBogus()) {
    527                status = U_MEMORY_ALLOCATION_ERROR;
    528                return nullptr;
    529            }
    530            cacheDescriptorList->adoptElement(idToCache.orphan(), status);
    531            if (U_FAILURE(status)) {
    532                return nullptr;
    533            }
    534        } while (key.fallback());
    535 outerEnd:
    536 
    537        if (result != nullptr) {
    538            if (putInCache && cacheResult) {
    539                serviceCache->put(result->actualDescriptor, result, status);
    540                if (U_FAILURE(status)) {
    541                    return nullptr;
    542                }
    543 
    544                if (cacheDescriptorList.isValid()) {
    545                    for (int32_t i = cacheDescriptorList->size(); --i >= 0;) {
    546                        UnicodeString* desc = static_cast<UnicodeString*>(cacheDescriptorList->elementAt(i));
    547 
    548                        serviceCache->put(*desc, result, status);
    549                        if (U_FAILURE(status)) {
    550                            return nullptr;
    551                        }
    552 
    553                        result->ref();
    554                        cacheDescriptorList->removeElementAt(i);
    555                    }
    556                }
    557            }
    558 
    559            if (actualReturn != nullptr) {
    560                // strip null prefix
    561                if (result->actualDescriptor.indexOf(static_cast<char16_t>(0x2f)) == 0) { // U+002f=slash (/)
    562                    actualReturn->remove();
    563                    actualReturn->append(result->actualDescriptor, 
    564                        1, 
    565                        result->actualDescriptor.length() - 1);
    566                } else {
    567                    *actualReturn = result->actualDescriptor;
    568                }
    569 
    570                if (actualReturn->isBogus()) {
    571                    status = U_MEMORY_ALLOCATION_ERROR;
    572                    delete result;
    573                    return nullptr;
    574                }
    575            }
    576 
    577            UObject* service = cloneInstance(result->service);
    578            if (putInCache && !cacheResult) {
    579                delete result;
    580            }
    581            return service;
    582        }
    583    }
    584 
    585    return handleDefault(key, actualReturn, status);
    586 }
    587 
    588 UObject* 
    589 ICUService::handleDefault(const ICUServiceKey& /* key */, UnicodeString* /* actualIDReturn */, UErrorCode& /* status */) const 
    590 {
    591    return nullptr;
    592 }
    593 
    594 UVector& 
    595 ICUService::getVisibleIDs(UVector& result, UErrorCode& status) const {
    596    return getVisibleIDs(result, nullptr, status);
    597 }
    598 
    599 UVector& 
    600 ICUService::getVisibleIDs(UVector& result, const UnicodeString* matchID, UErrorCode& status) const 
    601 {
    602    result.removeAllElements();
    603 
    604    if (U_FAILURE(status)) {
    605        return result;
    606    }
    607    UObjectDeleter *savedDeleter = result.setDeleter(uprv_deleteUObject);
    608 
    609    {
    610        Mutex mutex(&lock);
    611        const Hashtable* map = getVisibleIDMap(status);
    612        if (map != nullptr) {
    613            ICUServiceKey* fallbackKey = createKey(matchID, status);
    614 
    615            for (int32_t pos = UHASH_FIRST; U_SUCCESS(status); ) {
    616                const UHashElement* e = map->nextElement(pos);
    617                if (e == nullptr) {
    618                    break;
    619                }
    620 
    621                const UnicodeString* id = static_cast<const UnicodeString*>(e->key.pointer);
    622                if (fallbackKey != nullptr) {
    623                    if (!fallbackKey->isFallbackOf(*id)) {
    624                        continue;
    625                    }
    626                }
    627 
    628                LocalPointer<UnicodeString> idClone(id->clone(), status);
    629                result.adoptElement(idClone.orphan(), status);
    630            }
    631            delete fallbackKey;
    632        }
    633    }
    634    if (U_FAILURE(status)) {
    635        result.removeAllElements();
    636    }
    637    result.setDeleter(savedDeleter);
    638    return result;
    639 }
    640 
    641 const Hashtable* 
    642 ICUService::getVisibleIDMap(UErrorCode& status) const {
    643    if (U_FAILURE(status)) return nullptr;
    644 
    645    // must only be called when lock is already held
    646 
    647    ICUService* ncthis = const_cast<ICUService*>(this); // cast away semantic const
    648    if (idCache == nullptr) {
    649        ncthis->idCache = new Hashtable(status);
    650        if (idCache == nullptr) {
    651            status = U_MEMORY_ALLOCATION_ERROR;
    652        } else if (factories != nullptr) {
    653            for (int32_t pos = factories->size(); --pos >= 0;) {
    654                ICUServiceFactory* f = static_cast<ICUServiceFactory*>(factories->elementAt(pos));
    655                f->updateVisibleIDs(*idCache, status);
    656            }
    657            if (U_FAILURE(status)) {
    658                delete idCache;
    659                ncthis->idCache = nullptr;
    660            }
    661        }
    662    }
    663 
    664    return idCache;
    665 }
    666 
    667 
    668 UnicodeString& 
    669 ICUService::getDisplayName(const UnicodeString& id, UnicodeString& result) const 
    670 {
    671    return getDisplayName(id, result, Locale::getDefault());
    672 }
    673 
    674 UnicodeString& 
    675 ICUService::getDisplayName(const UnicodeString& id, UnicodeString& result, const Locale& locale) const 
    676 {
    677    {
    678        UErrorCode status = U_ZERO_ERROR;
    679        Mutex mutex(&lock);
    680        const Hashtable* map = getVisibleIDMap(status);
    681        if (map != nullptr) {
    682            ICUServiceFactory* f = static_cast<ICUServiceFactory*>(map->get(id));
    683            if (f != nullptr) {
    684                f->getDisplayName(id, locale, result);
    685                return result;
    686            }
    687 
    688            // fallback
    689            status = U_ZERO_ERROR;
    690            ICUServiceKey* fallbackKey = createKey(&id, status);
    691            while (fallbackKey != nullptr && fallbackKey->fallback()) {
    692                UnicodeString us;
    693                fallbackKey->currentID(us);
    694                f = static_cast<ICUServiceFactory*>(map->get(us));
    695                if (f != nullptr) {
    696                    f->getDisplayName(id, locale, result);
    697                    delete fallbackKey;
    698                    return result;
    699                }
    700            }
    701            delete fallbackKey;
    702        }
    703    }
    704    result.setToBogus();
    705    return result;
    706 }
    707 
    708 UVector& 
    709 ICUService::getDisplayNames(UVector& result, UErrorCode& status) const 
    710 {
    711    return getDisplayNames(result, Locale::getDefault(), nullptr, status);
    712 }
    713 
    714 
    715 UVector& 
    716 ICUService::getDisplayNames(UVector& result, const Locale& locale, UErrorCode& status) const 
    717 {
    718    return getDisplayNames(result, locale, nullptr, status);
    719 }
    720 
    721 UVector& 
    722 ICUService::getDisplayNames(UVector& result, 
    723                            const Locale& locale, 
    724                            const UnicodeString* matchID, 
    725                            UErrorCode& status) const 
    726 {
    727    result.removeAllElements();
    728    result.setDeleter(userv_deleteStringPair);
    729    if (U_SUCCESS(status)) {
    730        ICUService* ncthis = const_cast<ICUService*>(this); // cast away semantic const
    731        Mutex mutex(&lock);
    732 
    733        if (dnCache != nullptr && dnCache->locale != locale) {
    734            delete dnCache;
    735            ncthis->dnCache = nullptr;
    736        }
    737 
    738        if (dnCache == nullptr) {
    739            const Hashtable* m = getVisibleIDMap(status);
    740            if (U_FAILURE(status)) {
    741                return result;
    742            }
    743            ncthis->dnCache = new DNCache(locale); 
    744            if (dnCache == nullptr) {
    745                status = U_MEMORY_ALLOCATION_ERROR;
    746                return result;
    747            }
    748 
    749            int32_t pos = UHASH_FIRST;
    750            const UHashElement* entry = nullptr;
    751            while ((entry = m->nextElement(pos)) != nullptr) {
    752                const UnicodeString* id = static_cast<const UnicodeString*>(entry->key.pointer);
    753                ICUServiceFactory* f = static_cast<ICUServiceFactory*>(entry->value.pointer);
    754                UnicodeString dname;
    755                f->getDisplayName(*id, locale, dname);
    756                if (dname.isBogus()) {
    757                    status = U_MEMORY_ALLOCATION_ERROR;
    758                } else {
    759                    dnCache->cache.put(dname, (void*)id, status); // share pointer with visibleIDMap
    760                    if (U_SUCCESS(status)) {
    761                        continue;
    762                    }
    763                }
    764                delete dnCache;
    765                ncthis->dnCache = nullptr;
    766                return result;
    767            }
    768        }
    769    }
    770 
    771    ICUServiceKey* matchKey = createKey(matchID, status);
    772    /* To ensure that all elements in the hashtable are iterated, set pos to -1.
    773     * nextElement(pos) will skip the position at pos and begin the iteration
    774     * at the next position, which in this case will be 0.
    775     */
    776    int32_t pos = UHASH_FIRST; 
    777    const UHashElement *entry = nullptr;
    778    while ((entry = dnCache->cache.nextElement(pos)) != nullptr) {
    779        const UnicodeString* id = static_cast<const UnicodeString*>(entry->value.pointer);
    780        if (matchKey != nullptr && !matchKey->isFallbackOf(*id)) {
    781            continue;
    782        }
    783        const UnicodeString* dn = static_cast<const UnicodeString*>(entry->key.pointer);
    784        StringPair* sp = StringPair::create(*id, *dn, status);
    785        result.adoptElement(sp, status);
    786        if (U_FAILURE(status)) {
    787            result.removeAllElements();
    788            break;
    789        }
    790    }
    791    delete matchKey;
    792 
    793    return result;
    794 }
    795 
    796 URegistryKey
    797 ICUService::registerInstance(UObject* objToAdopt, const UnicodeString& id, UErrorCode& status) 
    798 {
    799    return registerInstance(objToAdopt, id, true, status);
    800 }
    801 
    802 URegistryKey
    803 ICUService::registerInstance(UObject* objToAdopt, const UnicodeString& id, UBool visible, UErrorCode& status) 
    804 {
    805    ICUServiceKey* key = createKey(&id, status);
    806    if (key != nullptr) {
    807        UnicodeString canonicalID;
    808        key->canonicalID(canonicalID);
    809        delete key;
    810 
    811        ICUServiceFactory* f = createSimpleFactory(objToAdopt, canonicalID, visible, status);
    812        if (f != nullptr) {
    813            return registerFactory(f, status);
    814        }
    815    }
    816    delete objToAdopt;
    817    return nullptr;
    818 }
    819 
    820 ICUServiceFactory* 
    821 ICUService::createSimpleFactory(UObject* objToAdopt, const UnicodeString& id, UBool visible, UErrorCode& status)
    822 {
    823    if (U_SUCCESS(status)) {
    824        if ((objToAdopt != nullptr) && (!id.isBogus())) {
    825            return new SimpleFactory(objToAdopt, id, visible);
    826        }
    827        status = U_ILLEGAL_ARGUMENT_ERROR;
    828    }
    829    return nullptr;
    830 }
    831 
    832 URegistryKey
    833 ICUService::registerFactory(ICUServiceFactory* factoryToAdopt, UErrorCode& status)
    834 {
    835    LocalPointer<ICUServiceFactory>lpFactoryToAdopt(factoryToAdopt);
    836    if (U_FAILURE(status) || factoryToAdopt == nullptr) {
    837        return nullptr;
    838    }
    839    {
    840        Mutex mutex(&lock);
    841 
    842        if (factories == nullptr) {
    843            LocalPointer<UVector> lpFactories(new UVector(uprv_deleteUObject, nullptr, status), status);
    844            if (U_FAILURE(status)) {
    845                return nullptr;
    846            }
    847            factories = lpFactories.orphan();
    848        }
    849        factories->insertElementAt(lpFactoryToAdopt.orphan(), 0, status);
    850        if (U_SUCCESS(status)) {
    851            clearCaches();
    852        }
    853    }   // Close of mutex lock block.
    854 
    855    if (U_SUCCESS(status)) {
    856        notifyChanged();
    857        return (URegistryKey)factoryToAdopt;
    858    } else {
    859        return nullptr;
    860    }
    861 }
    862 
    863 UBool 
    864 ICUService::unregister(URegistryKey rkey, UErrorCode& status) 
    865 {
    866    ICUServiceFactory *factory = (ICUServiceFactory*)rkey;
    867    UBool result = false;
    868    if (factory != nullptr && factories != nullptr) {
    869        Mutex mutex(&lock);
    870 
    871        if (factories->removeElement(factory)) {
    872            clearCaches();
    873            result = true;
    874        } else {
    875            status = U_ILLEGAL_ARGUMENT_ERROR;
    876            delete factory;
    877        }
    878    }
    879    if (result) {
    880        notifyChanged();
    881    }
    882    return result;
    883 }
    884 
    885 void 
    886 ICUService::reset() 
    887 {
    888    {
    889        Mutex mutex(&lock);
    890        reInitializeFactories();
    891        clearCaches();
    892    }
    893    notifyChanged();
    894 }
    895 
    896 void 
    897 ICUService::reInitializeFactories() 
    898 {
    899    if (factories != nullptr) {
    900        factories->removeAllElements();
    901    }
    902 }
    903 
    904 UBool 
    905 ICUService::isDefault() const 
    906 {
    907    return countFactories() == 0;
    908 }
    909 
    910 ICUServiceKey* 
    911 ICUService::createKey(const UnicodeString* id, UErrorCode& status) const 
    912 {
    913    return (U_FAILURE(status) || id == nullptr) ? nullptr : new ICUServiceKey(*id);
    914 }
    915 
    916 void 
    917 ICUService::clearCaches() 
    918 {
    919    // callers synchronize before use
    920    ++timestamp;
    921    delete dnCache;
    922    dnCache = nullptr;
    923    delete idCache;
    924    idCache = nullptr;
    925    delete serviceCache; serviceCache = nullptr;
    926 }
    927 
    928 void 
    929 ICUService::clearServiceCache() 
    930 {
    931    // callers synchronize before use
    932    delete serviceCache; serviceCache = nullptr;
    933 }
    934 
    935 UBool 
    936 ICUService::acceptsListener(const EventListener& l) const 
    937 {
    938    return dynamic_cast<const ServiceListener*>(&l) != nullptr;
    939 }
    940 
    941 void 
    942 ICUService::notifyListener(EventListener& l) const 
    943 {
    944    (static_cast<ServiceListener&>(l)).serviceChanged(*this);
    945 }
    946 
    947 UnicodeString&
    948 ICUService::getName(UnicodeString& result) const 
    949 {
    950    return result.append(name);
    951 }
    952 
    953 int32_t 
    954 ICUService::countFactories() const 
    955 {
    956    return factories == nullptr ? 0 : factories->size();
    957 }
    958 
    959 int32_t
    960 ICUService::getTimestamp() const
    961 {
    962    return timestamp;
    963 }
    964 
    965 U_NAMESPACE_END
    966 
    967 /* UCONFIG_NO_SERVICE */
    968 #endif