1 // © 2019 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html 3 4 // localeprioritylist.h 5 // created: 2019jul11 Markus W. Scherer 6 7 #ifndef __LOCALEPRIORITYLIST_H__ 8 #define __LOCALEPRIORITYLIST_H__ 9 10 #include "unicode/utypes.h" 11 #include "unicode/locid.h" 12 #include "unicode/stringpiece.h" 13 #include "unicode/uobject.h" 14 15 struct UHashtable; 16 17 U_NAMESPACE_BEGIN 18 19 struct LocaleAndWeightArray; 20 21 /** 22 * Parses a list of locales from an accept-language string. 23 * We are a bit more lenient than the spec: 24 * We accept extra whitespace in more places, empty range fields, 25 * and any number of qvalue fraction digits. 26 * 27 * https://tools.ietf.org/html/rfc2616#section-14.4 28 * 14.4 Accept-Language 29 * 30 * Accept-Language = "Accept-Language" ":" 31 * 1#( language-range [ ";" "q" "=" qvalue ] ) 32 * language-range = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" ) 33 * 34 * Each language-range MAY be given an associated quality value which 35 * represents an estimate of the user's preference for the languages 36 * specified by that range. The quality value defaults to "q=1". For 37 * example, 38 * 39 * Accept-Language: da, en-gb;q=0.8, en;q=0.7 40 * 41 * https://tools.ietf.org/html/rfc2616#section-3.9 42 * 3.9 Quality Values 43 * 44 * HTTP content negotiation (section 12) uses short "floating point" 45 * numbers to indicate the relative importance ("weight") of various 46 * negotiable parameters. A weight is normalized to a real number in 47 * the range 0 through 1, where 0 is the minimum and 1 the maximum 48 * value. If a parameter has a quality value of 0, then content with 49 * this parameter is `not acceptable' for the client. HTTP/1.1 50 * applications MUST NOT generate more than three digits after the 51 * decimal point. User configuration of these values SHOULD also be 52 * limited in this fashion. 53 * 54 * qvalue = ( "0" [ "." 0*3DIGIT ] ) 55 * | ( "1" [ "." 0*3("0") ] ) 56 */ 57 class U_COMMON_API LocalePriorityList : public UMemory { 58 public: 59 class Iterator : public Locale::Iterator { 60 public: hasNext()61 UBool hasNext() const override { return count < length; } 62 next()63 const Locale &next() override { 64 for(;;) { 65 const Locale *locale = list.localeAt(index++); 66 if (locale != nullptr) { 67 ++count; 68 return *locale; 69 } 70 } 71 } 72 73 private: 74 friend class LocalePriorityList; 75 Iterator(const LocalePriorityList & list)76 Iterator(const LocalePriorityList &list) : list(list), length(list.getLength()) {} 77 78 const LocalePriorityList &list; 79 int32_t index = 0; 80 int32_t count = 0; 81 const int32_t length; 82 }; 83 84 LocalePriorityList(StringPiece s, UErrorCode &errorCode); 85 86 ~LocalePriorityList(); 87 getLength()88 int32_t getLength() const { return listLength - numRemoved; } 89 getLengthIncludingRemoved()90 int32_t getLengthIncludingRemoved() const { return listLength; } 91 iterator()92 Iterator iterator() const { return Iterator(*this); } 93 94 const Locale *localeAt(int32_t i) const; 95 96 Locale *orphanLocaleAt(int32_t i); 97 98 private: 99 LocalePriorityList(const LocalePriorityList &) = delete; 100 LocalePriorityList &operator=(const LocalePriorityList &) = delete; 101 102 bool add(const Locale &locale, int32_t weight, UErrorCode &errorCode); 103 104 void sort(UErrorCode &errorCode); 105 106 LocaleAndWeightArray *list = nullptr; 107 int32_t listLength = 0; 108 int32_t numRemoved = 0; 109 bool hasWeights = false; // other than 1.0 110 UHashtable *map = nullptr; 111 }; 112 113 U_NAMESPACE_END 114 115 #endif // __LOCALEPRIORITYLIST_H__ 116