1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/icu/source/i18n/gender.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,251 @@ 1.4 +/* 1.5 +******************************************************************************* 1.6 +* Copyright (C) 2008-2013, International Business Machines Corporation and 1.7 +* others. All Rights Reserved. 1.8 +******************************************************************************* 1.9 +* 1.10 +* 1.11 +* File GENDER.CPP 1.12 +* 1.13 +* Modification History:* 1.14 +* Date Name Description 1.15 +* 1.16 +******************************************************************************** 1.17 +*/ 1.18 + 1.19 +#include "unicode/utypes.h" 1.20 + 1.21 +#if !UCONFIG_NO_FORMATTING 1.22 + 1.23 +#include "unicode/gender.h" 1.24 +#include "unicode/ugender.h" 1.25 +#include "unicode/ures.h" 1.26 + 1.27 +#include "cmemory.h" 1.28 +#include "cstring.h" 1.29 +#include "mutex.h" 1.30 +#include "uassert.h" 1.31 +#include "ucln_in.h" 1.32 +#include "umutex.h" 1.33 +#include "uhash.h" 1.34 + 1.35 +static UHashtable* gGenderInfoCache = NULL; 1.36 +static UMutex gGenderMetaLock = U_MUTEX_INITIALIZER; 1.37 +static const char* gNeutralStr = "neutral"; 1.38 +static const char* gMailTaintsStr = "maleTaints"; 1.39 +static const char* gMixedNeutralStr = "mixedNeutral"; 1.40 +static icu::GenderInfo* gObjs = NULL; 1.41 +static icu::UInitOnce gGenderInitOnce = U_INITONCE_INITIALIZER; 1.42 + 1.43 +enum GenderStyle { 1.44 + NEUTRAL, 1.45 + MIXED_NEUTRAL, 1.46 + MALE_TAINTS, 1.47 + GENDER_STYLE_LENGTH 1.48 +}; 1.49 + 1.50 +U_CDECL_BEGIN 1.51 + 1.52 +static UBool U_CALLCONV gender_cleanup(void) { 1.53 + if (gGenderInfoCache != NULL) { 1.54 + uhash_close(gGenderInfoCache); 1.55 + gGenderInfoCache = NULL; 1.56 + delete [] gObjs; 1.57 + } 1.58 + gGenderInitOnce.reset(); 1.59 + return TRUE; 1.60 +} 1.61 + 1.62 +U_CDECL_END 1.63 + 1.64 +U_NAMESPACE_BEGIN 1.65 + 1.66 +void U_CALLCONV GenderInfo_initCache(UErrorCode &status) { 1.67 + ucln_i18n_registerCleanup(UCLN_I18N_GENDERINFO, gender_cleanup); 1.68 + U_ASSERT(gGenderInfoCache == NULL); 1.69 + if (U_FAILURE(status)) { 1.70 + return; 1.71 + } 1.72 + gObjs = new GenderInfo[GENDER_STYLE_LENGTH]; 1.73 + if (gObjs == NULL) { 1.74 + status = U_MEMORY_ALLOCATION_ERROR; 1.75 + return; 1.76 + } 1.77 + for (int i = 0; i < GENDER_STYLE_LENGTH; i++) { 1.78 + gObjs[i]._style = i; 1.79 + } 1.80 + gGenderInfoCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status); 1.81 + if (U_FAILURE(status)) { 1.82 + delete [] gObjs; 1.83 + return; 1.84 + } 1.85 + uhash_setKeyDeleter(gGenderInfoCache, uprv_free); 1.86 +} 1.87 + 1.88 + 1.89 +GenderInfo::GenderInfo() { 1.90 +} 1.91 + 1.92 +GenderInfo::~GenderInfo() { 1.93 +} 1.94 + 1.95 +const GenderInfo* GenderInfo::getInstance(const Locale& locale, UErrorCode& status) { 1.96 + // Make sure our cache exists. 1.97 + umtx_initOnce(gGenderInitOnce, &GenderInfo_initCache, status); 1.98 + if (U_FAILURE(status)) { 1.99 + return NULL; 1.100 + } 1.101 + 1.102 + const GenderInfo* result = NULL; 1.103 + const char* key = locale.getName(); 1.104 + { 1.105 + Mutex lock(&gGenderMetaLock); 1.106 + result = (const GenderInfo*) uhash_get(gGenderInfoCache, key); 1.107 + } 1.108 + if (result) { 1.109 + return result; 1.110 + } 1.111 + 1.112 + // On cache miss, try to create GenderInfo from CLDR data 1.113 + result = loadInstance(locale, status); 1.114 + if (U_FAILURE(status)) { 1.115 + return NULL; 1.116 + } 1.117 + 1.118 + // Try to put our GenderInfo object in cache. If there is a race condition, 1.119 + // favor the GenderInfo object that is already in the cache. 1.120 + { 1.121 + Mutex lock(&gGenderMetaLock); 1.122 + GenderInfo* temp = (GenderInfo*) uhash_get(gGenderInfoCache, key); 1.123 + if (temp) { 1.124 + result = temp; 1.125 + } else { 1.126 + uhash_put(gGenderInfoCache, uprv_strdup(key), (void*) result, &status); 1.127 + if (U_FAILURE(status)) { 1.128 + return NULL; 1.129 + } 1.130 + } 1.131 + } 1.132 + return result; 1.133 +} 1.134 + 1.135 +const GenderInfo* GenderInfo::loadInstance(const Locale& locale, UErrorCode& status) { 1.136 + LocalUResourceBundlePointer rb( 1.137 + ures_openDirect(NULL, "genderList", &status)); 1.138 + if (U_FAILURE(status)) { 1.139 + return NULL; 1.140 + } 1.141 + LocalUResourceBundlePointer locRes(ures_getByKey(rb.getAlias(), "genderList", NULL, &status)); 1.142 + if (U_FAILURE(status)) { 1.143 + return NULL; 1.144 + } 1.145 + int32_t resLen = 0; 1.146 + const char* curLocaleName = locale.getName(); 1.147 + UErrorCode key_status = U_ZERO_ERROR; 1.148 + const UChar* s = ures_getStringByKey(locRes.getAlias(), curLocaleName, &resLen, &key_status); 1.149 + if (s == NULL) { 1.150 + key_status = U_ZERO_ERROR; 1.151 + char parentLocaleName[ULOC_FULLNAME_CAPACITY]; 1.152 + uprv_strcpy(parentLocaleName, curLocaleName); 1.153 + while (s == NULL && uloc_getParent(parentLocaleName, parentLocaleName, ULOC_FULLNAME_CAPACITY, &key_status) > 0) { 1.154 + key_status = U_ZERO_ERROR; 1.155 + resLen = 0; 1.156 + s = ures_getStringByKey(locRes.getAlias(), parentLocaleName, &resLen, &key_status); 1.157 + key_status = U_ZERO_ERROR; 1.158 + } 1.159 + } 1.160 + if (s == NULL) { 1.161 + return &gObjs[NEUTRAL]; 1.162 + } 1.163 + char type_str[256]; 1.164 + u_UCharsToChars(s, type_str, resLen + 1); 1.165 + if (uprv_strcmp(type_str, gNeutralStr) == 0) { 1.166 + return &gObjs[NEUTRAL]; 1.167 + } 1.168 + if (uprv_strcmp(type_str, gMixedNeutralStr) == 0) { 1.169 + return &gObjs[MIXED_NEUTRAL]; 1.170 + } 1.171 + if (uprv_strcmp(type_str, gMailTaintsStr) == 0) { 1.172 + return &gObjs[MALE_TAINTS]; 1.173 + } 1.174 + return &gObjs[NEUTRAL]; 1.175 +} 1.176 + 1.177 +UGender GenderInfo::getListGender(const UGender* genders, int32_t length, UErrorCode& status) const { 1.178 + if (U_FAILURE(status)) { 1.179 + return UGENDER_OTHER; 1.180 + } 1.181 + if (length == 0) { 1.182 + return UGENDER_OTHER; 1.183 + } 1.184 + if (length == 1) { 1.185 + return genders[0]; 1.186 + } 1.187 + UBool has_female = FALSE; 1.188 + UBool has_male = FALSE; 1.189 + switch (_style) { 1.190 + case NEUTRAL: 1.191 + return UGENDER_OTHER; 1.192 + case MIXED_NEUTRAL: 1.193 + for (int32_t i = 0; i < length; ++i) { 1.194 + switch (genders[i]) { 1.195 + case UGENDER_OTHER: 1.196 + return UGENDER_OTHER; 1.197 + break; 1.198 + case UGENDER_FEMALE: 1.199 + if (has_male) { 1.200 + return UGENDER_OTHER; 1.201 + } 1.202 + has_female = TRUE; 1.203 + break; 1.204 + case UGENDER_MALE: 1.205 + if (has_female) { 1.206 + return UGENDER_OTHER; 1.207 + } 1.208 + has_male = TRUE; 1.209 + break; 1.210 + default: 1.211 + break; 1.212 + } 1.213 + } 1.214 + return has_male ? UGENDER_MALE : UGENDER_FEMALE; 1.215 + break; 1.216 + case MALE_TAINTS: 1.217 + for (int32_t i = 0; i < length; ++i) { 1.218 + if (genders[i] != UGENDER_FEMALE) { 1.219 + return UGENDER_MALE; 1.220 + } 1.221 + } 1.222 + return UGENDER_FEMALE; 1.223 + break; 1.224 + default: 1.225 + return UGENDER_OTHER; 1.226 + break; 1.227 + } 1.228 +} 1.229 + 1.230 +const GenderInfo* GenderInfo::getNeutralInstance() { 1.231 + return &gObjs[NEUTRAL]; 1.232 +} 1.233 + 1.234 +const GenderInfo* GenderInfo::getMixedNeutralInstance() { 1.235 + return &gObjs[MIXED_NEUTRAL]; 1.236 +} 1.237 + 1.238 +const GenderInfo* GenderInfo::getMaleTaintsInstance() { 1.239 + return &gObjs[MALE_TAINTS]; 1.240 +} 1.241 + 1.242 +U_NAMESPACE_END 1.243 + 1.244 +U_CAPI const UGenderInfo* U_EXPORT2 1.245 +ugender_getInstance(const char* locale, UErrorCode* status) { 1.246 + return (const UGenderInfo*) icu::GenderInfo::getInstance(locale, *status); 1.247 +} 1.248 + 1.249 +U_CAPI UGender U_EXPORT2 1.250 +ugender_getListGender(const UGenderInfo* genderInfo, const UGender* genders, int32_t size, UErrorCode* status) { 1.251 + return ((const icu::GenderInfo *)genderInfo)->getListGender(genders, size, *status); 1.252 +} 1.253 + 1.254 +#endif /* #if !UCONFIG_NO_FORMATTING */