]> git.saurik.com Git - apple/icu.git/blame - icuSources/i18n/gender.cpp
ICU-551.51.4.tar.gz
[apple/icu.git] / icuSources / i18n / gender.cpp
CommitLineData
51004dcb
A
1/*
2*******************************************************************************
57a6839d 3* Copyright (C) 2008-2013, International Business Machines Corporation and
51004dcb
A
4* others. All Rights Reserved.
5*******************************************************************************
6*
7*
8* File GENDER.CPP
9*
10* Modification History:*
11* Date Name Description
12*
13********************************************************************************
14*/
15
16#include "unicode/utypes.h"
17
18#if !UCONFIG_NO_FORMATTING
19
20#include "unicode/gender.h"
21#include "unicode/ugender.h"
22#include "unicode/ures.h"
23
24#include "cmemory.h"
25#include "cstring.h"
26#include "mutex.h"
57a6839d 27#include "uassert.h"
51004dcb
A
28#include "ucln_in.h"
29#include "umutex.h"
30#include "uhash.h"
31
32static UHashtable* gGenderInfoCache = NULL;
33static UMutex gGenderMetaLock = U_MUTEX_INITIALIZER;
34static const char* gNeutralStr = "neutral";
35static const char* gMailTaintsStr = "maleTaints";
36static const char* gMixedNeutralStr = "mixedNeutral";
37static icu::GenderInfo* gObjs = NULL;
57a6839d 38static icu::UInitOnce gGenderInitOnce = U_INITONCE_INITIALIZER;
51004dcb
A
39
40enum GenderStyle {
41 NEUTRAL,
42 MIXED_NEUTRAL,
43 MALE_TAINTS,
44 GENDER_STYLE_LENGTH
45};
46
47U_CDECL_BEGIN
48
49static UBool U_CALLCONV gender_cleanup(void) {
50 if (gGenderInfoCache != NULL) {
51 uhash_close(gGenderInfoCache);
52 gGenderInfoCache = NULL;
53 delete [] gObjs;
54 }
57a6839d 55 gGenderInitOnce.reset();
51004dcb
A
56 return TRUE;
57}
58
59U_CDECL_END
60
61U_NAMESPACE_BEGIN
62
57a6839d
A
63void 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)) {
67 return;
68 }
69 gObjs = new GenderInfo[GENDER_STYLE_LENGTH];
70 if (gObjs == NULL) {
71 status = U_MEMORY_ALLOCATION_ERROR;
72 return;
73 }
74 for (int i = 0; i < GENDER_STYLE_LENGTH; i++) {
75 gObjs[i]._style = i;
76 }
77 gGenderInfoCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
78 if (U_FAILURE(status)) {
79 delete [] gObjs;
80 return;
81 }
82 uhash_setKeyDeleter(gGenderInfoCache, uprv_free);
83}
84
85
51004dcb
A
86GenderInfo::GenderInfo() {
87}
88
89GenderInfo::~GenderInfo() {
90}
91
92const GenderInfo* GenderInfo::getInstance(const Locale& locale, UErrorCode& status) {
57a6839d
A
93 // Make sure our cache exists.
94 umtx_initOnce(gGenderInitOnce, &GenderInfo_initCache, status);
51004dcb
A
95 if (U_FAILURE(status)) {
96 return NULL;
97 }
98
51004dcb
A
99 const GenderInfo* result = NULL;
100 const char* key = locale.getName();
101 {
102 Mutex lock(&gGenderMetaLock);
103 result = (const GenderInfo*) uhash_get(gGenderInfoCache, key);
104 }
105 if (result) {
106 return result;
107 }
108
109 // On cache miss, try to create GenderInfo from CLDR data
110 result = loadInstance(locale, status);
111 if (U_FAILURE(status)) {
112 return NULL;
113 }
114
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.
117 {
118 Mutex lock(&gGenderMetaLock);
119 GenderInfo* temp = (GenderInfo*) uhash_get(gGenderInfoCache, key);
120 if (temp) {
121 result = temp;
122 } else {
123 uhash_put(gGenderInfoCache, uprv_strdup(key), (void*) result, &status);
124 if (U_FAILURE(status)) {
125 return NULL;
126 }
127 }
128 }
129 return result;
130}
131
132const GenderInfo* GenderInfo::loadInstance(const Locale& locale, UErrorCode& status) {
133 LocalUResourceBundlePointer rb(
134 ures_openDirect(NULL, "genderList", &status));
135 if (U_FAILURE(status)) {
136 return NULL;
137 }
138 LocalUResourceBundlePointer locRes(ures_getByKey(rb.getAlias(), "genderList", NULL, &status));
139 if (U_FAILURE(status)) {
140 return NULL;
141 }
142 int32_t resLen = 0;
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);
146 if (s == NULL) {
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;
152 resLen = 0;
153 s = ures_getStringByKey(locRes.getAlias(), parentLocaleName, &resLen, &key_status);
154 key_status = U_ZERO_ERROR;
155 }
156 }
157 if (s == NULL) {
158 return &gObjs[NEUTRAL];
159 }
160 char type_str[256];
161 u_UCharsToChars(s, type_str, resLen + 1);
162 if (uprv_strcmp(type_str, gNeutralStr) == 0) {
163 return &gObjs[NEUTRAL];
164 }
165 if (uprv_strcmp(type_str, gMixedNeutralStr) == 0) {
166 return &gObjs[MIXED_NEUTRAL];
167 }
168 if (uprv_strcmp(type_str, gMailTaintsStr) == 0) {
169 return &gObjs[MALE_TAINTS];
170 }
171 return &gObjs[NEUTRAL];
172}
173
174UGender GenderInfo::getListGender(const UGender* genders, int32_t length, UErrorCode& status) const {
175 if (U_FAILURE(status)) {
176 return UGENDER_OTHER;
177 }
178 if (length == 0) {
179 return UGENDER_OTHER;
180 }
181 if (length == 1) {
182 return genders[0];
183 }
184 UBool has_female = FALSE;
185 UBool has_male = FALSE;
186 switch (_style) {
187 case NEUTRAL:
188 return UGENDER_OTHER;
189 case MIXED_NEUTRAL:
190 for (int32_t i = 0; i < length; ++i) {
191 switch (genders[i]) {
192 case UGENDER_OTHER:
193 return UGENDER_OTHER;
194 break;
195 case UGENDER_FEMALE:
196 if (has_male) {
197 return UGENDER_OTHER;
198 }
199 has_female = TRUE;
200 break;
201 case UGENDER_MALE:
202 if (has_female) {
203 return UGENDER_OTHER;
204 }
205 has_male = TRUE;
206 break;
207 default:
208 break;
209 }
210 }
211 return has_male ? UGENDER_MALE : UGENDER_FEMALE;
212 break;
213 case MALE_TAINTS:
214 for (int32_t i = 0; i < length; ++i) {
215 if (genders[i] != UGENDER_FEMALE) {
216 return UGENDER_MALE;
217 }
218 }
219 return UGENDER_FEMALE;
220 break;
221 default:
222 return UGENDER_OTHER;
223 break;
224 }
225}
226
227const GenderInfo* GenderInfo::getNeutralInstance() {
228 return &gObjs[NEUTRAL];
229}
230
231const GenderInfo* GenderInfo::getMixedNeutralInstance() {
232 return &gObjs[MIXED_NEUTRAL];
233}
234
235const GenderInfo* GenderInfo::getMaleTaintsInstance() {
236 return &gObjs[MALE_TAINTS];
237}
238
239U_NAMESPACE_END
240
241U_CAPI const UGenderInfo* U_EXPORT2
242ugender_getInstance(const char* locale, UErrorCode* status) {
243 return (const UGenderInfo*) icu::GenderInfo::getInstance(locale, *status);
244}
245
246U_CAPI UGender U_EXPORT2
247ugender_getListGender(const UGenderInfo* genderInfo, const UGender* genders, int32_t size, UErrorCode* status) {
248 return ((const icu::GenderInfo *)genderInfo)->getListGender(genders, size, *status);
249}
250
251#endif /* #if !UCONFIG_NO_FORMATTING */