QTZP: use binary search more on timezone ID tables
The zone and Windows data tables are sorted on Windows ID and its key (which are monotonic functions of one another) so we can use binary chop to find the first matching entry in each, when searching on these. Furthermore, the search for ID from key can be shortcut as the keys should normally be consecutive integers starting with 1. Change-Id: I53f7ff8c93fd6d3d9e48c7bb86060746b68fab3d Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
4b2eb26bf9
commit
0e8a8c3aa2
@ -37,32 +37,63 @@ static bool earlierWinData(const QWindowsData &less, const QWindowsData &more) n
|
|||||||
|| less.windowsId().compare(more.windowsId(), Qt::CaseInsensitive) < 0;
|
|| less.windowsId().compare(more.windowsId(), Qt::CaseInsensitive) < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// For use with std::lower_bound():
|
||||||
Static utilities for looking up Windows ID tables
|
constexpr bool atLowerUtcOffset(const QUtcData &entry, qint32 offsetSeconds) noexcept
|
||||||
*/
|
{
|
||||||
|
return entry.offsetFromUtc < offsetSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool atLowerWindowsKey(const QWindowsData &entry, qint16 winIdKey) noexcept
|
||||||
|
{
|
||||||
|
return entry.windowsIdKey < winIdKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool earlierWindowsId(const QWindowsData &entry, QByteArrayView winId) noexcept
|
||||||
|
{
|
||||||
|
return entry.windowsId().compare(winId, Qt::CaseInsensitive) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool zoneAtLowerWindowsKey(const QZoneData &entry, qint16 winIdKey) noexcept
|
||||||
|
{
|
||||||
|
return entry.windowsIdKey < winIdKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static table-lookup helpers
|
||||||
static quint16 toWindowsIdKey(const QByteArray &winId)
|
static quint16 toWindowsIdKey(const QByteArray &winId)
|
||||||
{
|
{
|
||||||
for (const QWindowsData &data : windowsDataTable) {
|
// Key and winId are monotonic, table is sorted on them.
|
||||||
if (data.windowsId() == winId)
|
const auto data = std::lower_bound(std::begin(windowsDataTable), std::end(windowsDataTable),
|
||||||
return data.windowsIdKey;
|
winId, earlierWindowsId);
|
||||||
}
|
if (data != std::end(windowsDataTable) && data->windowsId() == winId)
|
||||||
|
return data->windowsIdKey;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static QByteArray toWindowsIdLiteral(quint16 windowsIdKey)
|
static QByteArray toWindowsIdLiteral(quint16 windowsIdKey)
|
||||||
{
|
{
|
||||||
for (const QWindowsData &data : windowsDataTable) {
|
// Caller should be passing a valid (in range) key; and table is sorted in
|
||||||
if (data.windowsIdKey == windowsIdKey)
|
// increasing order, with no gaps in numbering, starting with key = 1 at
|
||||||
|
// index [0]. So this should normally work:
|
||||||
|
if (Q_LIKELY(windowsIdKey > 0 && windowsIdKey <= std::size(windowsDataTable))) {
|
||||||
|
const auto &data = windowsDataTable[windowsIdKey - 1];
|
||||||
|
if (Q_LIKELY(data.windowsIdKey == windowsIdKey))
|
||||||
return data.windowsId().toByteArray();
|
return data.windowsId().toByteArray();
|
||||||
}
|
}
|
||||||
|
// Fall back on binary chop - key and winId are monotonic, table is sorted on them:
|
||||||
|
const auto data = std::lower_bound(std::begin(windowsDataTable), std::end(windowsDataTable),
|
||||||
|
windowsIdKey, atLowerWindowsKey);
|
||||||
|
if (data != std::end(windowsDataTable) && data->windowsIdKey == windowsIdKey)
|
||||||
|
return data->windowsId().toByteArray();
|
||||||
|
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
// For use with std::lower_bound():
|
static auto zoneStartForWindowsId(quint16 windowsIdKey) noexcept
|
||||||
static bool atLowerUtcOffset(const QUtcData &entry, qint32 offsetSeconds)
|
|
||||||
{
|
{
|
||||||
return entry.offsetFromUtc < offsetSeconds;
|
// Caller must check the resulting iterator isn't std::end(zoneDataTable)
|
||||||
|
// and does match windowsIdKey, since this is just the lower bound.
|
||||||
|
return std::lower_bound(std::begin(zoneDataTable), std::end(zoneDataTable),
|
||||||
|
windowsIdKey, zoneAtLowerWindowsKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -530,14 +561,14 @@ QList<QByteArray> QTimeZonePrivate::availableTimeZoneIds(int offsetFromUtc) cons
|
|||||||
// First get all Zones in the table using the Offset
|
// First get all Zones in the table using the Offset
|
||||||
for (const QWindowsData &winData : windowsDataTable) {
|
for (const QWindowsData &winData : windowsDataTable) {
|
||||||
if (winData.offsetFromUtc == offsetFromUtc) {
|
if (winData.offsetFromUtc == offsetFromUtc) {
|
||||||
for (const QZoneData &data : zoneDataTable) {
|
for (auto data = zoneStartForWindowsId(winData.windowsIdKey);
|
||||||
if (data.windowsIdKey == winData.windowsIdKey) {
|
data != std::end(zoneDataTable) && data->windowsIdKey == winData.windowsIdKey;
|
||||||
for (auto l1 : data.ids())
|
++data) {
|
||||||
|
for (auto l1 : data->ids())
|
||||||
offsets << QByteArray(l1.data(), l1.size());
|
offsets << QByteArray(l1.data(), l1.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
std::sort(offsets.begin(), offsets.end());
|
std::sort(offsets.begin(), offsets.end());
|
||||||
offsets.erase(std::unique(offsets.begin(), offsets.end()), offsets.end());
|
offsets.erase(std::unique(offsets.begin(), offsets.end()), offsets.end());
|
||||||
@ -708,14 +739,14 @@ QByteArray QTimeZonePrivate::ianaIdToWindowsId(const QByteArray &id)
|
|||||||
|
|
||||||
QByteArray QTimeZonePrivate::windowsIdToDefaultIanaId(const QByteArray &windowsId)
|
QByteArray QTimeZonePrivate::windowsIdToDefaultIanaId(const QByteArray &windowsId)
|
||||||
{
|
{
|
||||||
for (const QWindowsData &data : windowsDataTable) {
|
const auto data = std::lower_bound(std::begin(windowsDataTable), std::end(windowsDataTable),
|
||||||
if (data.windowsId() == windowsId) {
|
windowsId, earlierWindowsId);
|
||||||
QByteArrayView id = data.ianaId();
|
if (data != std::end(windowsDataTable) && data->windowsId() == windowsId) {
|
||||||
|
QByteArrayView id = data->ianaId();
|
||||||
if (qsizetype cut = id.indexOf(' '); cut >= 0)
|
if (qsizetype cut = id.indexOf(' '); cut >= 0)
|
||||||
id = id.first(cut);
|
id = id.first(cut);
|
||||||
return id.toByteArray();
|
return id.toByteArray();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -731,12 +762,12 @@ QList<QByteArray> QTimeZonePrivate::windowsIdToIanaIds(const QByteArray &windows
|
|||||||
const quint16 windowsIdKey = toWindowsIdKey(windowsId);
|
const quint16 windowsIdKey = toWindowsIdKey(windowsId);
|
||||||
QList<QByteArray> list;
|
QList<QByteArray> list;
|
||||||
|
|
||||||
for (const QZoneData &data : zoneDataTable) {
|
for (auto data = zoneStartForWindowsId(windowsIdKey);
|
||||||
if (data.windowsIdKey == windowsIdKey) {
|
data != std::end(zoneDataTable) && data->windowsIdKey == windowsIdKey;
|
||||||
for (auto l1 : data.ids())
|
++data) {
|
||||||
|
for (auto l1 : data->ids())
|
||||||
list << QByteArray(l1.data(), l1.size());
|
list << QByteArray(l1.data(), l1.size());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Return the full list in alpha order
|
// Return the full list in alpha order
|
||||||
std::sort(list.begin(), list.end());
|
std::sort(list.begin(), list.end());
|
||||||
@ -749,10 +780,12 @@ QList<QByteArray> QTimeZonePrivate::windowsIdToIanaIds(const QByteArray &windows
|
|||||||
QList<QByteArray> list;
|
QList<QByteArray> list;
|
||||||
const quint16 windowsIdKey = toWindowsIdKey(windowsId);
|
const quint16 windowsIdKey = toWindowsIdKey(windowsId);
|
||||||
const qint16 land = static_cast<quint16>(territory);
|
const qint16 land = static_cast<quint16>(territory);
|
||||||
for (const QZoneData &data : zoneDataTable) {
|
for (auto data = zoneStartForWindowsId(windowsIdKey);
|
||||||
|
data != std::end(zoneDataTable) && data->windowsIdKey == windowsIdKey;
|
||||||
|
++data) {
|
||||||
// Return the region matches in preference order
|
// Return the region matches in preference order
|
||||||
if (data.windowsIdKey == windowsIdKey && data.territory == land) {
|
if (data->territory == land) {
|
||||||
for (auto l1 : data.ids())
|
for (auto l1 : data->ids())
|
||||||
list << QByteArray(l1.data(), l1.size());
|
list << QByteArray(l1.data(), l1.size());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user