serv.cpp 26 KB

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