Add ability to skip JSON writes if the params aren't modified

This commit is contained in:
Jon Evans 2020-05-30 12:56:16 -04:00
parent 0741bbb1b9
commit daad2824c5
7 changed files with 218 additions and 36 deletions

View File

@ -36,13 +36,14 @@ extern const char* traceSettings;
JSON_SETTINGS::JSON_SETTINGS( const std::string& aFilename, SETTINGS_LOC aLocation, JSON_SETTINGS::JSON_SETTINGS( const std::string& aFilename, SETTINGS_LOC aLocation,
int aSchemaVersion, bool aCreateIfMissing, bool aWriteFile, int aSchemaVersion, bool aCreateIfMissing, bool aCreateIfDefault,
nlohmann::json aDefault ) : bool aWriteFile ) :
nlohmann::json( std::move( aDefault ) ), nlohmann::json(),
m_filename( aFilename ), m_filename( aFilename ),
m_legacy_filename( "" ), m_legacy_filename( "" ),
m_location( aLocation ), m_location( aLocation ),
m_createIfMissing( aCreateIfMissing ), m_createIfMissing( aCreateIfMissing ),
m_createIfDefault( aCreateIfDefault ),
m_writeFile( aWriteFile ), m_writeFile( aWriteFile ),
m_schemaVersion( aSchemaVersion ), m_schemaVersion( aSchemaVersion ),
m_manager( nullptr ) m_manager( nullptr )
@ -206,10 +207,17 @@ void JSON_SETTINGS::LoadFromFile( const std::string& aDirectory )
} }
void JSON_SETTINGS::Store() bool JSON_SETTINGS::Store()
{ {
bool modified = false;
for( auto param : m_params ) for( auto param : m_params )
{
modified |= !param->MatchesFile( this );
param->Store( this ); param->Store( this );
}
return modified;
} }
@ -220,29 +228,49 @@ void JSON_SETTINGS::ResetToDefaults()
} }
void JSON_SETTINGS::SaveToFile( const std::string& aDirectory ) bool JSON_SETTINGS::SaveToFile( const std::string& aDirectory, bool aForce )
{ {
if( !m_writeFile ) if( !m_writeFile )
return; return false;
wxLogTrace( traceSettings, "Saving %s", m_filename );
wxFileName path( aDirectory, m_filename, "json" ); wxFileName path( aDirectory, m_filename, "json" );
if( !m_createIfMissing && !path.FileExists() ) if( !m_createIfMissing && !path.FileExists() )
return; {
wxLogTrace( traceSettings,
"File for %s doesn't exist and m_createIfMissing == false; not saving",
m_filename );
return false;
}
bool modified = false;
for( auto settings : m_nested_settings )
modified |= settings->SaveToFile();
modified |= Store();
if( !modified && !aForce && path.FileExists() )
{
wxLogTrace( traceSettings, "%s contents not modified, skipping save", m_filename );
return false;
}
else if( !modified && !aForce && !m_createIfDefault )
{
wxLogTrace( traceSettings,
"%s contents still default and m_createIfDefault == false; not saving",
m_filename );
return false;
}
if( !path.DirExists() && !path.Mkdir() ) if( !path.DirExists() && !path.Mkdir() )
{ {
wxLogTrace( traceSettings, "Warning: could not create path %s, can't save %s", wxLogTrace( traceSettings, "Warning: could not create path %s, can't save %s",
path.GetPath(), m_filename ); path.GetPath(), m_filename );
return; return false;
} }
for( auto settings : m_nested_settings ) wxLogTrace( traceSettings, "Saving %s", m_filename );
settings->SaveToFile();
Store();
LOCALE_IO dummy; LOCALE_IO dummy;
@ -258,6 +286,8 @@ void JSON_SETTINGS::SaveToFile( const std::string& aDirectory )
catch( ... ) catch( ... )
{ {
} }
return true;
} }

View File

@ -26,8 +26,8 @@ extern const char* traceSettings;
NESTED_SETTINGS::NESTED_SETTINGS( const std::string& aName, int aVersion, JSON_SETTINGS* aParent, NESTED_SETTINGS::NESTED_SETTINGS( const std::string& aName, int aVersion, JSON_SETTINGS* aParent,
const std::string& aPath, nlohmann::json aDefault ) : const std::string& aPath ) :
JSON_SETTINGS( aName, SETTINGS_LOC::NESTED, aVersion, std::move( aDefault ) ), JSON_SETTINGS( aName, SETTINGS_LOC::NESTED, aVersion ),
m_parent( aParent ), m_path( aPath ) m_parent( aParent ), m_path( aPath )
{ {
if( m_parent ) if( m_parent )
@ -70,9 +70,23 @@ void NESTED_SETTINGS::LoadFromFile( const std::string& aDirectory )
} }
void NESTED_SETTINGS::SaveToFile( const std::string& aDirectory ) bool NESTED_SETTINGS::SaveToFile( const std::string& aDirectory, bool aForce )
{ {
Store(); bool modified = Store();
try
{
nlohmann::json patch =
nlohmann::json::diff( *this, ( *m_parent )[PointerFromString( m_path )] );
modified |= !patch.empty();
}
catch( ... )
{
modified = true;
}
if( !modified && !aForce )
return false;
try try
{ {
@ -86,4 +100,6 @@ void NESTED_SETTINGS::SaveToFile( const std::string& aDirectory )
wxLogTrace( traceSettings, "NESTED_SETTINGS %s: Could not store to %s at %s", wxLogTrace( traceSettings, "NESTED_SETTINGS %s: Could not store to %s at %s",
m_filename, m_parent->GetFilename(), m_path ); m_filename, m_parent->GetFilename(), m_path );
} }
return modified;
} }

View File

@ -290,7 +290,12 @@ void SETTINGS_MANAGER::SaveColorSettings( COLOR_SETTINGS* aSettings, const std::
nlohmann::json::json_pointer ptr = JSON_SETTINGS::PointerFromString( aNamespace ); nlohmann::json::json_pointer ptr = JSON_SETTINGS::PointerFromString( aNamespace );
aSettings->Store(); if( !aSettings->Store() )
{
wxLogTrace( traceSettings, "Color scheme %s not modified; skipping save",
aSettings->GetFilename(), aNamespace );
return;
}
wxASSERT( aSettings->contains( ptr ) ); wxASSERT( aSettings->contains( ptr ) );
@ -305,7 +310,7 @@ void SETTINGS_MANAGER::SaveColorSettings( COLOR_SETTINGS* aSettings, const std::
( *aSettings )[ptr].update( backup ); ( *aSettings )[ptr].update( backup );
aSettings->Load(); aSettings->Load();
aSettings->SaveToFile( path ); aSettings->SaveToFile( path, true );
} }

View File

@ -133,14 +133,30 @@ public:
return m_default; return m_default;
} }
virtual void SetDefault() override void SetDefault() override
{ {
( *m_map )[ m_key ] = m_default; ( *m_map )[ m_key ] = m_default;
} }
bool IsDefault() const override
{
return ( *m_map )[ m_key ] == m_default;
}
bool MatchesFile( JSON_SETTINGS* aSettings ) const override
{
if( OPT<COLOR4D> optval = aSettings->Get<COLOR4D>( m_path ) )
return m_map->count( m_key ) && ( *optval == m_map->at( m_key ) );
// If the JSON doesn't exist, the map shouldn't exist either
return !m_map->count( m_key );
}
private: private:
int m_key; int m_key;
COLOR4D m_default; COLOR4D m_default;
std::unordered_map<int, COLOR4D>* m_map; std::unordered_map<int, COLOR4D>* m_map;
}; };

View File

@ -44,13 +44,11 @@ enum class SETTINGS_LOC {
class JSON_SETTINGS : public nlohmann::json class JSON_SETTINGS : public nlohmann::json
{ {
public: public:
JSON_SETTINGS( const std::string& aFilename, SETTINGS_LOC aLocation, int aSchemaVersion, JSON_SETTINGS( const std::string& aFilename, SETTINGS_LOC aLocation, int aSchemaVersion ) :
nlohmann::json aDefaultJson = nlohmann::json( {} ) ) : JSON_SETTINGS( aFilename, aLocation, aSchemaVersion, true, true, true ) {}
JSON_SETTINGS( aFilename, aLocation, aSchemaVersion, true, true, aDefaultJson ) {}
JSON_SETTINGS( const std::string& aFilename, SETTINGS_LOC aLocation, int aSchemaVersion, JSON_SETTINGS( const std::string& aFilename, SETTINGS_LOC aLocation, int aSchemaVersion,
bool aCreateIfMissing, bool aWriteFile, bool aCreateIfMissing, bool aCreateIfDefault, bool aWriteFile );
nlohmann::json aDefaultJson = nlohmann::json( {} ) );
virtual ~JSON_SETTINGS(); virtual ~JSON_SETTINGS();
@ -68,8 +66,9 @@ public:
/** /**
* Stores the current parameters into the JSON document represented by this object * Stores the current parameters into the JSON document represented by this object
* Note: this doesn't do any writing to disk; that's handled by SETTINGS_MANAGER * Note: this doesn't do any writing to disk; that's handled by SETTINGS_MANAGER
* @return true if any part of the JSON document was updated
*/ */
virtual void Store(); virtual bool Store();
/** /**
* Loads the backing file from disk and then calls Load() * Loads the backing file from disk and then calls Load()
@ -80,8 +79,10 @@ public:
/** /**
* Calls Store() and then writes the contents of the JSON document to a file * Calls Store() and then writes the contents of the JSON document to a file
* @param aDirectory is the directory to save to, including trailing separator * @param aDirectory is the directory to save to, including trailing separator
* @param aForce if true will always save, even if contents are not modified
* @return true if the file was saved
*/ */
virtual void SaveToFile( const std::string& aDirectory ); virtual bool SaveToFile( const std::string& aDirectory, bool aForce = false );
/** /**
* Resets all parameters to default values. Does NOT write to file or update underlying JSON. * Resets all parameters to default values. Does NOT write to file or update underlying JSON.
@ -228,6 +229,12 @@ protected:
/// Whether or not the backing store file should be created it if doesn't exist /// Whether or not the backing store file should be created it if doesn't exist
bool m_createIfMissing; bool m_createIfMissing;
/**
* Whether or not the backing store file should be created if all parameters are still
* at their default values. Ignored if m_createIfMissing is false or m_writeFile is false.
*/
bool m_createIfDefault;
/// Whether or not the backing store file should be written /// Whether or not the backing store file should be written
bool m_writeFile; bool m_writeFile;

View File

@ -32,7 +32,7 @@ class NESTED_SETTINGS : public JSON_SETTINGS
{ {
public: public:
NESTED_SETTINGS( const std::string& aName, int aSchemaVersion, JSON_SETTINGS* aParent, NESTED_SETTINGS( const std::string& aName, int aSchemaVersion, JSON_SETTINGS* aParent,
const std::string& aPath, nlohmann::json aDefault = nlohmann::json( {} ) ); const std::string& aPath );
virtual ~NESTED_SETTINGS(); virtual ~NESTED_SETTINGS();
@ -40,13 +40,14 @@ public:
* Loads the JSON document from the parent and then calls Load() * Loads the JSON document from the parent and then calls Load()
* @param aDirectory * @param aDirectory
*/ */
virtual void LoadFromFile( const std::string& aDirectory = "" ) override; void LoadFromFile( const std::string& aDirectory = "" ) override;
/** /**
* Calls Store() and then saves the JSON document contents into the parent JSON_SETTINGS * Calls Store() and then saves the JSON document contents into the parent JSON_SETTINGS
* @param aDirectory is ignored * @param aDirectory is ignored
* @return true if the document contents were updated
*/ */
virtual void SaveToFile( const std::string& aDirectory = "" ) override; bool SaveToFile( const std::string& aDirectory = "", bool aForce = false ) override;
private: private:

View File

@ -53,6 +53,19 @@ public:
virtual void SetDefault() = 0; virtual void SetDefault() = 0;
/**
* Checks whether or not this param has been changed from its default value
* @return true if the parameter in memory matches its default value
*/
virtual bool IsDefault() const = 0;
/**
* Checks whether the parameter in memory matches the one in a given JSON file
* @param aSettings is a JSON_SETTINGS to check the JSON file contents of
* @return true if the parameter in memory matches its value in the file
*/
virtual bool MatchesFile( JSON_SETTINGS* aSettings ) const = 0;
/** /**
* @return the path name of the parameter used to store it in the json file * @return the path name of the parameter used to store it in the json file
* mainly usefull in error messages * mainly usefull in error messages
@ -115,7 +128,7 @@ public:
*m_ptr = val; *m_ptr = val;
} }
void Store( JSON_SETTINGS* aSettings) const override void Store( JSON_SETTINGS* aSettings ) const override
{ {
aSettings->Set<ValueType>( m_path, *m_ptr ); aSettings->Set<ValueType>( m_path, *m_ptr );
} }
@ -125,11 +138,24 @@ public:
return m_default; return m_default;
} }
virtual void SetDefault() override void SetDefault() override
{ {
*m_ptr = m_default; *m_ptr = m_default;
} }
bool IsDefault() const override
{
return *m_ptr == m_default;
}
bool MatchesFile( JSON_SETTINGS* aSettings ) const override
{
if( OPT<ValueType> optval = aSettings->Get<ValueType>( m_path ) )
return *optval == *m_ptr;
return false;
}
private: private:
ValueType* m_ptr; ValueType* m_ptr;
ValueType m_default; ValueType m_default;
@ -193,11 +219,33 @@ public:
return m_default; return m_default;
} }
virtual void SetDefault() override void SetDefault() override
{ {
m_setter( m_default ); m_setter( m_default );
} }
bool IsDefault() const override
{
return m_getter() == m_default;
}
bool MatchesFile( JSON_SETTINGS* aSettings ) const override
{
if( std::is_same<ValueType, nlohmann::json>::value )
{
if( OPT<nlohmann::json> optval = aSettings->GetJson( m_path ) )
return *optval == m_default;
}
else
{
if( OPT<ValueType> optval = aSettings->Get<ValueType>( m_path ) )
return *optval == m_default;
}
// Not in file
return false;
}
private: private:
ValueType m_default; ValueType m_default;
@ -275,6 +323,19 @@ public:
*m_ptr = m_default; *m_ptr = m_default;
} }
bool IsDefault() const override
{
return *m_ptr == m_default;
}
bool MatchesFile( JSON_SETTINGS* aSettings ) const override
{
if( OPT<double> optval = aSettings->Get<double>( m_path ) )
return *optval == ( *m_ptr * m_scale );
return false;
}
private: private:
ValueType* m_ptr; ValueType* m_ptr;
ValueType m_default; ValueType m_default;
@ -333,11 +394,34 @@ public:
aSettings->Set<nlohmann::json>( m_path, js ); aSettings->Set<nlohmann::json>( m_path, js );
} }
virtual void SetDefault() override void SetDefault() override
{ {
*m_ptr = m_default; *m_ptr = m_default;
} }
bool IsDefault() const override
{
return *m_ptr == m_default;
}
bool MatchesFile( JSON_SETTINGS* aSettings ) const override
{
if( OPT<nlohmann::json> js = aSettings->GetJson( m_path ) )
{
if( js->is_array() )
{
std::vector<Type> val;
for( const auto& el : js->items() )
val.emplace_back( el.value().get<Type>() );
return val == *m_ptr;
}
}
return false;
}
private: private:
std::vector<Type>* m_ptr; std::vector<Type>* m_ptr;
@ -405,6 +489,29 @@ public:
*m_ptr = m_default; *m_ptr = m_default;
} }
bool IsDefault() const override
{
return *m_ptr == m_default;
}
bool MatchesFile( JSON_SETTINGS* aSettings ) const override
{
if( OPT<nlohmann::json> js = aSettings->GetJson( m_path ) )
{
if( js->is_object() )
{
std::map<std::string, Value> val;
for( const auto& el : js->items() )
val[ el.key() ] = el.value().get<Value>();
return val == *m_ptr;
}
}
return false;
}
private: private:
std::map<std::string, Value>* m_ptr; std::map<std::string, Value>* m_ptr;