KI18n

kcountrysubdivision.cpp
1/*
2 SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "kcountrysubdivision.h"
8#include "isocodes_p.h"
9#include "isocodescache_p.h"
10#include "kcountry.h"
11#include "ki18n_logging.h"
12#include "klocalizedstring.h"
13#include "spatial_index_p.h"
14#include "timezonedata_p.h"
15
16#include <cstring>
17
18static_assert(sizeof(KCountrySubdivision) == 4);
19
24
26KCountrySubdivision::~KCountrySubdivision() = default;
27KCountrySubdivision &KCountrySubdivision::operator=(const KCountrySubdivision &) = default;
28
29bool KCountrySubdivision::operator==(const KCountrySubdivision &other) const
30{
31 return d == other.d;
32}
33
34bool KCountrySubdivision::operator!=(const KCountrySubdivision &other) const
35{
36 return d != other.d;
37}
38
40{
41 return d != 0;
42}
43
44QString KCountrySubdivision::code() const
45{
46 if (d == 0) {
47 return {};
48 }
49
50 QString code;
51 code.reserve(6);
52 code += country().alpha2();
53 code += QLatin1Char('-');
54
55 auto key = d & 0xffff;
56 while (key) {
57 const auto c = IsoCodes::mapFromAlphaNumKey(key);
58 if (c) {
59 code.insert(3, QLatin1Char(c));
60 }
61 key /= IsoCodes::AlphaNumKeyFactor;
62 }
63
64 return code;
65}
66
67QString KCountrySubdivision::name() const
68{
69 if (d == 0) {
70 return {};
71 }
72
73 auto cache = IsoCodesCache::instance();
74 cache->loadIso3166_2();
75 const auto it = std::lower_bound(cache->subdivisionNameMapBegin(), cache->subdivisionNameMapEnd(), d);
76 if (it != cache->subdivisionNameMapEnd() && (*it).key == d) {
77 return i18nd("iso_3166-2", cache->subdivisionStringTableLookup((*it).value));
78 }
79 return {};
80}
81
82KCountry KCountrySubdivision::country() const
83{
84 KCountry c;
85 c.d = d >> 16;
86 return c;
87}
88
89KCountrySubdivision KCountrySubdivision::parent() const
90{
92 if (d == 0) {
93 return s;
94 }
95
96 auto cache = IsoCodesCache::instance();
97 cache->loadIso3166_2();
98
99 const auto it = std::lower_bound(cache->subdivisionParentMapBegin(), cache->subdivisionParentMapEnd(), d);
100 if (it != cache->subdivisionParentMapEnd() && (*it).key == d) {
101 s.d = (d & 0xffff0000) | (uint32_t)(*it).value;
102 }
103
104 return s;
105}
106
107QList<const char *> KCountrySubdivision::timeZoneIds() const
108{
110 if (d == 0) {
111 return tzs;
112 }
113
114 const auto [subdivBegin, subdivEnd] = std::equal_range(TimezoneData::subdivisionTimezoneMapBegin(), TimezoneData::subdivisionTimezoneMapEnd(), d);
115 if (subdivBegin != subdivEnd) {
116 tzs.reserve(std::distance(subdivBegin, subdivEnd));
117 for (auto it = subdivBegin; it != subdivEnd; ++it) {
118 tzs.push_back(TimezoneData::ianaIdLookup((*it).value));
119 }
120 return tzs;
121 }
122
123 const auto countryIt = std::lower_bound(TimezoneData::countryTimezoneMapBegin(), TimezoneData::countryTimezoneMapEnd(), uint16_t(d >> 16));
124 if (countryIt != TimezoneData::countryTimezoneMapEnd() && (*countryIt).key == (d >> 16)) {
125 tzs.push_back(TimezoneData::ianaIdLookup((*countryIt).value));
126 }
127
128 return tzs;
129}
130
131QList<KCountrySubdivision> KCountrySubdivision::subdivisions() const
132{
133 if (d == 0) {
134 return {};
135 }
136
138 auto cache = IsoCodesCache::instance();
139 cache->loadIso3166_2();
140 // we don't have a parent->child map, instead we use the child->parent map
141 // that is sorted by country (due to the country being in the two most significant bytes of its key),
142 // so we don't need to do a full sequential search here
143 auto it = std::lower_bound(cache->subdivisionParentMapBegin(), cache->subdivisionParentMapEnd(), d >> 16, [](auto lhs, auto rhs) {
144 return (lhs.key >> 16) < rhs;
145 });
146 for (; it != cache->subdivisionParentMapEnd() && ((*it).key >> 16) == (d >> 16); ++it) {
147 if ((*it).value == (d & 0xffff)) {
149 s.d = (*it).key;
150 l.push_back(s);
151 }
152 }
153
154 return l;
155}
156
157static uint32_t validatedSubdivisionKey(uint32_t key)
158{
159 if (!key) {
160 return 0;
161 }
162
163 auto cache = IsoCodesCache::instance();
164 cache->loadIso3166_2();
165
166 const auto it = std::lower_bound(cache->subdivisionNameMapBegin(), cache->subdivisionNameMapEnd(), key);
167 if (it != cache->subdivisionNameMapEnd() && (*it).key == key) {
168 return key;
169 }
170 return 0;
171}
172
174{
176 s.d = validatedSubdivisionKey(IsoCodes::subdivisionCodeToKey(code));
177 return s;
178}
179
181{
183 if (code) {
184 s.d = validatedSubdivisionKey(IsoCodes::subdivisionCodeToKey(code, std::strlen(code)));
185 }
186 return s;
187}
188
190{
191 const auto entry = SpatialIndex::lookup(latitude, longitude);
193 if (entry.m_subdiv & 0xffff) {
194 s.d = entry.m_subdiv;
195 }
196 return s;
197}
198
199QStringList KCountrySubdivision::timeZoneIdsStringList() const
200{
201 const auto tzIds = timeZoneIds();
202 QStringList l;
203 l.reserve(tzIds.size());
204 std::transform(tzIds.begin(), tzIds.end(), std::back_inserter(l), [](const char *tzId) {
205 return QString::fromUtf8(tzId);
206 });
207 return l;
208}
209
210#include "moc_kcountrysubdivision.cpp"
Information about an ISO 3166-2 country subdivision.
static KCountrySubdivision fromCode(QStringView code)
Create a KCountrySubdivision instance from an ISO 3166-2 code.
KCountrySubdivision()
Creates an invalid/empty KCountrySubdivision instance.
bool isValid() const
Returns false if this is an empty/invalid/default constructed instance, true otherwise.
static KCountrySubdivision fromLocation(float latitude, float longitude)
Looks up the country subdivision at the given geographic coordinate.
Information about an ISO 3166-1 country.
Definition kcountry.h:40
QString i18nd(const char *domain, const char *text, const TYPE &arg...)
Translate a string from domain and substitute any arguments.
void push_back(parameter_type value)
void reserve(qsizetype size)
QString & insert(qsizetype position, QChar ch)
void reserve(qsizetype size)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Apr 27 2024 22:16:14 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.