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
;
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 static UMutex gGenderMetaLock
;
102 const GenderInfo
* result
= NULL
;
103 const char* key
= locale
.getName();
105 Mutex
lock(&gGenderMetaLock
);
106 result
= (const GenderInfo
*) uhash_get(gGenderInfoCache
, key
);
112 // On cache miss, try to create GenderInfo from CLDR data
113 result
= loadInstance(locale
, status
);
114 if (U_FAILURE(status
)) {
118 // Try to put our GenderInfo object in cache. If there is a race condition,
119 // favor the GenderInfo object that is already in the cache.
121 Mutex
lock(&gGenderMetaLock
);
122 GenderInfo
* temp
= (GenderInfo
*) uhash_get(gGenderInfoCache
, key
);
126 uhash_put(gGenderInfoCache
, uprv_strdup(key
), (void*) result
, &status
);
127 if (U_FAILURE(status
)) {
135 const GenderInfo
* GenderInfo::loadInstance(const Locale
& locale
, UErrorCode
& status
) {
136 LocalUResourceBundlePointer
rb(
137 ures_openDirect(NULL
, "genderList", &status
));
138 if (U_FAILURE(status
)) {
141 LocalUResourceBundlePointer
locRes(ures_getByKey(rb
.getAlias(), "genderList", NULL
, &status
));
142 if (U_FAILURE(status
)) {
146 const char* curLocaleName
= locale
.getName();
147 UErrorCode key_status
= U_ZERO_ERROR
;
148 const UChar
* s
= ures_getStringByKey(locRes
.getAlias(), curLocaleName
, &resLen
, &key_status
);
150 key_status
= U_ZERO_ERROR
;
151 char parentLocaleName
[ULOC_FULLNAME_CAPACITY
];
152 uprv_strcpy(parentLocaleName
, curLocaleName
);
153 while (s
== NULL
&& uloc_getParent(parentLocaleName
, parentLocaleName
, ULOC_FULLNAME_CAPACITY
, &key_status
) > 0) {
154 key_status
= U_ZERO_ERROR
;
156 s
= ures_getStringByKey(locRes
.getAlias(), parentLocaleName
, &resLen
, &key_status
);
157 key_status
= U_ZERO_ERROR
;
161 return &gObjs
[NEUTRAL
];
164 u_UCharsToChars(s
, type_str
, resLen
+ 1);
165 if (uprv_strcmp(type_str
, gNeutralStr
) == 0) {
166 return &gObjs
[NEUTRAL
];
168 if (uprv_strcmp(type_str
, gMixedNeutralStr
) == 0) {
169 return &gObjs
[MIXED_NEUTRAL
];
171 if (uprv_strcmp(type_str
, gMailTaintsStr
) == 0) {
172 return &gObjs
[MALE_TAINTS
];
174 return &gObjs
[NEUTRAL
];
177 UGender
GenderInfo::getListGender(const UGender
* genders
, int32_t length
, UErrorCode
& status
) const {
178 if (U_FAILURE(status
)) {
179 return UGENDER_OTHER
;
182 return UGENDER_OTHER
;
187 UBool has_female
= FALSE
;
188 UBool has_male
= FALSE
;
191 return UGENDER_OTHER
;
193 for (int32_t i
= 0; i
< length
; ++i
) {
194 switch (genders
[i
]) {
196 return UGENDER_OTHER
;
200 return UGENDER_OTHER
;
206 return UGENDER_OTHER
;
214 return has_male
? UGENDER_MALE
: UGENDER_FEMALE
;
217 for (int32_t i
= 0; i
< length
; ++i
) {
218 if (genders
[i
] != UGENDER_FEMALE
) {
222 return UGENDER_FEMALE
;
225 return UGENDER_OTHER
;
230 const GenderInfo
* GenderInfo::getNeutralInstance() {
231 return &gObjs
[NEUTRAL
];
234 const GenderInfo
* GenderInfo::getMixedNeutralInstance() {
235 return &gObjs
[MIXED_NEUTRAL
];
238 const GenderInfo
* GenderInfo::getMaleTaintsInstance() {
239 return &gObjs
[MALE_TAINTS
];
244 U_CAPI
const UGenderInfo
* U_EXPORT2
245 ugender_getInstance(const char* locale
, UErrorCode
* status
) {
246 return (const UGenderInfo
*) icu::GenderInfo::getInstance(locale
, *status
);
249 U_CAPI UGender U_EXPORT2
250 ugender_getListGender(const UGenderInfo
* genderInfo
, const UGender
* genders
, int32_t size
, UErrorCode
* status
) {
251 return ((const icu::GenderInfo
*)genderInfo
)->getListGender(genders
, size
, *status
);
254 #endif /* #if !UCONFIG_NO_FORMATTING */