1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
#include <mbgl/style/expression/collator.hpp>
#include <sstream>
#import <Foundation/Foundation.h>
namespace mbgl {
namespace style {
namespace expression {
class Collator::Impl {
public:
Impl(bool caseSensitive, bool diacriticSensitive, optional<std::string> locale_)
: options((caseSensitive ? 0 : NSCaseInsensitiveSearch) |
(diacriticSensitive ? 0 : NSDiacriticInsensitiveSearch))
, locale(locale_ ?
[[NSLocale alloc] initWithLocaleIdentifier:@((*locale_).c_str())] :
[NSLocale currentLocale])
{}
bool operator==(const Impl& other) const {
return options == other.options &&
[[locale localeIdentifier] isEqualToString:[other.locale localeIdentifier]];
}
int compare(const std::string& lhs, const std::string& rhs) const {
NSString* nsLhs = @(lhs.c_str());
NSString* nsRhs = @(rhs.c_str());
// Limiting the compare range to the length of the LHS seems weird, but
// experimentally we've checked that if LHS is a prefix of RHS compare returns -1
// https://developer.apple.com/documentation/foundation/nsstring/1414561-compare
NSRange compareRange = NSMakeRange(0, nsLhs.length);
return [nsLhs compare:nsRhs options:options range:compareRange locale:locale];
}
std::string resolvedLocale() const {
// Following documentation at:
// https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPInternational/LanguageandLocaleIDs/LanguageandLocaleIDs.html#//apple_ref/doc/uid/10000171i-CH15-SW9
// We expect NSLocale to accept BCP 47 tags as localeIdentifier inputs, but the output format
// may append the region tag with an "_". Changing that to a "-" makes the identifier BCP 47 compliant.
// Experimentally, "zh-Hans-HK" and "zh-Hans_HK" both round trip -- if the second is used by
// `currentLocale`, we don't want to return the underscore.
return [[locale localeIdentifier] stringByReplacingOccurrencesOfString:@"_" withString:@"-"].UTF8String;
}
private:
NSStringCompareOptions options;
NSLocale* locale;
};
Collator::Collator(bool caseSensitive, bool diacriticSensitive, optional<std::string> locale_)
: impl(std::make_shared<Impl>(caseSensitive, diacriticSensitive, std::move(locale_)))
{}
bool Collator::operator==(const Collator& other) const {
return *impl == *(other.impl);
}
int Collator::compare(const std::string& lhs, const std::string& rhs) const {
return impl->compare(lhs, rhs);
}
std::string Collator::resolvedLocale() const {
return impl->resolvedLocale();
}
} // namespace expression
} // namespace style
} // namespace mbgl
|