KI18n

kcountrysubdivision.cpp
1 /*
2  SPDX-FileCopyrightText: 2021 Volker Krause <[email protected]>
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 
18 static_assert(sizeof(KCountrySubdivision) == 4);
19 
21  : d(0)
22 {
23 }
24 
26 KCountrySubdivision::~KCountrySubdivision() = default;
27 KCountrySubdivision &KCountrySubdivision::operator=(const KCountrySubdivision &) = default;
28 
29 bool KCountrySubdivision::operator==(const KCountrySubdivision &other) const
30 {
31  return d == other.d;
32 }
33 
34 bool KCountrySubdivision::operator!=(const KCountrySubdivision &other) const
35 {
36  return d != other.d;
37 }
38 
40 {
41  return d != 0;
42 }
43 
44 QString 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 
67 QString 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 
82 KCountry KCountrySubdivision::country() const
83 {
84  KCountry c;
85  c.d = d >> 16;
86  return c;
87 }
88 
89 KCountrySubdivision 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 
107 QList<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 
131 QList<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 
157 static 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 
199 QStringList 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 }
bool isValid() const
Returns false if this is an empty/invalid/default constructed instance, true otherwise.
KCountrySubdivision()
Creates an invalid/empty KCountrySubdivision instance.
void push_back(const T &value)
static KCountrySubdivision fromCode(QStringView code)
Create a KCountrySubdivision instance from an ISO 3166-2 code.
void reserve(int size)
void reserve(int alloc)
static KCountrySubdivision fromLocation(float latitude, float longitude)
Looks up the country subdivision at the given geographic coordinate.
QString i18nd(const char *domain, const char *text, const TYPE &arg...)
Translate a string from domain and substitute any arguments.
QString & insert(int position, QChar ch)
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Mon Aug 15 2022 04:07:44 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.