]> git.saurik.com Git - apple/icu.git/blob - icuSources/i18n/coll.cpp
ICU-3.13.tar.gz
[apple/icu.git] / icuSources / i18n / coll.cpp
1 /*
2 ******************************************************************************
3 * Copyright (C) 1996-2003, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 ******************************************************************************
6 */
7
8 /**
9 * File coll.cpp
10 *
11 * Created by: Helena Shih
12 *
13 * Modification History:
14 *
15 * Date Name Description
16 * 2/5/97 aliu Modified createDefault to load collation data from
17 * binary files when possible. Added related methods
18 * createCollationFromFile, chopLocale, createPathName.
19 * 2/11/97 aliu Added methods addToCache, findInCache, which implement
20 * a Collation cache. Modified createDefault to look in
21 * cache first, and also to store newly created Collation
22 * objects in the cache. Modified to not use gLocPath.
23 * 2/12/97 aliu Modified to create objects from RuleBasedCollator cache.
24 * Moved cache out of Collation class.
25 * 2/13/97 aliu Moved several methods out of this class and into
26 * RuleBasedCollator, with modifications. Modified
27 * createDefault() to call new RuleBasedCollator(Locale&)
28 * constructor. General clean up and documentation.
29 * 2/20/97 helena Added clone, operator==, operator!=, operator=, and copy
30 * constructor.
31 * 05/06/97 helena Added memory allocation error detection.
32 * 05/08/97 helena Added createInstance().
33 * 6/20/97 helena Java class name change.
34 * 04/23/99 stephen Removed EDecompositionMode, merged with
35 * Normalizer::EMode
36 * 11/23/9 srl Inlining of some critical functions
37 * 01/29/01 synwee Modified into a C++ wrapper calling C APIs (ucol.h)
38 */
39
40 #include "unicode/utypes.h"
41
42 #if !UCONFIG_NO_COLLATION
43
44 #include "unicode/coll.h"
45 #include "unicode/tblcoll.h"
46 #include "cmemory.h"
47 #include "mutex.h"
48 #include "iculserv.h"
49 #include "ucln_in.h"
50
51 U_NAMESPACE_BEGIN
52
53 // ------------------------------------------
54 //
55 // Registration
56 //
57
58 //-------------------------------------------
59
60 UBool
61 CollatorFactory::visible(void) const {
62 return TRUE;
63 }
64
65 //-------------------------------------------
66
67 UnicodeString&
68 CollatorFactory::getDisplayName(const Locale& objectLocale,
69 const Locale& displayLocale,
70 UnicodeString& result)
71 {
72 return objectLocale.getDisplayName(displayLocale, result);
73 }
74
75 // -------------------------------------
76
77 class ICUCollatorFactory : public ICUResourceBundleFactory {
78
79 virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const;
80 };
81
82 UObject*
83 ICUCollatorFactory::create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& status) const {
84 if (handlesKey(key, status)) {
85 const LocaleKey& lkey = (const LocaleKey&)key;
86 Locale loc;
87 // make sure the requested locale is correct
88 // default LocaleFactory uses currentLocale since that's the one vetted by handlesKey
89 // but for ICU rb resources we use the actual one since it will fallback again
90 lkey.canonicalLocale(loc);
91
92 return Collator::makeInstance(loc, status);
93 }
94 return NULL;
95 }
96
97 // -------------------------------------
98
99 class ICUCollatorService : public ICULocaleService {
100 public:
101 ICUCollatorService()
102 : ICULocaleService("Collator")
103 {
104 UErrorCode status = U_ZERO_ERROR;
105 registerFactory(new ICUCollatorFactory(), status);
106 }
107
108 virtual UObject* cloneInstance(UObject* instance) const {
109 return ((Collator*)instance)->clone();
110 }
111
112 virtual UObject* handleDefault(const ICUServiceKey& key, UnicodeString* actualID, UErrorCode& status) const {
113 LocaleKey& lkey = (LocaleKey&)key;
114 if (actualID) {
115 lkey.canonicalID(*actualID);
116 }
117 Locale loc;
118 lkey.canonicalLocale(loc);
119 return Collator::makeInstance(loc, status);
120 }
121
122 virtual UObject* getKey(ICUServiceKey& key, UnicodeString* actualReturn, UErrorCode& status) const {
123 UnicodeString ar;
124 if (actualReturn == NULL) {
125 actualReturn = &ar;
126 }
127 Collator* result = (Collator*)ICULocaleService::getKey(key, actualReturn, status);
128 if (result) {
129 const LocaleKey& lkey = (const LocaleKey&)key;
130 Locale canonicalLocale;
131 Locale currentLocale;
132
133 result->setLocales(lkey.canonicalLocale(canonicalLocale),
134 LocaleUtility::initLocaleFromName(*actualReturn, currentLocale));
135 }
136 return result;
137 }
138
139 virtual UBool isDefault() const {
140 return countFactories() == 1;
141 }
142 };
143
144 // -------------------------------------
145
146 class ICUCollatorService;
147
148 static ICULocaleService* gService = NULL;
149
150 static ICULocaleService*
151 getService(void)
152 {
153 UBool needInit;
154 {
155 Mutex mutex;
156 needInit = (UBool)(gService == NULL);
157 }
158 if(needInit) {
159 ICULocaleService *newservice = new ICUCollatorService();
160 if(newservice) {
161 Mutex mutex;
162 if(gService == NULL) {
163 gService = newservice;
164 newservice = NULL;
165 }
166 }
167 if(newservice) {
168 delete newservice;
169 } else {
170 ucln_i18n_registerCleanup();
171 }
172 }
173 return gService;
174 }
175
176 // -------------------------------------
177
178 static UBool
179 hasService(void)
180 {
181 Mutex mutex;
182 return gService != NULL;
183 }
184
185 // -------------------------------------
186
187 UCollator*
188 Collator::createUCollator(const char *loc,
189 UErrorCode *status)
190 {
191 UCollator *result = 0;
192 if (status && U_SUCCESS(*status) && hasService()) {
193 Locale desiredLocale(loc);
194 Collator *col = (Collator*)gService->get(desiredLocale, *status);
195 if (col && col->getDynamicClassID() == RuleBasedCollator::getStaticClassID()) {
196 RuleBasedCollator *rbc = (RuleBasedCollator *)col;
197 if (!rbc->dataIsOwned) {
198 result = ucol_safeClone(rbc->ucollator, NULL, NULL, status);
199 } else {
200 result = rbc->ucollator;
201 rbc->ucollator = NULL; // to prevent free on delete
202 }
203 }
204 delete col;
205 }
206 return result;
207 }
208
209 // Collator public methods -----------------------------------------------
210
211 Collator* Collator::createInstance(UErrorCode& success)
212 {
213 if (U_FAILURE(success))
214 return 0;
215 return createInstance(Locale::getDefault(), success);
216 }
217
218 Collator* Collator::createInstance(const Locale& desiredLocale,
219 UErrorCode& status)
220 {
221 if (U_FAILURE(status))
222 return 0;
223
224 if (hasService()) {
225 return (Collator*)gService->get(desiredLocale, status);
226 }
227 return makeInstance(desiredLocale, status);
228 }
229
230
231 Collator* Collator::makeInstance(const Locale& desiredLocale,
232 UErrorCode& status)
233 {
234 // A bit of explanation is required here. Although in the current
235 // implementation
236 // Collator::createInstance() is just turning around and calling
237 // RuleBasedCollator(Locale&), this will not necessarily always be the
238 // case. For example, suppose we modify this code to handle a
239 // non-table-based Collator, such as that for Thai. In this case,
240 // createInstance() will have to be modified to somehow determine this fact
241 // (perhaps a field in the resource bundle). Then it can construct the
242 // non-table-based Collator in some other way, when it sees that it needs
243 // to.
244 // The specific caution is this: RuleBasedCollator(Locale&) will ALWAYS
245 // return a valid collation object, if the system if functioning properly.
246 // The reason is that it will fall back, use the default locale, and even
247 // use the built-in default collation rules. THEREFORE, createInstance()
248 // should in general ONLY CALL RuleBasedCollator(Locale&) IF IT KNOWS IN
249 // ADVANCE that the given locale's collation is properly implemented as a
250 // RuleBasedCollator.
251 // Currently, we don't do this...we always return a RuleBasedCollator,
252 // whether it is strictly correct to do so or not, without checking, because
253 // we currently have no way of checking.
254
255 RuleBasedCollator* collation = new RuleBasedCollator(desiredLocale,
256 status);
257 /* test for NULL */
258 if (collation == 0) {
259 status = U_MEMORY_ALLOCATION_ERROR;
260 return 0;
261 }
262 if (U_FAILURE(status))
263 {
264 delete collation;
265 collation = 0;
266 }
267 return collation;
268 }
269
270 // !!! dlf the following is obsolete, ignore registration for this
271
272 Collator *
273 Collator::createInstance(const Locale &loc,
274 UVersionInfo version,
275 UErrorCode &status) {
276 Collator *collator;
277 UVersionInfo info;
278
279 collator=new RuleBasedCollator(loc, status);
280 /* test for NULL */
281 if (collator == 0) {
282 status = U_MEMORY_ALLOCATION_ERROR;
283 return 0;
284 }
285
286 if(U_SUCCESS(status)) {
287 collator->getVersion(info);
288 if(0!=uprv_memcmp(version, info, sizeof(UVersionInfo))) {
289 delete collator;
290 status=U_MISSING_RESOURCE_ERROR;
291 return 0;
292 }
293 }
294 return collator;
295 }
296
297 // implement deprecated, previously abstract method
298 Collator::EComparisonResult Collator::compare(const UnicodeString& source,
299 const UnicodeString& target) const
300 {
301 UErrorCode ec = U_ZERO_ERROR;
302 return (Collator::EComparisonResult)compare(source, target, ec);
303 }
304
305 // implement deprecated, previously abstract method
306 Collator::EComparisonResult Collator::compare(const UnicodeString& source,
307 const UnicodeString& target,
308 int32_t length) const
309 {
310 UErrorCode ec = U_ZERO_ERROR;
311 return (Collator::EComparisonResult)compare(source, target, length, ec);
312 }
313
314 // implement deprecated, previously abstract method
315 Collator::EComparisonResult Collator::compare(const UChar* source, int32_t sourceLength,
316 const UChar* target, int32_t targetLength)
317 const
318 {
319 UErrorCode ec = U_ZERO_ERROR;
320 return (Collator::EComparisonResult)compare(source, sourceLength, target, targetLength, ec);
321 }
322
323 UBool Collator::equals(const UnicodeString& source,
324 const UnicodeString& target) const
325 {
326 UErrorCode ec = U_ZERO_ERROR;
327 return (compare(source, target, ec) == UCOL_EQUAL);
328 }
329
330 UBool Collator::greaterOrEqual(const UnicodeString& source,
331 const UnicodeString& target) const
332 {
333 UErrorCode ec = U_ZERO_ERROR;
334 return (compare(source, target, ec) != UCOL_LESS);
335 }
336
337 UBool Collator::greater(const UnicodeString& source,
338 const UnicodeString& target) const
339 {
340 UErrorCode ec = U_ZERO_ERROR;
341 return (compare(source, target, ec) == UCOL_GREATER);
342 }
343
344 // this API ignores registered collators, since it returns an
345 // array of indefinite lifetime
346 const Locale* Collator::getAvailableLocales(int32_t& count)
347 {
348 return Locale::getAvailableLocales(count);
349 }
350
351 UnicodeString& Collator::getDisplayName(const Locale& objectLocale,
352 const Locale& displayLocale,
353 UnicodeString& name)
354 {
355 if (hasService()) {
356 return gService->getDisplayName(objectLocale.getName(), name, displayLocale);
357 }
358 return objectLocale.getDisplayName(displayLocale, name);
359 }
360
361 UnicodeString& Collator::getDisplayName(const Locale& objectLocale,
362 UnicodeString& name)
363 {
364 return getDisplayName(objectLocale, Locale::getDefault(), name);
365 }
366
367 /* This is useless information */
368 /*void Collator::getVersion(UVersionInfo versionInfo) const
369 {
370 if (versionInfo!=NULL)
371 uprv_memcpy(versionInfo, fVersion, U_MAX_VERSION_LENGTH);
372 }
373 */
374
375 // UCollator protected constructor destructor ----------------------------
376
377 /**
378 * Default constructor.
379 * Constructor is different from the old default Collator constructor.
380 * The task for determing the default collation strength and normalization mode
381 * is left to the child class.
382 */
383 Collator::Collator()
384 : UObject()
385 {
386 }
387
388 /**
389 * Constructor.
390 * Empty constructor, does not handle the arguments.
391 * This constructor is done for backward compatibility with 1.7 and 1.8.
392 * The task for handling the argument collation strength and normalization
393 * mode is left to the child class.
394 * @param collationStrength collation strength
395 * @param decompositionMode
396 * @deprecated 2.4 use the default constructor instead
397 */
398 Collator::Collator(UCollationStrength, UNormalizationMode )
399 : UObject()
400 {
401 }
402
403 Collator::~Collator()
404 {
405 }
406
407 Collator::Collator(const Collator &other)
408 : UObject(other)
409 {
410 }
411
412 int32_t Collator::getBound(const uint8_t *source,
413 int32_t sourceLength,
414 UColBoundMode boundType,
415 uint32_t noOfLevels,
416 uint8_t *result,
417 int32_t resultLength,
418 UErrorCode &status) {
419 return ucol_getBound(source, sourceLength, boundType, noOfLevels, result, resultLength, &status);
420 }
421
422 void
423 Collator::setLocales(const Locale& /* requestedLocale */, const Locale& /* validLocale */) {
424 }
425
426 // -------------------------------------
427
428 URegistryKey
429 Collator::registerInstance(Collator* toAdopt, const Locale& locale, UErrorCode& status)
430 {
431 if (U_SUCCESS(status)) {
432 return getService()->registerInstance(toAdopt, locale, status);
433 }
434 return NULL;
435 }
436
437 // -------------------------------------
438
439 class CFactory : public LocaleKeyFactory {
440 private:
441 CollatorFactory* _delegate;
442 Hashtable* _ids;
443
444 public:
445 CFactory(CollatorFactory* delegate, UErrorCode& status)
446 : LocaleKeyFactory(delegate->visible() ? VISIBLE : INVISIBLE)
447 , _delegate(delegate)
448 , _ids(NULL)
449 {
450 if (U_SUCCESS(status)) {
451 int32_t count = 0;
452 _ids = new Hashtable(status);
453 if (_ids) {
454 const UnicodeString * idlist = _delegate->getSupportedIDs(count, status);
455 for (int i = 0; i < count; ++i) {
456 _ids->put(idlist[i], (void*)this, status);
457 if (U_FAILURE(status)) {
458 delete _ids;
459 _ids = NULL;
460 return;
461 }
462 }
463 } else {
464 status = U_MEMORY_ALLOCATION_ERROR;
465 }
466 }
467 }
468
469 virtual ~CFactory()
470 {
471 delete _delegate;
472 delete _ids;
473 }
474
475 virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const;
476
477 protected:
478 virtual const Hashtable* getSupportedIDs(UErrorCode& status) const
479 {
480 if (U_SUCCESS(status)) {
481 return _ids;
482 }
483 return NULL;
484 }
485
486 virtual UnicodeString&
487 getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const;
488 };
489
490 UObject*
491 CFactory::create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& status) const
492 {
493 if (handlesKey(key, status)) {
494 const LocaleKey& lkey = (const LocaleKey&)key;
495 Locale validLoc;
496 lkey.currentLocale(validLoc);
497 return _delegate->createCollator(validLoc);
498 }
499 return NULL;
500 }
501
502 UnicodeString&
503 CFactory::getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const
504 {
505 if ((_coverage & 0x1) == 0) {
506 UErrorCode status = U_ZERO_ERROR;
507 const Hashtable* ids = getSupportedIDs(status);
508 if (ids && (ids->get(id) != NULL)) {
509 Locale loc;
510 LocaleUtility::initLocaleFromName(id, loc);
511 return _delegate->getDisplayName(loc, locale, result);
512 }
513 }
514 result.setToBogus();
515 return result;
516 }
517
518 URegistryKey
519 Collator::registerFactory(CollatorFactory* toAdopt, UErrorCode& status)
520 {
521 if (U_SUCCESS(status)) {
522 CFactory* f = new CFactory(toAdopt, status);
523 if (f) {
524 return getService()->registerFactory(f, status);
525 }
526 status = U_MEMORY_ALLOCATION_ERROR;
527 }
528 return NULL;
529 }
530
531 // -------------------------------------
532
533 UBool
534 Collator::unregister(URegistryKey key, UErrorCode& status)
535 {
536 if (U_SUCCESS(status)) {
537 if (hasService()) {
538 return gService->unregister(key, status);
539 }
540 status = U_ILLEGAL_ARGUMENT_ERROR;
541 }
542 return FALSE;
543 }
544
545 // -------------------------------------
546
547 StringEnumeration*
548 Collator::getAvailableLocales(void)
549 {
550 return getService()->getAvailableLocales();
551 }
552
553 // UCollator private data members ----------------------------------------
554
555 /* This is useless information */
556 /*const UVersionInfo Collator::fVersion = {1, 1, 0, 0};*/
557
558 // -------------------------------------
559
560 U_NAMESPACE_END
561
562 // defined in ucln_cmn.h
563
564 /**
565 * Release all static memory held by collator.
566 */
567 U_CFUNC UBool collator_cleanup(void) {
568 if (gService) {
569 delete gService;
570 gService = NULL;
571 }
572 return TRUE;
573 }
574
575 #endif /* #if !UCONFIG_NO_COLLATION */
576
577 /* eof */