2 *******************************************************************************
3 * Copyright (C) 2008-2012, 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"
31 static UHashtable
* gGenderInfoCache
= NULL
;
32 static UMutex gGenderMetaLock
= U_MUTEX_INITIALIZER
;
33 static const char* gNeutralStr
= "neutral";
34 static const char* gMailTaintsStr
= "maleTaints";
35 static const char* gMixedNeutralStr
= "mixedNeutral";
36 static icu::GenderInfo
* gObjs
= NULL
;
47 static UBool U_CALLCONV
gender_cleanup(void) {
48 if (gGenderInfoCache
!= NULL
) {
49 uhash_close(gGenderInfoCache
);
50 gGenderInfoCache
= NULL
;
60 GenderInfo::GenderInfo() {
63 GenderInfo::~GenderInfo() {
66 const GenderInfo
* GenderInfo::getInstance(const Locale
& locale
, UErrorCode
& status
) {
67 if (U_FAILURE(status
)) {
71 // Make sure our cache exists.
73 UMTX_CHECK(&gGenderMetaLock
, (gGenderInfoCache
== NULL
), needed
);
75 Mutex
lock(&gGenderMetaLock
);
76 if (gGenderInfoCache
== NULL
) {
77 gObjs
= new GenderInfo
[GENDER_STYLE_LENGTH
];
79 status
= U_MEMORY_ALLOCATION_ERROR
;
82 for (int i
= 0; i
< GENDER_STYLE_LENGTH
; i
++) {
85 gGenderInfoCache
= uhash_open(uhash_hashChars
, uhash_compareChars
, NULL
, &status
);
86 if (U_FAILURE(status
)) {
90 uhash_setKeyDeleter(gGenderInfoCache
, uprv_free
);
91 ucln_i18n_registerCleanup(UCLN_I18N_GENDERINFO
, gender_cleanup
);
95 const GenderInfo
* result
= NULL
;
96 const char* key
= locale
.getName();
98 Mutex
lock(&gGenderMetaLock
);
99 result
= (const GenderInfo
*) uhash_get(gGenderInfoCache
, key
);
105 // On cache miss, try to create GenderInfo from CLDR data
106 result
= loadInstance(locale
, status
);
107 if (U_FAILURE(status
)) {
111 // Try to put our GenderInfo object in cache. If there is a race condition,
112 // favor the GenderInfo object that is already in the cache.
114 Mutex
lock(&gGenderMetaLock
);
115 GenderInfo
* temp
= (GenderInfo
*) uhash_get(gGenderInfoCache
, key
);
119 uhash_put(gGenderInfoCache
, uprv_strdup(key
), (void*) result
, &status
);
120 if (U_FAILURE(status
)) {
128 const GenderInfo
* GenderInfo::loadInstance(const Locale
& locale
, UErrorCode
& status
) {
129 LocalUResourceBundlePointer
rb(
130 ures_openDirect(NULL
, "genderList", &status
));
131 if (U_FAILURE(status
)) {
134 LocalUResourceBundlePointer
locRes(ures_getByKey(rb
.getAlias(), "genderList", NULL
, &status
));
135 if (U_FAILURE(status
)) {
139 const char* curLocaleName
= locale
.getName();
140 UErrorCode key_status
= U_ZERO_ERROR
;
141 const UChar
* s
= ures_getStringByKey(locRes
.getAlias(), curLocaleName
, &resLen
, &key_status
);
143 key_status
= U_ZERO_ERROR
;
144 char parentLocaleName
[ULOC_FULLNAME_CAPACITY
];
145 uprv_strcpy(parentLocaleName
, curLocaleName
);
146 while (s
== NULL
&& uloc_getParent(parentLocaleName
, parentLocaleName
, ULOC_FULLNAME_CAPACITY
, &key_status
) > 0) {
147 key_status
= U_ZERO_ERROR
;
149 s
= ures_getStringByKey(locRes
.getAlias(), parentLocaleName
, &resLen
, &key_status
);
150 key_status
= U_ZERO_ERROR
;
154 return &gObjs
[NEUTRAL
];
157 u_UCharsToChars(s
, type_str
, resLen
+ 1);
158 if (uprv_strcmp(type_str
, gNeutralStr
) == 0) {
159 return &gObjs
[NEUTRAL
];
161 if (uprv_strcmp(type_str
, gMixedNeutralStr
) == 0) {
162 return &gObjs
[MIXED_NEUTRAL
];
164 if (uprv_strcmp(type_str
, gMailTaintsStr
) == 0) {
165 return &gObjs
[MALE_TAINTS
];
167 return &gObjs
[NEUTRAL
];
170 UGender
GenderInfo::getListGender(const UGender
* genders
, int32_t length
, UErrorCode
& status
) const {
171 if (U_FAILURE(status
)) {
172 return UGENDER_OTHER
;
175 return UGENDER_OTHER
;
180 UBool has_female
= FALSE
;
181 UBool has_male
= FALSE
;
184 return UGENDER_OTHER
;
186 for (int32_t i
= 0; i
< length
; ++i
) {
187 switch (genders
[i
]) {
189 return UGENDER_OTHER
;
193 return UGENDER_OTHER
;
199 return UGENDER_OTHER
;
207 return has_male
? UGENDER_MALE
: UGENDER_FEMALE
;
210 for (int32_t i
= 0; i
< length
; ++i
) {
211 if (genders
[i
] != UGENDER_FEMALE
) {
215 return UGENDER_FEMALE
;
218 return UGENDER_OTHER
;
223 const GenderInfo
* GenderInfo::getNeutralInstance() {
224 return &gObjs
[NEUTRAL
];
227 const GenderInfo
* GenderInfo::getMixedNeutralInstance() {
228 return &gObjs
[MIXED_NEUTRAL
];
231 const GenderInfo
* GenderInfo::getMaleTaintsInstance() {
232 return &gObjs
[MALE_TAINTS
];
237 U_CAPI
const UGenderInfo
* U_EXPORT2
238 ugender_getInstance(const char* locale
, UErrorCode
* status
) {
239 return (const UGenderInfo
*) icu::GenderInfo::getInstance(locale
, *status
);
242 U_CAPI UGender U_EXPORT2
243 ugender_getListGender(const UGenderInfo
* genderInfo
, const UGender
* genders
, int32_t size
, UErrorCode
* status
) {
244 return ((const icu::GenderInfo
*)genderInfo
)->getListGender(genders
, size
, *status
);
247 #endif /* #if !UCONFIG_NO_FORMATTING */