Commit b495de76 authored by Volker Krause's avatar Volker Krause

Don't reload forecast data from disk on every access

parent 97ccd4dc
......@@ -67,22 +67,20 @@ void WeatherForecastManager::monitorLocation(float latitude, float longitude)
QVariant WeatherForecastManager::forecast(float latitude, float longitude, const QDateTime& dt) const
{
WeatherTile t{latitude, longitude};
QFile f(cachePath(t) + QLatin1String("forecast.xml"));
if (f.exists() && f.open(QFile::ReadOnly)) {
QXmlStreamReader reader(&f);
auto forecasts = parseForecast(reader);
mergeForecasts(forecasts);
auto it = std::lower_bound(forecasts.begin(), forecasts.end(), dt, [](const WeatherForecast &lhs, const QDateTime &rhs) {
return lhs.dateTime() < rhs;
});
if (it != forecasts.begin()) {
--it;
}
if (it != forecasts.end()) {
return QVariant::fromValue(*it);
}
WeatherTile tile{latitude, longitude};
if (!loadForecastData(tile)) {
return {};
}
const auto &forecasts = m_forecastData[tile];
auto it = std::lower_bound(forecasts.begin(), forecasts.end(), dt, [](const WeatherForecast &lhs, const QDateTime &rhs) {
return lhs.dateTime() < rhs;
});
if (it != forecasts.begin()) {
--it;
}
if (it != forecasts.end()) {
return QVariant::fromValue(*it);
}
return {};
}
......@@ -214,6 +212,31 @@ void WeatherForecastManager::writeToCacheFile(QNetworkReply* reply) const
} else {
f.write(reply->readAll());
}
m_forecastData.erase(tile);
}
bool WeatherForecastManager::loadForecastData(WeatherTile tile) const
{
const auto it = m_forecastData.find(tile);
if (it != m_forecastData.end()) {
return true;
}
QFile f(cachePath(tile) + QLatin1String("forecast.xml"));
if (!f.exists() || !f.open(QFile::ReadOnly)) {
return false;
}
QXmlStreamReader reader(&f);
auto forecasts = parseForecast(reader);
mergeForecasts(forecasts);
if (forecasts.empty()) {
return false;
}
m_forecastData.insert(it, {tile, std::move(forecasts)});
return true;
}
void WeatherForecastManager::mergeForecasts(std::vector<WeatherForecast>& forecasts) const
......
......@@ -18,13 +18,15 @@
#ifndef WEATHERFORECASTMANAGER_H
#define WEATHERFORECASTMANAGER_H
#include "weathertile.h"
#include <QObject>
#include <deque>
#include <unordered_map>
#include <vector>
class WeatherForecast;
struct WeatherTile;
class QNetworkAccessManager;
class QNetworkReply;
......@@ -43,7 +45,6 @@ public:
/** Monitor the specified location for weather forecasts. */
void monitorLocation(float latitude, float longitude);
// TODO unmonitor location(s)?
/** Get the forecast for the given time and location. */
Q_INVOKABLE QVariant forecast(float latitude, float longitude, const QDateTime &dt) const;
......@@ -59,12 +60,14 @@ private:
QString cachePath(WeatherTile tile) const;
void writeToCacheFile(QNetworkReply *reply) const;
bool loadForecastData(WeatherTile tile) const;
void mergeForecasts(std::vector<WeatherForecast> &forecasts) const;
std::vector<WeatherForecast> parseForecast(QXmlStreamReader &reader) const;
WeatherForecast parseForecastElement(QXmlStreamReader &reader) const;
std::vector<WeatherTile> m_monitoredTiles;
std::deque<WeatherTile> m_pendingTiles;
mutable std::unordered_map<WeatherTile, std::vector<WeatherForecast>> m_forecastData;
QNetworkAccessManager *m_nam = nullptr;
QNetworkReply *m_pendingReply = nullptr;
......
......@@ -22,6 +22,7 @@
#include <cmath>
#include <cstdint>
#include <functional>
/** Weather forecast data tile coordinates */
struct WeatherTile
......@@ -51,5 +52,16 @@ struct WeatherTile
Q_DECLARE_METATYPE(WeatherTile)
namespace std
{
template<> struct hash<WeatherTile>
{
inline std::size_t operator()(const WeatherTile &t) const noexcept
{
return std::hash<uint32_t>{}(t.lat << 16 | t.lon);
}
};
}
#endif // WEATHERTILE_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment