2 ******************************************************************************
3 * Copyright (C) 1996-2003, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 ******************************************************************************
11 * Created by: Helena Shih
13 * Modification History:
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
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
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)
40 #include "unicode/utypes.h"
42 #if !UCONFIG_NO_COLLATION
44 #include "unicode/coll.h"
45 #include "unicode/tblcoll.h"
53 // ------------------------------------------
58 //-------------------------------------------
61 CollatorFactory::visible(void) const {
65 //-------------------------------------------
68 CollatorFactory::getDisplayName(const Locale
& objectLocale
,
69 const Locale
& displayLocale
,
70 UnicodeString
& result
)
72 return objectLocale
.getDisplayName(displayLocale
, result
);
75 // -------------------------------------
77 class ICUCollatorFactory
: public ICUResourceBundleFactory
{
79 virtual UObject
* create(const ICUServiceKey
& key
, const ICUService
* service
, UErrorCode
& status
) const;
83 ICUCollatorFactory::create(const ICUServiceKey
& key
, const ICUService
* /* service */, UErrorCode
& status
) const {
84 if (handlesKey(key
, status
)) {
85 const LocaleKey
& lkey
= (const LocaleKey
&)key
;
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
);
92 return Collator::makeInstance(loc
, status
);
97 // -------------------------------------
99 class ICUCollatorService
: public ICULocaleService
{
102 : ICULocaleService("Collator")
104 UErrorCode status
= U_ZERO_ERROR
;
105 registerFactory(new ICUCollatorFactory(), status
);
108 virtual UObject
* cloneInstance(UObject
* instance
) const {
109 return ((Collator
*)instance
)->clone();
112 virtual UObject
* handleDefault(const ICUServiceKey
& key
, UnicodeString
* actualID
, UErrorCode
& status
) const {
113 LocaleKey
& lkey
= (LocaleKey
&)key
;
115 lkey
.canonicalID(*actualID
);
118 lkey
.canonicalLocale(loc
);
119 return Collator::makeInstance(loc
, status
);
122 virtual UObject
* getKey(ICUServiceKey
& key
, UnicodeString
* actualReturn
, UErrorCode
& status
) const {
124 if (actualReturn
== NULL
) {
127 Collator
* result
= (Collator
*)ICULocaleService::getKey(key
, actualReturn
, status
);
129 const LocaleKey
& lkey
= (const LocaleKey
&)key
;
130 Locale canonicalLocale
;
131 Locale currentLocale
;
133 result
->setLocales(lkey
.canonicalLocale(canonicalLocale
),
134 LocaleUtility::initLocaleFromName(*actualReturn
, currentLocale
));
139 virtual UBool
isDefault() const {
140 return countFactories() == 1;
144 // -------------------------------------
146 class ICUCollatorService
;
148 static ICULocaleService
* gService
= NULL
;
150 static ICULocaleService
*
156 needInit
= (UBool
)(gService
== NULL
);
159 ICULocaleService
*newservice
= new ICUCollatorService();
162 if(gService
== NULL
) {
163 gService
= newservice
;
170 ucln_i18n_registerCleanup();
176 // -------------------------------------
182 return gService
!= NULL
;
185 // -------------------------------------
188 Collator::createUCollator(const char *loc
,
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
);
200 result
= rbc
->ucollator
;
201 rbc
->ucollator
= NULL
; // to prevent free on delete
209 // Collator public methods -----------------------------------------------
211 Collator
* Collator::createInstance(UErrorCode
& success
)
213 if (U_FAILURE(success
))
215 return createInstance(Locale::getDefault(), success
);
218 Collator
* Collator::createInstance(const Locale
& desiredLocale
,
221 if (U_FAILURE(status
))
225 return (Collator
*)gService
->get(desiredLocale
, status
);
227 return makeInstance(desiredLocale
, status
);
231 Collator
* Collator::makeInstance(const Locale
& desiredLocale
,
234 // A bit of explanation is required here. Although in the current
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
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.
255 RuleBasedCollator
* collation
= new RuleBasedCollator(desiredLocale
,
258 if (collation
== 0) {
259 status
= U_MEMORY_ALLOCATION_ERROR
;
262 if (U_FAILURE(status
))
270 // !!! dlf the following is obsolete, ignore registration for this
273 Collator::createInstance(const Locale
&loc
,
274 UVersionInfo version
,
275 UErrorCode
&status
) {
279 collator
=new RuleBasedCollator(loc
, status
);
282 status
= U_MEMORY_ALLOCATION_ERROR
;
286 if(U_SUCCESS(status
)) {
287 collator
->getVersion(info
);
288 if(0!=uprv_memcmp(version
, info
, sizeof(UVersionInfo
))) {
290 status
=U_MISSING_RESOURCE_ERROR
;
297 // implement deprecated, previously abstract method
298 Collator::EComparisonResult
Collator::compare(const UnicodeString
& source
,
299 const UnicodeString
& target
) const
301 UErrorCode ec
= U_ZERO_ERROR
;
302 return (Collator::EComparisonResult
)compare(source
, target
, ec
);
305 // implement deprecated, previously abstract method
306 Collator::EComparisonResult
Collator::compare(const UnicodeString
& source
,
307 const UnicodeString
& target
,
308 int32_t length
) const
310 UErrorCode ec
= U_ZERO_ERROR
;
311 return (Collator::EComparisonResult
)compare(source
, target
, length
, ec
);
314 // implement deprecated, previously abstract method
315 Collator::EComparisonResult
Collator::compare(const UChar
* source
, int32_t sourceLength
,
316 const UChar
* target
, int32_t targetLength
)
319 UErrorCode ec
= U_ZERO_ERROR
;
320 return (Collator::EComparisonResult
)compare(source
, sourceLength
, target
, targetLength
, ec
);
323 UBool
Collator::equals(const UnicodeString
& source
,
324 const UnicodeString
& target
) const
326 UErrorCode ec
= U_ZERO_ERROR
;
327 return (compare(source
, target
, ec
) == UCOL_EQUAL
);
330 UBool
Collator::greaterOrEqual(const UnicodeString
& source
,
331 const UnicodeString
& target
) const
333 UErrorCode ec
= U_ZERO_ERROR
;
334 return (compare(source
, target
, ec
) != UCOL_LESS
);
337 UBool
Collator::greater(const UnicodeString
& source
,
338 const UnicodeString
& target
) const
340 UErrorCode ec
= U_ZERO_ERROR
;
341 return (compare(source
, target
, ec
) == UCOL_GREATER
);
344 // this API ignores registered collators, since it returns an
345 // array of indefinite lifetime
346 const Locale
* Collator::getAvailableLocales(int32_t& count
)
348 return Locale::getAvailableLocales(count
);
351 UnicodeString
& Collator::getDisplayName(const Locale
& objectLocale
,
352 const Locale
& displayLocale
,
356 return gService
->getDisplayName(objectLocale
.getName(), name
, displayLocale
);
358 return objectLocale
.getDisplayName(displayLocale
, name
);
361 UnicodeString
& Collator::getDisplayName(const Locale
& objectLocale
,
364 return getDisplayName(objectLocale
, Locale::getDefault(), name
);
367 /* This is useless information */
368 /*void Collator::getVersion(UVersionInfo versionInfo) const
370 if (versionInfo!=NULL)
371 uprv_memcpy(versionInfo, fVersion, U_MAX_VERSION_LENGTH);
375 // UCollator protected constructor destructor ----------------------------
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.
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
398 Collator::Collator(UCollationStrength
, UNormalizationMode
)
403 Collator::~Collator()
407 Collator::Collator(const Collator
&other
)
412 int32_t Collator::getBound(const uint8_t *source
,
413 int32_t sourceLength
,
414 UColBoundMode boundType
,
417 int32_t resultLength
,
418 UErrorCode
&status
) {
419 return ucol_getBound(source
, sourceLength
, boundType
, noOfLevels
, result
, resultLength
, &status
);
423 Collator::setLocales(const Locale
& /* requestedLocale */, const Locale
& /* validLocale */) {
426 // -------------------------------------
429 Collator::registerInstance(Collator
* toAdopt
, const Locale
& locale
, UErrorCode
& status
)
431 if (U_SUCCESS(status
)) {
432 return getService()->registerInstance(toAdopt
, locale
, status
);
437 // -------------------------------------
439 class CFactory
: public LocaleKeyFactory
{
441 CollatorFactory
* _delegate
;
445 CFactory(CollatorFactory
* delegate
, UErrorCode
& status
)
446 : LocaleKeyFactory(delegate
->visible() ? VISIBLE
: INVISIBLE
)
447 , _delegate(delegate
)
450 if (U_SUCCESS(status
)) {
452 _ids
= new Hashtable(status
);
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
)) {
464 status
= U_MEMORY_ALLOCATION_ERROR
;
475 virtual UObject
* create(const ICUServiceKey
& key
, const ICUService
* service
, UErrorCode
& status
) const;
478 virtual const Hashtable
* getSupportedIDs(UErrorCode
& status
) const
480 if (U_SUCCESS(status
)) {
486 virtual UnicodeString
&
487 getDisplayName(const UnicodeString
& id
, const Locale
& locale
, UnicodeString
& result
) const;
491 CFactory::create(const ICUServiceKey
& key
, const ICUService
* /* service */, UErrorCode
& status
) const
493 if (handlesKey(key
, status
)) {
494 const LocaleKey
& lkey
= (const LocaleKey
&)key
;
496 lkey
.currentLocale(validLoc
);
497 return _delegate
->createCollator(validLoc
);
503 CFactory::getDisplayName(const UnicodeString
& id
, const Locale
& locale
, UnicodeString
& result
) const
505 if ((_coverage
& 0x1) == 0) {
506 UErrorCode status
= U_ZERO_ERROR
;
507 const Hashtable
* ids
= getSupportedIDs(status
);
508 if (ids
&& (ids
->get(id
) != NULL
)) {
510 LocaleUtility::initLocaleFromName(id
, loc
);
511 return _delegate
->getDisplayName(loc
, locale
, result
);
519 Collator::registerFactory(CollatorFactory
* toAdopt
, UErrorCode
& status
)
521 if (U_SUCCESS(status
)) {
522 CFactory
* f
= new CFactory(toAdopt
, status
);
524 return getService()->registerFactory(f
, status
);
526 status
= U_MEMORY_ALLOCATION_ERROR
;
531 // -------------------------------------
534 Collator::unregister(URegistryKey key
, UErrorCode
& status
)
536 if (U_SUCCESS(status
)) {
538 return gService
->unregister(key
, status
);
540 status
= U_ILLEGAL_ARGUMENT_ERROR
;
545 // -------------------------------------
548 Collator::getAvailableLocales(void)
550 return getService()->getAvailableLocales();
553 // UCollator private data members ----------------------------------------
555 /* This is useless information */
556 /*const UVersionInfo Collator::fVersion = {1, 1, 0, 0};*/
558 // -------------------------------------
562 // defined in ucln_cmn.h
565 * Release all static memory held by collator.
567 U_CFUNC UBool
collator_cleanup(void) {
575 #endif /* #if !UCONFIG_NO_COLLATION */