1 | // © 2019 and later: Unicode, Inc. and others. |
2 | // License & terms of use: http://www.unicode.org/copyright.html#License |
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: |
61 | UBool hasNext() const override { return count < length; } |
62 | |
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 | |
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 | |
88 | int32_t getLength() const { return listLength - numRemoved; } |
89 | |
90 | int32_t getLengthIncludingRemoved() const { return listLength; } |
91 | |
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 | |