1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 *******************************************************************************
5 * Copyright (C) 2008-2013, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 *******************************************************************************
12 * Modification History:*
13 * Date Name Description
15 ********************************************************************************
18 #include "unicode/utypes.h"
20 #if !UCONFIG_NO_FORMATTING
22 #include "unicode/gender.h"
23 #include "unicode/ugender.h"
24 #include "unicode/ures.h"
34 static UHashtable
* gGenderInfoCache
= NULL
;
35 static UMutex gGenderMetaLock
= U_MUTEX_INITIALIZER
;
36 static const char* gNeutralStr
= "neutral";
37 static const char* gMailTaintsStr
= "maleTaints";
38 static const char* gMixedNeutralStr
= "mixedNeutral";
39 static icu::GenderInfo
* gObjs
= NULL
;
40 static icu::UInitOnce gGenderInitOnce
= U_INITONCE_INITIALIZER
;
51 static UBool U_CALLCONV
gender_cleanup(void) {
52 if (gGenderInfoCache
!= NULL
) {
53 uhash_close(gGenderInfoCache
);
54 gGenderInfoCache
= NULL
;
57 gGenderInitOnce
.reset();
65 void U_CALLCONV
GenderInfo_initCache(UErrorCode
&status
) {
66 ucln_i18n_registerCleanup(UCLN_I18N_GENDERINFO
, gender_cleanup
);
67 U_ASSERT(gGenderInfoCache
== NULL
);
68 if (U_FAILURE(status
)) {
71 gObjs
= new GenderInfo
[GENDER_STYLE_LENGTH
];
73 status
= U_MEMORY_ALLOCATION_ERROR
;
76 for (int i
= 0; i
< GENDER_STYLE_LENGTH
; i
++) {
79 gGenderInfoCache
= uhash_open(uhash_hashChars
, uhash_compareChars
, NULL
, &status
);
80 if (U_FAILURE(status
)) {
84 uhash_setKeyDeleter(gGenderInfoCache
, uprv_free
);
88 GenderInfo::GenderInfo() {
91 GenderInfo::~GenderInfo() {
94 const GenderInfo
* GenderInfo::getInstance(const Locale
& locale
, UErrorCode
& status
) {
95 // Make sure our cache exists.
96 umtx_initOnce(gGenderInitOnce
, &GenderInfo_initCache
, status
);
97 if (U_FAILURE(status
)) {
101 const GenderInfo
* result
= NULL
;
102 const char* key
= locale
.getName();
104 Mutex
lock(&gGenderMetaLock
);
105 result
= (const GenderInfo
*) uhash_get(gGenderInfoCache
, key
);
111 // On cache miss, try to create GenderInfo from CLDR data
112 result
= loadInstance(locale
, status
);
113 if (U_FAILURE(status
)) {
117 // Try to put our GenderInfo object in cache. If there is a race condition,
118 // favor the GenderInfo object that is already in the cache.
120 Mutex
lock(&gGenderMetaLock
);
121 GenderInfo
* temp
= (GenderInfo
*) uhash_get(gGenderInfoCache
, key
);
125 uhash_put(gGenderInfoCache
, uprv_strdup(key
), (void*) result
, &status
);
126 if (U_FAILURE(status
)) {
134 const GenderInfo
* GenderInfo::loadInstance(const Locale
& locale
, UErrorCode
& status
) {
135 LocalUResourceBundlePointer
rb(
136 ures_openDirect(NULL
, "genderList", &status
));
137 if (U_FAILURE(status
)) {
140 LocalUResourceBundlePointer
locRes(ures_getByKey(rb
.getAlias(), "genderList", NULL
, &status
));
141 if (U_FAILURE(status
)) {
145 const char* curLocaleName
= locale
.getName();
146 UErrorCode key_status
= U_ZERO_ERROR
;
147 const UChar
* s
= ures_getStringByKey(locRes
.getAlias(), curLocaleName
, &resLen
, &key_status
);
149 key_status
= U_ZERO_ERROR
;
150 char parentLocaleName
[ULOC_FULLNAME_CAPACITY
];
151 uprv_strcpy(parentLocaleName
, curLocaleName
);
152 while (s
== NULL
&& uloc_getParent(parentLocaleName
, parentLocaleName
, ULOC_FULLNAME_CAPACITY
, &key_status
) > 0) {
153 key_status
= U_ZERO_ERROR
;
155 s
= ures_getStringByKey(locRes
.getAlias(), parentLocaleName
, &resLen
, &key_status
);
156 key_status
= U_ZERO_ERROR
;
160 return &gObjs
[NEUTRAL
];
163 u_UCharsToChars(s
, type_str
, resLen
+ 1);
164 if (uprv_strcmp(type_str
, gNeutralStr
) == 0) {
165 return &gObjs
[NEUTRAL
];
167 if (uprv_strcmp(type_str
, gMixedNeutralStr
) == 0) {
168 return &gObjs
[MIXED_NEUTRAL
];
170 if (uprv_strcmp(type_str
, gMailTaintsStr
) == 0) {
171 return &gObjs
[MALE_TAINTS
];
173 return &gObjs
[NEUTRAL
];
176 UGender
GenderInfo::getListGender(const UGender
* genders
, int32_t length
, UErrorCode
& status
) const {
177 if (U_FAILURE(status
)) {
178 return UGENDER_OTHER
;
181 return UGENDER_OTHER
;
186 UBool has_female
= FALSE
;
187 UBool has_male
= FALSE
;
190 return UGENDER_OTHER
;
192 for (int32_t i
= 0; i
< length
; ++i
) {
193 switch (genders
[i
]) {
195 return UGENDER_OTHER
;
199 return UGENDER_OTHER
;
205 return UGENDER_OTHER
;
213 return has_male
? UGENDER_MALE
: UGENDER_FEMALE
;
216 for (int32_t i
= 0; i
< length
; ++i
) {
217 if (genders
[i
] != UGENDER_FEMALE
) {
221 return UGENDER_FEMALE
;
224 return UGENDER_OTHER
;
229 const GenderInfo
* GenderInfo::getNeutralInstance() {
230 return &gObjs
[NEUTRAL
];
233 const GenderInfo
* GenderInfo::getMixedNeutralInstance() {
234 return &gObjs
[MIXED_NEUTRAL
];
237 const GenderInfo
* GenderInfo::getMaleTaintsInstance() {
238 return &gObjs
[MALE_TAINTS
];
243 U_CAPI
const UGenderInfo
* U_EXPORT2
244 ugender_getInstance(const char* locale
, UErrorCode
* status
) {
245 return (const UGenderInfo
*) icu::GenderInfo::getInstance(locale
, *status
);
248 U_CAPI UGender U_EXPORT2
249 ugender_getListGender(const UGenderInfo
* genderInfo
, const UGender
* genders
, int32_t size
, UErrorCode
* status
) {
250 return ((const icu::GenderInfo
*)genderInfo
)->getListGender(genders
, size
, *status
);
253 #endif /* #if !UCONFIG_NO_FORMATTING */