1 | #include <mbgl/style/expression/collator.hpp> |
2 | #include <mbgl/util/platform.hpp> |
3 | #include <libnu/strcoll.h> |
4 | #include <unaccent.hpp> |
5 | |
6 | /* |
7 | The default implementation of Collator ignores locale. |
8 | Case sensitivity and collation order are based on |
9 | Default Unicode Collation Element Table (DUCET). |
10 | |
11 | Diacritic-insensitivity is implemented with nunicode's |
12 | non-standard "unaccent" functionality, which is tailored |
13 | to European languages. |
14 | |
15 | It would be possible to implement locale awareness using ICU, |
16 | but would require bundling locale data. |
17 | */ |
18 | |
19 | namespace mbgl { |
20 | namespace style { |
21 | namespace expression { |
22 | |
23 | class Collator::Impl { |
24 | public: |
25 | Impl(bool caseSensitive_, bool diacriticSensitive_, optional<std::string>) |
26 | : caseSensitive(caseSensitive_) |
27 | , diacriticSensitive(diacriticSensitive_) |
28 | {} |
29 | |
30 | bool operator==(const Impl& other) const { |
31 | return caseSensitive == other.caseSensitive && |
32 | diacriticSensitive == other.diacriticSensitive; |
33 | } |
34 | |
35 | int compare(const std::string& lhs, const std::string& rhs) const { |
36 | if (caseSensitive && diacriticSensitive) { |
37 | return nu_strcoll(s1: lhs.c_str(), s2: rhs.c_str(), |
38 | s1_read: nu_utf8_read, s2_read: nu_utf8_read); |
39 | } else if (!caseSensitive && diacriticSensitive) { |
40 | return nu_strcasecoll(s1: lhs.c_str(), s2: rhs.c_str(), |
41 | s1_read: nu_utf8_read, s2_read: nu_utf8_read); |
42 | } else if (caseSensitive && !diacriticSensitive) { |
43 | return nu_strcoll(s1: platform::unaccent(string: lhs).c_str(), s2: platform::unaccent(string: rhs).c_str(), |
44 | s1_read: nu_utf8_read, s2_read: nu_utf8_read); |
45 | } else { |
46 | return nu_strcasecoll(s1: platform::unaccent(string: lhs).c_str(), s2: platform::unaccent(string: rhs).c_str(), |
47 | s1_read: nu_utf8_read, s2_read: nu_utf8_read); |
48 | } |
49 | } |
50 | |
51 | std::string resolvedLocale() const { |
52 | return "" ; |
53 | } |
54 | private: |
55 | bool caseSensitive; |
56 | bool diacriticSensitive; |
57 | }; |
58 | |
59 | |
60 | Collator::Collator(bool caseSensitive, bool diacriticSensitive, optional<std::string> locale_) |
61 | : impl(std::make_shared<Impl>(args&: caseSensitive, args&: diacriticSensitive, args: std::move(locale_))) |
62 | {} |
63 | |
64 | bool Collator::operator==(const Collator& other) const { |
65 | return *impl == *(other.impl); |
66 | } |
67 | |
68 | int Collator::compare(const std::string& lhs, const std::string& rhs) const { |
69 | return impl->compare(lhs, rhs); |
70 | } |
71 | |
72 | std::string Collator::resolvedLocale() const { |
73 | return impl->resolvedLocale(); |
74 | } |
75 | |
76 | |
77 | } // namespace expression |
78 | } // namespace style |
79 | } // namespace mbgl |
80 | |