2 *******************************************************************************
3 * Copyright (C) 2008-2013, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 *******************************************************************************
10 * Modification History:*
11 * Date Name Description
13 ********************************************************************************
16 #include "unicode/utypes.h"
18 #if !UCONFIG_NO_FORMATTING
20 #include "unicode/gender.h"
21 #include "unicode/ugender.h"
22 #include "unicode/ures.h"
32 static UHashtable
* gGenderInfoCache
= NULL
;
33 static UMutex gGenderMetaLock
= U_MUTEX_INITIALIZER
;
34 static const char* gNeutralStr
= "neutral";
35 static const char* gMailTaintsStr
= "maleTaints";
36 static const char* gMixedNeutralStr
= "mixedNeutral";
37 static icu::GenderInfo
* gObjs
= NULL
;
38 static icu::UInitOnce gGenderInitOnce
= U_INITONCE_INITIALIZER
;
49 static UBool U_CALLCONV
gender_cleanup(void) {
50 if (gGenderInfoCache
!= NULL
) {
51 uhash_close(gGenderInfoCache
);
52 gGenderInfoCache
= NULL
;
55 gGenderInitOnce
.reset();
63 void U_CALLCONV
GenderInfo_initCache(UErrorCode
&status
) {
64 ucln_i18n_registerCleanup(UCLN_I18N_GENDERINFO
, gender_cleanup
);
65 U_ASSERT(gGenderInfoCache
== NULL
);
66 if (U_FAILURE(status
)) {
69 gObjs
= new GenderInfo
[GENDER_STYLE_LENGTH
];
71 status
= U_MEMORY_ALLOCATION_ERROR
;
74 for (int i
= 0; i
< GENDER_STYLE_LENGTH
; i
++) {
77 gGenderInfoCache
= uhash_open(uhash_hashChars
, uhash_compareChars
, NULL
, &status
);
78 if (U_FAILURE(status
)) {
82 uhash_setKeyDeleter(gGenderInfoCache
, uprv_free
);
86 GenderInfo::GenderInfo() {
89 GenderInfo::~GenderInfo() {
92 const GenderInfo
* GenderInfo::getInstance(const Locale
& locale
, UErrorCode
& status
) {
93 // Make sure our cache exists.
94 umtx_initOnce(gGenderInitOnce
, &GenderInfo_initCache
, status
);
95 if (U_FAILURE(status
)) {
99 const GenderInfo
* result
= NULL
;
100 const char* key
= locale
.getName();
102 Mutex
lock(&gGenderMetaLock
);
103 result
= (const GenderInfo
*) uhash_get(gGenderInfoCache
, key
);
109 // On cache miss, try to create GenderInfo from CLDR data
110 result
= loadInstance(locale
, status
);
111 if (U_FAILURE(status
)) {
115 // Try to put our GenderInfo object in cache. If there is a race condition,
116 // favor the GenderInfo object that is already in the cache.
118 Mutex
lock(&gGenderMetaLock
);
119 GenderInfo
* temp
= (GenderInfo
*) uhash_get(gGenderInfoCache
, key
);
123 uhash_put(gGenderInfoCache
, uprv_strdup(key
), (void*) result
, &status
);
124 if (U_FAILURE(status
)) {
132 const GenderInfo
* GenderInfo::loadInstance(const Locale
& locale
, UErrorCode
& status
) {
133 LocalUResourceBundlePointer
rb(
134 ures_openDirect(NULL
, "genderList", &status
));
135 if (U_FAILURE(status
)) {
138 LocalUResourceBundlePointer
locRes(ures_getByKey(rb
.getAlias(), "genderList", NULL
, &status
));
139 if (U_FAILURE(status
)) {
143 const char* curLocaleName
= locale
.getName();
144 UErrorCode key_status
= U_ZERO_ERROR
;
145 const UChar
* s
= ures_getStringByKey(locRes
.getAlias(), curLocaleName
, &resLen
, &key_status
);
147 key_status
= U_ZERO_ERROR
;
148 char parentLocaleName
[ULOC_FULLNAME_CAPACITY
];
149 uprv_strcpy(parentLocaleName
, curLocaleName
);
150 while (s
== NULL
&& uloc_getParent(parentLocaleName
, parentLocaleName
, ULOC_FULLNAME_CAPACITY
, &key_status
) > 0) {
151 key_status
= U_ZERO_ERROR
;
153 s
= ures_getStringByKey(locRes
.getAlias(), parentLocaleName
, &resLen
, &key_status
);
154 key_status
= U_ZERO_ERROR
;
158 return &gObjs
[NEUTRAL
];
161 u_UCharsToChars(s
, type_str
, resLen
+ 1);
162 if (uprv_strcmp(type_str
, gNeutralStr
) == 0) {
163 return &gObjs
[NEUTRAL
];
165 if (uprv_strcmp(type_str
, gMixedNeutralStr
) == 0) {
166 return &gObjs
[MIXED_NEUTRAL
];
168 if (uprv_strcmp(type_str
, gMailTaintsStr
) == 0) {
169 return &gObjs
[MALE_TAINTS
];
171 return &gObjs
[NEUTRAL
];
174 UGender
GenderInfo::getListGender(const UGender
* genders
, int32_t length
, UErrorCode
& status
) const {
175 if (U_FAILURE(status
)) {
176 return UGENDER_OTHER
;
179 return UGENDER_OTHER
;
184 UBool has_female
= FALSE
;
185 UBool has_male
= FALSE
;
188 return UGENDER_OTHER
;
190 for (int32_t i
= 0; i
< length
; ++i
) {
191 switch (genders
[i
]) {
193 return UGENDER_OTHER
;
197 return UGENDER_OTHER
;
203 return UGENDER_OTHER
;
211 return has_male
? UGENDER_MALE
: UGENDER_FEMALE
;
214 for (int32_t i
= 0; i
< length
; ++i
) {
215 if (genders
[i
] != UGENDER_FEMALE
) {
219 return UGENDER_FEMALE
;
222 return UGENDER_OTHER
;
227 const GenderInfo
* GenderInfo::getNeutralInstance() {
228 return &gObjs
[NEUTRAL
];
231 const GenderInfo
* GenderInfo::getMixedNeutralInstance() {
232 return &gObjs
[MIXED_NEUTRAL
];
235 const GenderInfo
* GenderInfo::getMaleTaintsInstance() {
236 return &gObjs
[MALE_TAINTS
];
241 U_CAPI
const UGenderInfo
* U_EXPORT2
242 ugender_getInstance(const char* locale
, UErrorCode
* status
) {
243 return (const UGenderInfo
*) icu::GenderInfo::getInstance(locale
, *status
);
246 U_CAPI UGender U_EXPORT2
247 ugender_getListGender(const UGenderInfo
* genderInfo
, const UGender
* genders
, int32_t size
, UErrorCode
* status
) {
248 return ((const icu::GenderInfo
*)genderInfo
)->getListGender(genders
, size
, *status
);
251 #endif /* #if !UCONFIG_NO_FORMATTING */