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
15struct UHashtable;
16
17U_NAMESPACE_BEGIN
18
19struct 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 */
57class U_COMMON_API LocalePriorityList : public UMemory {
58public:
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
98private:
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
113U_NAMESPACE_END
114
115#endif // __LOCALEPRIORITYLIST_H__
116