intl/icu/source/i18n/gender.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /*
     2 *******************************************************************************
     3 * Copyright (C) 2008-2013, International Business Machines Corporation and
     4 * others. All Rights Reserved.
     5 *******************************************************************************
     6 *
     7 *
     8 * File GENDER.CPP
     9 *
    10 * Modification History:*
    11 *   Date        Name        Description
    12 *
    13 ********************************************************************************
    14 */
    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"
    24 #include "cmemory.h"
    25 #include "cstring.h"
    26 #include "mutex.h"
    27 #include "uassert.h"
    28 #include "ucln_in.h"
    29 #include "umutex.h"
    30 #include "uhash.h"
    32 static UHashtable* gGenderInfoCache = NULL;
    33 static UMutex gGenderMetaLock = U_MUTEX_INITIALIZER;
    34 static const char* gNeutralStr = "neutral";
    35 static const char* gMailTaintsStr = "maleTaints";
    36 static const char* gMixedNeutralStr = "mixedNeutral";
    37 static icu::GenderInfo* gObjs = NULL;
    38 static icu::UInitOnce gGenderInitOnce = U_INITONCE_INITIALIZER;
    40 enum GenderStyle {
    41   NEUTRAL,
    42   MIXED_NEUTRAL,
    43   MALE_TAINTS,
    44   GENDER_STYLE_LENGTH
    45 };
    47 U_CDECL_BEGIN
    49 static UBool U_CALLCONV gender_cleanup(void) {
    50   if (gGenderInfoCache != NULL) {
    51     uhash_close(gGenderInfoCache);
    52     gGenderInfoCache = NULL;
    53     delete [] gObjs;
    54   }
    55   gGenderInitOnce.reset();
    56   return TRUE;
    57 }
    59 U_CDECL_END
    61 U_NAMESPACE_BEGIN
    63 void 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 }
    86 GenderInfo::GenderInfo() {
    87 }
    89 GenderInfo::~GenderInfo() {
    90 }
    92 const GenderInfo* GenderInfo::getInstance(const Locale& locale, UErrorCode& status) {
    93   // Make sure our cache exists.
    94   umtx_initOnce(gGenderInitOnce, &GenderInfo_initCache, status);
    95   if (U_FAILURE(status)) {
    96     return NULL;
    97   }
    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   }
   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   }
   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 }
   132 const 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 }
   174 UGender 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 }
   227 const GenderInfo* GenderInfo::getNeutralInstance() {
   228   return &gObjs[NEUTRAL];
   229 }
   231 const GenderInfo* GenderInfo::getMixedNeutralInstance() {
   232   return &gObjs[MIXED_NEUTRAL];
   233 }
   235 const GenderInfo* GenderInfo::getMaleTaintsInstance() {
   236   return &gObjs[MALE_TAINTS];
   237 }
   239 U_NAMESPACE_END
   241 U_CAPI const UGenderInfo* U_EXPORT2
   242 ugender_getInstance(const char* locale, UErrorCode* status) {
   243   return (const UGenderInfo*) icu::GenderInfo::getInstance(locale, *status);
   244 }
   246 U_CAPI UGender U_EXPORT2
   247 ugender_getListGender(const UGenderInfo* genderInfo, const UGender* genders, int32_t size, UErrorCode* status) {
   248   return ((const icu::GenderInfo *)genderInfo)->getListGender(genders, size, *status);
   249 }
   251 #endif /* #if !UCONFIG_NO_FORMATTING */

mercurial