rm settings as magic behovioiral storage

This commit is contained in:
LaGrunge 2019-10-14 15:07:35 +03:00 committed by cc-engineering
parent 6681006e43
commit 3682dfc931
16 changed files with 22 additions and 753 deletions

View file

@ -215,7 +215,6 @@ int GeneratorToolMain(int argc, char ** argv)
if (!options.m_user_resource_path.empty())
{
pl.SetResourceDir(options.m_user_resource_path);
pl.SetSettingsDir(options.m_user_resource_path);
}
string const path =

View file

@ -21,10 +21,6 @@ set(
platform.hpp
preferred_languages.cpp
preferred_languages.hpp
settings.cpp
settings.hpp
string_storage_base.cpp
string_storage_base.hpp
target_os.hpp
)

View file

@ -3,7 +3,6 @@
#include "platform/country_file.hpp"
#include "platform/mwm_version.hpp"
#include "platform/platform.hpp"
#include "platform/settings.hpp"
#include "coding/internal/file_data.hpp"
#include "coding/reader.hpp"
@ -25,26 +24,6 @@ using namespace std;
namespace platform
{
namespace migrate
{
// Set of functions to support migration between different versions of MWM
// with totaly incompatible formats.
// 160302 - Migrate to small single file MWM
uint32_t constexpr kMinRequiredVersion = 160302;
bool NeedMigrate()
{
uint32_t version;
if (!settings::Get("LastMigration", version))
return true;
if (version >= kMinRequiredVersion)
return false;
return true;
}
void SetMigrationFlag() { settings::Set("LastMigration", kMinRequiredVersion); }
} // namespace migrate
namespace
{
@ -271,8 +250,7 @@ void FindAllLocalMapsAndCleanup(int64_t latestVersion, string const & dataDir,
// World and WorldCoasts can be stored in app bundle or in resources
// directory, thus it's better to get them via Platform.
string const world(WORLD_FILE_NAME);
string const worldCoasts(migrate::NeedMigrate() ? WORLD_COASTS_OBSOLETE_FILE_NAME
: WORLD_COASTS_FILE_NAME);
string const worldCoasts(WORLD_COASTS_FILE_NAME);
for (string const & file : {world, worldCoasts})
{
auto i = localFiles.begin();

View file

@ -11,12 +11,6 @@ class ModelReader;
namespace platform
{
namespace migrate
{
bool NeedMigrate();
void SetMigrationFlag();
}
// Removes all files downloader creates during downloading of a country.
// Note. The the maps are deleted from writable dir/|dataDir|/|version| directory.
// If |dataDir| is empty (or is not set) the function deletes maps from writable dir.

View file

@ -1,5 +1,4 @@
#include "platform/measurement_utils.hpp"
#include "platform/settings.hpp"
#include "geometry/mercator.hpp"
@ -11,10 +10,10 @@
#include <iomanip>
#include <sstream>
using namespace settings;
using namespace std;
using namespace strings;
namespace measurement_utils
{
string ToStringPrecision(double d, int pr)
@ -60,11 +59,9 @@ double ToSpeedKmPH(double speed, measurement_utils::Units units)
UNREACHABLE();
}
bool FormatDistanceWithLocalization(double m, string & res, char const * high, char const * low)
bool FormatDistanceWithLocalization(double m, string & res, char const * high, char const * low,
Units units)
{
auto units = Units::Metric;
TryGet(settings::kMeasurementUnits, units);
/// @todo Put string units resources.
switch (units)
{
@ -74,11 +71,8 @@ bool FormatDistanceWithLocalization(double m, string & res, char const * high, c
UNREACHABLE();
}
bool FormatDistance(double m, string & res)
bool FormatDistance(double m, string & res, Units units)
{
auto units = Units::Metric;
TryGet(settings::kMeasurementUnits, units);
/// @todo Put string units resources.
switch (units)
{
@ -183,11 +177,8 @@ void FormatMercator(m2::PointD const & mercator, string & lat, string & lon, int
lon = to_string_dac(MercatorBounds::XToLon(mercator.x), dac);
}
string FormatAltitude(double altitudeInMeters)
string FormatAltitude(double altitudeInMeters, Units units)
{
Units units = Units::Metric;
TryGet(settings::kMeasurementUnits, units);
ostringstream ss;
ss << fixed << setprecision(0);
@ -200,10 +191,8 @@ string FormatAltitude(double altitudeInMeters)
return ss.str();
}
string FormatSpeedWithDeviceUnits(double metersPerSecond)
string FormatSpeedWithDeviceUnits(double metersPerSecond, Units units)
{
auto units = Units::Metric;
TryGet(settings::kMeasurementUnits, units);
return FormatSpeedWithUnits(metersPerSecond, units);
}

View file

@ -41,13 +41,14 @@ double ToSpeedKmPH(double speed, measurement_utils::Units units);
/// @param[in] m meters
/// @param[out] res formatted std::string for search
/// @return should be direction arrow drawed? false if distance is to small (< 1.0)
bool FormatDistance(double m, std::string & res);
bool FormatDistanceWithLocalization(double m, std::string & res, char const * high, char const * low);
bool FormatDistance(double m, std::string & res, Units units = Units::Metric);
bool FormatDistanceWithLocalization(double m, std::string & res, char const * high,
char const * low, Units units = Units::Metric);
/// We always use meters and feet/yards for altitude
std::string FormatAltitude(double altitudeInMeters);
std::string FormatAltitude(double altitudeInMeters, Units units = Units::Metric);
// Return value is measured in km/h for Metric and in mph for Imperial.
std::string FormatSpeedWithDeviceUnits(double metersPerSecond);
std::string FormatSpeedWithDeviceUnits(double metersPerSecond, Units units = Units::Metric);
std::string FormatSpeedWithUnits(double metersPerSecond, Units units);
std::string FormatSpeed(double metersPerSecond, Units units);
std::string FormatSpeedUnits(Units units);

View file

@ -122,11 +122,6 @@ bool Platform::RmDirRecursively(string const & dirName)
return res;
}
void Platform::SetSettingsDir(string const & path)
{
m_settingsDir = base::AddSlashIfNeeded(path);
}
string Platform::ReadPathForFile(string const & file, string searchScope) const
{
if (searchScope.empty())
@ -139,7 +134,6 @@ string Platform::ReadPathForFile(string const & file, string searchScope) const
{
case 'w': fullPath = m_writableDir + file; break;
case 'r': fullPath = m_resourcesDir + file; break;
case 's': fullPath = m_settingsDir + file; break;
case 'f': fullPath = file; break;
default : CHECK(false, ("Unsupported searchScope:", searchScope)); break;
}
@ -147,7 +141,7 @@ string Platform::ReadPathForFile(string const & file, string searchScope) const
return fullPath;
}
string const possiblePaths = m_writableDir + "\n" + m_resourcesDir + "\n" + m_settingsDir;
string const possiblePaths = m_writableDir + "\n" + m_resourcesDir + "\n";
MYTHROW(FileAbsentException, ("File", file, "doesn't exist in the scope", searchScope,
"Have been looking in:\n", possiblePaths));
}
@ -463,16 +457,6 @@ Platform::Platform()
string path;
CHECK(GetBinaryDir(path), ("Can't retrieve path to executable"));
m_settingsDir = base::JoinPath(HomeDir(), ".config", "MapsWithMe");
if (!IsFileExistsByFullPath(base::JoinPath(m_settingsDir, SETTINGS_FILE_NAME)))
{
auto const configDir = base::JoinPath(HomeDir(), ".config");
if (!MkDirChecked(configDir))
MYTHROW(FileSystemException, ("Can't create directory", configDir));
if (!MkDirChecked(m_settingsDir))
MYTHROW(FileSystemException, ("Can't create directory", m_settingsDir));
}
char const * resDir = ::getenv("MWM_RESOURCES_DIR");
char const * writableDir = ::getenv("MWM_WRITABLE_DIR");
@ -521,7 +505,6 @@ Platform::Platform()
}
}
m_resourcesDir += '/';
m_settingsDir += '/';
m_writableDir += '/';
char const * tmpDir = ::getenv("TMPDIR");
@ -531,12 +514,9 @@ Platform::Platform()
m_tmpDir = "/tmp";
m_tmpDir += '/';
m_privateDir = m_settingsDir;
LOG(LDEBUG, ("Resources directory:", m_resourcesDir));
LOG(LDEBUG, ("Writable directory:", m_writableDir));
LOG(LDEBUG, ("Tmp directory:", m_tmpDir));
LOG(LDEBUG, ("Settings directory:", m_settingsDir));
}

View file

@ -69,12 +69,8 @@ protected:
/// Writable directory to store downloaded map data
/// @note on some systems it can point to external ejectable storage
std::string m_writableDir;
/// Application private directory.
std::string m_privateDir;
/// Temporary directory, can be cleaned up by the system
std::string m_tmpDir;
/// Writable directory to store persistent application data
std::string m_settingsDir;
/// Extended resource files.
/// Used in Android only (downloaded zip files as a container).
@ -104,7 +100,7 @@ public:
void SetWritableDirForTests(std::string const & path);
/// @return full path to file in user's writable directory
std::string WritablePathForFile(std::string const & file) const { return WritableDir() + file; }
/// Uses m_writeableDir [w], m_resourcesDir [r], m_settingsDir [s].
/// Uses m_writeableDir [w], m_resourcesDir [r]
std::string ReadPathForFile(std::string const & file,
std::string searchScope = std::string()) const;
@ -144,21 +140,11 @@ public:
/// @return full random path to temporary file.
std::string TmpPathForFile() const;
/// @return full path to the file where data for unit tests is stored.
std::string TestsDataPathForFile(std::string const & file) const { return ReadPathForFile(file); }
/// @return path for directory in the persistent memory, can be the same
/// as WritableDir, but on some platforms it's different
std::string const & SettingsDir() const { return m_settingsDir; }
void SetSettingsDir(std::string const & path);
/// @return full path to file in the settings directory
std::string SettingsPathForFile(std::string const & file) const { return SettingsDir() + file; }
/// @return reader for file decriptor.
/// @throws FileAbsentException
/// @param[in] file name or full path which we want to read
/// @param[in] searchScope looks for file in dirs in given order: \n
/// [w]ritable, [r]esources, [s]ettings, by [f]ull path, [e]xternal resources,
/// [w]ritable, [r]esources, by [f]ull path, [e]xternal resources,
std::unique_ptr<ModelReader> GetReader(std::string const & file,
std::string const & searchScope = std::string()) const;

View file

@ -1,7 +1,6 @@
#include "testing/testing.hpp"
#include "platform/measurement_utils.hpp"
#include "platform/settings.hpp"
#include "base/math.hpp"
@ -9,34 +8,10 @@
#include <utility>
using namespace measurement_utils;
using namespace settings;
struct ScopedSettings
{
ScopedSettings() { m_wasSet = Get(kMeasurementUnits, m_oldUnits); }
/// Saves/restores previous units and sets new units for a scope.
explicit ScopedSettings(Units newUnits) : ScopedSettings()
{
Set(kMeasurementUnits, newUnits);
}
~ScopedSettings()
{
if (m_wasSet)
Set(kMeasurementUnits, m_oldUnits);
else
Delete(kMeasurementUnits);
}
bool m_wasSet;
Units m_oldUnits;
};
UNIT_TEST(Measurement_Smoke)
{
ScopedSettings guard(Units::Metric);
using Pair = std::pair<double, char const *>;
Pair arr[] = {
@ -93,26 +68,17 @@ UNIT_TEST(LatLonToDMS_NoRounding)
UNIT_TEST(FormatAltitude)
{
ScopedSettings guard;
settings::Set(settings::kMeasurementUnits, Units::Imperial);
TEST_EQUAL(FormatAltitude(10000), "32808ft", ());
settings::Set(settings::kMeasurementUnits, Units::Metric);
TEST_EQUAL(FormatAltitude(5), "5m", ());
TEST_EQUAL(FormatAltitude(10000, Units::Imperial), "32808ft", ());
TEST_EQUAL(FormatAltitude(5, Units::Metric), "5m", ());
}
UNIT_TEST(FormatSpeedWithDeviceUnits)
{
{
ScopedSettings guard(Units::Metric);
TEST_EQUAL(FormatSpeedWithDeviceUnits(10), "36km/h", ());
TEST_EQUAL(FormatSpeedWithDeviceUnits(1), "3.6km/h", ());
}
{
ScopedSettings guard(Units::Imperial);
TEST_EQUAL(FormatSpeedWithDeviceUnits(10), "22mph", ());
TEST_EQUAL(FormatSpeedWithDeviceUnits(1), "2.2mph", ());
}
TEST_EQUAL(FormatSpeedWithDeviceUnits(10, Units::Metric), "36km/h", ());
TEST_EQUAL(FormatSpeedWithDeviceUnits(1, Units::Metric), "3.6km/h", ());
TEST_EQUAL(FormatSpeedWithDeviceUnits(10, Units::Imperial), "22mph", ());
TEST_EQUAL(FormatSpeedWithDeviceUnits(1, Units::Imperial), "2.2mph", ());
}
UNIT_TEST(FormatSpeedWithUnits)

View file

@ -8,8 +8,6 @@ set(
scoped_file.hpp
scoped_mwm.cpp
scoped_mwm.hpp
writable_dir_changer.cpp
writable_dir_changer.hpp
)
geocore_add_library(${PROJECT_NAME} ${SRC})

View file

@ -1,33 +0,0 @@
#include "testing/testing.hpp"
#include "writable_dir_changer.hpp"
#include "platform/platform.hpp"
#include "platform/settings.hpp"
WritableDirChanger::WritableDirChanger(string const & testDir, SettingsDirPolicy settingsDirPolicy)
: m_writableDirBeforeTest(GetPlatform().WritableDir())
, m_testDirFullPath(m_writableDirBeforeTest + testDir)
, m_settingsDirPolicy(settingsDirPolicy)
{
Platform & platform = GetPlatform();
platform.RmDirRecursively(m_testDirFullPath);
TEST(!platform.IsFileExistsByFullPath(m_testDirFullPath), ());
TEST_EQUAL(Platform::ERR_OK, platform.MkDir(m_testDirFullPath), ());
platform.SetWritableDirForTests(m_testDirFullPath);
if (m_settingsDirPolicy == SettingsDirPolicy::UseWritableDir)
platform.SetSettingsDir(m_testDirFullPath);
settings::Clear();
}
WritableDirChanger::~WritableDirChanger()
{
settings::Clear();
Platform & platform = GetPlatform();
string const writableDirForTest = platform.WritableDir();
platform.SetWritableDirForTests(m_writableDirBeforeTest);
if (m_settingsDirPolicy == SettingsDirPolicy::UseWritableDir)
platform.SetSettingsDir(m_writableDirBeforeTest);
platform.RmDirRecursively(writableDirForTest);
}

View file

@ -1,21 +0,0 @@
#pragma once
#include <string>
class WritableDirChanger
{
public:
enum class SettingsDirPolicy
{
UseDefault, UseWritableDir
};
WritableDirChanger(std::string const & testDir,
SettingsDirPolicy settingsDirPolicy = SettingsDirPolicy::UseDefault);
~WritableDirChanger();
private:
std::string const m_writableDirBeforeTest;
std::string const m_testDirFullPath;
SettingsDirPolicy m_settingsDirPolicy;
};

View file

@ -1,346 +0,0 @@
#include "platform/measurement_utils.hpp"
#include "platform/settings.hpp"
#include "platform/platform.hpp"
#include "defines.hpp"
#include "coding/transliteration.hpp"
#include "geometry/any_rect2d.hpp"
#include "geometry/rect2d.hpp"
#include "base/logging.hpp"
#include <cmath>
#include <iostream>
using namespace std;
namespace settings
{
char const * kLocationStateMode = "LastLocationStateMode";
char const * kMeasurementUnits = "Units";
StringStorage::StringStorage() : StringStorageBase(GetPlatform().SettingsPathForFile(SETTINGS_FILE_NAME)) {}
StringStorage & StringStorage::Instance()
{
static StringStorage inst;
return inst;
}
////////////////////////////////////////////////////////////////////////////////////////////
template <>
string ToString<string>(string const & str)
{
return str;
}
template <>
bool FromString<string>(string const & strIn, string & strOut)
{
strOut = strIn;
return true;
}
namespace impl
{
template <class T, size_t N>
bool FromStringArray(string const & s, T(&arr)[N])
{
istringstream in(s);
size_t count = 0;
while (count < N && in >> arr[count])
{
if (!isfinite(arr[count]))
return false;
++count;
}
return (!in.fail() && count == N);
}
} // namespace impl
template <>
string ToString<m2::AnyRectD>(m2::AnyRectD const & rect)
{
ostringstream out;
out.precision(12);
m2::PointD glbZero(rect.GlobalZero());
out << glbZero.x << " " << glbZero.y << " ";
out << rect.Angle().val() << " ";
m2::RectD const & r = rect.GetLocalRect();
out << r.minX() << " " << r.minY() << " " << r.maxX() << " " << r.maxY();
return out.str();
}
template <>
bool FromString<m2::AnyRectD>(string const & str, m2::AnyRectD & rect)
{
double val[7];
if (!impl::FromStringArray(str, val))
return false;
// Will get an assertion in DEBUG and false return in RELEASE.
m2::RectD const r(val[3], val[4], val[5], val[6]);
if (!r.IsValid())
return false;
rect = m2::AnyRectD(m2::PointD(val[0], val[1]), ang::AngleD(val[2]), r);
return true;
}
template <>
string ToString<m2::RectD>(m2::RectD const & rect)
{
ostringstream stream;
stream.precision(12);
stream << rect.minX() << " " << rect.minY() << " " << rect.maxX() << " " << rect.maxY();
return stream.str();
}
template <>
bool FromString<m2::RectD>(string const & str, m2::RectD & rect)
{
double val[4];
if (!impl::FromStringArray(str, val))
return false;
// Will get an assertion in DEBUG and false return in RELEASE.
rect = m2::RectD(val[0], val[1], val[2], val[3]);
return rect.IsValid();
}
template <>
string ToString<bool>(bool const & v)
{
return v ? "true" : "false";
}
template <>
bool FromString<bool>(string const & str, bool & v)
{
if (str == "true")
v = true;
else if (str == "false")
v = false;
else
return false;
return true;
}
namespace impl
{
template <typename T>
string ToStringScalar(T const & v)
{
ostringstream stream;
stream.precision(12);
stream << v;
return stream.str();
}
template <typename T>
bool FromStringScalar(string const & str, T & v)
{
istringstream stream(str);
if (stream)
{
stream >> v;
return !stream.fail();
}
else
return false;
}
} // namespace impl
template <>
string ToString<double>(double const & v)
{
return impl::ToStringScalar<double>(v);
}
template <>
bool FromString<double>(string const & str, double & v)
{
return impl::FromStringScalar<double>(str, v);
}
template <>
string ToString<int32_t>(int32_t const & v)
{
return impl::ToStringScalar<int32_t>(v);
}
template <>
bool FromString<int32_t>(string const & str, int32_t & v)
{
return impl::FromStringScalar<int32_t>(str, v);
}
template <>
string ToString<int64_t>(int64_t const & v)
{
return impl::ToStringScalar<int64_t>(v);
}
template <>
bool FromString<int64_t>(string const & str, int64_t & v)
{
return impl::FromStringScalar<int64_t>(str, v);
}
template <>
string ToString<uint32_t>(uint32_t const & v)
{
return impl::ToStringScalar<uint32_t>(v);
}
template <>
string ToString<uint64_t>(uint64_t const & v)
{
return impl::ToStringScalar<uint64_t>(v);
}
template <>
bool FromString<uint32_t>(string const & str, uint32_t & v)
{
return impl::FromStringScalar<uint32_t>(str, v);
}
template <>
bool FromString<uint64_t>(string const & str, uint64_t & v)
{
return impl::FromStringScalar<uint64_t>(str, v);
}
namespace impl
{
template <class TPair>
string ToStringPair(TPair const & value)
{
ostringstream stream;
stream.precision(12);
stream << value.first << " " << value.second;
return stream.str();
}
template <class TPair>
bool FromStringPair(string const & str, TPair & value)
{
istringstream stream(str);
if (stream)
{
stream >> value.first;
if (stream)
{
stream >> value.second;
return !stream.fail();
}
}
return false;
}
} // namespace impl
typedef pair<int, int> IPairT;
typedef pair<double, double> DPairT;
template <>
string ToString<IPairT>(IPairT const & v)
{
return impl::ToStringPair(v);
}
template <>
bool FromString<IPairT>(string const & s, IPairT & v)
{
return impl::FromStringPair(s, v);
}
template <>
string ToString<DPairT>(DPairT const & v)
{
return impl::ToStringPair(v);
}
template <>
bool FromString<DPairT>(string const & s, DPairT & v)
{
return impl::FromStringPair(s, v);
}
template <>
string ToString<measurement_utils::Units>(measurement_utils::Units const & v)
{
switch (v)
{
// The value "Foot" is left here for compatibility with old settings.ini files.
case measurement_utils::Units::Imperial: return "Foot";
case measurement_utils::Units::Metric: return "Metric";
}
UNREACHABLE();
}
template <>
bool FromString<measurement_utils::Units>(string const & s, measurement_utils::Units & v)
{
if (s == "Metric")
v = measurement_utils::Units::Metric;
else if (s == "Foot")
v = measurement_utils::Units::Imperial;
else
return false;
return true;
}
template <>
string ToString<Transliteration::Mode>(Transliteration::Mode const & mode)
{
switch (mode)
{
case Transliteration::Mode::Enabled: return "Enabled";
case Transliteration::Mode::Disabled: return "Disabled";
}
UNREACHABLE();
}
template <>
bool FromString<Transliteration::Mode>(string const & s, Transliteration::Mode & mode)
{
if (s == "Enabled")
mode = Transliteration::Mode::Enabled;
else if (s == "Disabled")
mode = Transliteration::Mode::Disabled;
else
return false;
return true;
}
bool IsFirstLaunchForDate(int date)
{
constexpr char const * kFirstLaunchKey = "FirstLaunchOnDate";
int savedDate;
if (!Get(kFirstLaunchKey, savedDate) || savedDate < date)
{
Set(kFirstLaunchKey, date);
return true;
}
else
return false;
}
} // namespace settings
namespace marketing
{
Settings::Settings() : platform::StringStorageBase(GetPlatform().SettingsPathForFile(MARKETING_SETTINGS_FILE_NAME)) {}
// static
Settings & Settings::Instance()
{
static Settings instance;
return instance;
}
} // namespace marketing

View file

@ -1,84 +0,0 @@
#pragma once
#include "platform/string_storage_base.hpp"
#include "base/macros.hpp"
#include <string>
namespace settings
{
/// Current location state mode. @See location::EMyPositionMode.
extern char const * kLocationStateMode;
/// Metric or Feet.
extern char const * kMeasurementUnits;
template <class T>
bool FromString(std::string const & str, T & outValue);
template <class T>
std::string ToString(T const & value);
class StringStorage : public platform::StringStorageBase
{
public:
static StringStorage & Instance();
private:
StringStorage();
};
/// Retrieve setting
/// @return false if setting is absent
template <class Value>
WARN_UNUSED_RESULT bool Get(std::string const & key, Value & outValue)
{
std::string strVal;
return StringStorage::Instance().GetValue(key, strVal) && FromString(strVal, outValue);
}
template <class Value>
void TryGet(std::string const & key, Value & outValue)
{
bool unused = Get(key, outValue);
UNUSED_VALUE(unused);
}
/// Automatically saves setting to external file
template <class Value>
void Set(std::string const & key, Value const & value)
{
StringStorage::Instance().SetValue(key, ToString(value));
}
inline void Delete(std::string const & key) { StringStorage::Instance().DeleteKeyAndValue(key); }
inline void Clear() { StringStorage::Instance().Clear(); }
/// Use this function for running some stuff once according to date.
/// @param[in] date Current date in format yymmdd.
bool IsFirstLaunchForDate(int date);
}
namespace marketing
{
class Settings : public platform::StringStorageBase
{
public:
template <class Value>
static void Set(std::string const & key, Value const & value)
{
Instance().SetValue(key, settings::ToString(value));
}
template <class Value>
WARN_UNUSED_RESULT static bool Get(std::string const & key, Value & outValue)
{
std::string strVal;
return Instance().GetValue(key, strVal) && settings::FromString(strVal, outValue);
}
private:
static Settings & Instance();
Settings();
};
} // namespace marketing

View file

@ -1,109 +0,0 @@
#include "string_storage_base.hpp"
#include "coding/reader_streambuf.hpp"
#include "coding/file_reader.hpp"
#include "coding/file_writer.hpp"
#include "base/exception.hpp"
#include "base/logging.hpp"
using namespace std;
namespace
{
constexpr char kDelimChar = '=';
} // namespace
namespace platform
{
StringStorageBase::StringStorageBase(string const & path) : m_path(path)
{
try
{
LOG(LINFO, ("Settings path:", m_path));
ReaderStreamBuf buffer(make_unique<FileReader>(m_path));
istream stream(&buffer);
string line;
while (getline(stream, line))
{
if (line.empty())
continue;
size_t const delimPos = line.find(kDelimChar);
if (delimPos == string::npos)
continue;
string const key = line.substr(0, delimPos);
string const value = line.substr(delimPos + 1);
if (!key.empty() && !value.empty())
m_values[key] = value;
}
}
catch (RootException const & ex)
{
LOG(LWARNING, ("Loading settings:", ex.Msg()));
}
}
void StringStorageBase::Save() const
{
try
{
FileWriter file(m_path);
for (auto const & value : m_values)
{
string line(value.first);
line += kDelimChar;
line += value.second;
line += '\n';
file.Write(line.data(), line.size());
}
}
catch (RootException const & ex)
{
// Ignore all settings saving exceptions.
LOG(LWARNING, ("Saving settings:", ex.Msg()));
}
}
void StringStorageBase::Clear()
{
lock_guard<mutex> guard(m_mutex);
m_values.clear();
Save();
}
bool StringStorageBase::GetValue(string const & key, string & outValue) const
{
lock_guard<mutex> guard(m_mutex);
auto const found = m_values.find(key);
if (found == m_values.end())
return false;
outValue = found->second;
return true;
}
void StringStorageBase::SetValue(string const & key, string && value)
{
lock_guard<mutex> guard(m_mutex);
m_values[key] = move(value);
Save();
}
void StringStorageBase::DeleteKeyAndValue(string const & key)
{
lock_guard<mutex> guard(m_mutex);
auto const found = m_values.find(key);
if (found != m_values.end())
{
m_values.erase(found);
Save();
}
}
} // namespace platform

View file

@ -1,25 +0,0 @@
#pragma once
#include <map>
#include <mutex>
#include <string>
namespace platform
{
class StringStorageBase
{
public:
explicit StringStorageBase(std::string const & path);
void Save() const;
void Clear();
bool GetValue(std::string const & key, std::string & outValue) const;
void SetValue(std::string const & key, std::string && value);
void DeleteKeyAndValue(std::string const & key);
private:
using Container = std::map<std::string, std::string>;
Container m_values;
mutable std::mutex m_mutex;
std::string const m_path;
};
} // namespace platform