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:
Impl(bool caseSensitive_,bool diacriticSensitive_,optional<std::string>)25     Impl(bool caseSensitive_, bool diacriticSensitive_, optional<std::string>)
26         : caseSensitive(caseSensitive_)
27         , diacriticSensitive(diacriticSensitive_)
28     {}
29 
operator ==(const Impl & other) const30     bool operator==(const Impl& other) const {
31         return caseSensitive == other.caseSensitive &&
32             diacriticSensitive == other.diacriticSensitive;
33     }
34 
compare(const std::string & lhs,const std::string & rhs) const35     int compare(const std::string& lhs, const std::string& rhs) const {
36         if (caseSensitive && diacriticSensitive) {
37             return nu_strcoll(lhs.c_str(), rhs.c_str(),
38                               nu_utf8_read, nu_utf8_read);
39         } else if (!caseSensitive && diacriticSensitive) {
40             return nu_strcasecoll(lhs.c_str(), rhs.c_str(),
41                                   nu_utf8_read, nu_utf8_read);
42         } else if (caseSensitive && !diacriticSensitive) {
43             return nu_strcoll(platform::unaccent(lhs).c_str(), platform::unaccent(rhs).c_str(),
44                               nu_utf8_read, nu_utf8_read);
45         } else {
46             return nu_strcasecoll(platform::unaccent(lhs).c_str(), platform::unaccent(rhs).c_str(),
47                                   nu_utf8_read, nu_utf8_read);
48         }
49     }
50 
resolvedLocale() const51     std::string resolvedLocale() const {
52         return "";
53     }
54 private:
55     bool caseSensitive;
56     bool diacriticSensitive;
57 };
58 
59 
Collator(bool caseSensitive,bool diacriticSensitive,optional<std::string> locale_)60 Collator::Collator(bool caseSensitive, bool diacriticSensitive, optional<std::string> locale_)
61     : impl(std::make_shared<Impl>(caseSensitive, diacriticSensitive, std::move(locale_)))
62 {}
63 
operator ==(const Collator & other) const64 bool Collator::operator==(const Collator& other) const {
65     return *impl == *(other.impl);
66 }
67 
compare(const std::string & lhs,const std::string & rhs) const68 int Collator::compare(const std::string& lhs, const std::string& rhs) const {
69     return impl->compare(lhs, rhs);
70 }
71 
resolvedLocale() const72 std::string Collator::resolvedLocale() const {
73     return impl->resolvedLocale();
74 }
75 
76 
77 } // namespace expression
78 } // namespace style
79 } // namespace mbgl
80