Optimization of the configuration layer:

The values of StaticPrintConfig derived objects were searched by a name
walking through a huge chained if.
Now they are being mapped with a std::map.
Also initialization of StaticPrintConfig classes from their ConfigOptionDef
defaults is done by maintaining a single global definition of each
StaticPrintConfig derived class, and a new instance is initialized
from this static copy.

Also the ConfigOption instances are casted using static_cast
wherever possible, and their types are verified by a virtual type() method.
This approach avoids insiginificant performance penalty of a dynamic_cast.

Also the compare and clone methods were added to ConfigOption,
and the cloning & compare work on binary values, not by serialization.
This commit is contained in:
bubnikv 2017-10-17 16:01:18 +02:00
parent a91d7cb2f7
commit 3731820c48
14 changed files with 1475 additions and 934 deletions

View file

@ -177,20 +177,24 @@ bool unescape_strings_cstyle(const std::string &str, std::vector<std::string> &o
}
}
void ConfigBase::apply(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent)
void ConfigBase::apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent)
{
// loop through options and apply them
for (const t_config_option_key &key : keys) {
ConfigOption *my_opt = this->option(key, true);
for (const t_config_option_key &opt_key : keys) {
// Create a new option with default value for the key.
// If the key is not in the parameter definition, or this ConfigBase is a static type and it does not support the parameter,
// an exception is thrown if not ignore_nonexistent.
ConfigOption *my_opt = this->option(opt_key, true);
if (my_opt == nullptr) {
if (! ignore_nonexistent)
throw "Attempt to apply non-existent option";
continue;
// opt_key does not exist in this ConfigBase and it cannot be created, because it is not defined by this->def().
// This is only possible if other is of DynamicConfig type.
if (ignore_nonexistent)
continue;
throw UnknownOptionException();
}
// not the most efficient way, but easier than casting pointers to subclasses
const ConfigOption *other_opt = other.option(key);
if (other_opt != nullptr && ! my_opt->deserialize(other_opt->serialize()))
CONFESS((std::string("Unexpected failure when deserializing serialized value for ") + key).c_str());
const ConfigOption *other_opt = other.option(opt_key);
if (other_opt != nullptr)
my_opt->set(other_opt);
}
}
@ -198,9 +202,12 @@ void ConfigBase::apply(const ConfigBase &other, const t_config_option_keys &keys
t_config_option_keys ConfigBase::diff(const ConfigBase &other) const
{
t_config_option_keys diff;
for (const t_config_option_key &opt_key : this->keys())
if (other.has(opt_key) && other.serialize(opt_key) != this->serialize(opt_key))
diff.push_back(opt_key);
for (const t_config_option_key &opt_key : this->keys()) {
const ConfigOption *this_opt = this->option(opt_key);
const ConfigOption *other_opt = other.option(opt_key);
if (this_opt != nullptr && other_opt != nullptr && *this_opt != *other_opt)
diff.emplace_back(opt_key);
}
return diff;
}
@ -211,12 +218,27 @@ std::string ConfigBase::serialize(const t_config_option_key &opt_key) const
return opt->serialize();
}
bool ConfigBase::set_deserialize(t_config_option_key opt_key, const std::string &str, bool append)
bool ConfigBase::set_deserialize(const t_config_option_key &opt_key_src, const std::string &value_src, bool append)
{
const ConfigOptionDef* optdef = this->def->get(opt_key);
t_config_option_key opt_key = opt_key_src;
std::string value = value_src;
// Both opt_key and value may be modified by _handle_legacy().
// If the opt_key is no more valid in this version of Slic3r, opt_key is cleared by _handle_legacy().
this->handle_legacy(opt_key, value);
if (opt_key.empty())
// Ignore the option.
return true;
return this->set_deserialize_raw(opt_key, value, append);
}
bool ConfigBase::set_deserialize_raw(const t_config_option_key &opt_key_src, const std::string &value, bool append)
{
t_config_option_key opt_key = opt_key_src;
// Try to deserialize the option by its name.
const ConfigOptionDef* optdef = this->def()->get(opt_key);
if (optdef == nullptr) {
// If we didn't find an option, look for any other option having this as an alias.
for (const auto &opt : this->def->options) {
for (const auto &opt : this->def()->options) {
for (const t_config_option_key &opt_key2 : opt.second.aliases) {
if (opt_key2 == opt_key) {
opt_key = opt_key2;
@ -232,44 +254,49 @@ bool ConfigBase::set_deserialize(t_config_option_key opt_key, const std::string
}
if (! optdef->shortcut.empty()) {
// Aliasing for example "solid_layers" to "top_solid_layers" and "bottom_solid_layers".
for (const t_config_option_key &shortcut : optdef->shortcut)
if (! this->set_deserialize(shortcut, str))
// Recursive call.
if (! this->set_deserialize_raw(shortcut, value, append))
return false;
return true;
}
ConfigOption *opt = this->option(opt_key, true);
assert(opt != nullptr);
return opt->deserialize(str, append);
return opt->deserialize(value, append);
}
// Return an absolute value of a possibly relative config variable.
// For example, return absolute infill extrusion width, either from an absolute value, or relative to the layer height.
double ConfigBase::get_abs_value(const t_config_option_key &opt_key) const
{
const ConfigOption* opt = this->option(opt_key);
if (const ConfigOptionFloatOrPercent* optv = dynamic_cast<const ConfigOptionFloatOrPercent*>(opt)) {
// get option definition
const ConfigOptionDef* def = this->def->get(opt_key);
// Get stored option value.
const ConfigOption *raw_opt = this->option(opt_key);
assert(raw_opt != nullptr);
if (raw_opt->type() == coFloat)
return static_cast<const ConfigOptionFloat*>(raw_opt)->value;
if (raw_opt->type() == coFloatOrPercent) {
// Get option definition.
const ConfigOptionDef *def = this->def()->get(opt_key);
assert(def != nullptr);
// compute absolute value over the absolute value of the base option
return optv->get_abs_value(this->get_abs_value(def->ratio_over));
} else if (const ConfigOptionFloat* optv = dynamic_cast<const ConfigOptionFloat*>(opt)) {
return optv->value;
} else {
throw "Not a valid option type for get_abs_value()";
// Compute absolute value over the absolute value of the base option.
return static_cast<const ConfigOptionFloatOrPercent*>(raw_opt)->get_abs_value(this->get_abs_value(def->ratio_over));
}
throw std::runtime_error("ConfigBase::get_abs_value(): Not a valid option type for get_abs_value()");
}
// Return an absolute value of a possibly relative config variable.
// For example, return absolute infill extrusion width, either from an absolute value, or relative to a provided value.
double ConfigBase::get_abs_value(const t_config_option_key &opt_key, double ratio_over) const
{
// get stored option value
const ConfigOptionFloatOrPercent* opt = dynamic_cast<const ConfigOptionFloatOrPercent*>(this->option(opt_key));
assert(opt != nullptr);
// compute absolute value
return opt->get_abs_value(ratio_over);
// Get stored option value.
const ConfigOption *raw_opt = this->option(opt_key);
assert(raw_opt != nullptr);
if (raw_opt->type() != coFloatOrPercent)
throw std::runtime_error("ConfigBase::get_abs_value(): opt_key is not of coFloatOrPercent");
// Compute absolute value.
return static_cast<const ConfigOptionFloatOrPercent*>(raw_opt)->get_abs_value(ratio_over);
}
void ConfigBase::setenv_()
@ -301,8 +328,7 @@ void ConfigBase::load(const std::string &file)
for (const pt::ptree::value_type &v : tree) {
try {
t_config_option_key opt_key = v.first;
std::string value = v.second.get_value<std::string>();
this->set_deserialize(opt_key, value);
this->set_deserialize(opt_key, v.second.get_value<std::string>());
} catch (UnknownOptionException & /* e */) {
// ignore
}
@ -400,64 +426,43 @@ void ConfigBase::save(const std::string &file) const
c.close();
}
ConfigOption* DynamicConfig::optptr(const t_config_option_key &opt_key, bool create) {
ConfigOption* DynamicConfig::optptr(const t_config_option_key &opt_key, bool create)
{
t_options_map::iterator it = options.find(opt_key);
if (it == options.end()) {
if (create) {
const ConfigOptionDef* optdef = this->def->get(opt_key);
assert(optdef != NULL);
ConfigOption* opt;
if (optdef->type == coFloat) {
opt = new ConfigOptionFloat ();
} else if (optdef->type == coFloats) {
opt = new ConfigOptionFloats ();
} else if (optdef->type == coInt) {
opt = new ConfigOptionInt ();
} else if (optdef->type == coInts) {
opt = new ConfigOptionInts ();
} else if (optdef->type == coString) {
opt = new ConfigOptionString ();
} else if (optdef->type == coStrings) {
opt = new ConfigOptionStrings ();
} else if (optdef->type == coPercent) {
opt = new ConfigOptionPercent ();
} else if (optdef->type == coPercents) {
opt = new ConfigOptionPercents ();
} else if (optdef->type == coFloatOrPercent) {
opt = new ConfigOptionFloatOrPercent ();
} else if (optdef->type == coPoint) {
opt = new ConfigOptionPoint ();
} else if (optdef->type == coPoints) {
opt = new ConfigOptionPoints ();
} else if (optdef->type == coBool) {
opt = new ConfigOptionBool ();
} else if (optdef->type == coBools) {
opt = new ConfigOptionBools ();
} else if (optdef->type == coEnum) {
ConfigOptionEnumGeneric* optv = new ConfigOptionEnumGeneric ();
optv->keys_map = &optdef->enum_keys_map;
opt = static_cast<ConfigOption*>(optv);
} else {
throw "Unknown option type";
}
this->options[opt_key] = opt;
return opt;
} else {
return NULL;
}
if (it != options.end())
// Option was found.
return it->second;
if (! create)
// Option was not found and a new option shall not be created.
return nullptr;
// Try to create a new ConfigOption.
const ConfigOptionDef *optdef = this->def()->get(opt_key);
if (optdef == nullptr)
// throw std::runtime_error(std::string("Invalid option name: ") + opt_key);
// Let the parent decide what to do if the opt_key is not defined by this->def().
return nullptr;
ConfigOption *opt = nullptr;
switch (optdef->type) {
case coFloat: opt = new ConfigOptionFloat(); break;
case coFloats: opt = new ConfigOptionFloats(); break;
case coInt: opt = new ConfigOptionInt(); break;
case coInts: opt = new ConfigOptionInts(); break;
case coString: opt = new ConfigOptionString(); break;
case coStrings: opt = new ConfigOptionStrings(); break;
case coPercent: opt = new ConfigOptionPercent(); break;
case coPercents: opt = new ConfigOptionPercents(); break;
case coFloatOrPercent: opt = new ConfigOptionFloatOrPercent(); break;
case coPoint: opt = new ConfigOptionPoint(); break;
case coPoints: opt = new ConfigOptionPoints(); break;
case coBool: opt = new ConfigOptionBool(); break;
case coBools: opt = new ConfigOptionBools(); break;
case coEnum: opt = new ConfigOptionEnumGeneric(optdef->enum_keys_map); break;
default: throw std::runtime_error(std::string("Unknown option type for option ") + opt_key);
}
return it->second;
this->options[opt_key] = opt;
return opt;
}
template<class T>
T* DynamicConfig::opt(const t_config_option_key &opt_key, bool create) {
return dynamic_cast<T*>(this->option(opt_key, create));
}
template ConfigOptionInt* DynamicConfig::opt<ConfigOptionInt>(const t_config_option_key &opt_key, bool create);
template ConfigOptionBool* DynamicConfig::opt<ConfigOptionBool>(const t_config_option_key &opt_key, bool create);
template ConfigOptionBools* DynamicConfig::opt<ConfigOptionBools>(const t_config_option_key &opt_key, bool create);
template ConfigOptionPercent* DynamicConfig::opt<ConfigOptionPercent>(const t_config_option_key &opt_key, bool create);
t_config_option_keys DynamicConfig::keys() const
{
t_config_option_keys keys;
@ -470,11 +475,13 @@ t_config_option_keys DynamicConfig::keys() const
void StaticConfig::set_defaults()
{
// use defaults from definition
if (this->def != nullptr) {
auto *defs = this->def();
if (defs != nullptr) {
for (const std::string &key : this->keys()) {
const ConfigOptionDef* def = this->def->get(key);
if (def->default_value != nullptr)
this->option(key)->set(*def->default_value);
const ConfigOptionDef *def = defs->get(key);
ConfigOption *opt = this->option(key);
if (def != nullptr && opt != nullptr && def->default_value != nullptr)
opt->set(def->default_value);
}
}
}
@ -483,7 +490,7 @@ t_config_option_keys StaticConfig::keys() const
{
t_config_option_keys keys;
assert(this->def != nullptr);
for (const auto &opt_def : this->def->options)
for (const auto &opt_def : this->def()->options)
if (this->option(opt_def.first) != nullptr)
keys.push_back(opt_def.first);
return keys;