diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp index ce1a8d6799..0d7438f192 100644 --- a/src/libslic3r/Config.cpp +++ b/src/libslic3r/Config.cpp @@ -25,69 +25,69 @@ #include #include #include -//BBS: add json support +// BBS: add json support #include "nlohmann/json.hpp" using namespace nlohmann; -//FIXME for GCodeFlavor and gcfMarlin (for forward-compatibility conversion) -// This is not nice, likely it would be better to pass the ConfigSubstitutionContext to handle_legacy(). +// FIXME for GCodeFlavor and gcfMarlin (for forward-compatibility conversion) +// This is not nice, likely it would be better to pass the ConfigSubstitutionContext to handle_legacy(). #include "PrintConfig.hpp" namespace Slic3r { -//BBS: add json support -//static const std::string CONFIG_VERSION_KEY = "version"; -//static const std::string CONFIG_NAME_KEY = "name"; -//static const std::string CONFIG_URL_KEY = "url"; -//static const std::string CONFIG_TYPE_KEY = "type"; -//static const std::string CONFIG_FROM_KEY = "from"; -//static const std::string CONFIG_INHERITS_KEY = "inherits"; -//static const std::string CONFIG_INSTANT_KEY = "instantiation"; +// BBS: add json support +// static const std::string CONFIG_VERSION_KEY = "version"; +// static const std::string CONFIG_NAME_KEY = "name"; +// static const std::string CONFIG_URL_KEY = "url"; +// static const std::string CONFIG_TYPE_KEY = "type"; +// static const std::string CONFIG_FROM_KEY = "from"; +// static const std::string CONFIG_INHERITS_KEY = "inherits"; +// static const std::string CONFIG_INSTANT_KEY = "instantiation"; // Escape double quotes, \n, \r and backslash -std::string escape_string_cstyle(const std::string &str) +std::string escape_string_cstyle(const std::string& str) { // Allocate a buffer twice the input string length, // so the output will fit even if all input characters get escaped. std::vector out(str.size() * 2, 0); - char *outptr = out.data(); - for (size_t i = 0; i < str.size(); ++ i) { + char* outptr = out.data(); + for (size_t i = 0; i < str.size(); ++i) { char c = str[i]; if (c == '\r') { - (*outptr ++) = '\\'; - (*outptr ++) = 'r'; + (*outptr++) = '\\'; + (*outptr++) = 'r'; } else if (c == '\n') { - (*outptr ++) = '\\'; - (*outptr ++) = 'n'; + (*outptr++) = '\\'; + (*outptr++) = 'n'; } else if (c == '\\' || c == '"') { (*outptr++) = '\\'; (*outptr++) = c; } else - (*outptr ++) = c; + (*outptr++) = c; } return std::string(out.data(), outptr - out.data()); } -std::string escape_strings_cstyle(const std::vector &strs) +std::string escape_strings_cstyle(const std::vector& strs) { // 1) Estimate the output buffer size to avoid buffer reallocation. size_t outbuflen = 0; - for (size_t i = 0; i < strs.size(); ++ i) + for (size_t i = 0; i < strs.size(); ++i) // Reserve space for every character escaped + quotes + semicolon. outbuflen += strs[i].size() * 2 + 3; // 2) Fill in the buffer. std::vector out(outbuflen, 0); - char *outptr = out.data(); - for (size_t j = 0; j < strs.size(); ++ j) { + char* outptr = out.data(); + for (size_t j = 0; j < strs.size(); ++j) { if (j > 0) // Separate the strings. - (*outptr ++) = ';'; - const std::string &str = strs[j]; + (*outptr++) = ';'; + const std::string& str = strs[j]; // Is the string simple or complex? Complex string contains spaces, tabs, new lines and other // escapable characters. Empty string shall be quoted as well, if it is the only string in strs. bool should_quote = strs.size() == 1 && str.empty(); - for (size_t i = 0; i < str.size(); ++ i) { + for (size_t i = 0; i < str.size(); ++i) { char c = str[i]; if (c == ' ' || c == '\t' || c == '\\' || c == '"' || c == '\r' || c == '\n') { should_quote = true; @@ -95,22 +95,22 @@ std::string escape_strings_cstyle(const std::vector &strs) } } if (should_quote) { - (*outptr ++) = '"'; - for (size_t i = 0; i < str.size(); ++ i) { + (*outptr++) = '"'; + for (size_t i = 0; i < str.size(); ++i) { char c = str[i]; if (c == '\\' || c == '"') { - (*outptr ++) = '\\'; - (*outptr ++) = c; + (*outptr++) = '\\'; + (*outptr++) = c; } else if (c == '\r') { - (*outptr ++) = '\\'; - (*outptr ++) = 'r'; + (*outptr++) = '\\'; + (*outptr++) = 'r'; } else if (c == '\n') { - (*outptr ++) = '\\'; - (*outptr ++) = 'n'; + (*outptr++) = '\\'; + (*outptr++) = 'n'; } else - (*outptr ++) = c; + (*outptr++) = c; } - (*outptr ++) = '"'; + (*outptr++) = '"'; } else { memcpy(outptr, str.data(), str.size()); outptr += str.size(); @@ -120,30 +120,30 @@ std::string escape_strings_cstyle(const std::vector &strs) } // Unescape double quotes, \n, \r and backslash -bool unescape_string_cstyle(const std::string &str, std::string &str_out) +bool unescape_string_cstyle(const std::string& str, std::string& str_out) { std::vector out(str.size(), 0); - char *outptr = out.data(); - for (size_t i = 0; i < str.size(); ++ i) { + char* outptr = out.data(); + for (size_t i = 0; i < str.size(); ++i) { char c = str[i]; if (c == '\\') { - if (++ i == str.size()) + if (++i == str.size()) return false; c = str[i]; if (c == 'r') - (*outptr ++) = '\r'; + (*outptr++) = '\r'; else if (c == 'n') - (*outptr ++) = '\n'; + (*outptr++) = '\n'; else - (*outptr ++) = c; + (*outptr++) = c; } else - (*outptr ++) = c; + (*outptr++) = c; } str_out.assign(out.data(), outptr - out.data()); return true; } -bool unescape_strings_cstyle(const std::string &str, std::vector &out) +bool unescape_strings_cstyle(const std::string& str, std::vector& out) { if (str.empty()) return true; @@ -153,7 +153,7 @@ bool unescape_strings_cstyle(const std::string &str, std::vector &o // Skip white spaces. char c = str[i]; while (c == ' ' || c == '\t') { - if (++ i == str.size()) + if (++i == str.size()) return true; c = str[i]; } @@ -164,14 +164,14 @@ bool unescape_strings_cstyle(const std::string &str, std::vector &o c = str[i]; if (c == '"') { // Complex case, string is enclosed in quotes. - for (++ i; i < str.size(); ++ i) { + for (++i; i < str.size(); ++i) { c = str[i]; if (c == '"') { // End of string. break; } if (c == '\\') { - if (++ i == str.size()) + if (++i == str.size()) return false; c = str[i]; if (c == 'r') @@ -183,9 +183,9 @@ bool unescape_strings_cstyle(const std::string &str, std::vector &o } if (i == str.size()) return false; - ++ i; + ++i; } else { - for (; i < str.size(); ++ i) { + for (; i < str.size(); ++i) { c = str[i]; if (c == ';') break; @@ -199,14 +199,14 @@ bool unescape_strings_cstyle(const std::string &str, std::vector &o // Skip white spaces. c = str[i]; while (c == ' ' || c == '\t') { - if (++ i == str.size()) + if (++i == str.size()) // End of string. This is correct. return true; c = str[i]; } if (c != ';') return false; - if (++ i == str.size()) { + if (++i == str.size()) { // Emit one additional empty string. out.push_back(std::string()); return true; @@ -219,7 +219,7 @@ std::string escape_ampersand(const std::string& str) // Allocate a buffer 2 times the input string length, // so the output will fit even if all input characters get escaped. std::vector out(str.size() * 6, 0); - char* outptr = out.data(); + char* outptr = out.data(); for (size_t i = 0; i < str.size(); ++i) { char c = str[i]; if (c == '&') { @@ -231,65 +231,64 @@ std::string escape_ampersand(const std::string& str) return std::string(out.data(), outptr - out.data()); } -void ConfigOptionDeleter::operator()(ConfigOption* p) { - delete p; -} +void ConfigOptionDeleter::operator()(ConfigOption* p) { delete p; } -std::vector ConfigOptionDef::cli_args(const std::string &key) const +std::vector ConfigOptionDef::cli_args(const std::string& key) const { - std::vector args; - if (this->cli != ConfigOptionDef::nocli) { - const std::string &cli = this->cli; - //FIXME What was that for? Check the "readline" documentation. - // Neither '=' nor '!' is used in any of the cli parameters currently defined by PrusaSlicer. -// std::string cli = this->cli.substr(0, this->cli.find("=")); -// boost::trim_right_if(cli, boost::is_any_of("!")); - if (cli.empty()) { + std::vector args; + if (this->cli != ConfigOptionDef::nocli) { + const std::string& cli = this->cli; + // FIXME What was that for? Check the "readline" documentation. + // Neither '=' nor '!' is used in any of the cli parameters currently defined by PrusaSlicer. + // std::string cli = this->cli.substr(0, this->cli.find("=")); + // boost::trim_right_if(cli, boost::is_any_of("!")); + if (cli.empty()) { // Convert an option key to CLI argument by replacing underscores with dashes. std::string opt = key; boost::replace_all(opt, "_", "-"); args.emplace_back(std::move(opt)); } else - boost::split(args, cli, boost::is_any_of("|")); + boost::split(args, cli, boost::is_any_of("|")); } return args; } ConfigOption* ConfigOptionDef::create_empty_option() const { - if (this->nullable) { - switch (this->type) { - case coFloats: return new ConfigOptionFloatsNullable(); - case coInts: return new ConfigOptionIntsNullable(); - case coPercents: return new ConfigOptionPercentsNullable(); + if (this->nullable) { + switch (this->type) { + case coFloats: return new ConfigOptionFloatsNullable(); + case coInts: return new ConfigOptionIntsNullable(); + case coPercents: return new ConfigOptionPercentsNullable(); case coFloatsOrPercents: return new ConfigOptionFloatsOrPercentsNullable(); - case coBools: return new ConfigOptionBoolsNullable(); - default: throw ConfigurationError(std::string("Unknown option type for nullable option ") + this->label); - } - } else { - switch (this->type) { - case coFloat: return new ConfigOptionFloat(); - case coFloats: return new ConfigOptionFloats(); - case coInt: return new ConfigOptionInt(); - case coInts: return new ConfigOptionInts(); - case coString: return new ConfigOptionString(); - case coStrings: return new ConfigOptionStrings(); - case coPercent: return new ConfigOptionPercent(); - case coPercents: return new ConfigOptionPercents(); - case coFloatOrPercent: return new ConfigOptionFloatOrPercent(); + case coBools: return new ConfigOptionBoolsNullable(); + default: throw ConfigurationError(std::string("Unknown option type for nullable option ") + this->label); + } + } else { + switch (this->type) { + case coFloat: return new ConfigOptionFloat(); + case coFloats: return new ConfigOptionFloats(); + case coInt: return new ConfigOptionInt(); + case coInts: return new ConfigOptionInts(); + case coString: return new ConfigOptionString(); + case coStrings: return new ConfigOptionStrings(); + case coPercent: return new ConfigOptionPercent(); + case coPercents: return new ConfigOptionPercents(); + case coFloatOrPercent: return new ConfigOptionFloatOrPercent(); case coFloatsOrPercents: return new ConfigOptionFloatsOrPercents(); - case coPoint: return new ConfigOptionPoint(); - case coPoints: return new ConfigOptionPoints(); - case coPoint3: return new ConfigOptionPoint3(); - // case coPoint3s: return new ConfigOptionPoint3s(); - case coBool: return new ConfigOptionBool(); - case coBools: return new ConfigOptionBools(); - case coEnum: return new ConfigOptionEnumGeneric(this->enum_keys_map); + case coPoint: return new ConfigOptionPoint(); + case coPoints: return new ConfigOptionPoints(); + case coPoint3: + return new ConfigOptionPoint3(); + // case coPoint3s: return new ConfigOptionPoint3s(); + case coBool: return new ConfigOptionBool(); + case coBools: return new ConfigOptionBools(); + case coEnum: return new ConfigOptionEnumGeneric(this->enum_keys_map); // BBS - case coEnums: return new ConfigOptionEnumsGeneric(this->enum_keys_map); - default: throw ConfigurationError(std::string("Unknown option type for option ") + this->label); - } - } + case coEnums: return new ConfigOptionEnumsGeneric(this->enum_keys_map); + default: throw ConfigurationError(std::string("Unknown option type for option ") + this->label); + } + } } ConfigOption* ConfigOptionDef::create_default_option() const @@ -302,12 +301,12 @@ ConfigOption* ConfigOptionDef::create_default_option() const if (type == coEnums) { auto dft = this->default_value->clone(); if (dft->nullable()) { - ConfigOptionEnumsGenericNullable *opt = dynamic_cast(this->default_value->clone()); - opt->keys_map = this->enum_keys_map; + ConfigOptionEnumsGenericNullable* opt = dynamic_cast(this->default_value->clone()); + opt->keys_map = this->enum_keys_map; return opt; } else { - ConfigOptionEnumsGeneric *opt = dynamic_cast(this->default_value->clone()); - opt->keys_map = this->enum_keys_map; + ConfigOptionEnumsGeneric* opt = dynamic_cast(this->default_value->clone()); + opt->keys_map = this->enum_keys_map; return opt; } delete dft; @@ -319,31 +318,31 @@ ConfigOption* ConfigOptionDef::create_default_option() const } // Assignment of the serialization IDs is not thread safe. The Defs shall be initialized from the main thread! -ConfigOptionDef* ConfigDef::add(const t_config_option_key &opt_key, ConfigOptionType type) +ConfigOptionDef* ConfigDef::add(const t_config_option_key& opt_key, ConfigOptionType type) { - static size_t serialization_key_ordinal_last = 0; - ConfigOptionDef *opt = &this->options[opt_key]; - opt->opt_key = opt_key; - opt->type = type; - opt->serialization_key_ordinal = ++ serialization_key_ordinal_last; + static size_t serialization_key_ordinal_last = 0; + ConfigOptionDef* opt = &this->options[opt_key]; + opt->opt_key = opt_key; + opt->type = type; + opt->serialization_key_ordinal = ++serialization_key_ordinal_last; this->by_serialization_key_ordinal[opt->serialization_key_ordinal] = opt; return opt; } -ConfigOptionDef* ConfigDef::add_nullable(const t_config_option_key &opt_key, ConfigOptionType type) +ConfigOptionDef* ConfigDef::add_nullable(const t_config_option_key& opt_key, ConfigOptionType type) { - ConfigOptionDef *def = this->add(opt_key, type); - def->nullable = true; - return def; + ConfigOptionDef* def = this->add(opt_key, type); + def->nullable = true; + return def; } -std::ostream& ConfigDef::print_cli_help(std::ostream& out, bool show_defaults, std::function filter) const +std::ostream& ConfigDef::print_cli_help(std::ostream& out, bool show_defaults, std::function filter) const { // prepare a function for wrapping text auto wrap = [](std::string text, size_t line_length) -> std::string { std::istringstream words(text); std::ostringstream wrapped; - std::string word; + std::string word; if (words >> word) { wrapped << word; @@ -378,17 +377,17 @@ std::ostream& ConfigDef::print_cli_help(std::ostream& out, bool show_defaults, s for (const auto& opt : this->options) { const ConfigOptionDef& def = opt.second; - if (def.category != category || def.cli == ConfigOptionDef::nocli || !filter(def)) + if (def.category != category || def.cli == ConfigOptionDef::nocli || !filter(def)) continue; // get all possible variations: --foo, --foobar, -f... std::vector cli_args = def.cli_args(opt.first); - if (cli_args.empty()) - continue; + if (cli_args.empty()) + continue; for (auto& arg : cli_args) { arg.insert(0, (arg.size() == 1) ? "-" : "--"); - //BBS: refine the print help format + // BBS: refine the print help format if (!def.cli_params.empty()) arg += " " + def.cli_params; /*if ( def.type == coInt || def.type == coInts) { @@ -409,10 +408,10 @@ std::ostream& ConfigDef::print_cli_help(std::ostream& out, bool show_defaults, s out << " " << std::left << std::setw(20) << cli; // right: option description - std::string descr = def.tooltip; - bool show_defaults_this = show_defaults || def.opt_key == "config_compatibility"; - if (show_defaults_this && def.default_value && def.type != coBool - && (def.type != coString || !def.default_value->serialize().empty())) { + std::string descr = def.tooltip; + bool show_defaults_this = show_defaults || def.opt_key == "config_compatibility"; + if (show_defaults_this && def.default_value && def.type != coBool && + (def.type != coString || !def.default_value->serialize().empty())) { descr += " ("; if (!def.sidetext.empty()) { descr += def.sidetext + ", "; @@ -440,27 +439,27 @@ std::ostream& ConfigDef::print_cli_help(std::ostream& out, bool show_defaults, s return out; } -void ConfigBase::apply_only(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 &opt_key : keys) { + 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); + ConfigOption* my_opt = this->option(opt_key, true); if (my_opt == nullptr) { // 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 (auto n = opt_key.find('#'); n != std::string::npos) { - auto opt_key2 = opt_key.substr(0, n); - auto my_opt2 = dynamic_cast(this->option(opt_key2)); + auto opt_key2 = opt_key.substr(0, n); + auto my_opt2 = dynamic_cast(this->option(opt_key2)); auto other_opt = other.option(opt_key2); if (my_opt2 == nullptr && other_opt) { - my_opt2 = dynamic_cast(this->option(opt_key2, true)); + my_opt2 = dynamic_cast(this->option(opt_key2, true)); if (my_opt2->empty()) { my_opt2->resize(1, other_opt); } - } + } if (my_opt2) { int index = std::atoi(opt_key.c_str() + n + 1); if (other_opt) @@ -472,24 +471,24 @@ void ConfigBase::apply_only(const ConfigBase &other, const t_config_option_keys continue; throw UnknownOptionException(opt_key); } - const ConfigOption *other_opt = other.option(opt_key); - if (other_opt == nullptr) { + const ConfigOption* other_opt = other.option(opt_key); + if (other_opt == nullptr) { // The key was not found in the source config, therefore it will not be initialized! -// printf("Not found, therefore not initialized: %s\n", opt_key.c_str()); - } else + // printf("Not found, therefore not initialized: %s\n", opt_key.c_str()); + } else my_opt->set(other_opt); } } // Are the two configs equal? Ignoring options not present in both configs. -//BBS: add skipped keys logic -bool ConfigBase::equals(const ConfigBase &other, const std::set* skipped_keys) const +// BBS: add skipped keys logic +bool ConfigBase::equals(const ConfigBase& other, const std::set* skipped_keys) const { - for (const t_config_option_key &opt_key : this->keys()) { + for (const t_config_option_key& opt_key : this->keys()) { if (skipped_keys && (skipped_keys->count(opt_key) != 0)) continue; - const ConfigOption *this_opt = this->option(opt_key); - const ConfigOption *other_opt = other.option(opt_key); + 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) return false; } @@ -497,12 +496,12 @@ bool ConfigBase::equals(const ConfigBase &other, const std::set* sk } // Returns options differing in the two configs, ignoring options not present in both configs. -t_config_option_keys ConfigBase::diff(const ConfigBase &other) const +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()) { - const ConfigOption *this_opt = this->option(opt_key); - const ConfigOption *other_opt = other.option(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); } @@ -510,49 +509,58 @@ t_config_option_keys ConfigBase::diff(const ConfigBase &other) const } // Returns options being equal in the two configs, ignoring options not present in both configs. -t_config_option_keys ConfigBase::equal(const ConfigBase &other) const +t_config_option_keys ConfigBase::equal(const ConfigBase& other) const { t_config_option_keys equal; - 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); + 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) equal.emplace_back(opt_key); } return equal; } -std::string ConfigBase::opt_serialize(const t_config_option_key &opt_key) const +std::string ConfigBase::opt_serialize(const t_config_option_key& opt_key) const { const ConfigOption* opt = this->option(opt_key); assert(opt != nullptr); return opt->serialize(); } -void ConfigBase::set(const std::string &opt_key, int value, bool create) +void ConfigBase::set(const std::string& opt_key, int value, bool create) { - ConfigOption *opt = this->option_throw(opt_key, create); + ConfigOption* opt = this->option_throw(opt_key, create); switch (opt->type()) { - case coInt: static_cast(opt)->value = value; break; - case coFloat: static_cast(opt)->value = value; break; - case coFloatOrPercent: static_cast(opt)->value = value; static_cast(opt)->percent = false; break; - case coString: static_cast(opt)->value = std::to_string(value); break; - default: throw BadOptionTypeException("Configbase::set() - conversion from int not possible"); + case coInt: static_cast(opt)->value = value; break; + case coFloat: static_cast(opt)->value = value; break; + case coFloatOrPercent: + static_cast(opt)->value = value; + static_cast(opt)->percent = false; + break; + case coString: static_cast(opt)->value = std::to_string(value); break; + default: throw BadOptionTypeException("Configbase::set() - conversion from int not possible"); } } -void ConfigBase::set(const std::string &opt_key, double value, bool create) +void ConfigBase::set(const std::string& opt_key, double value, bool create) { - ConfigOption *opt = this->option_throw(opt_key, create); + ConfigOption* opt = this->option_throw(opt_key, create); switch (opt->type()) { - case coFloat: static_cast(opt)->value = value; break; - case coFloatOrPercent: static_cast(opt)->value = value; static_cast(opt)->percent = false; break; - case coString: static_cast(opt)->value = float_to_string_decimal_point(value); break; - default: throw BadOptionTypeException("Configbase::set() - conversion from float not possible"); + case coFloat: static_cast(opt)->value = value; break; + case coFloatOrPercent: + static_cast(opt)->value = value; + static_cast(opt)->percent = false; + break; + case coString: static_cast(opt)->value = float_to_string_decimal_point(value); break; + default: throw BadOptionTypeException("Configbase::set() - conversion from float not possible"); } } -bool ConfigBase::set_deserialize_nothrow(const t_config_option_key &opt_key_src, const std::string &value_src, ConfigSubstitutionContext& substitutions_ctxt, bool append) +bool ConfigBase::set_deserialize_nothrow(const t_config_option_key& opt_key_src, + const std::string& value_src, + ConfigSubstitutionContext& substitutions_ctxt, + bool append) { t_config_option_key opt_key = opt_key_src; std::string value = value_src; @@ -561,7 +569,7 @@ bool ConfigBase::set_deserialize_nothrow(const t_config_option_key &opt_key_src, this->handle_legacy(opt_key, value); if (opt_key.empty()) { // Ignore the option. - //BBS: record these options, keep only one repeated opt_key + // BBS: record these options, keep only one repeated opt_key auto iter = std::find(substitutions_ctxt.unrecogized_keys.begin(), substitutions_ctxt.unrecogized_keys.end(), opt_key_src); if (iter == substitutions_ctxt.unrecogized_keys.end()) substitutions_ctxt.unrecogized_keys.push_back(opt_key_src); @@ -570,33 +578,39 @@ bool ConfigBase::set_deserialize_nothrow(const t_config_option_key &opt_key_src, return this->set_deserialize_raw(opt_key, value, substitutions_ctxt, append); } -void ConfigBase::set_deserialize(const t_config_option_key &opt_key_src, const std::string &value_src, ConfigSubstitutionContext& substitutions_ctxt, bool append) +void ConfigBase::set_deserialize(const t_config_option_key& opt_key_src, + const std::string& value_src, + ConfigSubstitutionContext& substitutions_ctxt, + bool append) { - if (! this->set_deserialize_nothrow(opt_key_src, value_src, substitutions_ctxt, append)) - throw BadOptionValueException(format("Invalid value provided for parameter %1%: %2%", opt_key_src, value_src)); + if (!this->set_deserialize_nothrow(opt_key_src, value_src, substitutions_ctxt, append)) + throw BadOptionValueException(format("Invalid value provided for parameter %1%: %2%", opt_key_src, value_src)); } void ConfigBase::set_deserialize(std::initializer_list items, ConfigSubstitutionContext& substitutions_ctxt) { - for (const SetDeserializeItem &item : items) - this->set_deserialize(item.opt_key, item.opt_value, substitutions_ctxt, item.append); + for (const SetDeserializeItem& item : items) + this->set_deserialize(item.opt_key, item.opt_value, substitutions_ctxt, item.append); } -bool ConfigBase::set_deserialize_raw(const t_config_option_key &opt_key_src, const std::string &value, ConfigSubstitutionContext& substitutions_ctxt, bool append) +bool ConfigBase::set_deserialize_raw(const t_config_option_key& opt_key_src, + const std::string& value, + ConfigSubstitutionContext& substitutions_ctxt, + bool append) { - t_config_option_key opt_key = opt_key_src; + t_config_option_key opt_key = opt_key_src; // Try to deserialize the option by its name. - const ConfigDef *def = this->def(); + const ConfigDef* def = this->def(); if (def == nullptr) throw NoDefinitionException(opt_key); - const ConfigOptionDef *optdef = def->get(opt_key); + const ConfigOptionDef* optdef = 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 : def->options) { - for (const t_config_option_key &opt_key2 : opt.second.aliases) { + for (const auto& opt : def->options) { + for (const t_config_option_key& opt_key2 : opt.second.aliases) { if (opt_key2 == opt_key) { opt_key = opt.first; - optdef = &opt.second; + optdef = &opt.second; break; } } @@ -607,53 +621,55 @@ bool ConfigBase::set_deserialize_raw(const t_config_option_key &opt_key_src, con throw UnknownOptionException(opt_key); } - if (! optdef->shortcut.empty()) { + if (!optdef->shortcut.empty()) { // Aliasing for example "solid_layers" to "top_shell_layers" and "bottom_shell_layers". - for (const t_config_option_key &shortcut : optdef->shortcut) + for (const t_config_option_key& shortcut : optdef->shortcut) // Recursive call. - if (! this->set_deserialize_raw(shortcut, value, substitutions_ctxt, append)) + if (!this->set_deserialize_raw(shortcut, value, substitutions_ctxt, append)) return false; return true; } - ConfigOption *opt = this->option(opt_key, true); + ConfigOption* opt = this->option(opt_key, true); assert(opt != nullptr); bool success = false; bool substituted = false; if (optdef->type == coBools && substitutions_ctxt.rule != ForwardCompatibilitySubstitutionRule::Disable) { - //FIXME Special handling of vectors of bools, quick and not so dirty solution before PrusaSlicer 2.3.2 release. - bool nullable = opt->nullable(); - ConfigHelpers::DeserializationSubstitution default_value = ConfigHelpers::DeserializationSubstitution::DefaultsToFalse; - if (optdef->default_value) { - // Default value for vectors of booleans used in a "per extruder" context, thus the default contains just a single value. - assert(dynamic_cast*>(optdef->default_value.get())); - auto &values = static_cast*>(optdef->default_value.get())->values; - if (values.size() == 1 && values.front() == 1) - default_value = ConfigHelpers::DeserializationSubstitution::DefaultsToTrue; - } - auto result = nullable ? - static_cast(opt)->deserialize_with_substitutions(value, append, default_value) : - static_cast(opt)->deserialize_with_substitutions(value, append, default_value); - success = result != ConfigHelpers::DeserializationResult::Failed; - substituted = result == ConfigHelpers::DeserializationResult::Substituted; + // FIXME Special handling of vectors of bools, quick and not so dirty solution before PrusaSlicer 2.3.2 release. + bool nullable = opt->nullable(); + ConfigHelpers::DeserializationSubstitution default_value = ConfigHelpers::DeserializationSubstitution::DefaultsToFalse; + if (optdef->default_value) { + // Default value for vectors of booleans used in a "per extruder" context, thus the default contains just a single value. + assert(dynamic_cast*>(optdef->default_value.get())); + auto& values = static_cast*>(optdef->default_value.get())->values; + if (values.size() == 1 && values.front() == 1) + default_value = ConfigHelpers::DeserializationSubstitution::DefaultsToTrue; + } + auto result = nullable ? + static_cast(opt)->deserialize_with_substitutions(value, append, default_value) : + static_cast(opt)->deserialize_with_substitutions(value, append, default_value); + success = result != ConfigHelpers::DeserializationResult::Failed; + substituted = result == ConfigHelpers::DeserializationResult::Substituted; } else { - //bool test = (opt_key == "filament_end_gcode"); - success = opt->deserialize(value, append); - if (! success && substitutions_ctxt.rule != ForwardCompatibilitySubstitutionRule::Disable && - // Only allow substitutions of an enum value by another enum value or a boolean value with an enum value. - // That means, we expect enum values being added in the future and possibly booleans being converted to enums. - (optdef->type == coEnum || optdef->type == coEnums || optdef->type == coBool) /*&& ConfigHelpers::looks_like_enum_value(value)*/) { - // Deserialize failed, try to substitute with a default value. - //assert(substitutions_ctxt.rule == ForwardCompatibilitySubstitutionRule::Enable || substitutions_ctxt.rule == ForwardCompatibilitySubstitutionRule::EnableSilent); - if (optdef->type == coBool) - static_cast(opt)->value = ConfigHelpers::enum_looks_like_true_value(value); - else - // Just use the default of the option. - opt->set(optdef->default_value.get()); + // bool test = (opt_key == "filament_end_gcode"); + success = opt->deserialize(value, append); + if (!success && substitutions_ctxt.rule != ForwardCompatibilitySubstitutionRule::Disable && + // Only allow substitutions of an enum value by another enum value or a boolean value with an enum value. + // That means, we expect enum values being added in the future and possibly booleans being converted to enums. + (optdef->type == coEnum || optdef->type == coEnums || + optdef->type == coBool) /*&& ConfigHelpers::looks_like_enum_value(value)*/) { + // Deserialize failed, try to substitute with a default value. + // assert(substitutions_ctxt.rule == ForwardCompatibilitySubstitutionRule::Enable || substitutions_ctxt.rule == + // ForwardCompatibilitySubstitutionRule::EnableSilent); + if (optdef->type == coBool) + static_cast(opt)->value = ConfigHelpers::enum_looks_like_true_value(value); + else + // Just use the default of the option. + opt->set(optdef->default_value.get()); success = true; substituted = true; - } - } + } + } if (substituted && (substitutions_ctxt.rule == ForwardCompatibilitySubstitutionRule::Enable || substitutions_ctxt.rule == ForwardCompatibilitySubstitutionRule::EnableSystemSilent)) { @@ -669,65 +685,64 @@ bool ConfigBase::set_deserialize_raw(const t_config_option_key &opt_key_src, con // 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 +double ConfigBase::get_abs_value(const t_config_option_key& opt_key) const { // Get stored option value. - const ConfigOption *raw_opt = this->option(opt_key); + const ConfigOption* raw_opt = this->option(opt_key); if (raw_opt == nullptr) { - std::stringstream ss; - ss << "You can't define an option that need " << opt_key << " without defining it!"; - throw std::runtime_error(ss.str()); + std::stringstream ss; + ss << "You can't define an option that need " << opt_key << " without defining it!"; + throw std::runtime_error(ss.str()); } assert(raw_opt != nullptr); if (raw_opt->type() == coFloat) return static_cast(raw_opt)->value; if (raw_opt->type() == coInt) - return static_cast(raw_opt)->value; + return static_cast(raw_opt)->value; if (raw_opt->type() == coBool) - return static_cast(raw_opt)->value ? 1 : 0; + return static_cast(raw_opt)->value ? 1 : 0; - const ConfigOptionPercent *cast_opt = nullptr; + const ConfigOptionPercent* cast_opt = nullptr; if (raw_opt->type() == coFloatOrPercent) { auto cofop = static_cast(raw_opt); - if (cofop->value == 0 && boost::ends_with(opt_key, "_line_width")) { - return this->get_abs_value("line_width"); - } - if (!cofop->percent) - return cofop->value; - cast_opt = cofop; + if (cofop->value == 0 && boost::ends_with(opt_key, "_line_width")) { + return this->get_abs_value("line_width"); + } + if (!cofop->percent) + return cofop->value; + cast_opt = cofop; } if (raw_opt->type() == coPercent) { - cast_opt = static_cast(raw_opt); + cast_opt = static_cast(raw_opt); } // Get option definition. - const ConfigDef *def = this->def(); + const ConfigDef* def = this->def(); if (def == nullptr) throw NoDefinitionException(opt_key); - const ConfigOptionDef *opt_def = def->get(opt_key); - + const ConfigOptionDef* opt_def = def->get(opt_key); assert(opt_def != nullptr); if (opt_def->ratio_over == "") return cast_opt->get_abs_value(1); // Compute absolute value over the absolute value of the base option. - //FIXME there are some ratio_over chains, which end with empty ratio_with. + // FIXME there are some ratio_over chains, which end with empty ratio_with. // For example, XXX_extrusion_width parameters are not handled by get_abs_value correctly. - return opt_def->ratio_over.empty() ? 0. : - static_cast(raw_opt)->get_abs_value(this->get_abs_value(opt_def->ratio_over)); - + return opt_def->ratio_over.empty() ? + 0. : + static_cast(raw_opt)->get_abs_value(this->get_abs_value(opt_def->ratio_over)); throw ConfigurationError("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 +double ConfigBase::get_abs_value(const t_config_option_key& opt_key, double ratio_over) const { // Get stored option value. - const ConfigOption *raw_opt = this->option(opt_key); + const ConfigOption* raw_opt = this->option(opt_key); assert(raw_opt != nullptr); if (raw_opt->type() != coFloatOrPercent) throw ConfigurationError("ConfigBase::get_abs_value(): opt_key is not of coFloatOrPercent"); @@ -747,33 +762,33 @@ void ConfigBase::setenv_() const // capitalize environment variable name for (size_t i = 0; i < envname.size(); ++i) - envname[i] = (envname[i] <= 'z' && envname[i] >= 'a') ? envname[i]-('a'-'A') : envname[i]; + envname[i] = (envname[i] <= 'z' && envname[i] >= 'a') ? envname[i] - ('a' - 'A') : envname[i]; boost::nowide::setenv(envname.c_str(), this->opt_serialize(*it).c_str(), 1); } } -//BBS -ConfigSubstitutions ConfigBase::load_string_map(std::map& key_values, ForwardCompatibilitySubstitutionRule compatibility_rule) +// BBS +ConfigSubstitutions ConfigBase::load_string_map(std::map& key_values, + ForwardCompatibilitySubstitutionRule compatibility_rule) { CNumericLocalesSetter locales_setter; - ConfigSubstitutionContext substitutions_ctxt(compatibility_rule); + ConfigSubstitutionContext substitutions_ctxt(compatibility_rule); std::map::iterator it; for (it = key_values.begin(); it != key_values.end(); it++) { try { t_config_option_key opt_key = it->first; this->set_deserialize(opt_key, it->second, substitutions_ctxt); - } - catch (UnknownOptionException& /* e */) { + } catch (UnknownOptionException& /* e */) { // ignore } } return std::move(substitutions_ctxt.substitutions); } -//BBS: add json support -ConfigSubstitutions ConfigBase::load(const std::string &file, ForwardCompatibilitySubstitutionRule compatibility_rule) +// BBS: add json support +ConfigSubstitutions ConfigBase::load(const std::string& file, ForwardCompatibilitySubstitutionRule compatibility_rule) { std::map key_values; if (is_gcode_file(file)) @@ -781,36 +796,44 @@ ConfigSubstitutions ConfigBase::load(const std::string &file, ForwardCompatibili else if (is_json_file(file)) { std::string reason; return this->load_from_json(file, compatibility_rule, key_values, reason); - } - else { + } else { BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "unsupported format for config file" << file; return ConfigSubstitutions(); - //return this->load_from_ini(file, compatibility_rule); + // return this->load_from_ini(file, compatibility_rule); } } -//BBS: add json support -ConfigSubstitutions ConfigBase::load_from_json(const std::string &file, ForwardCompatibilitySubstitutionRule compatibility_rule, std::map& key_values, std::string& reason) +// BBS: add json support +ConfigSubstitutions ConfigBase::load_from_json(const std::string& file, + ForwardCompatibilitySubstitutionRule compatibility_rule, + std::map& key_values, + std::string& reason) { - int ret = 0; + int ret = 0; ConfigSubstitutionContext substitutions_ctxt(compatibility_rule); ret = load_from_json(file, substitutions_ctxt, true, key_values, reason); return std::move(substitutions_ctxt.substitutions); } -int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContext& substitution_context, bool load_inherits_to_config, std::map& key_values, std::string& reason) +int ConfigBase::load_from_json(const std::string& file, + ConfigSubstitutionContext& substitution_context, + bool load_inherits_to_config, + std::map& key_values, + std::string& reason) { - json j; + json j; std::list different_settings_append; - std::string new_support_style; - std::string is_infill_first; - std::string get_wall_sequence; - bool is_project_settings = false; + std::string new_support_style; + std::string is_infill_first; + std::string get_wall_sequence; + bool is_project_settings = false; CNumericLocalesSetter locales_setter; - std::function parse_str_arr = [&parse_str_arr](const json::const_iterator& it, const char single_sep,const char array_sep,const bool escape_string_style,std::string& value_str)->bool { + std::function parse_str_arr = + [&parse_str_arr](const json::const_iterator& it, const char single_sep, const char array_sep, const bool escape_string_style, + std::string& value_str) -> bool { // must have consistent type name std::string consistent_type; for (auto iter = it.value().begin(); iter != it.value().end(); ++iter) { @@ -829,11 +852,10 @@ int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContex value_str += array_sep; else first = false; - bool success = parse_str_arr(iter, single_sep, array_sep,escape_string_style, value_str); + bool success = parse_str_arr(iter, single_sep, array_sep, escape_string_style, value_str); if (!success) return false; - } - else if (iter.value().is_string()) { + } else if (iter.value().is_string()) { if (!first) value_str += single_sep; else @@ -845,14 +867,13 @@ int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContex value_str += escape_string_cstyle(iter.value()); value_str += "\""; } - } - else { - //should not happen + } else { + // should not happen return false; } } return true; - }; + }; try { boost::nowide::ifstream ifs(file); @@ -864,62 +885,53 @@ int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContex BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": no config defs!"; return -1; } - //parse the json elements + // parse the json elements for (auto it = j.begin(); it != j.end(); it++) { - if (boost::iequals(it.key(),BBL_JSON_KEY_VERSION)) { + if (boost::iequals(it.key(), BBL_JSON_KEY_VERSION)) { key_values.emplace(BBL_JSON_KEY_VERSION, it.value()); - } - else if (boost::iequals(it.key(), BBL_JSON_KEY_IS_CUSTOM)) { - //skip it - } - else if (boost::iequals(it.key(), BBL_JSON_KEY_NAME)) { + } else if (boost::iequals(it.key(), BBL_JSON_KEY_IS_CUSTOM)) { + // skip it + } else if (boost::iequals(it.key(), BBL_JSON_KEY_NAME)) { key_values.emplace(BBL_JSON_KEY_NAME, it.value()); if (it.value() == "project_settings") is_project_settings = true; - } - else if (boost::iequals(it.key(), BBL_JSON_KEY_URL)) { + } else if (boost::iequals(it.key(), BBL_JSON_KEY_URL)) { key_values.emplace(BBL_JSON_KEY_URL, it.value()); - } - else if (boost::iequals(it.key(), BBL_JSON_KEY_TYPE)) { + } else if (boost::iequals(it.key(), BBL_JSON_KEY_TYPE)) { key_values.emplace(BBL_JSON_KEY_TYPE, it.value()); - } - else if (boost::iequals(it.key(), BBL_JSON_KEY_SETTING_ID)) { + } else if (boost::iequals(it.key(), BBL_JSON_KEY_SETTING_ID)) { key_values.emplace(BBL_JSON_KEY_SETTING_ID, it.value()); - } - else if (boost::iequals(it.key(), BBL_JSON_KEY_FILAMENT_ID)) { + } else if (boost::iequals(it.key(), BBL_JSON_KEY_FILAMENT_ID)) { key_values.emplace(BBL_JSON_KEY_FILAMENT_ID, it.value()); - } - else if (boost::iequals(it.key(), BBL_JSON_KEY_FROM)) { + } else if (boost::iequals(it.key(), BBL_JSON_KEY_FROM)) { key_values.emplace(BBL_JSON_KEY_FROM, it.value()); - } - else if (boost::iequals(it.key(), BBL_JSON_KEY_DESCRIPTION)) { + } else if (boost::iequals(it.key(), BBL_JSON_KEY_DESCRIPTION)) { key_values.emplace(BBL_JSON_KEY_DESCRIPTION, it.value()); - } - else if (boost::iequals(it.key(), BBL_JSON_KEY_INSTANTIATION)) { + } else if (boost::iequals(it.key(), BBL_JSON_KEY_INSTANTIATION)) { key_values.emplace(BBL_JSON_KEY_INSTANTIATION, it.value()); - } - else if (!load_inherits_to_config && boost::iequals(it.key(), BBL_JSON_KEY_INHERITS)) { + } else if (!load_inherits_to_config && boost::iequals(it.key(), BBL_JSON_KEY_INHERITS)) { key_values.emplace(BBL_JSON_KEY_INHERITS, it.value()); } else if (boost::iequals(it.key(), ORCA_JSON_KEY_RENAMED_FROM)) { key_values.emplace(ORCA_JSON_KEY_RENAMED_FROM, it.value()); } else { t_config_option_key opt_key = it.key(); - std::string value_str; + std::string value_str; if (it.value().is_string()) { - //bool test1 = (it.key() == std::string("end_gcode")); + // bool test1 = (it.key() == std::string("end_gcode")); this->set_deserialize(opt_key, it.value(), substitution_context); - //some logic for special values + // some logic for special values if (opt_key == "support_type") { - //std::string new_value = dynamic_cast(this->option(opt_key))->value; + // std::string new_value = dynamic_cast(this->option(opt_key))->value; if (it.value() == "hybrid(auto)") { different_settings_append.push_back(opt_key); different_settings_append.push_back("support_style"); new_support_style = "tree_hybrid"; } } else if (opt_key == "wall_infill_order") { - //BBS: check wall_infill order to decide if it be different and append to diff_setting_append - if (it.value() == "outer wall/inner wall/infill" || it.value() == "infill/outer wall/inner wall" || it.value() == "inner-outer-inner wall/infill") { + // BBS: check wall_infill order to decide if it be different and append to diff_setting_append + if (it.value() == "outer wall/inner wall/infill" || it.value() == "infill/outer wall/inner wall" || + it.value() == "inner-outer-inner wall/infill") { get_wall_sequence = "wall_seq_diff_to_system"; } @@ -928,16 +940,15 @@ int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContex is_infill_first = "true"; } } - } - else if (it.value().is_array()) { + } else if (it.value().is_array()) { t_config_option_key opt_key_src = opt_key; this->handle_legacy(opt_key, value_str); if (opt_key.empty()) { - //BBS: record these options + // BBS: record these options substitution_context.unrecogized_keys.push_back(opt_key_src); continue; } - bool valid = true, first = true; + bool valid = true, first = true; const ConfigOptionDef* optdef = config_def->get(opt_key); if (optdef == nullptr) { // If we didn't find an option, look for any other option having this as an alias. @@ -945,7 +956,7 @@ int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContex for (const t_config_option_key& opt_key2 : opt.second.aliases) { if (opt_key2 == opt_key) { opt_key = opt.first; - optdef = &opt.second; + optdef = &opt.second; break; } } @@ -954,70 +965,64 @@ int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContex } } - char single_sep = ','; - char array_sep = '#'; // currenty not used + char single_sep = ','; + char array_sep = '#'; // currenty not used bool escape_string_type = false; if (optdef) { - switch (optdef->type) - { + switch (optdef->type) { case coStrings: escape_string_type = true; - single_sep = ';'; - break; - case coPointsGroups: - single_sep = '#'; - break; - default: + single_sep = ';'; break; + case coPointsGroups: single_sep = '#'; break; + default: break; } } // BBS: we only support 2 depth array - valid = parse_str_arr(it, single_sep, array_sep,escape_string_type, value_str); + valid = parse_str_arr(it, single_sep, array_sep, escape_string_type, value_str); if (!valid) { BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": parse " << file << " error, invalid json array for " << it.key(); break; } if (valid) this->set_deserialize(opt_key, value_str, substitution_context); - } - else { - //should not happen - BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< ": parse "<* opt = this->option>("support_style", true); - opt->value = smsTreeHybrid; + opt->value = smsTreeHybrid; } if (!is_infill_first.empty()) { - ConfigOptionBool *opt = this->option("is_infill_first", true); - opt->value = true; + ConfigOptionBool* opt = this->option("is_infill_first", true); + opt->value = true; } if (is_project_settings) { - std::vector& different_settings = this->option("different_settings_to_system", true)->values; + std::vector& different_settings = this->option("different_settings_to_system", true) + ->values; size_t size = different_settings.size(); if (size == 0) { size = this->option("filament_settings_id")->values.size() + 2; different_settings.resize(size); } - std::vector is_first(size, false); + std::vector is_first(size, false); std::vector> original_diffs(size); - for (int index = 0; index < size; index++) - { + for (int index = 0; index < size; index++) { if (different_settings[index].empty()) { is_first[index] = true; - } - else { + } else { // remove unneeded key if (get_wall_sequence.empty()) { std::string wall_sqe_string = "wall_sequence"; - int pos=different_settings[index].find(wall_sqe_string); + int pos = different_settings[index].find(wall_sqe_string); if (pos != different_settings[index].npos) { int erase_len = wall_sqe_string.size(); @@ -1025,7 +1030,6 @@ int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContex erase_len++; different_settings[index].erase(pos, erase_len); } - } if (different_settings[index].empty()) { @@ -1037,10 +1041,9 @@ int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContex } } - for (auto diff_key : different_settings_append) - { - //get the index in the group - int index = 0; + for (auto diff_key : different_settings_append) { + // get the index in the group + int index = 0; bool need_insert = true; if (diff_key == "support_type") index = 0; @@ -1049,7 +1052,7 @@ int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContex else if (diff_key == "is_infill_first") index = 0; - //check whether exist firstly + // check whether exist firstly if (!original_diffs[index].empty()) { for (int j = 0; j < original_diffs[index].size(); j++) { if (original_diffs[index][j] == diff_key) { @@ -1061,7 +1064,7 @@ int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContex if (!need_insert) continue; - //insert this key + // insert this key if (!is_first[index]) different_settings[index] += ";"; else @@ -1070,52 +1073,49 @@ int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContex } } } - + // Do legacy conversion on a completely loaded dictionary. // Perform composite conversions, for example merging multiple keys into one key. this->handle_legacy_composite(); return 0; - } - catch (const std::ifstream::failure &err) { - BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< ": parse "<load(tree, compatibility_rule); - } catch (const ConfigurationError &e) { + } catch (const ConfigurationError& e) { throw ConfigurationError(format("Failed loading configuration file \"%1%\": %2%", file, e.what())); } } -ConfigSubstitutions ConfigBase::load_from_ini_string(const std::string &data, ForwardCompatibilitySubstitutionRule compatibility_rule) +ConfigSubstitutions ConfigBase::load_from_ini_string(const std::string& data, ForwardCompatibilitySubstitutionRule compatibility_rule) { boost::property_tree::ptree tree; - std::istringstream iss(data); + std::istringstream iss(data); boost::property_tree::read_ini(iss, tree); return this->load(tree, compatibility_rule); } // Loading a "will be one day a legacy format" of configuration stored into 3MF or AMF. // Accepts the same data as load_from_ini_string(), only with each configuration line possibly prefixed with a semicolon (G-code comment). -ConfigSubstitutions ConfigBase::load_from_ini_string_commented(std::string &&data, ForwardCompatibilitySubstitutionRule compatibility_rule) +ConfigSubstitutions ConfigBase::load_from_ini_string_commented(std::string&& data, ForwardCompatibilitySubstitutionRule compatibility_rule) { // Convert the "data" string into INI format by removing the semi-colons at the start of a line. // Also the "; generated by PrusaSlicer ..." comment line will be removed. @@ -1126,40 +1126,43 @@ ConfigSubstitutions ConfigBase::load_from_ini_string_commented(std::string &&dat if (data[i] == '\n') { // Consume LF, don't keep empty lines. if (j > 0 && data[j - 1] != '\n') - data[j ++] = data[i]; - ++ i; + data[j++] = data[i]; + ++i; } // Skip all leading spaces; - for (; i < data.size() && (data[i] == ' ' || data[i] == '\t'); ++ i) ; + for (; i < data.size() && (data[i] == ' ' || data[i] == '\t'); ++i) + ; // Skip the semicolon (comment indicator). if (i < data.size() && data[i] == ';') - ++ i; + ++i; // Skip all leading spaces after semicolon. - for (; i < data.size() && (data[i] == ' ' || data[i] == '\t'); ++ i) ; + for (; i < data.size() && (data[i] == ' ' || data[i] == '\t'); ++i) + ; if (strncmp(data.data() + i, "generated by ", 13) == 0) { // Skip the "; generated by ..." line. - for (; i < data.size() && data[i] != '\n'; ++ i); + for (; i < data.size() && data[i] != '\n'; ++i) + ; } } else if (data[i] == '\r' && i + 1 < data.size() && data[i + 1] == '\n') { // Skip CR. - ++ i; + ++i; } else { // Consume the rest of the data. - data[j ++] = data[i ++]; + data[j++] = data[i++]; } data.erase(data.begin() + j, data.end()); return this->load_from_ini_string(data, compatibility_rule); } -ConfigSubstitutions ConfigBase::load(const boost::property_tree::ptree &tree, ForwardCompatibilitySubstitutionRule compatibility_rule) +ConfigSubstitutions ConfigBase::load(const boost::property_tree::ptree& tree, ForwardCompatibilitySubstitutionRule compatibility_rule) { ConfigSubstitutionContext substitutions_ctxt(compatibility_rule); - for (const boost::property_tree::ptree::value_type &v : tree) { + for (const boost::property_tree::ptree::value_type& v : tree) { try { t_config_option_key opt_key = v.first; this->set_deserialize(opt_key, v.second.get_value(), substitutions_ctxt); - } catch (UnknownOptionException & /* e */) { + } catch (UnknownOptionException& /* e */) { // ignore } } @@ -1170,18 +1173,20 @@ ConfigSubstitutions ConfigBase::load(const boost::property_tree::ptree &tree, Fo } // BBS -static bool is_whitespace(char c) { return c == ' ' || c == '\t'; } -static bool is_end_of_line(char c) { return c == '\r' || c == '\n' || c == 0; } -static bool is_end_of_gcode_line(char c) { return c == ';' || is_end_of_line(c); } -static bool is_end_of_word(char c) { return is_whitespace(c) || is_end_of_gcode_line(c); } +static bool is_whitespace(char c) { return c == ' ' || c == '\t'; } +static bool is_end_of_line(char c) { return c == '\r' || c == '\n' || c == 0; } +static bool is_end_of_gcode_line(char c) { return c == ';' || is_end_of_line(c); } +static bool is_end_of_word(char c) { return is_whitespace(c) || is_end_of_gcode_line(c); } -static const char* skip_word(const char* c) { +static const char* skip_word(const char* c) +{ for (; !is_end_of_word(*c); ++c) ; // silence -Wempty-body return c; } -static const char* skip_whitespaces(const char* c) { +static const char* skip_whitespaces(const char* c) +{ for (; is_whitespace(*c); ++c) ; // silence -Wempty-body return c; @@ -1194,48 +1199,51 @@ size_t ConfigBase::load_from_gcode_string_legacy(ConfigBase& config, const char* return 0; // BBS. Remove line numbers. - std::regex match_pattern("\nN[0-9]* *"); + std::regex match_pattern("\nN[0-9]* *"); std::string replace_pattern = "\n"; - char* result = (char*)calloc(strlen(str) + 1, 1); + char* result = (char*) calloc(strlen(str) + 1, 1); std::regex_replace(result, str, str + strlen(str), match_pattern, replace_pattern); // Walk line by line in reverse until a non-configuration key appears. - const char *data_start = result; - data_start = skip_whitespaces(data_start); + const char* data_start = result; + data_start = skip_whitespaces(data_start); if (std::toupper(*data_start) == 'N') data_start = skip_word(data_start); // boost::nowide::ifstream seems to cook the text data somehow, so less then the 64k of characters may be retrieved. - const char *end = data_start + strlen(data_start); - size_t num_key_value_pairs = 0; + const char* end = data_start + strlen(data_start); + size_t num_key_value_pairs = 0; for (;;) { // Extract next line. - for (--end; end > data_start && (*end == '\r' || *end == '\n'); --end); + for (--end; end > data_start && (*end == '\r' || *end == '\n'); --end) + ; if (end == data_start) break; - const char *start = end ++; - for (; start > data_start && *start != '\r' && *start != '\n'; --start); + const char* start = end++; + for (; start > data_start && *start != '\r' && *start != '\n'; --start) + ; if (start == data_start) break; // Extracted a line from start to end. Extract the key = value pair. - if (end - (++ start) < 10 || start[0] != ';' || start[1] != ' ') + if (end - (++start) < 10 || start[0] != ';' || start[1] != ' ') break; - const char *key = start + 2; + const char* key = start + 2; if (!((*key >= 'a' && *key <= 'z') || (*key >= 'A' && *key <= 'Z'))) // A key must start with a letter. break; - const char *sep = key; - for (; sep != end && *sep != '='; ++ sep) ; + const char* sep = key; + for (; sep != end && *sep != '='; ++sep) + ; if (sep == end || sep[-1] != ' ' || sep[1] != ' ') break; - const char *value = sep + 2; + const char* value = sep + 2; if (value > end) break; - const char *key_end = sep - 1; + const char* key_end = sep - 1; if (key_end - key < 3) break; // The key may contain letters, digits and underscores. - for (const char *c = key; c != key_end; ++ c) + for (const char* c = key; c != key_end; ++c) if (!((*c >= 'a' && *c <= 'z') || (*c >= 'A' && *c <= 'Z') || (*c >= '0' && *c <= '9') || *c == '_')) { key = nullptr; break; @@ -1245,8 +1253,7 @@ size_t ConfigBase::load_from_gcode_string_legacy(ConfigBase& config, const char* try { config.set_deserialize(std::string(key, key_end), std::string(value, end), substitutions); ++num_key_value_pairs; - } - catch (UnknownOptionException & /* e */) { + } catch (UnknownOptionException& /* e */) { // ignore } end = start; @@ -1268,14 +1275,15 @@ public: using pos_type = boost::nowide::ifstream::pos_type; // Stop at file_start - ReverseLineReader(boost::nowide::ifstream &ifs, pos_type file_start) : m_ifs(ifs), m_file_start(file_start) + ReverseLineReader(boost::nowide::ifstream& ifs, pos_type file_start) : m_ifs(ifs), m_file_start(file_start) { m_ifs.seekg(0, m_ifs.end); m_file_pos = m_ifs.tellg(); m_block.assign(m_block_size, 0); } - bool getline(std::string &out) { + bool getline(std::string& out) + { out.clear(); for (;;) { if (m_block_len == 0) { @@ -1285,14 +1293,14 @@ public: return false; m_file_pos -= m_block_len; m_ifs.seekg(m_file_pos, m_ifs.beg); - if (! m_ifs.read(m_block.data(), m_block_len)) + if (!m_ifs.read(m_block.data(), m_block_len)) return false; } assert(m_block_len > 0); // Non-empty buffer. Find another LF. int i = int(m_block_len) - 1; - for (; i >= 0; -- i) + for (; i >= 0; --i) if (m_block[i] == '\n') break; // i is position of LF or -1 if not found. @@ -1308,7 +1316,7 @@ public: m_block_len = i; // Remove CRLF from the end of the block. if (m_block_len > 0 && m_block[m_block_len - 1] == '\r') - -- m_block_len; + --m_block_len; return true; } } @@ -1317,26 +1325,26 @@ public: } private: - boost::nowide::ifstream &m_ifs; + boost::nowide::ifstream& m_ifs; std::vector m_block; size_t m_block_size = 65536; size_t m_block_len = 0; pos_type m_file_start; - pos_type m_file_pos = 0; + pos_type m_file_pos = 0; }; // Load the config keys from the tail of a G-code file. -ConfigSubstitutions ConfigBase::load_from_gcode_file(const std::string &file, ForwardCompatibilitySubstitutionRule compatibility_rule) +ConfigSubstitutions ConfigBase::load_from_gcode_file(const std::string& file, ForwardCompatibilitySubstitutionRule compatibility_rule) { // Read a 64k block from the end of the G-code. - boost::nowide::ifstream ifs(file); + boost::nowide::ifstream ifs(file); BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": before parse_file %1%") % file.c_str(); // Look for Slic3r or OrcaSlicer header. // Look for the header across the whole file as the G-code may have been extended at the start by a post-processing script or the user. - //BBS + // BBS bool has_delimiters = true; { - //BBS + // BBS std::string bambuslicer_gcode_header = "; OrcaSlicer"; std::string orcaslicer_gcode_header = std::string("; generated by "); @@ -1369,28 +1377,28 @@ ConfigSubstitutions ConfigBase::load_from_gcode_file(const std::string &file, Fo ConfigSubstitutionContext substitutions_ctxt(compatibility_rule); size_t key_value_pairs = 0; - if (has_delimiters) - { - //BBS - // PrusaSlicer starting with 2.4.0-alpha0 delimits the config section stored into G-code with - // ; CONFIG_BLOCK_START - // ... - // ; CONFIG_BLOCK_END - bool begin_found = false; - bool end_found = false; + if (has_delimiters) { + // BBS + // PrusaSlicer starting with 2.4.0-alpha0 delimits the config section stored into G-code with + // ; CONFIG_BLOCK_START + // ... + // ; CONFIG_BLOCK_END + bool begin_found = false; + bool end_found = false; std::string line; while (std::getline(ifs, line)) - if (line.rfind("; CONFIG_BLOCK_START",0)==0) { + if (line.rfind("; CONFIG_BLOCK_START", 0) == 0) { begin_found = true; break; } if (!begin_found) { - //BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << format("Configuration block closing tag \"; CONFIG_BLOCK_START\" not found when reading %1%", file); + // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << format("Configuration block closing tag \"; CONFIG_BLOCK_START\" not found when + // reading %1%", file); throw Slic3r::RuntimeError(format("Config tag \"; CONFIG_BLOCK_START\" not found")); } std::string key, value; while (std::getline(ifs, line)) { - if (line.rfind("; CONFIG_BLOCK_END",0)==0) { + if (line.rfind("; CONFIG_BLOCK_END", 0) == 0) { end_found = true; break; } @@ -1403,26 +1411,25 @@ ConfigSubstitutions ConfigBase::load_from_gcode_file(const std::string &file, Fo boost::trim(value); try { this->set_deserialize(key, value, substitutions_ctxt); - ++ key_value_pairs; - } catch (UnknownOptionException & /* e */) { + ++key_value_pairs; + } catch (UnknownOptionException& /* e */) { // ignore } } } if (!end_found) { - //BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << format("Configuration block opening tag \"; CONFIG_BLOCK_END\" not found when reading %1%", file); + // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << format("Configuration block opening tag \"; CONFIG_BLOCK_END\" not found when + // reading %1%", file); throw Slic3r::RuntimeError(format("Config tag \"; CONFIG_BLOCK_END\" not found")); } - } - else - { - auto header_end_pos = ifs.tellg(); + } else { + auto header_end_pos = ifs.tellg(); // Slicer older than 2.4.0-alpha0 do not emit any delimiter. // Try a heuristics reading the G-code from back. ifs.seekg(0, ifs.end); auto file_length = ifs.tellg(); - auto data_length = std::min(65535, file_length - header_end_pos); - ifs.seekg(file_length - data_length, ifs.beg); + auto data_length = std::min(65535, file_length - header_end_pos); + ifs.seekg(file_length - data_length, ifs.beg); std::vector data(size_t(data_length) + 1, 0); ifs.read(data.data(), data_length); ifs.close(); @@ -1430,7 +1437,8 @@ ConfigSubstitutions ConfigBase::load_from_gcode_file(const std::string &file, Fo } if (key_value_pairs < 80) { - BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << format("Suspiciously low number of configuration values extracted from %1%: %2%", file, key_value_pairs); + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ + << format("Suspiciously low number of configuration values extracted from %1%: %2%", file, key_value_pairs); throw Slic3r::RuntimeError(format("Suspiciously low number of configuration values extracted from %1%: %2%", file, key_value_pairs)); } @@ -1442,29 +1450,27 @@ ConfigSubstitutions ConfigBase::load_from_gcode_file(const std::string &file, Fo return std::move(substitutions_ctxt.substitutions); } -//BBS: add json support -void ConfigBase::save_to_json(const std::string &file, const std::string &name, const std::string &from, const std::string &version) const +// BBS: add json support +void ConfigBase::save_to_json(const std::string& file, const std::string& name, const std::string& from, const std::string& version) const { json j; - //record the headers + // record the headers j[BBL_JSON_KEY_VERSION] = version; - j[BBL_JSON_KEY_NAME] = name; - j[BBL_JSON_KEY_FROM] = from; + j[BBL_JSON_KEY_NAME] = name; + j[BBL_JSON_KEY_FROM] = from; - //record all the key-values - for (const std::string &opt_key : this->keys()) - { + // record all the key-values + for (const std::string& opt_key : this->keys()) { const ConfigOption* opt = this->option(opt_key); - if ( opt->is_scalar() ) { + if (opt->is_scalar()) { if (opt->type() == coString && (opt_key != "bed_custom_texture" && opt_key != "bed_custom_model")) - //keep \n, \r, \t - j[opt_key] = (dynamic_cast(opt))->value; + // keep \n, \r, \t + j[opt_key] = (dynamic_cast(opt))->value; else j[opt_key] = opt->serialize(); - } - else { + } else { const ConfigOptionVectorBase* vec = static_cast(opt); - //if (!vec->empty()) + // if (!vec->empty()) std::vector string_values = vec->vserialize(); /*for (int i = 0; i < string_values.size(); i++) @@ -1483,88 +1489,88 @@ void ConfigBase::save_to_json(const std::string &file, const std::string &name, c << std::setw(4) << j << std::endl; c.close(); - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(", saved config to %1%\n")%file; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", saved config to %1%\n") % file; } -void ConfigBase::save(const std::string &file) const +void ConfigBase::save(const std::string& file) const { boost::nowide::ofstream c; c.open(file, std::ios::out | std::ios::trunc); c << "# " << Slic3r::header_slic3r_generated() << std::endl; - for (const std::string &opt_key : this->keys()) + for (const std::string& opt_key : this->keys()) c << opt_key << " = " << this->opt_serialize(opt_key) << std::endl; c.close(); - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(", saved config to %1%\n")%file; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", saved config to %1%\n") % file; } // Set all the nullable values to nils. void ConfigBase::null_nullables() { - for (const std::string &opt_key : this->keys()) { - ConfigOption *opt = this->optptr(opt_key, false); + for (const std::string& opt_key : this->keys()) { + ConfigOption* opt = this->optptr(opt_key, false); assert(opt != nullptr); if (opt->nullable()) - opt->deserialize("nil", ForwardCompatibilitySubstitutionRule::Disable); + opt->deserialize("nil", ForwardCompatibilitySubstitutionRule::Disable); } } DynamicConfig::DynamicConfig(const ConfigBase& rhs, const t_config_option_keys& keys) { - for (const t_config_option_key& opt_key : keys) - this->options[opt_key] = std::unique_ptr(rhs.option(opt_key)->clone()); + for (const t_config_option_key& opt_key : keys) + this->options[opt_key] = std::unique_ptr(rhs.option(opt_key)->clone()); } -bool DynamicConfig::operator==(const DynamicConfig &rhs) const +bool DynamicConfig::operator==(const DynamicConfig& rhs) const { auto it1 = this->options.begin(); auto it1_end = this->options.end(); auto it2 = rhs.options.begin(); auto it2_end = rhs.options.end(); - for (; it1 != it1_end && it2 != it2_end; ++ it1, ++ it2) - if (it1->first != it2->first || *it1->second != *it2->second) - // key or value differ - return false; + for (; it1 != it1_end && it2 != it2_end; ++it1, ++it2) + if (it1->first != it2->first || *it1->second != *it2->second) + // key or value differ + return false; return it1 == it1_end && it2 == it2_end; } // Remove options with all nil values, those are optional and it does not help to hold them. size_t DynamicConfig::remove_nil_options() { - size_t cnt_removed = 0; - for (auto it = options.begin(); it != options.end();) - if (it->second->is_nil()) { - it = options.erase(it); - ++ cnt_removed; - } else - ++ it; - return cnt_removed; + size_t cnt_removed = 0; + for (auto it = options.begin(); it != options.end();) + if (it->second->is_nil()) { + it = options.erase(it); + ++cnt_removed; + } else + ++it; + return cnt_removed; } -ConfigOption* DynamicConfig::optptr(const t_config_option_key &opt_key, bool create) +ConfigOption* DynamicConfig::optptr(const t_config_option_key& opt_key, bool create) { auto it = options.find(opt_key); if (it != options.end()) // Option was found. return it->second.get(); - if (! create) + if (!create) // Option was not found and a new option shall not be created. return nullptr; // Try to create a new ConfigOption. - const ConfigDef *def = this->def(); + const ConfigDef* def = this->def(); if (def == nullptr) throw NoDefinitionException(opt_key); - const ConfigOptionDef *optdef = def->get(opt_key); + const ConfigOptionDef* optdef = def->get(opt_key); if (optdef == nullptr) -// throw ConfigurationError(std::string("Invalid option name: ") + opt_key); + // throw ConfigurationError(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 = optdef->create_default_option(); + ConfigOption* opt = optdef->create_default_option(); this->options.emplace_hint(it, opt_key, std::unique_ptr(opt)); return opt; } -const ConfigOption* DynamicConfig::optptr(const t_config_option_key &opt_key) const +const ConfigOption* DynamicConfig::optptr(const t_config_option_key& opt_key) const { auto it = options.find(opt_key); return (it == options.end()) ? nullptr : it->second.get(); @@ -1573,16 +1579,16 @@ const ConfigOption* DynamicConfig::optptr(const t_config_option_key &opt_key) co bool DynamicConfig::read_cli(int argc, const char* const argv[], t_config_option_keys* extra, t_config_option_keys* keys) { // cache the CLI option => opt_key mapping - std::map opts; - for (const auto &oit : this->def()->options) - for (const std::string &t : oit.second.cli_args(oit.first)) + std::map opts; + for (const auto& oit : this->def()->options) + for (const std::string& t : oit.second.cli_args(oit.first)) opts[t] = oit.first; bool parse_options = true; - for (int i = 1; i < argc; ++ i) { + for (int i = 1; i < argc; ++i) { std::string token = argv[i]; // Store non-option arguments in the provided vector. - if (! parse_options || ! boost::starts_with(token, "-")) { + if (!parse_options || !boost::starts_with(token, "-")) { extra->push_back(token); continue; } @@ -1604,7 +1610,7 @@ bool DynamicConfig::read_cli(int argc, const char* const argv[], t_config_option { size_t equals_pos = token.find("="); if (equals_pos != std::string::npos) { - value = token.substr(equals_pos+1); + value = token.substr(equals_pos + 1); token.erase(equals_pos); } } @@ -1612,7 +1618,7 @@ bool DynamicConfig::read_cli(int argc, const char* const argv[], t_config_option auto it = opts.find(token); bool no = false; if (it == opts.end()) { - //BBS: don't use 'no-' for boolean options + // BBS: don't use 'no-' for boolean options boost::nowide::cerr << "Invalid option --" << token.c_str() << std::endl; return false; /* Remove the "no-" prefix used to negate boolean options. @@ -1630,17 +1636,17 @@ bool DynamicConfig::read_cli(int argc, const char* const argv[], t_config_option token = yes_token;*/ } - const t_config_option_key &opt_key = it->second; - const ConfigOptionDef &optdef = this->def()->options.at(opt_key); + const t_config_option_key& opt_key = it->second; + const ConfigOptionDef& optdef = this->def()->options.at(opt_key); // If the option type expects a value and it was not already provided, // look for it in the next token. if (value.empty() && optdef.type != coBool && optdef.type != coBools) { - if (i == argc-1) { + if (i == argc - 1) { boost::nowide::cerr << "Need values for option --" << token.c_str() << std::endl; return false; } - value = argv[++ i]; + value = argv[++i]; } /*if (no) { @@ -1652,17 +1658,17 @@ bool DynamicConfig::read_cli(int argc, const char* const argv[], t_config_option }*/ // Store the option value. - const bool existing = this->has(opt_key); - if (keys != nullptr && ! existing) { + const bool existing = this->has(opt_key); + if (keys != nullptr && !existing) { // Save the order of detected keys. keys->push_back(opt_key); } - ConfigOption *opt_base = this->option(opt_key, true); - ConfigOptionVectorBase *opt_vector = opt_base->is_vector() ? static_cast(opt_base) : nullptr; + ConfigOption* opt_base = this->option(opt_key, true); + ConfigOptionVectorBase* opt_vector = opt_base->is_vector() ? static_cast(opt_base) : nullptr; if (opt_vector) { - if (! existing) - // remove the default values - opt_vector->clear(); + if (!existing) + // remove the default values + opt_vector->clear(); // Vector values will be chained. Repeated use of a parameter will append the parameter or parameters // to the end of the value. if (opt_base->type() == coBools && value.empty()) @@ -1672,7 +1678,7 @@ bool DynamicConfig::read_cli(int argc, const char* const argv[], t_config_option // they get deserialized from an .ini file. For ConfigOptionStrings, that means that the C-style unescape // will be applied for values enclosed in quotes, while values non-enclosed in quotes are left to be // unescaped by the calling shell. - opt_vector->deserialize(value, true); + opt_vector->deserialize(value, true); } else if (opt_base->type() == coBool) { if (value.empty()) static_cast(opt_base)->value = !no; @@ -1685,10 +1691,10 @@ bool DynamicConfig::read_cli(int argc, const char* const argv[], t_config_option // Just bail out if the configuration value is not understood. ConfigSubstitutionContext context(ForwardCompatibilitySubstitutionRule::Disable); // Any scalar value of a type different from Bool and String. - if (! this->set_deserialize_nothrow(opt_key, value, context, false)) { - boost::nowide::cerr << "Invalid value for option --" << token.c_str() << std::endl; - return false; - } + if (!this->set_deserialize_nothrow(opt_key, value, context, false)) { + boost::nowide::cerr << "Invalid value for option --" << token.c_str() << std::endl; + return false; + } } } return true; @@ -1698,62 +1704,55 @@ t_config_option_keys DynamicConfig::keys() const { t_config_option_keys keys; keys.reserve(this->options.size()); - for (const auto &opt : this->options) + for (const auto& opt : this->options) keys.emplace_back(opt.first); return keys; } -DynamicConfig::DynamicConfigDifference DynamicConfig::diff_report(const DynamicConfig& rhs) const { +DynamicConfig::DynamicConfigDifference DynamicConfig::diff_report(const DynamicConfig& rhs) const +{ DynamicConfig::DynamicConfigDifference result; std::set all_keys; for (const auto& kvp : this->options) { - all_keys.insert(kvp.first); + all_keys.insert(kvp.first); } for (const auto& kvp : rhs.options) { - all_keys.insert(kvp.first); + all_keys.insert(kvp.first); } for (const auto& key : all_keys) { - auto left_it = this->options.find(key); - auto right_it = rhs.options.find(key); + auto left_it = this->options.find(key); + auto right_it = rhs.options.find(key); - bool left_has = (left_it != this->options.end()); - bool right_has = (right_it != rhs.options.end()); + bool left_has = (left_it != this->options.end()); + bool right_has = (right_it != rhs.options.end()); - if (left_has && right_has) { - if (*left_it->second != *right_it->second) { - result.differences[key] = { - left_it->second->serialize(), - right_it->second->serialize() - }; - } - } else if (left_has) { - result.differences[key] = { - left_it->second->serialize(), - std::nullopt - }; - } else if (right_has) { - result.differences[key] = { - std::nullopt, - right_it->second->serialize() - }; - } + if (left_has && right_has) { + if (*left_it->second != *right_it->second) { + result.differences[key] = {left_it->second->serialize(), right_it->second->serialize()}; + } + } else if (left_has) { + result.differences[key] = {left_it->second->serialize(), std::nullopt}; + } else if (right_has) { + result.differences[key] = {std::nullopt, right_it->second->serialize()}; + } } return result; } -std::ostream& operator<<(std::ostream& os, const DynamicConfig::DynamicConfigDifference& diff) { +std::ostream& operator<<(std::ostream& os, const DynamicConfig::DynamicConfigDifference& diff) +{ if (!diff.is_different()) { os << "Configurations are identical.\n"; return os; } - int missing_right=0, missing_left=0, differ=0; + int missing_right = 0, missing_left = 0, differ = 0; os << "DynamicConfig Differences Found (" << diff.differences.size() << " keys):\n"; for (const auto& kvp : diff.differences) { - const auto& key = kvp.first; + const auto& key = kvp.first; const auto& detail = kvp.second; os << " Key: **" << key << "**\n"; @@ -1762,30 +1761,31 @@ std::ostream& operator<<(std::ostream& os, const DynamicConfig::DynamicConfigDif // Determine which side is missing the key if (detail.left_value.has_value()) { os << " - **Missing in Right**: Key exists in left config. Value: " << detail.left_value.value() << "\n"; - missing_right++; + missing_right++; } else { os << " - **Missing in Left**: Key exists in right config. Value: " << detail.right_value.value() << "\n"; - missing_left++; + missing_left++; } } else if (detail.is_different_value()) { - differ++; + differ++; os << " - **Value Differs**:\n"; os << " -> Left Value: " << detail.left_value.value() << "\n"; os << " -> Right Value: " << detail.right_value.value() << "\n"; } } - os << "Summary: " << missing_right << " missing on right, " << missing_left << " missing on left, and " << differ << " have differing values\n"; + os << "Summary: " << missing_right << " missing on right, " << missing_left << " missing on left, and " << differ + << " have differing values\n"; return os; } void StaticConfig::set_defaults() { // use defaults from definition - auto *defs = this->def(); + auto* defs = this->def(); if (defs != nullptr) { - for (const std::string &key : this->keys()) { - const ConfigOptionDef *def = defs->get(key); - ConfigOption *opt = this->option(key); + for (const std::string& key : this->keys()) { + const ConfigOptionDef* def = defs->get(key); + ConfigOption* opt = this->option(key); if (def != nullptr && opt != nullptr && def->default_value) opt->set(def->default_value.get()); } @@ -1796,7 +1796,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; @@ -1804,71 +1804,70 @@ t_config_option_keys StaticConfig::keys() const // Iterate over the pairs of options with equal keys, call the fn. // Returns true on early exit by fn(). -//BBS: add skipped key logic +// BBS: add skipped key logic template -static inline bool dynamic_config_iterate(const DynamicConfig &lhs, const DynamicConfig &rhs, Fn fn, const std::set* skipped_keys = nullptr) +static inline bool dynamic_config_iterate(const DynamicConfig& lhs, + const DynamicConfig& rhs, + Fn fn, + const std::set* skipped_keys = nullptr) { std::map>::const_iterator i = lhs.cbegin(); std::map>::const_iterator j = rhs.cbegin(); while (i != lhs.cend() && j != rhs.cend()) if (i->first < j->first) - ++ i; + ++i; else if (i->first > j->first) - ++ j; + ++j; else { assert(i->first == j->first); - if (skipped_keys && (skipped_keys->count(i->first) != 0)) - { - //do nothing - } - else if (fn(i->first, i->second.get(), j->second.get())) + if (skipped_keys && (skipped_keys->count(i->first) != 0)) { + // do nothing + } else if (fn(i->first, i->second.get(), j->second.get())) // Early exit by fn. return true; - ++ i; - ++ j; + ++i; + ++j; } // Finished to the end. return false; } // Are the two configs equal? Ignoring options not present in both configs. -//BBS: add skipped keys logic -bool DynamicConfig::equals(const DynamicConfig &other, const std::set* skipped_keys) const +// BBS: add skipped keys logic +bool DynamicConfig::equals(const DynamicConfig& other, const std::set* skipped_keys) const { - return ! dynamic_config_iterate(*this, other, - [](const t_config_option_key & /* key */, const ConfigOption *l, const ConfigOption *r) { return *l != *r; }, + return !dynamic_config_iterate( + *this, other, [](const t_config_option_key& /* key */, const ConfigOption* l, const ConfigOption* r) { return *l != *r; }, skipped_keys); } // Returns options differing in the two configs, ignoring options not present in both configs. -t_config_option_keys DynamicConfig::diff(const DynamicConfig &other) const +t_config_option_keys DynamicConfig::diff(const DynamicConfig& other) const { t_config_option_keys diff; - dynamic_config_iterate(*this, other, - [&diff](const t_config_option_key &key, const ConfigOption *l, const ConfigOption *r) { - if (*l != *r) - diff.emplace_back(key); - // Continue iterating. - return false; - }); + dynamic_config_iterate(*this, other, [&diff](const t_config_option_key& key, const ConfigOption* l, const ConfigOption* r) { + if (*l != *r) + diff.emplace_back(key); + // Continue iterating. + return false; + }); return diff; } // Returns options being equal in the two configs, ignoring options not present in both configs. -t_config_option_keys DynamicConfig::equal(const DynamicConfig &other) const +t_config_option_keys DynamicConfig::equal(const DynamicConfig& other) const { t_config_option_keys equal; - dynamic_config_iterate(*this, other, - [&equal](const t_config_option_key &key, const ConfigOption *l, const ConfigOption *r) { - if (*l == *r) - equal.emplace_back(key); - // Continue iterating. - return false; - }); + dynamic_config_iterate(*this, other, [&equal](const t_config_option_key& key, const ConfigOption* l, const ConfigOption* r) { + if (*l == *r) + equal.emplace_back(key); + // Continue iterating. + return false; + }); return equal; } -} +} // namespace Slic3r #include CEREAL_REGISTER_TYPE(Slic3r::ConfigOption) diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index b94d617315..d0e9c15bdf 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -26,120 +26,129 @@ #include namespace Slic3r { - struct FloatOrPercent - { - double value; - bool percent; - private: - friend class cereal::access; - template void serialize(Archive& ar) { ar(this->value); ar(this->percent); } - }; +struct FloatOrPercent +{ + double value; + bool percent; - inline bool operator==(const FloatOrPercent& l, const FloatOrPercent& r) throw() { return l.value == r.value && l.percent == r.percent; } - inline bool operator!=(const FloatOrPercent& l, const FloatOrPercent& r) throw() { return !(l == r); } - inline bool operator< (const FloatOrPercent& l, const FloatOrPercent& r) throw() { return l.value < r.value || (l.value == r.value && int(l.percent) < int(r.percent)); } +private: + friend class cereal::access; + template void serialize(Archive& ar) + { + ar(this->value); + ar(this->percent); + } +}; + +inline bool operator==(const FloatOrPercent& l, const FloatOrPercent& r) throw() { return l.value == r.value && l.percent == r.percent; } +inline bool operator!=(const FloatOrPercent& l, const FloatOrPercent& r) throw() { return !(l == r); } +inline bool operator<(const FloatOrPercent& l, const FloatOrPercent& r) throw() +{ + return l.value < r.value || (l.value == r.value && int(l.percent) < int(r.percent)); } +} // namespace Slic3r namespace std { - template<> struct hash { - std::size_t operator()(const Slic3r::FloatOrPercent& v) const noexcept { - std::size_t seed = std::hash{}(v.value); - return v.percent ? seed ^ 0x9e3779b9 : seed; - } - }; +template<> struct hash +{ + std::size_t operator()(const Slic3r::FloatOrPercent& v) const noexcept + { + std::size_t seed = std::hash{}(v.value); + return v.percent ? seed ^ 0x9e3779b9 : seed; + } +}; - template<> struct hash { - std::size_t operator()(const Slic3r::Vec2d& v) const noexcept { - std::size_t seed = std::hash{}(v.x()); - boost::hash_combine(seed, std::hash{}(v.y())); - return seed; - } - }; +template<> struct hash +{ + std::size_t operator()(const Slic3r::Vec2d& v) const noexcept + { + std::size_t seed = std::hash{}(v.x()); + boost::hash_combine(seed, std::hash{}(v.y())); + return seed; + } +}; - template<> struct hash { - std::size_t operator()(const Slic3r::Vec3d& v) const noexcept { - std::size_t seed = std::hash{}(v.x()); - boost::hash_combine(seed, std::hash{}(v.y())); - boost::hash_combine(seed, std::hash{}(v.z())); - return seed; - } - }; -} +template<> struct hash +{ + std::size_t operator()(const Slic3r::Vec3d& v) const noexcept + { + std::size_t seed = std::hash{}(v.x()); + boost::hash_combine(seed, std::hash{}(v.y())); + boost::hash_combine(seed, std::hash{}(v.z())); + return seed; + } +}; +} // namespace std namespace Slic3r { // Name of the configuration option. -typedef std::string t_config_option_key; -typedef std::vector t_config_option_keys; +typedef std::string t_config_option_key; +typedef std::vector t_config_option_keys; -extern std::string escape_string_cstyle(const std::string &str); -extern std::string escape_strings_cstyle(const std::vector &strs); -extern bool unescape_string_cstyle(const std::string &str, std::string &out); -extern bool unescape_strings_cstyle(const std::string &str, std::vector &out); +extern std::string escape_string_cstyle(const std::string& str); +extern std::string escape_strings_cstyle(const std::vector& strs); +extern bool unescape_string_cstyle(const std::string& str, std::string& out); +extern bool unescape_strings_cstyle(const std::string& str, std::vector& out); -extern std::string escape_ampersand(const std::string& str); +extern std::string escape_ampersand(const std::string& str); namespace ConfigHelpers { - inline bool looks_like_enum_value(std::string value) - { - boost::trim(value); - if (value.empty() || value.size() > 64 || ! isalpha(value.front())) - return false; - for (const char c : value) - if (! (isalnum(c) || c == '_' || c == '-')) - return false; - return true; - } +inline bool looks_like_enum_value(std::string value) +{ + boost::trim(value); + if (value.empty() || value.size() > 64 || !isalpha(value.front())) + return false; + for (const char c : value) + if (!(isalnum(c) || c == '_' || c == '-')) + return false; + return true; +} - inline bool enum_looks_like_true_value(std::string value) { - boost::trim(value); - return boost::iequals(value, "enabled") || boost::iequals(value, "on"); - } +inline bool enum_looks_like_true_value(std::string value) +{ + boost::trim(value); + return boost::iequals(value, "enabled") || boost::iequals(value, "on"); +} - enum class DeserializationSubstitution { - Disabled, - DefaultsToFalse, - DefaultsToTrue - }; +enum class DeserializationSubstitution { Disabled, DefaultsToFalse, DefaultsToTrue }; - enum class DeserializationResult { - Loaded, - Substituted, - Failed, - }; +enum class DeserializationResult { + Loaded, + Substituted, + Failed, }; +}; // namespace ConfigHelpers // Base for all exceptions thrown by the configuration layer. -class ConfigurationError : public Slic3r::RuntimeError { +class ConfigurationError : public Slic3r::RuntimeError +{ public: using RuntimeError::RuntimeError; }; // Specialization of std::exception to indicate that an unknown config option has been encountered. -class UnknownOptionException : public ConfigurationError { +class UnknownOptionException : public ConfigurationError +{ public: - UnknownOptionException() : - ConfigurationError("Unknown option exception") {} - UnknownOptionException(const std::string &opt_key) : - ConfigurationError(std::string("Unknown option exception: ") + opt_key) {} + UnknownOptionException() : ConfigurationError("Unknown option exception") {} + UnknownOptionException(const std::string& opt_key) : ConfigurationError(std::string("Unknown option exception: ") + opt_key) {} }; // Indicate that the ConfigBase derived class does not provide config definition (the method def() returns null). class NoDefinitionException : public ConfigurationError { public: - NoDefinitionException() : - ConfigurationError("No definition exception") {} - NoDefinitionException(const std::string &opt_key) : - ConfigurationError(std::string("No definition exception: ") + opt_key) {} + NoDefinitionException() : ConfigurationError("No definition exception") {} + NoDefinitionException(const std::string& opt_key) : ConfigurationError(std::string("No definition exception: ") + opt_key) {} }; // Indicate that an unsupported accessor was called on a config option. class BadOptionTypeException : public ConfigurationError { public: - BadOptionTypeException() : ConfigurationError("Bad option type exception") {} - BadOptionTypeException(const std::string &message) : ConfigurationError(message) {} + BadOptionTypeException() : ConfigurationError("Bad option type exception") {} + BadOptionTypeException(const std::string& message) : ConfigurationError(message) {} BadOptionTypeException(const char* message) : ConfigurationError(message) {} }; @@ -148,50 +157,50 @@ class BadOptionValueException : public ConfigurationError { public: BadOptionValueException() : ConfigurationError("Bad option value exception") {} - BadOptionValueException(const std::string &message) : ConfigurationError(message) {} + BadOptionValueException(const std::string& message) : ConfigurationError(message) {} BadOptionValueException(const char* message) : ConfigurationError(message) {} }; // Type of a configuration value. enum ConfigOptionType { - coVectorType = 0x4000, - coNone = 0, + coVectorType = 0x4000, + coNone = 0, // single float - coFloat = 1, + coFloat = 1, // vector of floats - coFloats = coFloat + coVectorType, + coFloats = coFloat + coVectorType, // single int - coInt = 2, + coInt = 2, // vector of ints - coInts = coInt + coVectorType, + coInts = coInt + coVectorType, // single string - coString = 3, + coString = 3, // vector of strings - coStrings = coString + coVectorType, + coStrings = coString + coVectorType, // percent value. Currently only used for infill. - coPercent = 4, + coPercent = 4, // percents value. Currently used for retract before wipe only. - coPercents = coPercent + coVectorType, + coPercents = coPercent + coVectorType, // a fraction or an absolute value coFloatOrPercent = 5, // vector of the above coFloatsOrPercents = coFloatOrPercent + coVectorType, // single 2d point (Point2f). Currently not used. - coPoint = 6, + coPoint = 6, // vector of 2d points (Point2f). Currently used for the definition of the print bed and for the extruder offsets. - coPoints = coPoint + coVectorType, - coPoint3 = 7, -// coPoint3s = coPoint3 + coVectorType, + coPoints = coPoint + coVectorType, + coPoint3 = 7, + // coPoint3s = coPoint3 + coVectorType, // single boolean value - coBool = 8, + coBool = 8, // vector of boolean values - coBools = coBool + coVectorType, + coBools = coBool + coVectorType, // a generic enum - coEnum = 9, + coEnum = 9, // BBS: vector of enums - coEnums = coEnum + coVectorType, - coPointsGroups = 10 + coVectorType, - coIntsGroups = 11 + coVectorType + coEnums = coEnum + coVectorType, + coPointsGroups = 10 + coVectorType, + coIntsGroups = 11 + coVectorType }; enum ConfigOptionMode { @@ -200,8 +209,7 @@ enum ConfigOptionMode { comDevelop, }; -enum PrinterTechnology : unsigned char -{ +enum PrinterTechnology : unsigned char { // Fused Filament Fabrication ptFFF, // Stereolitography @@ -212,8 +220,7 @@ enum PrinterTechnology : unsigned char ptAny }; -enum ForwardCompatibilitySubstitutionRule -{ +enum ForwardCompatibilitySubstitutionRule { // Disable susbtitution, throw exception if an option value is not recognized. Disable, // Enable substitution of an unknown option value with default. Log the substitution. @@ -222,26 +229,31 @@ enum ForwardCompatibilitySubstitutionRule EnableSilent, // Enable substitution of an unknown option value with default. Log substitutions in user profiles, don't log substitutions in system profiles. EnableSystemSilent, - // Enable silent substitution of an unknown option value with default when loading user profiles. Throw on an unknown option value in a system profile. + // Enable silent substitution of an unknown option value with default when loading user profiles. Throw on an unknown option value in a + // system profile. EnableSilentDisableSystem, }; -class ConfigOption; -class ConfigOptionDef; +class ConfigOption; +class ConfigOptionDef; // For forward definition of ConfigOption in ConfigOptionUniquePtr, we have to define a custom deleter. -struct ConfigOptionDeleter { void operator()(ConfigOption* p); }; -using ConfigOptionUniquePtr = std::unique_ptr; +struct ConfigOptionDeleter +{ + void operator()(ConfigOption* p); +}; +using ConfigOptionUniquePtr = std::unique_ptr; // When parsing a configuration value, if the old_value is not understood by this OrcaSlicer version, // it is being substituted with some default value that this OrcaSlicer could work with. // This structure serves to inform the user about the substitutions having been done during file import. -struct ConfigSubstitution { - const ConfigOptionDef *opt_def { nullptr }; - std::string old_value; - ConfigOptionUniquePtr new_value; +struct ConfigSubstitution +{ + const ConfigOptionDef* opt_def{nullptr}; + std::string old_value; + ConfigOptionUniquePtr new_value; }; -using ConfigSubstitutions = std::vector; +using ConfigSubstitutions = std::vector; // Filled in by ConfigBase::set_deserialize_raw(), which based on "rule" either bails out // or performs substitutions when encountering an unknown configuration value. @@ -250,47 +262,50 @@ struct ConfigSubstitutionContext ConfigSubstitutionContext(ForwardCompatibilitySubstitutionRule rl) : rule(rl) {} bool empty() const throw() { return substitutions.empty(); } - ForwardCompatibilitySubstitutionRule rule; - ConfigSubstitutions substitutions; - std::vector unrecogized_keys; + ForwardCompatibilitySubstitutionRule rule; + ConfigSubstitutions substitutions; + std::vector unrecogized_keys; }; // A generic value of a configuration option. -class ConfigOption { +class ConfigOption +{ public: virtual ~ConfigOption() {} - virtual ConfigOptionType type() const = 0; - virtual std::string serialize() const = 0; - virtual bool deserialize(const std::string &str, bool append = false) = 0; - virtual ConfigOption* clone() const = 0; + virtual ConfigOptionType type() const = 0; + virtual std::string serialize() const = 0; + virtual bool deserialize(const std::string& str, bool append = false) = 0; + virtual ConfigOption* clone() const = 0; // Set a value from a ConfigOption. The two options should be compatible. - virtual void set(const ConfigOption *option) = 0; - virtual int getInt() const { throw BadOptionTypeException("Calling ConfigOption::getInt on a non-int ConfigOption"); } - virtual double getFloat() const { throw BadOptionTypeException("Calling ConfigOption::getFloat on a non-float ConfigOption"); } - virtual bool getBool() const { throw BadOptionTypeException("Calling ConfigOption::getBool on a non-boolean ConfigOption"); } - virtual void setInt(int /* val */) { throw BadOptionTypeException("Calling ConfigOption::setInt on a non-int ConfigOption"); } - virtual bool operator==(const ConfigOption &rhs) const = 0; - bool operator!=(const ConfigOption &rhs) const { return ! (*this == rhs); } - virtual size_t hash() const throw() = 0; - bool is_scalar() const { return (int(this->type()) & int(coVectorType)) == 0; } - bool is_vector() const { return ! this->is_scalar(); } + virtual void set(const ConfigOption* option) = 0; + virtual int getInt() const { throw BadOptionTypeException("Calling ConfigOption::getInt on a non-int ConfigOption"); } + virtual double getFloat() const { throw BadOptionTypeException("Calling ConfigOption::getFloat on a non-float ConfigOption"); } + virtual bool getBool() const { throw BadOptionTypeException("Calling ConfigOption::getBool on a non-boolean ConfigOption"); } + virtual void setInt(int /* val */) { throw BadOptionTypeException("Calling ConfigOption::setInt on a non-int ConfigOption"); } + virtual bool operator==(const ConfigOption& rhs) const = 0; + bool operator!=(const ConfigOption& rhs) const { return !(*this == rhs); } + virtual size_t hash() const throw() = 0; + bool is_scalar() const { return (int(this->type()) & int(coVectorType)) == 0; } + bool is_vector() const { return !this->is_scalar(); } // If this option is nullable, then it may have its value or values set to nil. - virtual bool nullable() const { return false; } + virtual bool nullable() const { return false; } // A scalar is nil, or all values of a vector are nil. - virtual bool is_nil() const { return false; } + virtual bool is_nil() const { return false; } // Is this option overridden by another option? // An option overrides another option if it is not nil and not equal. - virtual bool overriden_by(const ConfigOption *rhs) const { - assert(! this->nullable() && ! rhs->nullable()); - return *this != *rhs; + virtual bool overriden_by(const ConfigOption* rhs) const + { + assert(!this->nullable() && !rhs->nullable()); + return *this != *rhs; } // Apply an override option, possibly a nullable one. - virtual bool apply_override(const ConfigOption *rhs, std::vector& default_index) { - if (*this == *rhs) - return false; - *this = *rhs; - return true; + virtual bool apply_override(const ConfigOption* rhs, std::vector& default_index) + { + if (*this == *rhs) + return false; + *this = *rhs; + return true; } }; @@ -298,14 +313,14 @@ typedef ConfigOption* ConfigOptionPtr; typedef const ConfigOption* ConfigOptionConstPtr; // Value of a single valued option (bool, int, float, string, point, enum) -template -class ConfigOptionSingle : public ConfigOption { +template class ConfigOptionSingle : public ConfigOption +{ public: T value; explicit ConfigOptionSingle(T value) : value(std::move(value)) {} operator T() const { return this->value; } - void set(const ConfigOption *rhs) override + void set(const ConfigOption* rhs) override { if (rhs->type() != this->type()) throw ConfigurationError("ConfigOptionSingle: Assigning an incompatible type"); @@ -313,7 +328,7 @@ public: this->value = static_cast*>(rhs)->value; } - bool operator==(const ConfigOption &rhs) const override + bool operator==(const ConfigOption& rhs) const override { if (rhs.type() != this->type()) throw ConfigurationError("ConfigOptionSingle: Comparing incompatible types"); @@ -321,19 +336,20 @@ public: return this->value == static_cast*>(&rhs)->value; } - bool operator==(const T &rhs) const throw() { return this->value == rhs; } - bool operator!=(const T &rhs) const throw() { return this->value != rhs; } - bool operator< (const T &rhs) const throw() { return this->value < rhs; } + bool operator==(const T& rhs) const throw() { return this->value == rhs; } + bool operator!=(const T& rhs) const throw() { return this->value != rhs; } + bool operator<(const T& rhs) const throw() { return this->value < rhs; } size_t hash() const throw() override { return std::hash{}(this->value); } private: - friend class cereal::access; - template void serialize(Archive & ar) { ar(this->value); } + friend class cereal::access; + template void serialize(Archive& ar) { ar(this->value); } }; // Value of a vector valued option (bools, ints, floats, strings, points) -class ConfigOptionVectorBase : public ConfigOption { +class ConfigOptionVectorBase : public ConfigOption +{ public: // Currently used only to initialize the PlaceholderParser. virtual std::vector vserialize() const = 0; @@ -341,54 +357,52 @@ public: // If the rhs ConfigOption is scalar, then its value is used, // otherwise for each of rhs, the first value of a vector is used. // This function is useful to collect values for multiple extrder / filament settings. - virtual void set(const std::vector &rhs) = 0; + virtual void set(const std::vector& rhs) = 0; // Set a single vector item from either a scalar option or the first value of a vector option.vector of ConfigOptions. // This function is useful to split values from multiple extrder / filament settings into separate configurations. - virtual void set_at(const ConfigOption *rhs, size_t i, size_t j) = 0; - //BBS - virtual void set_at_to_nil(size_t i) = 0; - virtual void append(const ConfigOption *rhs) = 0; - virtual void set(const ConfigOption* rhs, size_t start, size_t len) = 0; - virtual void set_with_restore(const ConfigOptionVectorBase* rhs, std::vector& restore_index, int stride) = 0; + virtual void set_at(const ConfigOption* rhs, size_t i, size_t j) = 0; + // BBS + virtual void set_at_to_nil(size_t i) = 0; + virtual void append(const ConfigOption* rhs) = 0; + virtual void set(const ConfigOption* rhs, size_t start, size_t len) = 0; + virtual void set_with_restore(const ConfigOptionVectorBase* rhs, std::vector& restore_index, int stride) = 0; virtual void set_with_restore_2(const ConfigOptionVectorBase* rhs, std::vector& restore_index, int start, int len) = 0; - virtual void set_only_diff(const ConfigOptionVectorBase* rhs, std::vector& diff_index, int stride) = 0; - virtual void set_with_nil(const ConfigOptionVectorBase* rhs, const ConfigOptionVectorBase* inherits, int stride) = 0; + virtual void set_only_diff(const ConfigOptionVectorBase* rhs, std::vector& diff_index, int stride) = 0; + virtual void set_with_nil(const ConfigOptionVectorBase* rhs, const ConfigOptionVectorBase* inherits, int stride) = 0; // Resize the vector of values, copy the newly added values from opt_default if provided. - virtual void resize(size_t n, const ConfigOption *opt_default = nullptr) = 0; + virtual void resize(size_t n, const ConfigOption* opt_default = nullptr) = 0; // Clear the values vector. virtual void clear() = 0; // Get size of this vector. - virtual size_t size() const = 0; + virtual size_t size() const = 0; // Is this vector empty? - virtual bool empty() const = 0; + virtual bool empty() const = 0; // Is the value nil? That should only be possible if this->nullable(). - virtual bool is_nil(size_t idx) const = 0; + virtual bool is_nil(size_t idx) const = 0; // We just overloaded and hid two base class virtual methods. // Let's show it was intentional (warnings). using ConfigOption::set; using ConfigOption::is_nil; - protected: // Used to verify type compatibility when assigning to / from a scalar ConfigOption. ConfigOptionType scalar_type() const { return static_cast(this->type() - coVectorType); } }; // Value of a vector valued option (bools, ints, floats, strings, points), template -template -class ConfigOptionVector : public ConfigOptionVectorBase +template class ConfigOptionVector : public ConfigOptionVectorBase { public: ConfigOptionVector() {} - explicit ConfigOptionVector(size_t n, const T &value) : values(n, value) {} + explicit ConfigOptionVector(size_t n, const T& value) : values(n, value) {} explicit ConfigOptionVector(std::initializer_list il) : values(std::move(il)) {} - explicit ConfigOptionVector(const std::vector &values) : values(values) {} - explicit ConfigOptionVector(std::vector &&values) : values(std::move(values)) {} + explicit ConfigOptionVector(const std::vector& values) : values(values) {} + explicit ConfigOptionVector(std::vector&& values) : values(std::move(values)) {} std::vector values; - void set(const ConfigOption *rhs) override + void set(const ConfigOption* rhs) override { if (rhs->type() != this->type()) throw ConfigurationError("ConfigOptionVector: Assigning an incompatible type"); @@ -400,11 +414,11 @@ public: // If the rhs ConfigOption is scalar, then its value is used, // otherwise for each of rhs, the first value of a vector is used. // This function is useful to collect values for multiple extrder / filament settings. - void set(const std::vector &rhs) override + void set(const std::vector& rhs) override { this->values.clear(); this->values.reserve(rhs.size()); - for (const ConfigOption *opt : rhs) { + for (const ConfigOption* opt : rhs) { if (opt->type() == this->type()) { auto other = static_cast*>(opt); if (other->values.empty()) @@ -419,10 +433,10 @@ public: // Set a single vector item from either a scalar option or the first value of a vector option.vector of ConfigOptions. // This function is useful to split values from multiple extrder / filament settings into separate configurations. - void set_at(const ConfigOption *rhs, size_t i, size_t j) override + void set_at(const ConfigOption* rhs, size_t i, size_t j) override { // It is expected that the vector value has at least one value, which is the default, if not overwritten. - assert(! this->values.empty()); + assert(!this->values.empty()); if (this->values.size() <= i) { // Resize this vector, fill in the new vector fields with the copy of the first field. T v = this->values.front(); @@ -440,10 +454,10 @@ public: throw ConfigurationError("ConfigOptionVector::set_at(): Assigning an incompatible type"); } - //BBS + // BBS virtual void set_at_to_nil(size_t i) override {} - void append(const ConfigOption *rhs) override + void append(const ConfigOption* rhs) override { if (rhs->type() == this->type()) { // Assign the first value of the rhs vector. @@ -468,60 +482,58 @@ public: if (rhs->type() == this->type()) { // Assign the first value of the rhs vector. auto other = static_cast*>(rhs); - if (other->values.size() < (start+len)) + if (other->values.size() < (start + len)) throw ConfigurationError("ConfigOptionVector::set_with(): Assigning from an vector with invalid size"); for (size_t i = 0; i < len; i++) - this->values[i] = other->get_at(start+i); - } - else + this->values[i] = other->get_at(start + i); + } else throw ConfigurationError("ConfigOptionVector::set_with(): Assigning an incompatible type"); } - //set a item related with extruder variants when loading config from 3mf, restore the non change values to system config - //rhs: item from systemconfig(inherits) - //keep_index: which index in this vector need to be restored + // set a item related with extruder variants when loading config from 3mf, restore the non change values to system config + // rhs: item from systemconfig(inherits) + // keep_index: which index in this vector need to be restored virtual void set_with_restore(const ConfigOptionVectorBase* rhs, std::vector& restore_index, int stride) override { if (rhs->type() == this->type()) { - //backup original ones + // backup original ones std::vector backup_values = this->values; // Assign the first value of the rhs vector. - auto other = static_cast*>(rhs); + auto other = static_cast*>(rhs); this->values = other->values; - if (other->values.size() != (restore_index.size()*stride)) - throw ConfigurationError("ConfigOptionVector::set_with_restore(): Assigning from an vector with invalid restore_index size"); + if (other->values.size() != (restore_index.size() * stride)) + throw ConfigurationError( + "ConfigOptionVector::set_with_restore(): Assigning from an vector with invalid restore_index size"); for (size_t i = 0; i < restore_index.size(); i++) { if (restore_index[i] != -1) { for (size_t j = 0; j < stride; j++) - this->values[i * stride +j] = backup_values[restore_index[i] * stride +j]; + this->values[i * stride + j] = backup_values[restore_index[i] * stride + j]; } } - } - else + } else throw ConfigurationError("ConfigOptionVector::set_with_restore(): Assigning an incompatible type"); } - //set a item related with extruder variants when loading config from filament json, replace the original filament items - //rhs: item from seperate filament config - //restore_index: which index in this vector need to be restored - //start: which index in this vector need to be replaced - //count: how many items in this vector need to be replaced + // set a item related with extruder variants when loading config from filament json, replace the original filament items + // rhs: item from seperate filament config + // restore_index: which index in this vector need to be restored + // start: which index in this vector need to be replaced + // count: how many items in this vector need to be replaced virtual void set_with_restore_2(const ConfigOptionVectorBase* rhs, std::vector& restore_index, int start, int len) override { if (rhs->type() == this->type()) { - //backup original ones + // backup original ones std::vector backup_values = this->values; if (this->values.size() < start) { throw ConfigurationError("ConfigOptionVector::set_with_restore_2(): invalid size found"); - } - else { + } else { if (this->values.size() < start + len) len = this->values.size() - start; - //erase the original ones + // erase the original ones if (len > 0) this->values.erase(this->values.begin() + start, this->values.begin() + start + len); } @@ -530,54 +542,51 @@ public: auto other = static_cast*>(rhs); if (other->values.size() != (restore_index.size())) - throw ConfigurationError("ConfigOptionVector::set_with_restore_2(): Assigning from an vector with invalid restore_index size"); + throw ConfigurationError( + "ConfigOptionVector::set_with_restore_2(): Assigning from an vector with invalid restore_index size"); for (size_t i = 0; i < restore_index.size(); i++) { - if ((restore_index[i] != -1)&&(restore_index[i] < backup_values.size())) { + if ((restore_index[i] != -1) && (restore_index[i] < backup_values.size())) { this->values.insert(this->values.begin() + start + i, backup_values[restore_index[i]]); - } - else + } else this->values.insert(this->values.begin() + start + i, other->values[i]); } - } - else + } else throw ConfigurationError("ConfigOptionVector::set_with_restore_2(): Assigning an incompatible type"); } - //set a item related with extruder variants when loading user config, only set the different value of some extruder - //rhs: item from user config - //diff_index: which index in this vector need to be set + // set a item related with extruder variants when loading user config, only set the different value of some extruder + // rhs: item from user config + // diff_index: which index in this vector need to be set virtual void set_only_diff(const ConfigOptionVectorBase* rhs, std::vector& diff_index, int stride) override { if (rhs->type() == this->type()) { // Assign the first value of the rhs vector. auto other = static_cast*>(rhs); - if (this->values.size() != (diff_index.size()*stride)) + if (this->values.size() != (diff_index.size() * stride)) throw ConfigurationError("ConfigOptionVector::set_only_diff(): Assigning from an vector with invalid diff_index size"); for (size_t i = 0; i < diff_index.size(); i++) { if (diff_index[i] != -1) { - for (size_t j = 0; j < stride; j++) - { + for (size_t j = 0; j < stride; j++) { if (!other->is_nil(diff_index[i])) - this->values[i * stride +j] = other->values[diff_index[i] * stride +j]; + this->values[i * stride + j] = other->values[diff_index[i] * stride + j]; } } } - } - else + } else throw ConfigurationError("ConfigOptionVector::set_only_diff(): Assigning an incompatible type"); } - //set a item related with extruder variants when saving user config, set the non-diff value of some extruder to nill - //this item has different value with inherit config - //rhs: item from userconfig - //inherits: item from inherit config + // set a item related with extruder variants when saving user config, set the non-diff value of some extruder to nill + // this item has different value with inherit config + // rhs: item from userconfig + // inherits: item from inherit config virtual void set_with_nil(const ConfigOptionVectorBase* rhs, const ConfigOptionVectorBase* inherits, int stride) override { if ((rhs->type() == this->type()) && (inherits->type() == this->type())) { - auto rhs_opt = static_cast*>(rhs); + auto rhs_opt = static_cast*>(rhs); auto inherits_opt = static_cast*>(inherits); if (inherits->size() != rhs->size()) @@ -585,10 +594,10 @@ public: this->values.resize(inherits->size(), this->values.front()); - for (size_t i = 0; i < inherits_opt->size(); i= i+stride) { + for (size_t i = 0; i < inherits_opt->size(); i = i + stride) { bool set_nil = true; for (size_t j = 0; j < stride; j++) { - if (inherits_opt->values[i +j] != rhs_opt->values[i +j]) { + if (inherits_opt->values[i + j] != rhs_opt->values[i + j]) { set_nil = false; break; } @@ -596,20 +605,18 @@ public: for (size_t j = 0; j < stride; j++) { if (set_nil) { - this->set_at_to_nil(i +j); - } - else - this->values[i +j] = rhs_opt->values[i +j]; + this->set_at_to_nil(i + j); + } else + this->values[i + j] = rhs_opt->values[i + j]; } } - } - else + } else throw ConfigurationError("ConfigOptionVector::set_with_nil(): Assigning an incompatible type"); } const T& get_at(size_t i) const { - assert(! this->values.empty()); + assert(!this->values.empty()); return (i < this->values.size()) ? this->values[i] : this->values.front(); } @@ -618,11 +625,11 @@ public: // Resize this vector by duplicating the /*last*/first value. // If the current vector is empty, the default value is used instead. // BBS: support scaler opt_default - void resize(size_t n, const ConfigOption *opt_default = nullptr) override + void resize(size_t n, const ConfigOption* opt_default = nullptr) override { - //assert(opt_default == nullptr || opt_default->is_vector()); -// assert(opt_default == nullptr || dynamic_cast>(opt_default)); - assert(! this->values.empty() || opt_default != nullptr); + // assert(opt_default == nullptr || opt_default->is_vector()); + // assert(opt_default == nullptr || dynamic_cast>(opt_default)); + assert(!this->values.empty() || opt_default != nullptr); if (n == 0) this->values.clear(); @@ -632,30 +639,28 @@ public: if (this->values.empty()) { if (opt_default == nullptr) { throw ConfigurationError("ConfigOptionVector::resize(): No default value provided."); - } - else if (opt_default->is_vector()) { + } else if (opt_default->is_vector()) { if (opt_default->type() != this->type()) throw ConfigurationError("ConfigOptionVector::resize(): Extending with an incompatible type."); this->values.resize(n, static_cast*>(opt_default)->values.front()); - } - else { + } else { if (opt_default->type() != this->scalar_type()) throw ConfigurationError("ConfigOptionVector::resize(): Extending with an incompatible type."); this->values.resize(n, static_cast*>(opt_default)->value); } } else { // Resize by duplicating the last value. - this->values.resize(n, this->values./*back*/front()); + this->values.resize(n, this->values./*back*/ front()); } } } // Clear the values vector. void clear() override { this->values.clear(); } - size_t size() const override { return this->values.size(); } + size_t size() const override { return this->values.size(); } bool empty() const override { return this->values.empty(); } - bool operator==(const ConfigOption &rhs) const override + bool operator==(const ConfigOption& rhs) const override { if (rhs.type() != this->type()) throw ConfigurationError("ConfigOptionVector: Comparing incompatible types"); @@ -663,55 +668,58 @@ public: return this->values == static_cast*>(&rhs)->values; } - bool operator==(const std::vector &rhs) const throw() { return this->values == rhs; } - bool operator!=(const std::vector &rhs) const throw() { return this->values != rhs; } + bool operator==(const std::vector& rhs) const throw() { return this->values == rhs; } + bool operator!=(const std::vector& rhs) const throw() { return this->values != rhs; } - size_t hash() const throw() override { + size_t hash() const throw() override + { std::hash hasher; - size_t seed = 0; - for (const auto &v : this->values) + size_t seed = 0; + for (const auto& v : this->values) boost::hash_combine(seed, hasher(v)); return seed; } // Is this option overridden by another option? // An option overrides another option if it is not nil and not equal. - bool overriden_by(const ConfigOption *rhs) const override { + bool overriden_by(const ConfigOption* rhs) const override + { if (this->nullable()) - throw ConfigurationError("Cannot override a nullable ConfigOption."); + throw ConfigurationError("Cannot override a nullable ConfigOption."); if (rhs->type() != this->type()) throw ConfigurationError("ConfigOptionVector.overriden_by() applied to different types."); - auto rhs_vec = static_cast*>(rhs); - if (! rhs->nullable()) - // Overridding a non-nullable object with another non-nullable object. - return this->values != rhs_vec->values; - size_t i = 0; - size_t cnt = std::min(this->size(), rhs_vec->size()); - for (; i < cnt; ++ i) - if (! rhs_vec->is_nil(i) && this->values[i] != rhs_vec->values[i]) - return true; - for (; i < rhs_vec->size(); ++ i) - if (! rhs_vec->is_nil(i)) - return true; - return false; + auto rhs_vec = static_cast*>(rhs); + if (!rhs->nullable()) + // Overridding a non-nullable object with another non-nullable object. + return this->values != rhs_vec->values; + size_t i = 0; + size_t cnt = std::min(this->size(), rhs_vec->size()); + for (; i < cnt; ++i) + if (!rhs_vec->is_nil(i) && this->values[i] != rhs_vec->values[i]) + return true; + for (; i < rhs_vec->size(); ++i) + if (!rhs_vec->is_nil(i)) + return true; + return false; } // Apply an override option, possibly a nullable one. - bool apply_override(const ConfigOption *rhs, std::vector& default_index) override { + bool apply_override(const ConfigOption* rhs, std::vector& default_index) override + { if (this->nullable()) - throw ConfigurationError("Cannot override a nullable ConfigOption."); + throw ConfigurationError("Cannot override a nullable ConfigOption."); if (rhs->type() != this->type()) - throw ConfigurationError("ConfigOptionVector.apply_override() applied to different types."); - auto rhs_vec = static_cast*>(rhs); - if (! rhs->nullable()) { - // Overridding a non-nullable object with another non-nullable object. - if (this->values != rhs_vec->values) { - this->values = rhs_vec->values; - return true; - } - return false; - } + throw ConfigurationError("ConfigOptionVector.apply_override() applied to different types."); + auto rhs_vec = static_cast*>(rhs); + if (!rhs->nullable()) { + // Overridding a non-nullable object with another non-nullable object. + if (this->values != rhs_vec->values) { + this->values = rhs_vec->values; + return true; + } + return false; + } - size_t cnt = std::min(this->size(), rhs_vec->size()); + size_t cnt = std::min(this->size(), rhs_vec->size()); if (cnt < 1) return false; @@ -741,8 +749,8 @@ public: } private: - friend class cereal::access; - template void serialize(Archive & ar) { ar(this->values); } + friend class cereal::access; + template void serialize(Archive& ar) { ar(this->values); } }; class ConfigOptionFloat : public ConfigOptionSingle @@ -752,11 +760,11 @@ public: explicit ConfigOptionFloat(double _value) : ConfigOptionSingle(_value) {} static ConfigOptionType static_type() { return coFloat; } - ConfigOptionType type() const override { return static_type(); } - double getFloat() const override { return this->value; } - ConfigOption* clone() const override { return new ConfigOptionFloat(*this); } - bool operator==(const ConfigOptionFloat &rhs) const throw() { return this->value == rhs.value; } - bool operator< (const ConfigOptionFloat &rhs) const throw() { return this->value < rhs.value; } + ConfigOptionType type() const override { return static_type(); } + double getFloat() const override { return this->value; } + ConfigOption* clone() const override { return new ConfigOptionFloat(*this); } + bool operator==(const ConfigOptionFloat& rhs) const throw() { return this->value == rhs.value; } + bool operator<(const ConfigOptionFloat& rhs) const throw() { return this->value < rhs.value; } std::string serialize() const override { @@ -765,7 +773,7 @@ public: return ss.str(); } - bool deserialize(const std::string &str, bool append = false) override + bool deserialize(const std::string& str, bool append = false) override { UNUSED(append); std::istringstream iss(str); @@ -773,45 +781,51 @@ public: return !iss.fail(); } - ConfigOptionFloat& operator=(const ConfigOption *opt) + ConfigOptionFloat& operator=(const ConfigOption* opt) { this->set(opt); return *this; } private: - friend class cereal::access; - template void serialize(Archive &ar) { ar(cereal::base_class>(this)); } + friend class cereal::access; + template void serialize(Archive& ar) { ar(cereal::base_class>(this)); } }; -template -class ConfigOptionFloatsTempl : public ConfigOptionVector +template class ConfigOptionFloatsTempl : public ConfigOptionVector { public: ConfigOptionFloatsTempl() : ConfigOptionVector() {} explicit ConfigOptionFloatsTempl(size_t n, double value) : ConfigOptionVector(n, value) {} explicit ConfigOptionFloatsTempl(std::initializer_list il) : ConfigOptionVector(std::move(il)) {} - explicit ConfigOptionFloatsTempl(const std::vector &vec) : ConfigOptionVector(vec) {} - explicit ConfigOptionFloatsTempl(std::vector &&vec) : ConfigOptionVector(std::move(vec)) {} + explicit ConfigOptionFloatsTempl(const std::vector& vec) : ConfigOptionVector(vec) {} + explicit ConfigOptionFloatsTempl(std::vector&& vec) : ConfigOptionVector(std::move(vec)) {} static ConfigOptionType static_type() { return coFloats; } - ConfigOptionType type() const override { return static_type(); } + ConfigOptionType type() const override { return static_type(); } ConfigOption* clone() const override { return new ConfigOptionFloatsTempl(*this); } - bool operator==(const ConfigOptionFloatsTempl &rhs) const throw() { return vectors_equal(this->values, rhs.values); } - bool operator< (const ConfigOptionFloatsTempl &rhs) const throw() { return vectors_lower(this->values, rhs.values); } - bool operator==(const ConfigOption &rhs) const override { + bool operator==(const ConfigOptionFloatsTempl& rhs) const throw() { return vectors_equal(this->values, rhs.values); } + bool operator<(const ConfigOptionFloatsTempl& rhs) const throw() { return vectors_lower(this->values, rhs.values); } + bool operator==(const ConfigOption& rhs) const override + { if (rhs.type() != this->type()) throw ConfigurationError("ConfigOptionFloatsTempl: Comparing incompatible types"); assert(dynamic_cast*>(&rhs)); return vectors_equal(this->values, static_cast*>(&rhs)->values); } // Could a special "nil" value be stored inside the vector, indicating undefined value? - bool nullable() const override { return NULLABLE; } + bool nullable() const override { return NULLABLE; } // Special "nil" value to be stored into the vector if this->supports_nil(). - static double nil_value() { return std::numeric_limits::quiet_NaN(); } + static double nil_value() { return std::numeric_limits::quiet_NaN(); } // A scalar is nil, or all values of a vector are nil. - bool is_nil() const override { for (auto v : this->values) if (! std::isnan(v)) return false; return true; } - bool is_nil(size_t idx) const override { return std::isnan(this->values[idx]); } + bool is_nil() const override + { + for (auto v : this->values) + if (!std::isnan(v)) + return false; + return true; + } + bool is_nil(size_t idx) const override { return std::isnan(this->values[idx]); } virtual void set_at_to_nil(size_t i) override { assert(nullable() && (i < this->values.size())); @@ -821,9 +835,9 @@ public: std::string serialize() const override { std::ostringstream ss; - for (const double &v : this->values) { + for (const double& v : this->values) { if (&v != &this->values.front()) - ss << ","; + ss << ","; serialize_single_value(ss, v); } return ss.str(); @@ -835,15 +849,15 @@ public: vv.reserve(this->values.size()); for (const double v : this->values) { std::ostringstream ss; - serialize_single_value(ss, v); + serialize_single_value(ss, v); vv.push_back(ss.str()); } return vv; } - bool deserialize(const std::string &str, bool append = false) override + bool deserialize(const std::string& str, bool append = false) override { - if (! append) + if (!append) this->values.clear(); if (str.empty()) { @@ -851,64 +865,65 @@ public: return true; } std::istringstream is(str); - std::string item_str; + std::string item_str; while (std::getline(is, item_str, ',')) { - boost::trim(item_str); - if (item_str == "nil") { - if (NULLABLE) - this->values.push_back(nil_value()); - else - throw ConfigurationError("Deserializing nil into a non-nullable object"); - } else { - std::istringstream iss(item_str); - double value; - iss >> value; - this->values.push_back(value); - } + boost::trim(item_str); + if (item_str == "nil") { + if (NULLABLE) + this->values.push_back(nil_value()); + else + throw ConfigurationError("Deserializing nil into a non-nullable object"); + } else { + std::istringstream iss(item_str); + double value; + iss >> value; + this->values.push_back(value); + } } return true; } - static bool validate_string(const std::string &str) + static bool validate_string(const std::string& str) { // should only have number and commas - return std::all_of(str.begin(), str.end(), [](char c) { - return std::isdigit(c) || c == ','|| std::isspace(c); - }); + return std::all_of(str.begin(), str.end(), [](char c) { return std::isdigit(c) || c == ',' || std::isspace(c); }); } - ConfigOptionFloatsTempl& operator=(const ConfigOption *opt) + ConfigOptionFloatsTempl& operator=(const ConfigOption* opt) { this->set(opt); return *this; } protected: - void serialize_single_value(std::ostringstream &ss, const double v) const { - if (std::isfinite(v)) - ss << v; - else if (std::isnan(v)) { - if (NULLABLE) - ss << "nil"; - else - throw ConfigurationError("Serializing NaN"); - } else - throw ConfigurationError("Serializing invalid number"); - } - static bool vectors_equal(const std::vector &v1, const std::vector &v2) { - if (NULLABLE) { - if (v1.size() != v2.size()) - return false; - for (auto it1 = v1.begin(), it2 = v2.begin(); it1 != v1.end(); ++ it1, ++ it2) - if (! ((std::isnan(*it1) && std::isnan(*it2)) || *it1 == *it2)) - return false; - return true; - } else - // Not supporting nullable values, the default vector compare is cheaper. - return v1 == v2; + void serialize_single_value(std::ostringstream& ss, const double v) const + { + if (std::isfinite(v)) + ss << v; + else if (std::isnan(v)) { + if (NULLABLE) + ss << "nil"; + else + throw ConfigurationError("Serializing NaN"); + } else + throw ConfigurationError("Serializing invalid number"); } - static bool vectors_lower(const std::vector &v1, const std::vector &v2) { + static bool vectors_equal(const std::vector& v1, const std::vector& v2) + { if (NULLABLE) { - for (auto it1 = v1.begin(), it2 = v2.begin(); it1 != v1.end() && it2 != v2.end(); ++ it1, ++ it2) { + if (v1.size() != v2.size()) + return false; + for (auto it1 = v1.begin(), it2 = v2.begin(); it1 != v1.end(); ++it1, ++it2) + if (!((std::isnan(*it1) && std::isnan(*it2)) || *it1 == *it2)) + return false; + return true; + } else + // Not supporting nullable values, the default vector compare is cheaper. + return v1 == v2; + } + static bool vectors_lower(const std::vector& v1, const std::vector& v2) + { + if (NULLABLE) { + for (auto it1 = v1.begin(), it2 = v2.begin(); it1 != v1.end() && it2 != v2.end(); ++it1, ++it2) { auto null1 = int(std::isnan(*it1)); auto null2 = int(std::isnan(*it2)); return (null1 < null2) || (null1 == null2 && *it1 < *it2); @@ -920,11 +935,11 @@ protected: } private: - friend class cereal::access; - template void serialize(Archive &ar) { ar(cereal::base_class>(this)); } + friend class cereal::access; + template void serialize(Archive& ar) { ar(cereal::base_class>(this)); } }; -using ConfigOptionFloats = ConfigOptionFloatsTempl; +using ConfigOptionFloats = ConfigOptionFloatsTempl; using ConfigOptionFloatsNullable = ConfigOptionFloatsTempl; class ConfigOptionInt : public ConfigOptionSingle @@ -935,11 +950,11 @@ public: explicit ConfigOptionInt(double _value) : ConfigOptionSingle(int(floor(_value + 0.5))) {} static ConfigOptionType static_type() { return coInt; } - ConfigOptionType type() const override { return static_type(); } + ConfigOptionType type() const override { return static_type(); } int getInt() const override { return this->value; } void setInt(int val) override { this->value = val; } - ConfigOption* clone() const override { return new ConfigOptionInt(*this); } - bool operator==(const ConfigOptionInt &rhs) const throw() { return this->value == rhs.value; } + ConfigOption* clone() const override { return new ConfigOptionInt(*this); } + bool operator==(const ConfigOptionInt& rhs) const throw() { return this->value == rhs.value; } std::string serialize() const override { @@ -948,7 +963,7 @@ public: return ss.str(); } - bool deserialize(const std::string &str, bool append = false) override + bool deserialize(const std::string& str, bool append = false) override { UNUSED(append); std::istringstream iss(str); @@ -956,1154 +971,53 @@ public: return !iss.fail(); } - ConfigOptionInt& operator=(const ConfigOption *opt) + ConfigOptionInt& operator=(const ConfigOption* opt) { this->set(opt); return *this; } private: - friend class cereal::access; - template void serialize(Archive &ar) { ar(cereal::base_class>(this)); } + friend class cereal::access; + template void serialize(Archive& ar) { ar(cereal::base_class>(this)); } }; -template -class ConfigOptionIntsTempl : public ConfigOptionVector +template class ConfigOptionIntsTempl : public ConfigOptionVector { public: ConfigOptionIntsTempl() : ConfigOptionVector() {} explicit ConfigOptionIntsTempl(size_t n, int value) : ConfigOptionVector(n, value) {} explicit ConfigOptionIntsTempl(std::initializer_list il) : ConfigOptionVector(std::move(il)) {} - explicit ConfigOptionIntsTempl(const std::vector &vec) : ConfigOptionVector(vec) {} - explicit ConfigOptionIntsTempl(std::vector &&vec) : ConfigOptionVector(std::move(vec)) {} + explicit ConfigOptionIntsTempl(const std::vector& vec) : ConfigOptionVector(vec) {} + explicit ConfigOptionIntsTempl(std::vector&& vec) : ConfigOptionVector(std::move(vec)) {} static ConfigOptionType static_type() { return coInts; } - ConfigOptionType type() const override { return static_type(); } + ConfigOptionType type() const override { return static_type(); } ConfigOption* clone() const override { return new ConfigOptionIntsTempl(*this); } - ConfigOptionIntsTempl& operator= (const ConfigOption *opt) { this->set(opt); return *this; } - bool operator==(const ConfigOptionIntsTempl &rhs) const throw() { return this->values == rhs.values; } - bool operator< (const ConfigOptionIntsTempl &rhs) const throw() { return this->values < rhs.values; } - // Could a special "nil" value be stored inside the vector, indicating undefined value? - bool nullable() const override { return NULLABLE; } - // Special "nil" value to be stored into the vector if this->supports_nil(). - static int nil_value() { return std::numeric_limits::max(); } - // A scalar is nil, or all values of a vector are nil. - bool is_nil() const override { for (auto v : this->values) if (v != nil_value()) return false; return true; } - bool is_nil(size_t idx) const override { return this->values[idx] == nil_value(); } - virtual void set_at_to_nil(size_t i) override - { - assert(nullable() && (i < this->values.size())); - this->values[i] = nil_value(); - } - - std::string serialize() const override - { - std::ostringstream ss; - for (const int &v : this->values) { - if (&v != &this->values.front()) - ss << ","; - serialize_single_value(ss, v); - } - return ss.str(); - } - - std::vector vserialize() const override - { - std::vector vv; - vv.reserve(this->values.size()); - for (const int v : this->values) { - std::ostringstream ss; - serialize_single_value(ss, v); - vv.push_back(ss.str()); - } - return vv; - } - - bool deserialize(const std::string &str, bool append = false) override - { - if (! append) - this->values.clear(); - std::istringstream is(str); - std::string item_str; - while (std::getline(is, item_str, ',')) { - boost::trim(item_str); - if (item_str == "nil") { - if (NULLABLE) - this->values.push_back(nil_value()); - else - throw ConfigurationError("Deserializing nil into a non-nullable object"); - } else { - std::istringstream iss(item_str); - int value; - iss >> value; - this->values.push_back(value); - } - } - return true; - } - -private: - void serialize_single_value(std::ostringstream &ss, const int v) const { - if (v == nil_value()) { - if (NULLABLE) - ss << "nil"; - else - throw ConfigurationError("Serializing NaN"); - } else - ss << v; - } - - friend class cereal::access; - template void serialize(Archive &ar) { ar(cereal::base_class>(this)); } -}; - -using ConfigOptionInts = ConfigOptionIntsTempl; -using ConfigOptionIntsNullable = ConfigOptionIntsTempl; - -class ConfigOptionString : public ConfigOptionSingle -{ -public: - ConfigOptionString() : ConfigOptionSingle(std::string{}) {} - explicit ConfigOptionString(std::string value) : ConfigOptionSingle(std::move(value)) {} - - static ConfigOptionType static_type() { return coString; } - ConfigOptionType type() const override { return static_type(); } - ConfigOption* clone() const override { return new ConfigOptionString(*this); } - ConfigOptionString& operator=(const ConfigOption *opt) { this->set(opt); return *this; } - bool operator==(const ConfigOptionString &rhs) const throw() { return this->value == rhs.value; } - bool operator< (const ConfigOptionString &rhs) const throw() { return this->value < rhs.value; } - bool empty() const { return this->value.empty(); } - - std::string serialize() const override - { - return escape_string_cstyle(this->value); - } - - bool deserialize(const std::string &str, bool append = false) override - { - UNUSED(append); - return unescape_string_cstyle(str, this->value); - } - -private: - friend class cereal::access; - template void serialize(Archive &ar) { ar(cereal::base_class>(this)); } -}; - -// semicolon-separated strings -class ConfigOptionStrings : public ConfigOptionVector -{ -public: - ConfigOptionStrings() : ConfigOptionVector() {} - explicit ConfigOptionStrings(size_t n, const std::string &value) : ConfigOptionVector(n, value) {} - explicit ConfigOptionStrings(const std::vector &values) : ConfigOptionVector(values) {} - explicit ConfigOptionStrings(std::vector &&values) : ConfigOptionVector(std::move(values)) {} - explicit ConfigOptionStrings(std::initializer_list il) : ConfigOptionVector(std::move(il)) {} - - static ConfigOptionType static_type() { return coStrings; } - ConfigOptionType type() const override { return static_type(); } - ConfigOption* clone() const override { return new ConfigOptionStrings(*this); } - ConfigOptionStrings& operator=(const ConfigOption *opt) { this->set(opt); return *this; } - bool operator==(const ConfigOptionStrings &rhs) const throw() { return this->values == rhs.values; } - bool operator< (const ConfigOptionStrings &rhs) const throw() { return this->values < rhs.values; } - bool is_nil(size_t) const override { return false; } - - std::string serialize() const override - { - return escape_strings_cstyle(this->values); - } - - std::vector vserialize() const override - { - //BBS: add serialize - /*std::vector result; - result.resize(this->values.size()); - for (int i = 0; i < this->values.size(); i++) - { - result[i] = escape_string_cstyle(this->values[i]); - } - return result;*/ - return this->values; - } - - bool deserialize(const std::string &str, bool append = false) override - { - if (! append) - this->values.clear(); - return unescape_strings_cstyle(str, this->values); - } - -private: - friend class cereal::access; - template void serialize(Archive &ar) { ar(cereal::base_class>(this)); } -}; - -class ConfigOptionPercent : public ConfigOptionFloat -{ -public: - ConfigOptionPercent() : ConfigOptionFloat(0) {} - explicit ConfigOptionPercent(double _value) : ConfigOptionFloat(_value) {} - - static ConfigOptionType static_type() { return coPercent; } - ConfigOptionType type() const override { return static_type(); } - ConfigOption* clone() const override { return new ConfigOptionPercent(*this); } - ConfigOptionPercent& operator= (const ConfigOption *opt) { this->set(opt); return *this; } - bool operator==(const ConfigOptionPercent &rhs) const throw() { return this->value == rhs.value; } - bool operator< (const ConfigOptionPercent &rhs) const throw() { return this->value < rhs.value; } - - double get_abs_value(double ratio_over) const { return ratio_over * this->value / 100; } - - std::string serialize() const override - { - std::ostringstream ss; - ss << this->value; - std::string s(ss.str()); - s += "%"; - return s; - } - - bool deserialize(const std::string &str, bool append = false) override - { - UNUSED(append); - // don't try to parse the trailing % since it's optional - std::istringstream iss(str); - iss >> this->value; - return !iss.fail(); - } - -private: - friend class cereal::access; - template void serialize(Archive &ar) { ar(cereal::base_class(this)); } -}; - -template -class ConfigOptionPercentsTempl : public ConfigOptionFloatsTempl -{ -public: - ConfigOptionPercentsTempl() : ConfigOptionFloatsTempl() {} - explicit ConfigOptionPercentsTempl(size_t n, double value) : ConfigOptionFloatsTempl(n, value) {} - explicit ConfigOptionPercentsTempl(std::initializer_list il) : ConfigOptionFloatsTempl(std::move(il)) {} - explicit ConfigOptionPercentsTempl(const std::vector& vec) : ConfigOptionFloatsTempl(vec) {} - explicit ConfigOptionPercentsTempl(std::vector&& vec) : ConfigOptionFloatsTempl(std::move(vec)) {} - - static ConfigOptionType static_type() { return coPercents; } - ConfigOptionType type() const override { return static_type(); } - ConfigOption* clone() const override { return new ConfigOptionPercentsTempl(*this); } - ConfigOptionPercentsTempl& operator=(const ConfigOption *opt) { this->set(opt); return *this; } - bool operator==(const ConfigOptionPercentsTempl &rhs) const throw() { return ConfigOptionFloatsTempl::vectors_equal(this->values, rhs.values); } - bool operator< (const ConfigOptionPercentsTempl &rhs) const throw() { return ConfigOptionFloatsTempl::vectors_lower(this->values, rhs.values); } - - std::string serialize() const override - { - std::ostringstream ss; - for (const double &v : this->values) { - if (&v != &this->values.front()) - ss << ","; - this->serialize_single_value(ss, v); - if (! std::isnan(v)) - ss << "%"; - } - std::string str = ss.str(); - return str; - } - - std::vector vserialize() const override - { - std::vector vv; - vv.reserve(this->values.size()); - for (const double v : this->values) { - std::ostringstream ss; - this->serialize_single_value(ss, v); - if (! std::isnan(v)) - ss << "%"; - vv.push_back(ss.str()); - } - return vv; - } - - // The float's deserialize function shall ignore the trailing optional %. - // bool deserialize(const std::string &str, bool append = false) override; - -private: - friend class cereal::access; - template void serialize(Archive &ar) { ar(cereal::base_class>(this)); } -}; - -using ConfigOptionPercents = ConfigOptionPercentsTempl; -using ConfigOptionPercentsNullable = ConfigOptionPercentsTempl; - -class ConfigOptionFloatOrPercent : public ConfigOptionPercent -{ -public: - bool percent; - ConfigOptionFloatOrPercent() : ConfigOptionPercent(0), percent(false) {} - explicit ConfigOptionFloatOrPercent(double _value, bool _percent) : ConfigOptionPercent(_value), percent(_percent) {} - - static ConfigOptionType static_type() { return coFloatOrPercent; } - ConfigOptionType type() const override { return static_type(); } - ConfigOption* clone() const override { return new ConfigOptionFloatOrPercent(*this); } - ConfigOptionFloatOrPercent& operator=(const ConfigOption *opt) { this->set(opt); return *this; } - bool operator==(const ConfigOption &rhs) const override - { - if (rhs.type() != this->type()) - throw ConfigurationError("ConfigOptionFloatOrPercent: Comparing incompatible types"); - assert(dynamic_cast(&rhs)); - return *this == *static_cast(&rhs); - } - bool operator==(const ConfigOptionFloatOrPercent &rhs) const throw() - { return this->value == rhs.value && this->percent == rhs.percent; } - size_t hash() const throw() override - { size_t seed = std::hash{}(this->value); return this->percent ? seed ^ 0x9e3779b9 : seed; } - bool operator< (const ConfigOptionFloatOrPercent &rhs) const throw() - { return this->value < rhs.value || (this->value == rhs.value && int(this->percent) < int(rhs.percent)); } - - double get_abs_value(double ratio_over) const - { return this->percent ? (ratio_over * this->value / 100) : this->value; } - - void set(const ConfigOption *rhs) override { - if (rhs->type() != this->type()) - throw ConfigurationError("ConfigOptionFloatOrPercent: Assigning an incompatible type"); - assert(dynamic_cast(rhs)); - *this = *static_cast(rhs); - } - - std::string serialize() const override - { - std::ostringstream ss; - ss << this->value; - std::string s(ss.str()); - if (this->percent) s += "%"; - return s; - } - - bool deserialize(const std::string &str, bool append = false) override - { - UNUSED(append); - this->percent = str.find_first_of("%") != std::string::npos; - std::istringstream iss(str); - iss >> this->value; - return !iss.fail(); - } - -private: - friend class cereal::access; - template void serialize(Archive &ar) { ar(cereal::base_class(this), percent); } -}; - -template -class ConfigOptionFloatsOrPercentsTempl : public ConfigOptionVector -{ -public: - ConfigOptionFloatsOrPercentsTempl() : ConfigOptionVector() {} - explicit ConfigOptionFloatsOrPercentsTempl(size_t n, FloatOrPercent value) : ConfigOptionVector(n, value) {} - explicit ConfigOptionFloatsOrPercentsTempl(std::initializer_list il) : ConfigOptionVector(std::move(il)) {} - explicit ConfigOptionFloatsOrPercentsTempl(const std::vector &vec) : ConfigOptionVector(vec) {} - explicit ConfigOptionFloatsOrPercentsTempl(std::vector &&vec) : ConfigOptionVector(std::move(vec)) {} - - static ConfigOptionType static_type() { return coFloatsOrPercents; } - ConfigOptionType type() const override { return static_type(); } - ConfigOption* clone() const override { return new ConfigOptionFloatsOrPercentsTempl(*this); } - bool operator==(const ConfigOptionFloatsOrPercentsTempl &rhs) const throw() { return vectors_equal(this->values, rhs.values); } - bool operator==(const ConfigOption &rhs) const override { - if (rhs.type() != this->type()) - throw ConfigurationError("ConfigOptionFloatsOrPercentsTempl: Comparing incompatible types"); - assert(dynamic_cast*>(&rhs)); - return vectors_equal(this->values, static_cast*>(&rhs)->values); - } - bool operator< (const ConfigOptionFloatsOrPercentsTempl &rhs) const throw() { return vectors_lower(this->values, rhs.values); } - - // Could a special "nil" value be stored inside the vector, indicating undefined value? - bool nullable() const override { return NULLABLE; } - // Special "nil" value to be stored into the vector if this->supports_nil(). - static FloatOrPercent nil_value() { return { std::numeric_limits::quiet_NaN(), false }; } - // A scalar is nil, or all values of a vector are nil. - bool is_nil() const override { for (auto v : this->values) if (! std::isnan(v.value)) return false; return true; } - bool is_nil(size_t idx) const override { return std::isnan(this->values[idx].value); } - virtual void set_at_to_nil(size_t i) override - { - assert(nullable() && (i < this->values.size())); - this->values[i] = nil_value(); - } - - std::string serialize() const override - { - std::ostringstream ss; - for (const FloatOrPercent &v : this->values) { - if (&v != &this->values.front()) - ss << ","; - serialize_single_value(ss, v); - } - return ss.str(); - } - - std::vector vserialize() const override - { - std::vector vv; - vv.reserve(this->values.size()); - for (const FloatOrPercent &v : this->values) { - std::ostringstream ss; - serialize_single_value(ss, v); - vv.push_back(ss.str()); - } - return vv; - } - - bool deserialize(const std::string &str, bool append = false) override - { - if (! append) - this->values.clear(); - std::istringstream is(str); - std::string item_str; - while (std::getline(is, item_str, ',')) { - boost::trim(item_str); - if (item_str == "nil") { - if (NULLABLE) - this->values.push_back(nil_value()); - else - throw ConfigurationError("Deserializing nil into a non-nullable object"); - } else { - bool percent = item_str.find_first_of("%") != std::string::npos; - std::istringstream iss(item_str); - double value; - iss >> value; - this->values.push_back({ value, percent }); - } - } - return true; - } - - ConfigOptionFloatsOrPercentsTempl& operator=(const ConfigOption *opt) + ConfigOptionIntsTempl& operator=(const ConfigOption* opt) { this->set(opt); return *this; } - -protected: - void serialize_single_value(std::ostringstream &ss, const FloatOrPercent &v) const { - if (std::isfinite(v.value)) { - ss << v.value; - if (v.percent) - ss << "%"; - } else if (std::isnan(v.value)) { - if (NULLABLE) - ss << "nil"; - else - throw ConfigurationError("Serializing NaN"); - } else - throw ConfigurationError("Serializing invalid number"); - } - static bool vectors_equal(const std::vector &v1, const std::vector &v2) { - if (NULLABLE) { - if (v1.size() != v2.size()) - return false; - for (auto it1 = v1.begin(), it2 = v2.begin(); it1 != v1.end(); ++ it1, ++ it2) - if (! ((std::isnan(it1->value) && std::isnan(it2->value)) || *it1 == *it2)) - return false; - return true; - } else - // Not supporting nullable values, the default vector compare is cheaper. - return v1 == v2; - } - static bool vectors_lower(const std::vector &v1, const std::vector &v2) { - if (NULLABLE) { - for (auto it1 = v1.begin(), it2 = v2.begin(); it1 != v1.end() && it2 != v2.end(); ++ it1, ++ it2) { - auto null1 = int(std::isnan(it1->value)); - auto null2 = int(std::isnan(it2->value)); - return (null1 < null2) || (null1 == null2 && *it1 < *it2); - } - return v1.size() < v2.size(); - } else - // Not supporting nullable values, the default vector compare is cheaper. - return v1 < v2; - } - -private: - friend class cereal::access; - template void serialize(Archive &ar) { ar(cereal::base_class>(this)); } -}; - -using ConfigOptionFloatsOrPercents = ConfigOptionFloatsOrPercentsTempl; -using ConfigOptionFloatsOrPercentsNullable = ConfigOptionFloatsOrPercentsTempl; - -class ConfigOptionPoint : public ConfigOptionSingle -{ -public: - ConfigOptionPoint() : ConfigOptionSingle(Vec2d(0,0)) {} - explicit ConfigOptionPoint(const Vec2d &value) : ConfigOptionSingle(value) {} - - static ConfigOptionType static_type() { return coPoint; } - ConfigOptionType type() const override { return static_type(); } - ConfigOption* clone() const override { return new ConfigOptionPoint(*this); } - ConfigOptionPoint& operator=(const ConfigOption *opt) { this->set(opt); return *this; } - bool operator==(const ConfigOptionPoint &rhs) const throw() { return this->value == rhs.value; } - bool operator< (const ConfigOptionPoint &rhs) const throw() { return this->value < rhs.value; } - - std::string serialize() const override - { - std::ostringstream ss; - ss << this->value(0); - ss << ","; - ss << this->value(1); - return ss.str(); - } - - bool deserialize(const std::string &str, bool append = false) override - { - UNUSED(append); - char dummy; - return sscanf(str.data(), " %lf , %lf %c", &this->value(0), &this->value(1), &dummy) == 2 || - sscanf(str.data(), " %lf x %lf %c", &this->value(0), &this->value(1), &dummy) == 2; - } - -private: - friend class cereal::access; - template void serialize(Archive &ar) { ar(cereal::base_class>(this)); } -}; - -class ConfigOptionPoints : public ConfigOptionVector -{ -public: - ConfigOptionPoints() : ConfigOptionVector() {} - explicit ConfigOptionPoints(size_t n, const Vec2d &value) : ConfigOptionVector(n, value) {} - explicit ConfigOptionPoints(std::initializer_list il) : ConfigOptionVector(std::move(il)) {} - explicit ConfigOptionPoints(const std::vector &values) : ConfigOptionVector(values) {} - - static ConfigOptionType static_type() { return coPoints; } - ConfigOptionType type() const override { return static_type(); } - ConfigOption* clone() const override { return new ConfigOptionPoints(*this); } - ConfigOptionPoints& operator= (const ConfigOption *opt) { this->set(opt); return *this; } - bool operator==(const ConfigOptionPoints &rhs) const throw() { return this->values == rhs.values; } - bool operator< (const ConfigOptionPoints &rhs) const throw() - { return std::lexicographical_compare(this->values.begin(), this->values.end(), rhs.values.begin(), rhs.values.end(), [](const auto &l, const auto &r){ return l < r; }); } - bool is_nil(size_t) const override { return false; } - - std::string serialize() const override - { - std::ostringstream ss; - for (Pointfs::const_iterator it = this->values.begin(); it != this->values.end(); ++it) { - if (it - this->values.begin() != 0) ss << ","; - ss << (*it)(0); - ss << "x"; - ss << (*it)(1); - } - return ss.str(); - } - - std::vector vserialize() const override - { - std::vector vv; - for (Pointfs::const_iterator it = this->values.begin(); it != this->values.end(); ++it) { - std::ostringstream ss; - //BBS: add json format - //ss << *it; - ss << (*it)(0); - ss << "x"; - ss << (*it)(1); - vv.push_back(ss.str()); - } - return vv; - } - - bool deserialize(const std::string &str, bool append = false) override - { - if (! append) - this->values.clear(); - std::istringstream is(str); - std::string point_str; - while (std::getline(is, point_str, ',')) { - Vec2d point(Vec2d::Zero()); - std::istringstream iss(point_str); - std::string coord_str; - if (std::getline(iss, coord_str, 'x')) { - std::istringstream(coord_str) >> point(0); - if (std::getline(iss, coord_str, 'x')) { - std::istringstream(coord_str) >> point(1); - } - } - this->values.push_back(point); - } - return true; - } - -private: - friend class cereal::access; - template void save(Archive& archive) const { - size_t cnt = this->values.size(); - archive(cnt); - archive.saveBinary((const char*)this->values.data(), sizeof(Vec2d) * cnt); - } - template void load(Archive& archive) { - size_t cnt; - archive(cnt); - this->values.assign(cnt, Vec2d()); - archive.loadBinary((char*)this->values.data(), sizeof(Vec2d) * cnt); - } -}; - -class ConfigOptionPoint3 : public ConfigOptionSingle -{ -public: - ConfigOptionPoint3() : ConfigOptionSingle(Vec3d(0,0,0)) {} - explicit ConfigOptionPoint3(const Vec3d &value) : ConfigOptionSingle(value) {} - - static ConfigOptionType static_type() { return coPoint3; } - ConfigOptionType type() const override { return static_type(); } - ConfigOption* clone() const override { return new ConfigOptionPoint3(*this); } - ConfigOptionPoint3& operator=(const ConfigOption *opt) { this->set(opt); return *this; } - bool operator==(const ConfigOptionPoint3 &rhs) const throw() { return this->value == rhs.value; } - bool operator< (const ConfigOptionPoint3 &rhs) const throw() - { return this->value.x() < rhs.value.x() || (this->value.x() == rhs.value.x() && (this->value.y() < rhs.value.y() || (this->value.y() == rhs.value.y() && this->value.z() < rhs.value.z()))); } - - std::string serialize() const override - { - std::ostringstream ss; - ss << this->value(0); - ss << ","; - ss << this->value(1); - ss << ","; - ss << this->value(2); - return ss.str(); - } - - bool deserialize(const std::string &str, bool append = false) override - { - UNUSED(append); - char dummy; - return sscanf(str.data(), " %lf , %lf , %lf %c", &this->value(0), &this->value(1), &this->value(2), &dummy) == 3 || - sscanf(str.data(), " %lf x %lf x %lf %c", &this->value(0), &this->value(1), &this->value(2), &dummy) == 3; - } - -private: - friend class cereal::access; - template void serialize(Archive &ar) { ar(cereal::base_class>(this)); } -}; - -class ConfigOptionPointsGroups :public ConfigOptionVector -{ -public: - ConfigOptionPointsGroups() :ConfigOptionVector() {} - explicit ConfigOptionPointsGroups(std::initializer_list il) :ConfigOptionVector(std::move(il)) {} - explicit ConfigOptionPointsGroups(const std::vector& values) :ConfigOptionVector(values) {} - - static ConfigOptionType static_type() { return coPointsGroups; } - ConfigOptionType type()const override { return static_type(); } - ConfigOption* clone()const override { return new ConfigOptionPointsGroups(*this); } - ConfigOptionPointsGroups& operator=(const ConfigOption* opt) { this->set(opt); return *this; } - bool operator == (const ConfigOptionPointsGroups& rhs)const throw() { return this->values == rhs.values; } - bool operator == (const ConfigOption& rhs) const override { - if (rhs.type() != this->type()) - throw ConfigurationError("ConfigOptionPointsGroupsTempl: Comparing incompatible types"); - assert(dynamic_cast*>(&rhs)); - - return this->values == static_cast*>(&rhs)->values; - } - bool nullable() const override { return false; } - bool is_nil(size_t) const override { return false; } - - std::string serialize()const override - { - std::ostringstream ss; - for (auto iter = this->values.begin(); iter != this->values.end(); ++iter) { - if (iter != this->values.begin()) - ss << "#"; - serialize_single_value(ss, *iter); - } - - return ss.str(); - } - - std::vector vserialize()const override - { - std::vectorret; - for (const auto& points : this->values) { - std::ostringstream ss; - serialize_single_value(ss, points); - ret.emplace_back(ss.str()); - } - return ret; - } - - bool deserialize(const std::string& str, bool append = false) override - { - if (!append) - this->values.clear(); - std::istringstream is(str); - std::string group_str; - while (std::getline(is, group_str, '#')) { - Vec2ds group; - std::istringstream iss(group_str); - std::string point_str; - while (std::getline(iss, point_str, ',')) { - Vec2d point(Vec2d::Zero()); - std::istringstream iss(point_str); - std::string coord_str; - if (std::getline(iss, coord_str, 'x')) { - std::istringstream(coord_str) >> point(0); - if (std::getline(iss, coord_str, 'x')) { - std::istringstream(coord_str) >> point(1); - } - } - group.push_back(point); - } - this->values.emplace_back(std::move(group)); - } - return true; - } - std::vector vserialize_single(int idx) const - { - std::vectorret; - assert(idx < this->size()); - for (auto iter = values[idx].begin(); iter != values[idx].end(); ++iter) { - std::ostringstream ss; - ss << (*iter)(0); - ss << "x"; - ss << (*iter)(1); - ret.emplace_back(ss.str()); - } - return ret; - } -protected: - void serialize_single_value(std::ostringstream& ss, const Vec2ds& v) const { - for (auto iter = v.begin(); iter != v.end(); ++iter) { - if (iter - v.begin() != 0) - ss << ","; - ss << (*iter)(0); - ss << "x"; - ss << (*iter)(1); - } - } -private: - friend class cereal::access; - template void serialize(Archive& ar) { ar(cereal::base_class(this)); } -}; - -class ConfigOptionIntsGroups : public ConfigOptionVector> -{ -public: - ConfigOptionIntsGroups() : ConfigOptionVector>() {} - explicit ConfigOptionIntsGroups(std::initializer_list> il) : ConfigOptionVector>(std::move(il)) {} - explicit ConfigOptionIntsGroups(const std::vector> &values) : ConfigOptionVector>(values) {} - - static ConfigOptionType static_type() { return coIntsGroups; } - ConfigOptionType type() const override { return static_type(); } - ConfigOption *clone() const override { return new ConfigOptionIntsGroups(*this); } - ConfigOptionIntsGroups &operator=(const ConfigOption *opt) - { - this->set(opt); - return *this; - } - bool operator==(const ConfigOptionIntsGroups &rhs) const throw() { return this->values == rhs.values; } - bool operator==(const ConfigOption &rhs) const override - { - if (rhs.type() != this->type()) throw ConfigurationError("ConfigConfigOptionIntsGroups: Comparing incompatible types"); - assert(dynamic_cast> *>(&rhs)); - - return this->values == static_cast> *>(&rhs)->values; - } - bool operator<(const ConfigOptionIntsGroups &rhs) const throw() { - bool is_lower = true; - for (size_t i = 0; i < values.size(); ++i) { - if (this->values[i] == rhs.values[i]) - continue; - - return (this->values[i] < rhs.values[i]); - } - return is_lower; - } - bool nullable() const override { return false; } - bool is_nil(size_t) const override { return false; } - - std::string serialize() const override - { - std::ostringstream ss; - for (auto iter = this->values.begin(); iter != this->values.end(); ++iter) { - if (iter != this->values.begin()) - ss << "#"; - serialize_single_value(ss, *iter); - } - - return ss.str(); - } - - std::vector vserialize() const override - { - std::vector ret; - for (const auto &value : this->values) { - std::ostringstream ss; - serialize_single_value(ss, value); - ret.emplace_back(ss.str()); - } - return ret; - } - - bool deserialize(const std::string &str, bool append = false) override - { - if (!append) this->values.clear(); - std::istringstream is(str); - std::string group_str; - while (std::getline(is, group_str, '#')) { - std::vector group_values; - std::istringstream iss(group_str); - std::string value_str; - while (std::getline(iss, value_str, ',')) { - int value; - std::istringstream(value_str) >> value; - group_values.push_back(value); - } - this->values.emplace_back(std::move(group_values)); - } - return true; - } - std::vector vserialize_single(int idx) const - { - std::vector ret; - assert(idx < this->size()); - for (auto iter = values[idx].begin(); iter != values[idx].end(); ++iter) { - std::ostringstream ss; - ss << (*iter); - ret.emplace_back(ss.str()); - } - return ret; - } - -protected: - void serialize_single_value(std::ostringstream &ss, const std::vector &v) const - { - for (auto iter = v.begin(); iter != v.end(); ++iter) { - if (iter - v.begin() != 0) - ss << ","; - ss << (*iter); - } - } - -private: - friend class cereal::access; - template void serialize(Archive &ar) { ar(cereal::base_class(this)); } -}; - - -class ConfigOptionBool : public ConfigOptionSingle -{ -public: - ConfigOptionBool() : ConfigOptionSingle(false) {} - explicit ConfigOptionBool(bool _value) : ConfigOptionSingle(_value) {} - - static ConfigOptionType static_type() { return coBool; } - ConfigOptionType type() const override { return static_type(); } - bool getBool() const override { return this->value; } - ConfigOption* clone() const override { return new ConfigOptionBool(*this); } - ConfigOptionBool& operator=(const ConfigOption *opt) { this->set(opt); return *this; } - bool operator==(const ConfigOptionBool &rhs) const throw() { return this->value == rhs.value; } - bool operator< (const ConfigOptionBool &rhs) const throw() { return int(this->value) < int(rhs.value); } - - std::string serialize() const override - { - return std::string(this->value ? "1" : "0"); - } - - bool deserialize(const std::string &str, bool append = false) override - { - UNUSED(append); - - // Orca: take the first value if input is an array - std::istringstream is(str); - std::string item_str; - if (std::getline(is, item_str, ',')) { - boost::trim(item_str); - - if (item_str == "1") { - this->value = true; - return true; - } - if (item_str == "0") { - this->value = false; - return true; - } - } - - return false; - } - -private: - friend class cereal::access; - template void serialize(Archive &ar) { ar(cereal::base_class>(this)); } -}; - -template -class ConfigOptionBoolsTempl : public ConfigOptionVector -{ -public: - ConfigOptionBoolsTempl() : ConfigOptionVector() {} - explicit ConfigOptionBoolsTempl(size_t n, bool value) : ConfigOptionVector(n, (unsigned char)value) {} - explicit ConfigOptionBoolsTempl(std::initializer_list il) { values.reserve(il.size()); for (bool b : il) values.emplace_back((unsigned char)b); } - explicit ConfigOptionBoolsTempl(std::initializer_list il) { values.reserve(il.size()); for (unsigned char b : il) values.emplace_back(b); } - explicit ConfigOptionBoolsTempl(const std::vector& vec) : ConfigOptionVector(vec) {} - explicit ConfigOptionBoolsTempl(std::vector&& vec) : ConfigOptionVector(std::move(vec)) {} - - static ConfigOptionType static_type() { return coBools; } - ConfigOptionType type() const override { return static_type(); } - ConfigOption* clone() const override { return new ConfigOptionBoolsTempl(*this); } - ConfigOptionBoolsTempl& operator=(const ConfigOption *opt) { this->set(opt); return *this; } - bool operator==(const ConfigOptionBoolsTempl &rhs) const throw() { return this->values == rhs.values; } - bool operator< (const ConfigOptionBoolsTempl &rhs) const throw() { return this->values < rhs.values; } + bool operator==(const ConfigOptionIntsTempl& rhs) const throw() { return this->values == rhs.values; } + bool operator<(const ConfigOptionIntsTempl& rhs) const throw() { return this->values < rhs.values; } // Could a special "nil" value be stored inside the vector, indicating undefined value? - bool nullable() const override { return NULLABLE; } - // Special "nil" value to be stored into the vector if this->supports_nil(). - static unsigned char nil_value() { return std::numeric_limits::max(); } - // A scalar is nil, or all values of a vector are nil. - bool is_nil() const override { for (auto v : this->values) if (v != nil_value()) return false; return true; } - bool is_nil(size_t idx) const override { return this->values[idx] == nil_value(); } - virtual void set_at_to_nil(size_t i) override - { - assert(nullable() && (i < this->values.size())); - this->values[i] = nil_value(); - } - - bool& get_at(size_t i) { - assert(! this->values.empty()); - return *reinterpret_cast(&((i < this->values.size()) ? this->values[i] : this->values.front())); - } - - //FIXME this smells, the parent class has the method declared returning (unsigned char&). - bool get_at(size_t i) const { return ((i < this->values.size()) ? this->values[i] : this->values.front()) != 0; } - - std::string serialize() const override - { - std::ostringstream ss; - for (const unsigned char &v : this->values) { - if (&v != &this->values.front()) - ss << ","; - this->serialize_single_value(ss, v); - } - return ss.str(); - } - - std::vector vserialize() const override - { - std::vector vv; - for (const unsigned char v : this->values) { - std::ostringstream ss; - this->serialize_single_value(ss, v); - vv.push_back(ss.str()); - } - return vv; - } - - ConfigHelpers::DeserializationResult deserialize_with_substitutions(const std::string &str, bool append, ConfigHelpers::DeserializationSubstitution substitution) - { - if (! append) - this->values.clear(); - std::istringstream is(str); - std::string item_str; - bool substituted = false; - while (std::getline(is, item_str, ',')) { - boost::trim(item_str); - unsigned char new_value = 0; - if (item_str == "nil") { - if (NULLABLE) - new_value = nil_value(); - else - throw ConfigurationError("Deserializing nil into a non-nullable object"); - } else if (item_str == "1") { - new_value = true; - } else if (item_str == "0") { - new_value = false; - } else if (substitution != ConfigHelpers::DeserializationSubstitution::Disabled && ConfigHelpers::looks_like_enum_value(item_str)) { - new_value = ConfigHelpers::enum_looks_like_true_value(item_str) || substitution == ConfigHelpers::DeserializationSubstitution::DefaultsToTrue; - substituted = true; - } else - return ConfigHelpers::DeserializationResult::Failed; - this->values.push_back(new_value); - } - return substituted ? ConfigHelpers::DeserializationResult::Substituted : ConfigHelpers::DeserializationResult::Loaded; - } - - bool deserialize(const std::string &str, bool append = false) override - { - return this->deserialize_with_substitutions(str, append, ConfigHelpers::DeserializationSubstitution::Disabled) == ConfigHelpers::DeserializationResult::Loaded; - } - -protected: - void serialize_single_value(std::ostringstream &ss, const unsigned char v) const { - if (v == nil_value()) { - if (NULLABLE) - ss << "nil"; - else - throw ConfigurationError("Serializing NaN"); - } else - ss << (v ? "1" : "0"); - } - -private: - friend class cereal::access; - template void serialize(Archive &ar) { ar(cereal::base_class>(this)); } -}; - -using ConfigOptionBools = ConfigOptionBoolsTempl; -using ConfigOptionBoolsNullable = ConfigOptionBoolsTempl; - -// Map from an enum integer value to an enum name. -typedef std::vector t_config_enum_names; -// Map from an enum name to an enum integer value. -typedef std::map t_config_enum_values; - -template -class ConfigOptionEnum : public ConfigOptionSingle -{ -public: - // by default, use the first value (0) of the T enum type - ConfigOptionEnum() : ConfigOptionSingle(static_cast(0)) {} - explicit ConfigOptionEnum(T _value) : ConfigOptionSingle(_value) {} - - static ConfigOptionType static_type() { return coEnum; } - ConfigOptionType type() const override { return static_type(); } - ConfigOption* clone() const override { return new ConfigOptionEnum(*this); } - ConfigOptionEnum& operator=(const ConfigOption *opt) { this->set(opt); return *this; } - bool operator==(const ConfigOptionEnum &rhs) const throw() { return this->value == rhs.value; } - bool operator< (const ConfigOptionEnum &rhs) const throw() { return int(this->value) < int(rhs.value); } - int getInt() const override { return (int)this->value; } - void setInt(int val) override { this->value = T(val); } - - bool operator==(const ConfigOption &rhs) const override - { - if (rhs.type() != this->type()) - throw ConfigurationError("ConfigOptionEnum: Comparing incompatible types"); - // rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum - return this->value == (T)rhs.getInt(); - } - - void set(const ConfigOption *rhs) override { - if (rhs->type() != this->type()) - throw ConfigurationError("ConfigOptionEnum: Assigning an incompatible type"); - // rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum - this->value = (T)rhs->getInt(); - } - - std::string serialize() const override - { - const t_config_enum_names& names = ConfigOptionEnum::get_enum_names(); - assert(static_cast(this->value) < int(names.size())); - return names[static_cast(this->value)]; - } - - bool deserialize(const std::string &str, bool append = false) override - { - UNUSED(append); - return from_string(str, this->value); - } - - static bool has(T value) - { - for (const auto &kvp : ConfigOptionEnum::get_enum_values()) - if (kvp.second == value) - return true; - return false; - } - - // Map from an enum name to an enum integer value. - static const t_config_enum_names& get_enum_names(); - // Map from an enum name to an enum integer value. - static const t_config_enum_values& get_enum_values(); - - static bool from_string(const std::string &str, T &value) - { - const t_config_enum_values &enum_keys_map = ConfigOptionEnum::get_enum_values(); - auto it = enum_keys_map.find(str); - if (it == enum_keys_map.end()) - return false; - value = static_cast(it->second); - return true; - } -}; - -// Generic enum configuration value. -// We use this one in DynamicConfig objects when creating a config value object for ConfigOptionType == coEnum. -// In the StaticConfig, it is better to use the specialized ConfigOptionEnum containers. -class ConfigOptionEnumGeneric : public ConfigOptionInt -{ -public: - ConfigOptionEnumGeneric(const t_config_enum_values* keys_map = nullptr) : keys_map(keys_map) {} - explicit ConfigOptionEnumGeneric(const t_config_enum_values* keys_map, int value) : ConfigOptionInt(value), keys_map(keys_map) {} - - const t_config_enum_values* keys_map; - - static ConfigOptionType static_type() { return coEnum; } - ConfigOptionType type() const override { return static_type(); } - ConfigOption* clone() const override { return new ConfigOptionEnumGeneric(*this); } - ConfigOptionEnumGeneric& operator= (const ConfigOption *opt) { this->set(opt); return *this; } - bool operator==(const ConfigOptionEnumGeneric &rhs) const throw() { return this->value == rhs.value; } - bool operator< (const ConfigOptionEnumGeneric &rhs) const throw() { return this->value < rhs.value; } - - bool operator==(const ConfigOption &rhs) const override - { - if (rhs.type() != this->type()) - throw ConfigurationError("ConfigOptionEnumGeneric: Comparing incompatible types"); - // rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum - return this->value == rhs.getInt(); - } - - void set(const ConfigOption *rhs) override { - if (rhs->type() != this->type()) - throw ConfigurationError("ConfigOptionEnumGeneric: Assigning an incompatible type"); - // rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum - this->value = rhs->getInt(); - } - - std::string serialize() const override - { - for (const auto &kvp : *this->keys_map) - if (kvp.second == this->value) - return kvp.first; - return std::string(); - } - - bool deserialize(const std::string &str, bool append = false) override - { - UNUSED(append); - auto it = this->keys_map->find(str); - if (it == this->keys_map->end()) - return false; - this->value = it->second; - return true; - } - -private: - friend class cereal::access; - template void serialize(Archive& ar) { ar(cereal::base_class(this)); } -}; - -// BBS -template -class ConfigOptionEnumsGenericTempl : public ConfigOptionInts -{ -public: - ConfigOptionEnumsGenericTempl(const t_config_enum_values *keys_map = nullptr) : keys_map(keys_map) {} - explicit ConfigOptionEnumsGenericTempl(const t_config_enum_values *keys_map, size_t size, int value) : ConfigOptionInts(size, value), keys_map(keys_map) {} - explicit ConfigOptionEnumsGenericTempl(std::initializer_list il) : ConfigOptionInts(std::move(il)), keys_map(keys_map) {} - explicit ConfigOptionEnumsGenericTempl(const std::vector &vec) : ConfigOptionInts(vec) {} - explicit ConfigOptionEnumsGenericTempl(std::vector &&vec) : ConfigOptionInts(std::move(vec)) {} - - const t_config_enum_values* keys_map = nullptr; - - static ConfigOptionType static_type() { return coEnums; } - ConfigOptionType type() const override { return static_type(); } - ConfigOption* clone() const override { return new ConfigOptionEnumsGenericTempl(*this); } - ConfigOptionEnumsGenericTempl& operator= (const ConfigOption* opt) { this->set(opt); return *this; } - bool operator< (const ConfigOptionInts& rhs) const throw() { return this->values < rhs.values; } - - bool operator==(const ConfigOptionInts& rhs) const - { - if (rhs.type() != this->type()) - throw ConfigurationError("ConfigOptionEnumsGeneric: Comparing incompatible types"); - return this->values == rhs.values; - } bool nullable() const override { return NULLABLE; } - - void set(const ConfigOption* rhs) override { - if (rhs->type() != this->type()) - throw ConfigurationError("ConfigOptionEnumGeneric: Assigning an incompatible type"); - // rhs could be of the following type: ConfigOptionEnumsGeneric - this->values = dynamic_cast(rhs)->values; + // Special "nil" value to be stored into the vector if this->supports_nil(). + static int nil_value() { return std::numeric_limits::max(); } + // A scalar is nil, or all values of a vector are nil. + bool is_nil() const override + { + for (auto v : this->values) + if (v != nil_value()) + return false; + return true; + } + bool is_nil(size_t idx) const override { return this->values[idx] == nil_value(); } + virtual void set_at_to_nil(size_t i) override + { + assert(nullable() && (i < this->values.size())); + this->values[i] = nil_value(); } std::string serialize() const override @@ -2134,7 +1048,7 @@ public: if (!append) this->values.clear(); std::istringstream is(str); - std::string item_str; + std::string item_str; while (std::getline(is, item_str, ',')) { boost::trim(item_str); if (item_str == "nil") { @@ -2142,8 +1056,1229 @@ public: this->values.push_back(nil_value()); else throw ConfigurationError("Deserializing nil into a non-nullable object"); + } else { + std::istringstream iss(item_str); + int value; + iss >> value; + this->values.push_back(value); } - else { + } + return true; + } + +private: + void serialize_single_value(std::ostringstream& ss, const int v) const + { + if (v == nil_value()) { + if (NULLABLE) + ss << "nil"; + else + throw ConfigurationError("Serializing NaN"); + } else + ss << v; + } + + friend class cereal::access; + template void serialize(Archive& ar) { ar(cereal::base_class>(this)); } +}; + +using ConfigOptionInts = ConfigOptionIntsTempl; +using ConfigOptionIntsNullable = ConfigOptionIntsTempl; + +class ConfigOptionString : public ConfigOptionSingle +{ +public: + ConfigOptionString() : ConfigOptionSingle(std::string{}) {} + explicit ConfigOptionString(std::string value) : ConfigOptionSingle(std::move(value)) {} + + static ConfigOptionType static_type() { return coString; } + ConfigOptionType type() const override { return static_type(); } + ConfigOption* clone() const override { return new ConfigOptionString(*this); } + ConfigOptionString& operator=(const ConfigOption* opt) + { + this->set(opt); + return *this; + } + bool operator==(const ConfigOptionString& rhs) const throw() { return this->value == rhs.value; } + bool operator<(const ConfigOptionString& rhs) const throw() { return this->value < rhs.value; } + bool empty() const { return this->value.empty(); } + + std::string serialize() const override { return escape_string_cstyle(this->value); } + + bool deserialize(const std::string& str, bool append = false) override + { + UNUSED(append); + return unescape_string_cstyle(str, this->value); + } + +private: + friend class cereal::access; + template void serialize(Archive& ar) { ar(cereal::base_class>(this)); } +}; + +// semicolon-separated strings +class ConfigOptionStrings : public ConfigOptionVector +{ +public: + ConfigOptionStrings() : ConfigOptionVector() {} + explicit ConfigOptionStrings(size_t n, const std::string& value) : ConfigOptionVector(n, value) {} + explicit ConfigOptionStrings(const std::vector& values) : ConfigOptionVector(values) {} + explicit ConfigOptionStrings(std::vector&& values) : ConfigOptionVector(std::move(values)) {} + explicit ConfigOptionStrings(std::initializer_list il) : ConfigOptionVector(std::move(il)) {} + + static ConfigOptionType static_type() { return coStrings; } + ConfigOptionType type() const override { return static_type(); } + ConfigOption* clone() const override { return new ConfigOptionStrings(*this); } + ConfigOptionStrings& operator=(const ConfigOption* opt) + { + this->set(opt); + return *this; + } + bool operator==(const ConfigOptionStrings& rhs) const throw() { return this->values == rhs.values; } + bool operator<(const ConfigOptionStrings& rhs) const throw() { return this->values < rhs.values; } + bool is_nil(size_t) const override { return false; } + + std::string serialize() const override { return escape_strings_cstyle(this->values); } + + std::vector vserialize() const override + { + // BBS: add serialize + /*std::vector result; + result.resize(this->values.size()); + for (int i = 0; i < this->values.size(); i++) + { + result[i] = escape_string_cstyle(this->values[i]); + } + return result;*/ + return this->values; + } + + bool deserialize(const std::string& str, bool append = false) override + { + if (!append) + this->values.clear(); + return unescape_strings_cstyle(str, this->values); + } + +private: + friend class cereal::access; + template void serialize(Archive& ar) { ar(cereal::base_class>(this)); } +}; + +class ConfigOptionPercent : public ConfigOptionFloat +{ +public: + ConfigOptionPercent() : ConfigOptionFloat(0) {} + explicit ConfigOptionPercent(double _value) : ConfigOptionFloat(_value) {} + + static ConfigOptionType static_type() { return coPercent; } + ConfigOptionType type() const override { return static_type(); } + ConfigOption* clone() const override { return new ConfigOptionPercent(*this); } + ConfigOptionPercent& operator=(const ConfigOption* opt) + { + this->set(opt); + return *this; + } + bool operator==(const ConfigOptionPercent& rhs) const throw() { return this->value == rhs.value; } + bool operator<(const ConfigOptionPercent& rhs) const throw() { return this->value < rhs.value; } + + double get_abs_value(double ratio_over) const { return ratio_over * this->value / 100; } + + std::string serialize() const override + { + std::ostringstream ss; + ss << this->value; + std::string s(ss.str()); + s += "%"; + return s; + } + + bool deserialize(const std::string& str, bool append = false) override + { + UNUSED(append); + // don't try to parse the trailing % since it's optional + std::istringstream iss(str); + iss >> this->value; + return !iss.fail(); + } + +private: + friend class cereal::access; + template void serialize(Archive& ar) { ar(cereal::base_class(this)); } +}; + +template class ConfigOptionPercentsTempl : public ConfigOptionFloatsTempl +{ +public: + ConfigOptionPercentsTempl() : ConfigOptionFloatsTempl() {} + explicit ConfigOptionPercentsTempl(size_t n, double value) : ConfigOptionFloatsTempl(n, value) {} + explicit ConfigOptionPercentsTempl(std::initializer_list il) : ConfigOptionFloatsTempl(std::move(il)) {} + explicit ConfigOptionPercentsTempl(const std::vector& vec) : ConfigOptionFloatsTempl(vec) {} + explicit ConfigOptionPercentsTempl(std::vector&& vec) : ConfigOptionFloatsTempl(std::move(vec)) {} + + static ConfigOptionType static_type() { return coPercents; } + ConfigOptionType type() const override { return static_type(); } + ConfigOption* clone() const override { return new ConfigOptionPercentsTempl(*this); } + ConfigOptionPercentsTempl& operator=(const ConfigOption* opt) + { + this->set(opt); + return *this; + } + bool operator==(const ConfigOptionPercentsTempl& rhs) const throw() + { + return ConfigOptionFloatsTempl::vectors_equal(this->values, rhs.values); + } + bool operator<(const ConfigOptionPercentsTempl& rhs) const throw() + { + return ConfigOptionFloatsTempl::vectors_lower(this->values, rhs.values); + } + + std::string serialize() const override + { + std::ostringstream ss; + for (const double& v : this->values) { + if (&v != &this->values.front()) + ss << ","; + this->serialize_single_value(ss, v); + if (!std::isnan(v)) + ss << "%"; + } + std::string str = ss.str(); + return str; + } + + std::vector vserialize() const override + { + std::vector vv; + vv.reserve(this->values.size()); + for (const double v : this->values) { + std::ostringstream ss; + this->serialize_single_value(ss, v); + if (!std::isnan(v)) + ss << "%"; + vv.push_back(ss.str()); + } + return vv; + } + + // The float's deserialize function shall ignore the trailing optional %. + // bool deserialize(const std::string &str, bool append = false) override; + +private: + friend class cereal::access; + template void serialize(Archive& ar) { ar(cereal::base_class>(this)); } +}; + +using ConfigOptionPercents = ConfigOptionPercentsTempl; +using ConfigOptionPercentsNullable = ConfigOptionPercentsTempl; + +class ConfigOptionFloatOrPercent : public ConfigOptionPercent +{ +public: + bool percent; + ConfigOptionFloatOrPercent() : ConfigOptionPercent(0), percent(false) {} + explicit ConfigOptionFloatOrPercent(double _value, bool _percent) : ConfigOptionPercent(_value), percent(_percent) {} + + static ConfigOptionType static_type() { return coFloatOrPercent; } + ConfigOptionType type() const override { return static_type(); } + ConfigOption* clone() const override { return new ConfigOptionFloatOrPercent(*this); } + ConfigOptionFloatOrPercent& operator=(const ConfigOption* opt) + { + this->set(opt); + return *this; + } + bool operator==(const ConfigOption& rhs) const override + { + if (rhs.type() != this->type()) + throw ConfigurationError("ConfigOptionFloatOrPercent: Comparing incompatible types"); + assert(dynamic_cast(&rhs)); + return *this == *static_cast(&rhs); + } + bool operator==(const ConfigOptionFloatOrPercent& rhs) const throw() + { + return this->value == rhs.value && this->percent == rhs.percent; + } + size_t hash() const throw() override + { + size_t seed = std::hash{}(this->value); + return this->percent ? seed ^ 0x9e3779b9 : seed; + } + bool operator<(const ConfigOptionFloatOrPercent& rhs) const throw() + { + return this->value < rhs.value || (this->value == rhs.value && int(this->percent) < int(rhs.percent)); + } + + double get_abs_value(double ratio_over) const { return this->percent ? (ratio_over * this->value / 100) : this->value; } + + void set(const ConfigOption* rhs) override + { + if (rhs->type() != this->type()) + throw ConfigurationError("ConfigOptionFloatOrPercent: Assigning an incompatible type"); + assert(dynamic_cast(rhs)); + *this = *static_cast(rhs); + } + + std::string serialize() const override + { + std::ostringstream ss; + ss << this->value; + std::string s(ss.str()); + if (this->percent) + s += "%"; + return s; + } + + bool deserialize(const std::string& str, bool append = false) override + { + UNUSED(append); + this->percent = str.find_first_of("%") != std::string::npos; + std::istringstream iss(str); + iss >> this->value; + return !iss.fail(); + } + +private: + friend class cereal::access; + template void serialize(Archive& ar) { ar(cereal::base_class(this), percent); } +}; + +template class ConfigOptionFloatsOrPercentsTempl : public ConfigOptionVector +{ +public: + ConfigOptionFloatsOrPercentsTempl() : ConfigOptionVector() {} + explicit ConfigOptionFloatsOrPercentsTempl(size_t n, FloatOrPercent value) : ConfigOptionVector(n, value) {} + explicit ConfigOptionFloatsOrPercentsTempl(std::initializer_list il) : ConfigOptionVector(std::move(il)) + {} + explicit ConfigOptionFloatsOrPercentsTempl(const std::vector& vec) : ConfigOptionVector(vec) {} + explicit ConfigOptionFloatsOrPercentsTempl(std::vector&& vec) : ConfigOptionVector(std::move(vec)) {} + + static ConfigOptionType static_type() { return coFloatsOrPercents; } + ConfigOptionType type() const override { return static_type(); } + ConfigOption* clone() const override { return new ConfigOptionFloatsOrPercentsTempl(*this); } + bool operator==(const ConfigOptionFloatsOrPercentsTempl& rhs) const throw() { return vectors_equal(this->values, rhs.values); } + bool operator==(const ConfigOption& rhs) const override + { + if (rhs.type() != this->type()) + throw ConfigurationError("ConfigOptionFloatsOrPercentsTempl: Comparing incompatible types"); + assert(dynamic_cast*>(&rhs)); + return vectors_equal(this->values, static_cast*>(&rhs)->values); + } + bool operator<(const ConfigOptionFloatsOrPercentsTempl& rhs) const throw() { return vectors_lower(this->values, rhs.values); } + + // Could a special "nil" value be stored inside the vector, indicating undefined value? + bool nullable() const override { return NULLABLE; } + // Special "nil" value to be stored into the vector if this->supports_nil(). + static FloatOrPercent nil_value() { return {std::numeric_limits::quiet_NaN(), false}; } + // A scalar is nil, or all values of a vector are nil. + bool is_nil() const override + { + for (auto v : this->values) + if (!std::isnan(v.value)) + return false; + return true; + } + bool is_nil(size_t idx) const override { return std::isnan(this->values[idx].value); } + virtual void set_at_to_nil(size_t i) override + { + assert(nullable() && (i < this->values.size())); + this->values[i] = nil_value(); + } + + std::string serialize() const override + { + std::ostringstream ss; + for (const FloatOrPercent& v : this->values) { + if (&v != &this->values.front()) + ss << ","; + serialize_single_value(ss, v); + } + return ss.str(); + } + + std::vector vserialize() const override + { + std::vector vv; + vv.reserve(this->values.size()); + for (const FloatOrPercent& v : this->values) { + std::ostringstream ss; + serialize_single_value(ss, v); + vv.push_back(ss.str()); + } + return vv; + } + + bool deserialize(const std::string& str, bool append = false) override + { + if (!append) + this->values.clear(); + std::istringstream is(str); + std::string item_str; + while (std::getline(is, item_str, ',')) { + boost::trim(item_str); + if (item_str == "nil") { + if (NULLABLE) + this->values.push_back(nil_value()); + else + throw ConfigurationError("Deserializing nil into a non-nullable object"); + } else { + bool percent = item_str.find_first_of("%") != std::string::npos; + std::istringstream iss(item_str); + double value; + iss >> value; + this->values.push_back({value, percent}); + } + } + return true; + } + + ConfigOptionFloatsOrPercentsTempl& operator=(const ConfigOption* opt) + { + this->set(opt); + return *this; + } + +protected: + void serialize_single_value(std::ostringstream& ss, const FloatOrPercent& v) const + { + if (std::isfinite(v.value)) { + ss << v.value; + if (v.percent) + ss << "%"; + } else if (std::isnan(v.value)) { + if (NULLABLE) + ss << "nil"; + else + throw ConfigurationError("Serializing NaN"); + } else + throw ConfigurationError("Serializing invalid number"); + } + static bool vectors_equal(const std::vector& v1, const std::vector& v2) + { + if (NULLABLE) { + if (v1.size() != v2.size()) + return false; + for (auto it1 = v1.begin(), it2 = v2.begin(); it1 != v1.end(); ++it1, ++it2) + if (!((std::isnan(it1->value) && std::isnan(it2->value)) || *it1 == *it2)) + return false; + return true; + } else + // Not supporting nullable values, the default vector compare is cheaper. + return v1 == v2; + } + static bool vectors_lower(const std::vector& v1, const std::vector& v2) + { + if (NULLABLE) { + for (auto it1 = v1.begin(), it2 = v2.begin(); it1 != v1.end() && it2 != v2.end(); ++it1, ++it2) { + auto null1 = int(std::isnan(it1->value)); + auto null2 = int(std::isnan(it2->value)); + return (null1 < null2) || (null1 == null2 && *it1 < *it2); + } + return v1.size() < v2.size(); + } else + // Not supporting nullable values, the default vector compare is cheaper. + return v1 < v2; + } + +private: + friend class cereal::access; + template void serialize(Archive& ar) { ar(cereal::base_class>(this)); } +}; + +using ConfigOptionFloatsOrPercents = ConfigOptionFloatsOrPercentsTempl; +using ConfigOptionFloatsOrPercentsNullable = ConfigOptionFloatsOrPercentsTempl; + +class ConfigOptionPoint : public ConfigOptionSingle +{ +public: + ConfigOptionPoint() : ConfigOptionSingle(Vec2d(0, 0)) {} + explicit ConfigOptionPoint(const Vec2d& value) : ConfigOptionSingle(value) {} + + static ConfigOptionType static_type() { return coPoint; } + ConfigOptionType type() const override { return static_type(); } + ConfigOption* clone() const override { return new ConfigOptionPoint(*this); } + ConfigOptionPoint& operator=(const ConfigOption* opt) + { + this->set(opt); + return *this; + } + bool operator==(const ConfigOptionPoint& rhs) const throw() { return this->value == rhs.value; } + bool operator<(const ConfigOptionPoint& rhs) const throw() { return this->value < rhs.value; } + + std::string serialize() const override + { + std::ostringstream ss; + ss << this->value(0); + ss << ","; + ss << this->value(1); + return ss.str(); + } + + bool deserialize(const std::string& str, bool append = false) override + { + UNUSED(append); + char dummy; + return sscanf(str.data(), " %lf , %lf %c", &this->value(0), &this->value(1), &dummy) == 2 || + sscanf(str.data(), " %lf x %lf %c", &this->value(0), &this->value(1), &dummy) == 2; + } + +private: + friend class cereal::access; + template void serialize(Archive& ar) { ar(cereal::base_class>(this)); } +}; + +class ConfigOptionPoints : public ConfigOptionVector +{ +public: + ConfigOptionPoints() : ConfigOptionVector() {} + explicit ConfigOptionPoints(size_t n, const Vec2d& value) : ConfigOptionVector(n, value) {} + explicit ConfigOptionPoints(std::initializer_list il) : ConfigOptionVector(std::move(il)) {} + explicit ConfigOptionPoints(const std::vector& values) : ConfigOptionVector(values) {} + + static ConfigOptionType static_type() { return coPoints; } + ConfigOptionType type() const override { return static_type(); } + ConfigOption* clone() const override { return new ConfigOptionPoints(*this); } + ConfigOptionPoints& operator=(const ConfigOption* opt) + { + this->set(opt); + return *this; + } + bool operator==(const ConfigOptionPoints& rhs) const throw() { return this->values == rhs.values; } + bool operator<(const ConfigOptionPoints& rhs) const throw() + { + return std::lexicographical_compare(this->values.begin(), this->values.end(), rhs.values.begin(), rhs.values.end(), + [](const auto& l, const auto& r) { return l < r; }); + } + bool is_nil(size_t) const override { return false; } + + std::string serialize() const override + { + std::ostringstream ss; + for (Pointfs::const_iterator it = this->values.begin(); it != this->values.end(); ++it) { + if (it - this->values.begin() != 0) + ss << ","; + ss << (*it)(0); + ss << "x"; + ss << (*it)(1); + } + return ss.str(); + } + + std::vector vserialize() const override + { + std::vector vv; + for (Pointfs::const_iterator it = this->values.begin(); it != this->values.end(); ++it) { + std::ostringstream ss; + // BBS: add json format + // ss << *it; + ss << (*it)(0); + ss << "x"; + ss << (*it)(1); + vv.push_back(ss.str()); + } + return vv; + } + + bool deserialize(const std::string& str, bool append = false) override + { + if (!append) + this->values.clear(); + std::istringstream is(str); + std::string point_str; + while (std::getline(is, point_str, ',')) { + Vec2d point(Vec2d::Zero()); + std::istringstream iss(point_str); + std::string coord_str; + if (std::getline(iss, coord_str, 'x')) { + std::istringstream(coord_str) >> point(0); + if (std::getline(iss, coord_str, 'x')) { + std::istringstream(coord_str) >> point(1); + } + } + this->values.push_back(point); + } + return true; + } + +private: + friend class cereal::access; + template void save(Archive& archive) const + { + size_t cnt = this->values.size(); + archive(cnt); + archive.saveBinary((const char*) this->values.data(), sizeof(Vec2d) * cnt); + } + template void load(Archive& archive) + { + size_t cnt; + archive(cnt); + this->values.assign(cnt, Vec2d()); + archive.loadBinary((char*) this->values.data(), sizeof(Vec2d) * cnt); + } +}; + +class ConfigOptionPoint3 : public ConfigOptionSingle +{ +public: + ConfigOptionPoint3() : ConfigOptionSingle(Vec3d(0, 0, 0)) {} + explicit ConfigOptionPoint3(const Vec3d& value) : ConfigOptionSingle(value) {} + + static ConfigOptionType static_type() { return coPoint3; } + ConfigOptionType type() const override { return static_type(); } + ConfigOption* clone() const override { return new ConfigOptionPoint3(*this); } + ConfigOptionPoint3& operator=(const ConfigOption* opt) + { + this->set(opt); + return *this; + } + bool operator==(const ConfigOptionPoint3& rhs) const throw() { return this->value == rhs.value; } + bool operator<(const ConfigOptionPoint3& rhs) const throw() + { + return this->value.x() < rhs.value.x() || + (this->value.x() == rhs.value.x() && + (this->value.y() < rhs.value.y() || (this->value.y() == rhs.value.y() && this->value.z() < rhs.value.z()))); + } + + std::string serialize() const override + { + std::ostringstream ss; + ss << this->value(0); + ss << ","; + ss << this->value(1); + ss << ","; + ss << this->value(2); + return ss.str(); + } + + bool deserialize(const std::string& str, bool append = false) override + { + UNUSED(append); + char dummy; + return sscanf(str.data(), " %lf , %lf , %lf %c", &this->value(0), &this->value(1), &this->value(2), &dummy) == 3 || + sscanf(str.data(), " %lf x %lf x %lf %c", &this->value(0), &this->value(1), &this->value(2), &dummy) == 3; + } + +private: + friend class cereal::access; + template void serialize(Archive& ar) { ar(cereal::base_class>(this)); } +}; + +class ConfigOptionPointsGroups : public ConfigOptionVector +{ +public: + ConfigOptionPointsGroups() : ConfigOptionVector() {} + explicit ConfigOptionPointsGroups(std::initializer_list il) : ConfigOptionVector(std::move(il)) {} + explicit ConfigOptionPointsGroups(const std::vector& values) : ConfigOptionVector(values) {} + + static ConfigOptionType static_type() { return coPointsGroups; } + ConfigOptionType type() const override { return static_type(); } + ConfigOption* clone() const override { return new ConfigOptionPointsGroups(*this); } + ConfigOptionPointsGroups& operator=(const ConfigOption* opt) + { + this->set(opt); + return *this; + } + bool operator==(const ConfigOptionPointsGroups& rhs) const throw() { return this->values == rhs.values; } + bool operator==(const ConfigOption& rhs) const override + { + if (rhs.type() != this->type()) + throw ConfigurationError("ConfigOptionPointsGroupsTempl: Comparing incompatible types"); + assert(dynamic_cast*>(&rhs)); + + return this->values == static_cast*>(&rhs)->values; + } + bool nullable() const override { return false; } + bool is_nil(size_t) const override { return false; } + + std::string serialize() const override + { + std::ostringstream ss; + for (auto iter = this->values.begin(); iter != this->values.end(); ++iter) { + if (iter != this->values.begin()) + ss << "#"; + serialize_single_value(ss, *iter); + } + + return ss.str(); + } + + std::vector vserialize() const override + { + std::vector ret; + for (const auto& points : this->values) { + std::ostringstream ss; + serialize_single_value(ss, points); + ret.emplace_back(ss.str()); + } + return ret; + } + + bool deserialize(const std::string& str, bool append = false) override + { + if (!append) + this->values.clear(); + std::istringstream is(str); + std::string group_str; + while (std::getline(is, group_str, '#')) { + Vec2ds group; + std::istringstream iss(group_str); + std::string point_str; + while (std::getline(iss, point_str, ',')) { + Vec2d point(Vec2d::Zero()); + std::istringstream iss(point_str); + std::string coord_str; + if (std::getline(iss, coord_str, 'x')) { + std::istringstream(coord_str) >> point(0); + if (std::getline(iss, coord_str, 'x')) { + std::istringstream(coord_str) >> point(1); + } + } + group.push_back(point); + } + this->values.emplace_back(std::move(group)); + } + return true; + } + std::vector vserialize_single(int idx) const + { + std::vector ret; + assert(idx < this->size()); + for (auto iter = values[idx].begin(); iter != values[idx].end(); ++iter) { + std::ostringstream ss; + ss << (*iter)(0); + ss << "x"; + ss << (*iter)(1); + ret.emplace_back(ss.str()); + } + return ret; + } + +protected: + void serialize_single_value(std::ostringstream& ss, const Vec2ds& v) const + { + for (auto iter = v.begin(); iter != v.end(); ++iter) { + if (iter - v.begin() != 0) + ss << ","; + ss << (*iter)(0); + ss << "x"; + ss << (*iter)(1); + } + } + +private: + friend class cereal::access; + template void serialize(Archive& ar) { ar(cereal::base_class(this)); } +}; + +class ConfigOptionIntsGroups : public ConfigOptionVector> +{ +public: + ConfigOptionIntsGroups() : ConfigOptionVector>() {} + explicit ConfigOptionIntsGroups(std::initializer_list> il) : ConfigOptionVector>(std::move(il)) {} + explicit ConfigOptionIntsGroups(const std::vector>& values) : ConfigOptionVector>(values) {} + + static ConfigOptionType static_type() { return coIntsGroups; } + ConfigOptionType type() const override { return static_type(); } + ConfigOption* clone() const override { return new ConfigOptionIntsGroups(*this); } + ConfigOptionIntsGroups& operator=(const ConfigOption* opt) + { + this->set(opt); + return *this; + } + bool operator==(const ConfigOptionIntsGroups& rhs) const throw() { return this->values == rhs.values; } + bool operator==(const ConfigOption& rhs) const override + { + if (rhs.type() != this->type()) + throw ConfigurationError("ConfigConfigOptionIntsGroups: Comparing incompatible types"); + assert(dynamic_cast>*>(&rhs)); + + return this->values == static_cast>*>(&rhs)->values; + } + bool operator<(const ConfigOptionIntsGroups& rhs) const throw() + { + bool is_lower = true; + for (size_t i = 0; i < values.size(); ++i) { + if (this->values[i] == rhs.values[i]) + continue; + + return (this->values[i] < rhs.values[i]); + } + return is_lower; + } + bool nullable() const override { return false; } + bool is_nil(size_t) const override { return false; } + + std::string serialize() const override + { + std::ostringstream ss; + for (auto iter = this->values.begin(); iter != this->values.end(); ++iter) { + if (iter != this->values.begin()) + ss << "#"; + serialize_single_value(ss, *iter); + } + + return ss.str(); + } + + std::vector vserialize() const override + { + std::vector ret; + for (const auto& value : this->values) { + std::ostringstream ss; + serialize_single_value(ss, value); + ret.emplace_back(ss.str()); + } + return ret; + } + + bool deserialize(const std::string& str, bool append = false) override + { + if (!append) + this->values.clear(); + std::istringstream is(str); + std::string group_str; + while (std::getline(is, group_str, '#')) { + std::vector group_values; + std::istringstream iss(group_str); + std::string value_str; + while (std::getline(iss, value_str, ',')) { + int value; + std::istringstream(value_str) >> value; + group_values.push_back(value); + } + this->values.emplace_back(std::move(group_values)); + } + return true; + } + std::vector vserialize_single(int idx) const + { + std::vector ret; + assert(idx < this->size()); + for (auto iter = values[idx].begin(); iter != values[idx].end(); ++iter) { + std::ostringstream ss; + ss << (*iter); + ret.emplace_back(ss.str()); + } + return ret; + } + +protected: + void serialize_single_value(std::ostringstream& ss, const std::vector& v) const + { + for (auto iter = v.begin(); iter != v.end(); ++iter) { + if (iter - v.begin() != 0) + ss << ","; + ss << (*iter); + } + } + +private: + friend class cereal::access; + template void serialize(Archive& ar) { ar(cereal::base_class(this)); } +}; + +class ConfigOptionBool : public ConfigOptionSingle +{ +public: + ConfigOptionBool() : ConfigOptionSingle(false) {} + explicit ConfigOptionBool(bool _value) : ConfigOptionSingle(_value) {} + + static ConfigOptionType static_type() { return coBool; } + ConfigOptionType type() const override { return static_type(); } + bool getBool() const override { return this->value; } + ConfigOption* clone() const override { return new ConfigOptionBool(*this); } + ConfigOptionBool& operator=(const ConfigOption* opt) + { + this->set(opt); + return *this; + } + bool operator==(const ConfigOptionBool& rhs) const throw() { return this->value == rhs.value; } + bool operator<(const ConfigOptionBool& rhs) const throw() { return int(this->value) < int(rhs.value); } + + std::string serialize() const override { return std::string(this->value ? "1" : "0"); } + + bool deserialize(const std::string& str, bool append = false) override + { + UNUSED(append); + + // Orca: take the first value if input is an array + std::istringstream is(str); + std::string item_str; + if (std::getline(is, item_str, ',')) { + boost::trim(item_str); + + if (item_str == "1") { + this->value = true; + return true; + } + if (item_str == "0") { + this->value = false; + return true; + } + } + + return false; + } + +private: + friend class cereal::access; + template void serialize(Archive& ar) { ar(cereal::base_class>(this)); } +}; + +template class ConfigOptionBoolsTempl : public ConfigOptionVector +{ +public: + ConfigOptionBoolsTempl() : ConfigOptionVector() {} + explicit ConfigOptionBoolsTempl(size_t n, bool value) : ConfigOptionVector(n, (unsigned char) value) {} + explicit ConfigOptionBoolsTempl(std::initializer_list il) + { + values.reserve(il.size()); + for (bool b : il) + values.emplace_back((unsigned char) b); + } + explicit ConfigOptionBoolsTempl(std::initializer_list il) + { + values.reserve(il.size()); + for (unsigned char b : il) + values.emplace_back(b); + } + explicit ConfigOptionBoolsTempl(const std::vector& vec) : ConfigOptionVector(vec) {} + explicit ConfigOptionBoolsTempl(std::vector&& vec) : ConfigOptionVector(std::move(vec)) {} + + static ConfigOptionType static_type() { return coBools; } + ConfigOptionType type() const override { return static_type(); } + ConfigOption* clone() const override { return new ConfigOptionBoolsTempl(*this); } + ConfigOptionBoolsTempl& operator=(const ConfigOption* opt) + { + this->set(opt); + return *this; + } + bool operator==(const ConfigOptionBoolsTempl& rhs) const throw() { return this->values == rhs.values; } + bool operator<(const ConfigOptionBoolsTempl& rhs) const throw() { return this->values < rhs.values; } + // Could a special "nil" value be stored inside the vector, indicating undefined value? + bool nullable() const override { return NULLABLE; } + // Special "nil" value to be stored into the vector if this->supports_nil(). + static unsigned char nil_value() { return std::numeric_limits::max(); } + // A scalar is nil, or all values of a vector are nil. + bool is_nil() const override + { + for (auto v : this->values) + if (v != nil_value()) + return false; + return true; + } + bool is_nil(size_t idx) const override { return this->values[idx] == nil_value(); } + virtual void set_at_to_nil(size_t i) override + { + assert(nullable() && (i < this->values.size())); + this->values[i] = nil_value(); + } + + bool& get_at(size_t i) + { + assert(!this->values.empty()); + return *reinterpret_cast(&((i < this->values.size()) ? this->values[i] : this->values.front())); + } + + // FIXME this smells, the parent class has the method declared returning (unsigned char&). + bool get_at(size_t i) const { return ((i < this->values.size()) ? this->values[i] : this->values.front()) != 0; } + + std::string serialize() const override + { + std::ostringstream ss; + for (const unsigned char& v : this->values) { + if (&v != &this->values.front()) + ss << ","; + this->serialize_single_value(ss, v); + } + return ss.str(); + } + + std::vector vserialize() const override + { + std::vector vv; + for (const unsigned char v : this->values) { + std::ostringstream ss; + this->serialize_single_value(ss, v); + vv.push_back(ss.str()); + } + return vv; + } + + ConfigHelpers::DeserializationResult deserialize_with_substitutions(const std::string& str, + bool append, + ConfigHelpers::DeserializationSubstitution substitution) + { + if (!append) + this->values.clear(); + std::istringstream is(str); + std::string item_str; + bool substituted = false; + while (std::getline(is, item_str, ',')) { + boost::trim(item_str); + unsigned char new_value = 0; + if (item_str == "nil") { + if (NULLABLE) + new_value = nil_value(); + else + throw ConfigurationError("Deserializing nil into a non-nullable object"); + } else if (item_str == "1") { + new_value = true; + } else if (item_str == "0") { + new_value = false; + } else if (substitution != ConfigHelpers::DeserializationSubstitution::Disabled && + ConfigHelpers::looks_like_enum_value(item_str)) { + new_value = ConfigHelpers::enum_looks_like_true_value(item_str) || + substitution == ConfigHelpers::DeserializationSubstitution::DefaultsToTrue; + substituted = true; + } else + return ConfigHelpers::DeserializationResult::Failed; + this->values.push_back(new_value); + } + return substituted ? ConfigHelpers::DeserializationResult::Substituted : ConfigHelpers::DeserializationResult::Loaded; + } + + bool deserialize(const std::string& str, bool append = false) override + { + return this->deserialize_with_substitutions(str, append, ConfigHelpers::DeserializationSubstitution::Disabled) == + ConfigHelpers::DeserializationResult::Loaded; + } + +protected: + void serialize_single_value(std::ostringstream& ss, const unsigned char v) const + { + if (v == nil_value()) { + if (NULLABLE) + ss << "nil"; + else + throw ConfigurationError("Serializing NaN"); + } else + ss << (v ? "1" : "0"); + } + +private: + friend class cereal::access; + template void serialize(Archive& ar) { ar(cereal::base_class>(this)); } +}; + +using ConfigOptionBools = ConfigOptionBoolsTempl; +using ConfigOptionBoolsNullable = ConfigOptionBoolsTempl; + +// Map from an enum integer value to an enum name. +typedef std::vector t_config_enum_names; +// Map from an enum name to an enum integer value. +typedef std::map t_config_enum_values; + +template class ConfigOptionEnum : public ConfigOptionSingle +{ +public: + // by default, use the first value (0) of the T enum type + ConfigOptionEnum() : ConfigOptionSingle(static_cast(0)) {} + explicit ConfigOptionEnum(T _value) : ConfigOptionSingle(_value) {} + + static ConfigOptionType static_type() { return coEnum; } + ConfigOptionType type() const override { return static_type(); } + ConfigOption* clone() const override { return new ConfigOptionEnum(*this); } + ConfigOptionEnum& operator=(const ConfigOption* opt) + { + this->set(opt); + return *this; + } + bool operator==(const ConfigOptionEnum& rhs) const throw() { return this->value == rhs.value; } + bool operator<(const ConfigOptionEnum& rhs) const throw() { return int(this->value) < int(rhs.value); } + int getInt() const override { return (int) this->value; } + void setInt(int val) override { this->value = T(val); } + + bool operator==(const ConfigOption& rhs) const override + { + if (rhs.type() != this->type()) + throw ConfigurationError("ConfigOptionEnum: Comparing incompatible types"); + // rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum + return this->value == (T) rhs.getInt(); + } + + void set(const ConfigOption* rhs) override + { + if (rhs->type() != this->type()) + throw ConfigurationError("ConfigOptionEnum: Assigning an incompatible type"); + // rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum + this->value = (T) rhs->getInt(); + } + + std::string serialize() const override + { + const t_config_enum_names& names = ConfigOptionEnum::get_enum_names(); + assert(static_cast(this->value) < int(names.size())); + return names[static_cast(this->value)]; + } + + bool deserialize(const std::string& str, bool append = false) override + { + UNUSED(append); + return from_string(str, this->value); + } + + static bool has(T value) + { + for (const auto& kvp : ConfigOptionEnum::get_enum_values()) + if (kvp.second == value) + return true; + return false; + } + + // Map from an enum name to an enum integer value. + static const t_config_enum_names& get_enum_names(); + // Map from an enum name to an enum integer value. + static const t_config_enum_values& get_enum_values(); + + static bool from_string(const std::string& str, T& value) + { + const t_config_enum_values& enum_keys_map = ConfigOptionEnum::get_enum_values(); + auto it = enum_keys_map.find(str); + if (it == enum_keys_map.end()) + return false; + value = static_cast(it->second); + return true; + } +}; + +// Generic enum configuration value. +// We use this one in DynamicConfig objects when creating a config value object for ConfigOptionType == coEnum. +// In the StaticConfig, it is better to use the specialized ConfigOptionEnum containers. +class ConfigOptionEnumGeneric : public ConfigOptionInt +{ +public: + ConfigOptionEnumGeneric(const t_config_enum_values* keys_map = nullptr) : keys_map(keys_map) {} + explicit ConfigOptionEnumGeneric(const t_config_enum_values* keys_map, int value) : ConfigOptionInt(value), keys_map(keys_map) {} + + const t_config_enum_values* keys_map; + + static ConfigOptionType static_type() { return coEnum; } + ConfigOptionType type() const override { return static_type(); } + ConfigOption* clone() const override { return new ConfigOptionEnumGeneric(*this); } + ConfigOptionEnumGeneric& operator=(const ConfigOption* opt) + { + this->set(opt); + return *this; + } + bool operator==(const ConfigOptionEnumGeneric& rhs) const throw() { return this->value == rhs.value; } + bool operator<(const ConfigOptionEnumGeneric& rhs) const throw() { return this->value < rhs.value; } + + bool operator==(const ConfigOption& rhs) const override + { + if (rhs.type() != this->type()) + throw ConfigurationError("ConfigOptionEnumGeneric: Comparing incompatible types"); + // rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum + return this->value == rhs.getInt(); + } + + void set(const ConfigOption* rhs) override + { + if (rhs->type() != this->type()) + throw ConfigurationError("ConfigOptionEnumGeneric: Assigning an incompatible type"); + // rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum + this->value = rhs->getInt(); + } + + std::string serialize() const override + { + for (const auto& kvp : *this->keys_map) + if (kvp.second == this->value) + return kvp.first; + return std::string(); + } + + bool deserialize(const std::string& str, bool append = false) override + { + UNUSED(append); + auto it = this->keys_map->find(str); + if (it == this->keys_map->end()) + return false; + this->value = it->second; + return true; + } + +private: + friend class cereal::access; + template void serialize(Archive& ar) { ar(cereal::base_class(this)); } +}; + +// BBS +template class ConfigOptionEnumsGenericTempl : public ConfigOptionInts +{ +public: + ConfigOptionEnumsGenericTempl(const t_config_enum_values* keys_map = nullptr) : keys_map(keys_map) {} + explicit ConfigOptionEnumsGenericTempl(const t_config_enum_values* keys_map, size_t size, int value) + : ConfigOptionInts(size, value), keys_map(keys_map) + {} + explicit ConfigOptionEnumsGenericTempl(std::initializer_list il) : ConfigOptionInts(std::move(il)), keys_map(keys_map) {} + explicit ConfigOptionEnumsGenericTempl(const std::vector& vec) : ConfigOptionInts(vec) {} + explicit ConfigOptionEnumsGenericTempl(std::vector&& vec) : ConfigOptionInts(std::move(vec)) {} + + const t_config_enum_values* keys_map = nullptr; + + static ConfigOptionType static_type() { return coEnums; } + ConfigOptionType type() const override { return static_type(); } + ConfigOption* clone() const override { return new ConfigOptionEnumsGenericTempl(*this); } + ConfigOptionEnumsGenericTempl& operator=(const ConfigOption* opt) + { + this->set(opt); + return *this; + } + bool operator<(const ConfigOptionInts& rhs) const throw() { return this->values < rhs.values; } + + bool operator==(const ConfigOptionInts& rhs) const + { + if (rhs.type() != this->type()) + throw ConfigurationError("ConfigOptionEnumsGeneric: Comparing incompatible types"); + return this->values == rhs.values; + } + bool nullable() const override { return NULLABLE; } + + void set(const ConfigOption* rhs) override + { + if (rhs->type() != this->type()) + throw ConfigurationError("ConfigOptionEnumGeneric: Assigning an incompatible type"); + // rhs could be of the following type: ConfigOptionEnumsGeneric + this->values = dynamic_cast(rhs)->values; + } + + std::string serialize() const override + { + std::ostringstream ss; + for (const int& v : this->values) { + if (&v != &this->values.front()) + ss << ","; + serialize_single_value(ss, v); + } + return ss.str(); + } + + std::vector vserialize() const override + { + std::vector vv; + vv.reserve(this->values.size()); + for (const int v : this->values) { + std::ostringstream ss; + serialize_single_value(ss, v); + vv.push_back(ss.str()); + } + return vv; + } + + bool deserialize(const std::string& str, bool append = false) override + { + if (!append) + this->values.clear(); + std::istringstream is(str); + std::string item_str; + while (std::getline(is, item_str, ',')) { + boost::trim(item_str); + if (item_str == "nil") { + if (NULLABLE) + this->values.push_back(nil_value()); + else + throw ConfigurationError("Deserializing nil into a non-nullable object"); + } else { auto it = this->keys_map->find(item_str); if (it == this->keys_map->end()) return false; @@ -2161,8 +2296,7 @@ private: ss << "nil"; else throw ConfigurationError("Serializing NaN"); - } - else { + } else { for (const auto& kvp : *this->keys_map) if (kvp.second == v) ss << kvp.first; @@ -2198,188 +2332,292 @@ public: one_string, }; - // Identifier of this option. It is stored here so that it is accessible through the by_serialization_key_ordinal map. - t_config_option_key opt_key; + // Identifier of this option. It is stored here so that it is accessible through the by_serialization_key_ordinal map. + t_config_option_key opt_key; // What type? bool, int, string etc. - ConfigOptionType type = coNone; - // If a type is nullable, then it accepts a "nil" value (scalar) or "nil" values (vector). - bool nullable = false; + ConfigOptionType type = coNone; + // If a type is nullable, then it accepts a "nil" value (scalar) or "nil" values (vector). + bool nullable = false; // Default value of this option. The default value object is owned by ConfigDef, it is released in its destructor. Slic3r::clonable_ptr default_value; - void set_default_value(const ConfigOption* ptr) { this->default_value = Slic3r::clonable_ptr(ptr); } - template const T* get_default_value() const { return static_cast(this->default_value.get()); } + void set_default_value(const ConfigOption* ptr) { this->default_value = Slic3r::clonable_ptr(ptr); } + template const T* get_default_value() const { return static_cast(this->default_value.get()); } // Create an empty option to be used as a base for deserialization of DynamicConfig. - ConfigOption* create_empty_option() const; + ConfigOption* create_empty_option() const; // Create a default option to be inserted into a DynamicConfig. - ConfigOption* create_default_option() const; + ConfigOption* create_default_option() const; - bool is_scalar() const { return (int(this->type) & int(coVectorType)) == 0; } + bool is_scalar() const { return (int(this->type) & int(coVectorType)) == 0; } - template ConfigOption* load_option_from_archive(Archive &archive) const { - if (this->nullable) { - switch (this->type) { - case coFloats: { auto opt = new ConfigOptionFloatsNullable(); archive(*opt); return opt; } - case coInts: { auto opt = new ConfigOptionIntsNullable(); archive(*opt); return opt; } - case coPercents: { auto opt = new ConfigOptionPercentsNullable();archive(*opt); return opt; } - case coBools: { auto opt = new ConfigOptionBoolsNullable(); archive(*opt); return opt; } - case coFloatsOrPercents:{ auto opt = new ConfigOptionFloatsOrPercentsNullable();archive(*opt); return opt; } - default: throw ConfigurationError(std::string("ConfigOptionDef::load_option_from_archive(): Unknown nullable option type for option ") + this->opt_key); - } - } else { - switch (this->type) { - case coFloat: { auto opt = new ConfigOptionFloat(); archive(*opt); return opt; } - case coFloats: { auto opt = new ConfigOptionFloats(); archive(*opt); return opt; } - case coInt: { auto opt = new ConfigOptionInt(); archive(*opt); return opt; } - case coInts: { auto opt = new ConfigOptionInts(); archive(*opt); return opt; } - case coString: { auto opt = new ConfigOptionString(); archive(*opt); return opt; } - case coStrings: { auto opt = new ConfigOptionStrings(); archive(*opt); return opt; } - case coPercent: { auto opt = new ConfigOptionPercent(); archive(*opt); return opt; } - case coPercents: { auto opt = new ConfigOptionPercents(); archive(*opt); return opt; } - case coFloatOrPercent: { auto opt = new ConfigOptionFloatOrPercent(); archive(*opt); return opt; } - case coFloatsOrPercents: { auto opt = new ConfigOptionFloatsOrPercents(); archive(*opt); return opt; } - case coPoint: { auto opt = new ConfigOptionPoint(); archive(*opt); return opt; } - case coPoints: { auto opt = new ConfigOptionPoints(); archive(*opt); return opt; } - case coPoint3: { auto opt = new ConfigOptionPoint3(); archive(*opt); return opt; } - case coBool: { auto opt = new ConfigOptionBool(); archive(*opt); return opt; } - case coBools: { auto opt = new ConfigOptionBools(); archive(*opt); return opt; } - case coEnum: { auto opt = new ConfigOptionEnumGeneric(this->enum_keys_map); archive(*opt); return opt; } + template ConfigOption* load_option_from_archive(Archive& archive) const + { + if (this->nullable) { + switch (this->type) { + case coFloats: { + auto opt = new ConfigOptionFloatsNullable(); + archive(*opt); + return opt; + } + case coInts: { + auto opt = new ConfigOptionIntsNullable(); + archive(*opt); + return opt; + } + case coPercents: { + auto opt = new ConfigOptionPercentsNullable(); + archive(*opt); + return opt; + } + case coBools: { + auto opt = new ConfigOptionBoolsNullable(); + archive(*opt); + return opt; + } + case coFloatsOrPercents: { + auto opt = new ConfigOptionFloatsOrPercentsNullable(); + archive(*opt); + return opt; + } + default: + throw ConfigurationError( + std::string("ConfigOptionDef::load_option_from_archive(): Unknown nullable option type for option ") + this->opt_key); + } + } else { + switch (this->type) { + case coFloat: { + auto opt = new ConfigOptionFloat(); + archive(*opt); + return opt; + } + case coFloats: { + auto opt = new ConfigOptionFloats(); + archive(*opt); + return opt; + } + case coInt: { + auto opt = new ConfigOptionInt(); + archive(*opt); + return opt; + } + case coInts: { + auto opt = new ConfigOptionInts(); + archive(*opt); + return opt; + } + case coString: { + auto opt = new ConfigOptionString(); + archive(*opt); + return opt; + } + case coStrings: { + auto opt = new ConfigOptionStrings(); + archive(*opt); + return opt; + } + case coPercent: { + auto opt = new ConfigOptionPercent(); + archive(*opt); + return opt; + } + case coPercents: { + auto opt = new ConfigOptionPercents(); + archive(*opt); + return opt; + } + case coFloatOrPercent: { + auto opt = new ConfigOptionFloatOrPercent(); + archive(*opt); + return opt; + } + case coFloatsOrPercents: { + auto opt = new ConfigOptionFloatsOrPercents(); + archive(*opt); + return opt; + } + case coPoint: { + auto opt = new ConfigOptionPoint(); + archive(*opt); + return opt; + } + case coPoints: { + auto opt = new ConfigOptionPoints(); + archive(*opt); + return opt; + } + case coPoint3: { + auto opt = new ConfigOptionPoint3(); + archive(*opt); + return opt; + } + case coBool: { + auto opt = new ConfigOptionBool(); + archive(*opt); + return opt; + } + case coBools: { + auto opt = new ConfigOptionBools(); + archive(*opt); + return opt; + } + case coEnum: { + auto opt = new ConfigOptionEnumGeneric(this->enum_keys_map); + archive(*opt); + return opt; + } // BBS - case coEnums: { auto opt = new ConfigOptionEnumsGeneric(this->enum_keys_map); archive(*opt); return opt; } - case coIntsGroups: { auto opt = new ConfigOptionIntsGroups(); archive(*opt); return opt; } - default: throw ConfigurationError(std::string("ConfigOptionDef::load_option_from_archive(): Unknown option type for option ") + this->opt_key); - } - } - } + case coEnums: { + auto opt = new ConfigOptionEnumsGeneric(this->enum_keys_map); + archive(*opt); + return opt; + } + case coIntsGroups: { + auto opt = new ConfigOptionIntsGroups(); + archive(*opt); + return opt; + } + default: + throw ConfigurationError(std::string("ConfigOptionDef::load_option_from_archive(): Unknown option type for option ") + + this->opt_key); + } + } + } - template ConfigOption* save_option_to_archive(Archive &archive, const ConfigOption *opt) const { - if (this->nullable) { - switch (this->type) { - case coFloats: archive(*static_cast(opt)); break; - case coInts: archive(*static_cast(opt)); break; - case coPercents: archive(*static_cast(opt));break; - case coBools: archive(*static_cast(opt)); break; + template ConfigOption* save_option_to_archive(Archive& archive, const ConfigOption* opt) const + { + if (this->nullable) { + switch (this->type) { + case coFloats: archive(*static_cast(opt)); break; + case coInts: archive(*static_cast(opt)); break; + case coPercents: archive(*static_cast(opt)); break; + case coBools: archive(*static_cast(opt)); break; case coFloatsOrPercents: archive(*static_cast(opt)); break; - default: throw ConfigurationError(std::string("ConfigOptionDef::save_option_to_archive(): Unknown nullable option type for option ") + this->opt_key); - } - } else { - switch (this->type) { - case coFloat: archive(*static_cast(opt)); break; - case coFloats: archive(*static_cast(opt)); break; - case coInt: archive(*static_cast(opt)); break; - case coInts: archive(*static_cast(opt)); break; - case coString: archive(*static_cast(opt)); break; - case coStrings: archive(*static_cast(opt)); break; - case coPercent: archive(*static_cast(opt)); break; - case coPercents: archive(*static_cast(opt)); break; - case coFloatOrPercent: archive(*static_cast(opt)); break; - case coFloatsOrPercents: archive(*static_cast(opt)); break; - case coPoint: archive(*static_cast(opt)); break; - case coPoints: archive(*static_cast(opt)); break; - case coPoint3: archive(*static_cast(opt)); break; - case coBool: archive(*static_cast(opt)); break; - case coBools: archive(*static_cast(opt)); break; - case coEnum: archive(*static_cast(opt)); break; + default: + throw ConfigurationError( + std::string("ConfigOptionDef::save_option_to_archive(): Unknown nullable option type for option ") + this->opt_key); + } + } else { + switch (this->type) { + case coFloat: archive(*static_cast(opt)); break; + case coFloats: archive(*static_cast(opt)); break; + case coInt: archive(*static_cast(opt)); break; + case coInts: archive(*static_cast(opt)); break; + case coString: archive(*static_cast(opt)); break; + case coStrings: archive(*static_cast(opt)); break; + case coPercent: archive(*static_cast(opt)); break; + case coPercents: archive(*static_cast(opt)); break; + case coFloatOrPercent: archive(*static_cast(opt)); break; + case coFloatsOrPercents: archive(*static_cast(opt)); break; + case coPoint: archive(*static_cast(opt)); break; + case coPoints: archive(*static_cast(opt)); break; + case coPoint3: archive(*static_cast(opt)); break; + case coBool: archive(*static_cast(opt)); break; + case coBools: archive(*static_cast(opt)); break; + case coEnum: archive(*static_cast(opt)); break; // BBS - case coEnums: archive(*static_cast(opt)); break; - case coIntsGroups: archive(*static_cast(opt)); break; - default: throw ConfigurationError(std::string("ConfigOptionDef::save_option_to_archive(): Unknown option type for option ") + this->opt_key); - } - } - // Make the compiler happy, shut up the warnings. - return nullptr; - } + case coEnums: archive(*static_cast(opt)); break; + case coIntsGroups: archive(*static_cast(opt)); break; + default: + throw ConfigurationError(std::string("ConfigOptionDef::save_option_to_archive(): Unknown option type for option ") + + this->opt_key); + } + } + // Make the compiler happy, shut up the warnings. + return nullptr; + } // Usually empty. // Special values - "i_enum_open", "f_enum_open" to provide combo box for int or float selection, // "select_open" - to open a selection dialog (currently only a serial port selection). - GUIType gui_type { GUIType::undefined }; + GUIType gui_type{GUIType::undefined}; // Usually empty. Otherwise "serialized" or "show_value" // The flags may be combined. // "serialized" - vector valued option is entered in a single edit field. Values are separated by a semicolon. // "show_value" - even if enum_values / enum_labels are set, still display the value, not the enum label. - std::string gui_flags; + std::string gui_flags; // Label of the GUI input field. // In case the GUI input fields are grouped in some views, the label defines a short label of a grouped value, // while full_label contains a label of a stand-alone field. // The full label is shown, when adding an override parameter for an object or a modified object. - std::string label; - std::string full_label; + std::string label; + std::string full_label; // With which printer technology is this configuration valid? - PrinterTechnology printer_technology = ptUnknown; + PrinterTechnology printer_technology = ptUnknown; // Category of a configuration field, from the GUI perspective. // One of: "Layers and Perimeters", "Infill", "Support material", "Speed", "Extruders", "Advanced", "Extrusion Width" - std::string category; + std::string category; // A tooltip text shown in the GUI. - std::string tooltip; + std::string tooltip; // Text right from the input field, usually a unit of measurement. - std::string sidetext; + std::string sidetext; // Format of this parameter on a command line. - std::string cli; - //BBS: add cli command line params - std::string cli_params; + std::string cli; + // BBS: add cli command line params + std::string cli_params; // Set for type == coFloatOrPercent. // It provides a link to a configuration value, of which this option provides a ratio. // For example, // For example outer_wall_speed may be defined as a fraction of inner_wall_speed. - t_config_option_key ratio_over; + t_config_option_key ratio_over; // True for multiline strings. - bool multiline = false; + bool multiline = false; // For text input: If true, the GUI text box spans the complete page width. - bool full_width = false; + bool full_width = false; // For text input: If true, the GUI formats text as code (fixed-width) - bool is_code = false; + bool is_code = false; // Not editable. Currently only used for the display of the number of threads. - bool readonly = false; + bool readonly = false; // Height of a multiline GUI text box. - int height = -1; + int height = -1; // Optional width of an input field. - int width = -1; + int width = -1; // limit of a numeric input. // If not set, the is set to // By setting min=0, only nonnegative input is allowed. - int min = INT_MIN; - int max = INT_MAX; + int min = INT_MIN; + int max = INT_MAX; // To check if it's not a typo and a % is missing - double max_literal = 1; - ConfigOptionMode mode = comSimple; + double max_literal = 1; + ConfigOptionMode mode = comSimple; // Legacy names for this configuration option. // Used when parsing legacy configuration file. - std::vector aliases; + std::vector aliases; // Sometimes a single value may well define multiple values in a "beginner" mode. // Currently used for aliasing "solid_layers" to "top_shell_layers", "bottom_shell_layers". - std::vector shortcut; + std::vector shortcut; // Definition of values / labels for a combo box. // Mostly used for enums (when type == coEnum), but may be used for ints resp. floats, if gui_type is set to "i_enum_open" resp. "f_enum_open". - std::vector enum_values; - std::vector enum_labels; + std::vector enum_values; + std::vector enum_labels; // For enums (when type == coEnum). Maps enum_values to enums. // Initialized by ConfigOptionEnum::get_enum_values() - const t_config_enum_values *enum_keys_map = nullptr; + const t_config_enum_values* enum_keys_map = nullptr; - bool has_enum_value(const std::string &value) const { - for (const std::string &v : enum_values) + bool has_enum_value(const std::string& value) const + { + for (const std::string& v : enum_values) if (v == value) return true; return false; } // 0 is an invalid key. - size_t serialization_key_ordinal = 0; + size_t serialization_key_ordinal = 0; // Returns the alternative CLI arguments for the given option. // If there are no cli arguments defined, use the key and replace underscores with dashes. - std::vector cli_args(const std::string &key) const; + std::vector cli_args(const std::string& key) const; // Assign this key to cli to disable CLI for this option. - static const constexpr char *nocli = "~~~noCLI"; + static const constexpr char* nocli = "~~~noCLI"; }; -inline bool operator<(const ConfigSubstitution &lhs, const ConfigSubstitution &rhs) throw() { - return lhs.opt_def->opt_key < rhs.opt_def->opt_key || - (lhs.opt_def->opt_key == rhs.opt_def->opt_key && lhs.old_value < rhs.old_value); +inline bool operator<(const ConfigSubstitution& lhs, const ConfigSubstitution& rhs) throw() +{ + return lhs.opt_def->opt_key < rhs.opt_def->opt_key || (lhs.opt_def->opt_key == rhs.opt_def->opt_key && lhs.old_value < rhs.old_value); } -inline bool operator==(const ConfigSubstitution &lhs, const ConfigSubstitution &rhs) throw() { +inline bool operator==(const ConfigSubstitution& lhs, const ConfigSubstitution& rhs) throw() +{ return lhs.opt_def == rhs.opt_def && lhs.old_value == rhs.old_value; } @@ -2394,31 +2632,34 @@ typedef std::map t_optiondef_map; class ConfigDef { public: - t_optiondef_map options; - std::map by_serialization_key_ordinal; + t_optiondef_map options; + std::map by_serialization_key_ordinal; - bool has(const t_config_option_key &opt_key) const { return this->options.count(opt_key) > 0; } - const ConfigOptionDef* get(const t_config_option_key &opt_key) const { + bool has(const t_config_option_key& opt_key) const { return this->options.count(opt_key) > 0; } + const ConfigOptionDef* get(const t_config_option_key& opt_key) const + { t_optiondef_map::iterator it = const_cast(this)->options.find(opt_key); return (it == this->options.end()) ? nullptr : &it->second; } - std::vector keys() const { + std::vector keys() const + { std::vector out; out.reserve(options.size()); - for(auto const& kvp : options) + for (auto const& kvp : options) out.push_back(kvp.first); return out; } - bool empty() { return options.empty(); } + bool empty() { return options.empty(); } // Iterate through all of the CLI options and write them to a stream. - std::ostream& print_cli_help( - std::ostream& out, bool show_defaults, - std::function filter = [](const ConfigOptionDef &){ return true; }) const; + std::ostream& print_cli_help( + std::ostream& out, bool show_defaults, std::function filter = [](const ConfigOptionDef&) { + return true; + }) const; protected: - ConfigOptionDef* add(const t_config_option_key &opt_key, ConfigOptionType type); - ConfigOptionDef* add_nullable(const t_config_option_key &opt_key, ConfigOptionType type); + ConfigOptionDef* add(const t_config_option_key& opt_key, ConfigOptionType type); + ConfigOptionDef* add_nullable(const t_config_option_key& opt_key, ConfigOptionType type); }; // A pure interface to resolving ConfigOptions. @@ -2431,20 +2672,19 @@ public: virtual ~ConfigOptionResolver() {} // Find a ConfigOption instance for a given name. - virtual const ConfigOption* optptr(const t_config_option_key &opt_key) const = 0; + virtual const ConfigOption* optptr(const t_config_option_key& opt_key) const = 0; - bool has(const t_config_option_key &opt_key) const { return this->optptr(opt_key) != nullptr; } + bool has(const t_config_option_key& opt_key) const { return this->optptr(opt_key) != nullptr; } - const ConfigOption* option(const t_config_option_key &opt_key) const { return this->optptr(opt_key); } + const ConfigOption* option(const t_config_option_key& opt_key) const { return this->optptr(opt_key); } - template - const TYPE* option(const t_config_option_key& opt_key) const + template const TYPE* option(const t_config_option_key& opt_key) const { const ConfigOption* opt = this->optptr(opt_key); return (opt == nullptr || opt->type() != TYPE::static_type()) ? nullptr : static_cast(opt); } - const ConfigOption* option_throw(const t_config_option_key& opt_key) const + const ConfigOption* option_throw(const t_config_option_key& opt_key) const { const ConfigOption* opt = this->optptr(opt_key); if (opt == nullptr) @@ -2452,8 +2692,7 @@ public: return opt; } - template - const TYPE* option_throw(const t_config_option_key& opt_key) const + template const TYPE* option_throw(const t_config_option_key& opt_key) const { const ConfigOption* opt = this->option_throw(opt_key); if (opt->type() != TYPE::static_type()) @@ -2462,8 +2701,6 @@ public: } }; - - // An abstract configuration store. class ConfigBase : public ConfigOptionResolver { @@ -2472,57 +2709,54 @@ public: // The configuration definition is static: It does not carry the actual configuration values, // but it carries the defaults of the configuration values. - ConfigBase() = default; + ConfigBase() = default; ~ConfigBase() override = default; // Virtual overridables: public: // Static configuration definition. Any value stored into this ConfigBase shall have its definition here. - virtual const ConfigDef* def() const = 0; + virtual const ConfigDef* def() const = 0; // Find ando/or create a ConfigOption instance for a given name. using ConfigOptionResolver::optptr; - virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) = 0; + virtual ConfigOption* optptr(const t_config_option_key& opt_key, bool create = false) = 0; // Collect names of all configuration values maintained by this configuration store. - virtual t_config_option_keys keys() const = 0; + virtual t_config_option_keys keys() const = 0; protected: // Verify whether the opt_key has not been obsoleted or renamed. // 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(). // handle_legacy() is called internally by set_deserialize(). - virtual void handle_legacy(t_config_option_key &/*opt_key*/, std::string &/*value*/) const {} + virtual void handle_legacy(t_config_option_key& /*opt_key*/, std::string& /*value*/) const {} // Called after a config is loaded as a whole. // Perform composite conversions, for example merging multiple keys into one key. // For conversion of single options, the handle_legacy() method above is called. - virtual void handle_legacy_composite() {} + virtual void handle_legacy_composite() {} public: - using ConfigOptionResolver::option; - using ConfigOptionResolver::option_throw; + using ConfigOptionResolver::option; + using ConfigOptionResolver::option_throw; // Non-virtual methods: - ConfigOption* option(const t_config_option_key &opt_key, bool create = false) - { return this->optptr(opt_key, create); } + ConfigOption* option(const t_config_option_key& opt_key, bool create = false) { return this->optptr(opt_key, create); } - template - TYPE* option(const t_config_option_key &opt_key, bool create = false) + template TYPE* option(const t_config_option_key& opt_key, bool create = false) { - ConfigOption *opt = this->optptr(opt_key, create); + ConfigOption* opt = this->optptr(opt_key, create); return (opt == nullptr || opt->type() != TYPE::static_type()) ? nullptr : static_cast(opt); } - ConfigOption* option_throw(const t_config_option_key &opt_key, bool create = false) + ConfigOption* option_throw(const t_config_option_key& opt_key, bool create = false) { - ConfigOption *opt = this->optptr(opt_key, create); + ConfigOption* opt = this->optptr(opt_key, create); if (opt == nullptr) throw UnknownOptionException(opt_key); return opt; } - template - TYPE* option_throw(const t_config_option_key &opt_key, bool create = false) + template TYPE* option_throw(const t_config_option_key& opt_key, bool create = false) { - ConfigOption *opt = this->option_throw(opt_key, create); + ConfigOption* opt = this->option_throw(opt_key, create); if (opt->type() != TYPE::static_type()) throw BadOptionTypeException("Conversion to a wrong type"); return static_cast(opt); @@ -2531,89 +2765,141 @@ public: // Apply all keys of other ConfigBase defined by this->def() to this ConfigBase. // An UnknownOptionException is thrown in case some option keys of other are not defined by this->def(), // or this ConfigBase is of a StaticConfig type and it does not support some of the keys, and ignore_nonexistent is not set. - void apply(const ConfigBase &other, bool ignore_nonexistent = false) { this->apply_only(other, other.keys(), ignore_nonexistent); } + void apply(const ConfigBase& other, bool ignore_nonexistent = false) { this->apply_only(other, other.keys(), ignore_nonexistent); } // Apply explicitely enumerated keys of other ConfigBase defined by this->def() to this ConfigBase. // An UnknownOptionException is thrown in case some option keys are not defined by this->def(), // or this ConfigBase is of a StaticConfig type and it does not support some of the keys, and ignore_nonexistent is not set. - void apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent = false); + void apply_only(const ConfigBase& other, const t_config_option_keys& keys, bool ignore_nonexistent = false); // Are the two configs equal? Ignoring options not present in both configs. - //BBS: add skipped_keys logic - bool equals(const ConfigBase &other, const std::set* skipped_keys = nullptr) const; + // BBS: add skipped_keys logic + bool equals(const ConfigBase& other, const std::set* skipped_keys = nullptr) const; // Returns options differing in the two configs, ignoring options not present in both configs. - t_config_option_keys diff(const ConfigBase &other) const; + t_config_option_keys diff(const ConfigBase& other) const; // Returns options being equal in the two configs, ignoring options not present in both configs. - t_config_option_keys equal(const ConfigBase &other) const; - std::string opt_serialize(const t_config_option_key &opt_key) const; + t_config_option_keys equal(const ConfigBase& other) const; + std::string opt_serialize(const t_config_option_key& opt_key) const; // Set a value. Convert numeric types using a C style implicit conversion / promotion model. // Throw if option is not avaiable and create is not enabled, // or if the conversion is not possible. // Conversion to string is always possible. - void set(const std::string &opt_key, bool value, bool create = false) - { this->option_throw(opt_key, create)->value = value; } - void set(const std::string &opt_key, int value, bool create = false); - void set(const std::string &opt_key, double value, bool create = false); - void set(const std::string &opt_key, const char *value, bool create = false) - { this->option_throw(opt_key, create)->value = value; } - void set(const std::string &opt_key, const std::string &value, bool create = false) - { this->option_throw(opt_key, create)->value = value; } + void set(const std::string& opt_key, bool value, bool create = false) + { + this->option_throw(opt_key, create)->value = value; + } + void set(const std::string& opt_key, int value, bool create = false); + void set(const std::string& opt_key, double value, bool create = false); + void set(const std::string& opt_key, const char* value, bool create = false) + { + this->option_throw(opt_key, create)->value = value; + } + void set(const std::string& opt_key, const std::string& value, bool create = false) + { + this->option_throw(opt_key, create)->value = value; + } // Set a configuration value from a string, it will call an overridable handle_legacy() // to resolve renamed and removed configuration keys. - bool set_deserialize_nothrow(const t_config_option_key &opt_key_src, const std::string &value_src, ConfigSubstitutionContext& substitutions, bool append = false); - // May throw BadOptionTypeException() if the operation fails. - void set_deserialize(const t_config_option_key &opt_key, const std::string &str, ConfigSubstitutionContext& config_substitutions, bool append = false); - void set_deserialize_strict(const t_config_option_key &opt_key, const std::string &str, bool append = false) - { ConfigSubstitutionContext ctxt{ ForwardCompatibilitySubstitutionRule::Disable }; this->set_deserialize(opt_key, str, ctxt, append); } - struct SetDeserializeItem { - SetDeserializeItem(const char *opt_key, const char *opt_value, bool append = false) : opt_key(opt_key), opt_value(opt_value), append(append) {} - SetDeserializeItem(const std::string &opt_key, const std::string &opt_value, bool append = false) : opt_key(opt_key), opt_value(opt_value), append(append) {} - SetDeserializeItem(const char *opt_key, const bool value, bool append = false) : opt_key(opt_key), opt_value(value ? "1" : "0"), append(append) {} - SetDeserializeItem(const std::string &opt_key, const bool value, bool append = false) : opt_key(opt_key), opt_value(value ? "1" : "0"), append(append) {} - SetDeserializeItem(const char *opt_key, const int value, bool append = false) : opt_key(opt_key), opt_value(std::to_string(value)), append(append) {} - SetDeserializeItem(const std::string &opt_key, const int value, bool append = false) : opt_key(opt_key), opt_value(std::to_string(value)), append(append) {} - SetDeserializeItem(const char *opt_key, const float value, bool append = false) : opt_key(opt_key), opt_value(float_to_string_decimal_point(value)), append(append) {} - SetDeserializeItem(const std::string &opt_key, const float value, bool append = false) : opt_key(opt_key), opt_value(float_to_string_decimal_point(value)), append(append) {} - SetDeserializeItem(const char *opt_key, const double value, bool append = false) : opt_key(opt_key), opt_value(float_to_string_decimal_point(value)), append(append) {} - SetDeserializeItem(const std::string &opt_key, const double value, bool append = false) : opt_key(opt_key), opt_value(float_to_string_decimal_point(value)), append(append) {} - std::string opt_key; std::string opt_value; bool append = false; + bool set_deserialize_nothrow(const t_config_option_key& opt_key_src, + const std::string& value_src, + ConfigSubstitutionContext& substitutions, + bool append = false); + // May throw BadOptionTypeException() if the operation fails. + void set_deserialize(const t_config_option_key& opt_key, + const std::string& str, + ConfigSubstitutionContext& config_substitutions, + bool append = false); + void set_deserialize_strict(const t_config_option_key& opt_key, const std::string& str, bool append = false) + { + ConfigSubstitutionContext ctxt{ForwardCompatibilitySubstitutionRule::Disable}; + this->set_deserialize(opt_key, str, ctxt, append); + } + struct SetDeserializeItem + { + SetDeserializeItem(const char* opt_key, const char* opt_value, bool append = false) + : opt_key(opt_key), opt_value(opt_value), append(append) + {} + SetDeserializeItem(const std::string& opt_key, const std::string& opt_value, bool append = false) + : opt_key(opt_key), opt_value(opt_value), append(append) + {} + SetDeserializeItem(const char* opt_key, const bool value, bool append = false) + : opt_key(opt_key), opt_value(value ? "1" : "0"), append(append) + {} + SetDeserializeItem(const std::string& opt_key, const bool value, bool append = false) + : opt_key(opt_key), opt_value(value ? "1" : "0"), append(append) + {} + SetDeserializeItem(const char* opt_key, const int value, bool append = false) + : opt_key(opt_key), opt_value(std::to_string(value)), append(append) + {} + SetDeserializeItem(const std::string& opt_key, const int value, bool append = false) + : opt_key(opt_key), opt_value(std::to_string(value)), append(append) + {} + SetDeserializeItem(const char* opt_key, const float value, bool append = false) + : opt_key(opt_key), opt_value(float_to_string_decimal_point(value)), append(append) + {} + SetDeserializeItem(const std::string& opt_key, const float value, bool append = false) + : opt_key(opt_key), opt_value(float_to_string_decimal_point(value)), append(append) + {} + SetDeserializeItem(const char* opt_key, const double value, bool append = false) + : opt_key(opt_key), opt_value(float_to_string_decimal_point(value)), append(append) + {} + SetDeserializeItem(const std::string& opt_key, const double value, bool append = false) + : opt_key(opt_key), opt_value(float_to_string_decimal_point(value)), append(append) + {} + std::string opt_key; + std::string opt_value; + bool append = false; }; - // May throw BadOptionTypeException() if the operation fails. + // May throw BadOptionTypeException() if the operation fails. void set_deserialize(std::initializer_list items, ConfigSubstitutionContext& substitutions); void set_deserialize_strict(std::initializer_list items) - { ConfigSubstitutionContext ctxt{ ForwardCompatibilitySubstitutionRule::Disable }; this->set_deserialize(items, ctxt); } + { + ConfigSubstitutionContext ctxt{ForwardCompatibilitySubstitutionRule::Disable}; + this->set_deserialize(items, ctxt); + } - double get_abs_value(const t_config_option_key &opt_key) const; - double get_abs_value(const t_config_option_key &opt_key, double ratio_over) const; - void setenv_() const; - ConfigSubstitutions load(const std::string &file, ForwardCompatibilitySubstitutionRule compatibility_rule); - //BBS support load from ini string - ConfigSubstitutions load_string_map(std::map &key_values, ForwardCompatibilitySubstitutionRule compatibility_rule); - //BBS: add json support - int load_from_json(const std::string &file, ConfigSubstitutionContext& substitutions, bool load_inherits_in_config, std::map& key_values, std::string& reason); - ConfigSubstitutions load_from_json(const std::string &file, ForwardCompatibilitySubstitutionRule compatibility_rule, std::map& key_values, std::string& reason); + double get_abs_value(const t_config_option_key& opt_key) const; + double get_abs_value(const t_config_option_key& opt_key, double ratio_over) const; + void setenv_() const; + ConfigSubstitutions load(const std::string& file, ForwardCompatibilitySubstitutionRule compatibility_rule); + // BBS support load from ini string + ConfigSubstitutions load_string_map(std::map& key_values, + ForwardCompatibilitySubstitutionRule compatibility_rule); + // BBS: add json support + int load_from_json(const std::string& file, + ConfigSubstitutionContext& substitutions, + bool load_inherits_in_config, + std::map& key_values, + std::string& reason); + ConfigSubstitutions load_from_json(const std::string& file, + ForwardCompatibilitySubstitutionRule compatibility_rule, + std::map& key_values, + std::string& reason); - ConfigSubstitutions load_from_ini(const std::string &file, ForwardCompatibilitySubstitutionRule compatibility_rule); - ConfigSubstitutions load_from_ini_string(const std::string &data, ForwardCompatibilitySubstitutionRule compatibility_rule); + ConfigSubstitutions load_from_ini(const std::string& file, ForwardCompatibilitySubstitutionRule compatibility_rule); + ConfigSubstitutions load_from_ini_string(const std::string& data, ForwardCompatibilitySubstitutionRule compatibility_rule); // Loading a "will be one day a legacy format" of configuration stored into 3MF or AMF. // Accepts the same data as load_from_ini_string(), only with each configuration line possibly prefixed with a semicolon (G-code comment). - ConfigSubstitutions load_from_ini_string_commented(std::string &&data, ForwardCompatibilitySubstitutionRule compatibility_rule); - ConfigSubstitutions load_from_gcode_file(const std::string &file, ForwardCompatibilitySubstitutionRule compatibility_rule); - ConfigSubstitutions load(const boost::property_tree::ptree &tree, ForwardCompatibilitySubstitutionRule compatibility_rule); - void save(const std::string &file) const; + ConfigSubstitutions load_from_ini_string_commented(std::string&& data, ForwardCompatibilitySubstitutionRule compatibility_rule); + ConfigSubstitutions load_from_gcode_file(const std::string& file, ForwardCompatibilitySubstitutionRule compatibility_rule); + ConfigSubstitutions load(const boost::property_tree::ptree& tree, ForwardCompatibilitySubstitutionRule compatibility_rule); + void save(const std::string& file) const; - //BBS: add json support - void save_to_json(const std::string &file, const std::string &name, const std::string &from, const std::string &version) const; + // BBS: add json support + void save_to_json(const std::string& file, const std::string& name, const std::string& from, const std::string& version) const; - // Set all the nullable values to nils. + // Set all the nullable values to nils. void null_nullables(); static size_t load_from_gcode_string_legacy(ConfigBase& config, const char* str, ConfigSubstitutionContext& substitutions); private: // Set a configuration value from a string. - bool set_deserialize_raw(const t_config_option_key& opt_key_src, const std::string& value, ConfigSubstitutionContext& substitutions, bool append); + bool set_deserialize_raw(const t_config_option_key& opt_key_src, + const std::string& value, + ConfigSubstitutionContext& substitutions, + bool append); }; // Configuration store with dynamic number of configuration values. @@ -2622,26 +2908,26 @@ class DynamicConfig : public virtual ConfigBase { public: DynamicConfig() = default; - DynamicConfig(const DynamicConfig &rhs) { *this = rhs; } - DynamicConfig(DynamicConfig &&rhs) noexcept : options(std::move(rhs.options)) { rhs.options.clear(); } - explicit DynamicConfig(const ConfigBase &rhs, const t_config_option_keys &keys); - explicit DynamicConfig(const ConfigBase& rhs) : DynamicConfig(rhs, rhs.keys()) {} - virtual ~DynamicConfig() override = default; + DynamicConfig(const DynamicConfig& rhs) { *this = rhs; } + DynamicConfig(DynamicConfig&& rhs) noexcept : options(std::move(rhs.options)) { rhs.options.clear(); } + explicit DynamicConfig(const ConfigBase& rhs, const t_config_option_keys& keys); + explicit DynamicConfig(const ConfigBase& rhs) : DynamicConfig(rhs, rhs.keys()) {} + virtual ~DynamicConfig() override = default; // Copy a content of one DynamicConfig to another DynamicConfig. // If rhs.def() is not null, then it has to be equal to this->def(). - DynamicConfig& operator=(const DynamicConfig &rhs) + DynamicConfig& operator=(const DynamicConfig& rhs) { assert(this->def() == nullptr || this->def() == rhs.def()); this->clear(); - for (const auto &kvp : rhs.options) + for (const auto& kvp : rhs.options) this->options[kvp.first].reset(kvp.second->clone()); return *this; } // Move a content of one DynamicConfig to another DynamicConfig. // If rhs.def() is not null, then it has to be equal to this->def(). - DynamicConfig& operator=(DynamicConfig &&rhs) noexcept + DynamicConfig& operator=(DynamicConfig&& rhs) noexcept { assert(this->def() == nullptr || this->def() == rhs.def()); this->clear(); @@ -2652,10 +2938,10 @@ public: // Add a content of one DynamicConfig to another DynamicConfig. // If rhs.def() is not null, then it has to be equal to this->def(). - DynamicConfig& operator+=(const DynamicConfig &rhs) + DynamicConfig& operator+=(const DynamicConfig& rhs) { assert(this->def() == nullptr || this->def() == rhs.def()); - for (const auto &kvp : rhs.options) { + for (const auto& kvp : rhs.options) { auto it = this->options.find(kvp.first); if (it == this->options.end()) this->options[kvp.first].reset(kvp.second->clone()); @@ -2672,10 +2958,10 @@ public: // Move a content of one DynamicConfig to another DynamicConfig. // If rhs.def() is not null, then it has to be equal to this->def(). - DynamicConfig& operator+=(DynamicConfig &&rhs) + DynamicConfig& operator+=(DynamicConfig&& rhs) { assert(this->def() == nullptr || this->def() == rhs.def()); - for (auto &kvp : rhs.options) { + for (auto& kvp : rhs.options) { auto it = this->options.find(kvp.first); if (it == this->options.end()) { this->options.insert(std::make_pair(kvp.first, std::move(kvp.second))); @@ -2688,20 +2974,14 @@ public: return *this; } - bool operator==(const DynamicConfig &rhs) const; - bool operator!=(const DynamicConfig &rhs) const { return ! (*this == rhs); } + bool operator==(const DynamicConfig& rhs) const; + bool operator!=(const DynamicConfig& rhs) const { return !(*this == rhs); } - void swap(DynamicConfig &other) - { - std::swap(this->options, other.options); - } + void swap(DynamicConfig& other) { std::swap(this->options, other.options); } - void clear() - { - this->options.clear(); - } + void clear() { this->options.clear(); } - bool erase(const t_config_option_key &opt_key) + bool erase(const t_config_option_key& opt_key) { auto it = this->options.find(opt_key); if (it == this->options.end()) @@ -2715,23 +2995,24 @@ public: // Allow DynamicConfig to be instantiated on ints own without a definition. // If the definition is not defined, the method requiring the definition will throw NoDefinitionException. - const ConfigDef* def() const override { return nullptr; } - template T* opt(const t_config_option_key &opt_key, bool create = false) - { return dynamic_cast(this->option(opt_key, create)); } - template const T* opt(const t_config_option_key &opt_key) const - { return dynamic_cast(this->option(opt_key)); } + const ConfigDef* def() const override { return nullptr; } + template T* opt(const t_config_option_key& opt_key, bool create = false) + { + return dynamic_cast(this->option(opt_key, create)); + } + template const T* opt(const t_config_option_key& opt_key) const { return dynamic_cast(this->option(opt_key)); } // Overrides ConfigResolver::optptr(). - const ConfigOption* optptr(const t_config_option_key &opt_key) const override; + const ConfigOption* optptr(const t_config_option_key& opt_key) const override; // Overrides ConfigBase::optptr(). Find ando/or create a ConfigOption instance for a given name. - ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) override; + ConfigOption* optptr(const t_config_option_key& opt_key, bool create = false) override; // Overrides ConfigBase::keys(). Collect names of all configuration values maintained by this configuration store. - t_config_option_keys keys() const override; - bool empty() const { return options.empty(); } + t_config_option_keys keys() const override; + bool empty() const { return options.empty(); } // Set a value for an opt_key. Returns true if the value did not exist yet. // This DynamicConfig will take ownership of opt. // Be careful, as this method does not test the existence of opt_key in this->def(). - bool set_key_value(const std::string &opt_key, ConfigOption *opt) + bool set_key_value(const std::string& opt_key, ConfigOption* opt) { auto it = this->options.find(opt_key); if (it == this->options.end()) { @@ -2744,56 +3025,88 @@ public: } // Are the two configs equal? Ignoring options not present in both configs. - //BBS: add skipped_keys logic - bool equals(const DynamicConfig &other, const std::set* skipped_keys = nullptr) const; + // BBS: add skipped_keys logic + bool equals(const DynamicConfig& other, const std::set* skipped_keys = nullptr) const; // Returns options differing in the two configs, ignoring options not present in both configs. - t_config_option_keys diff(const DynamicConfig &other) const; + t_config_option_keys diff(const DynamicConfig& other) const; // Returns options being equal in the two configs, ignoring options not present in both configs. - t_config_option_keys equal(const DynamicConfig &other) const; + t_config_option_keys equal(const DynamicConfig& other) const; - std::string& opt_string(const t_config_option_key &opt_key, bool create = false) { return this->option(opt_key, create)->value; } - const std::string& opt_string(const t_config_option_key &opt_key) const { return const_cast(this)->opt_string(opt_key); } - std::string& opt_string(const t_config_option_key &opt_key, unsigned int idx) { return this->option(opt_key)->get_at(idx); } - const std::string& opt_string(const t_config_option_key &opt_key, unsigned int idx) const { return const_cast(this)->opt_string(opt_key, idx); } + std::string& opt_string(const t_config_option_key& opt_key, bool create = false) + { + return this->option(opt_key, create)->value; + } + const std::string& opt_string(const t_config_option_key& opt_key) const + { + return const_cast(this)->opt_string(opt_key); + } + std::string& opt_string(const t_config_option_key& opt_key, unsigned int idx) + { + return this->option(opt_key)->get_at(idx); + } + const std::string& opt_string(const t_config_option_key& opt_key, unsigned int idx) const + { + return const_cast(this)->opt_string(opt_key, idx); + } - double& opt_float(const t_config_option_key &opt_key) { return this->option(opt_key)->value; } - const double& opt_float(const t_config_option_key &opt_key) const { return dynamic_cast(this->option(opt_key))->value; } - double& opt_float(const t_config_option_key &opt_key, unsigned int idx) { return this->option(opt_key)->get_at(idx); } - const double& opt_float(const t_config_option_key &opt_key, unsigned int idx) const { return dynamic_cast(this->option(opt_key))->get_at(idx); } + double& opt_float(const t_config_option_key& opt_key) { return this->option(opt_key)->value; } + const double& opt_float(const t_config_option_key& opt_key) const + { + return dynamic_cast(this->option(opt_key))->value; + } + double& opt_float(const t_config_option_key& opt_key, unsigned int idx) + { + return this->option(opt_key)->get_at(idx); + } + const double& opt_float(const t_config_option_key& opt_key, unsigned int idx) const + { + return dynamic_cast(this->option(opt_key))->get_at(idx); + } - int& opt_int(const t_config_option_key &opt_key) { return this->option(opt_key)->value; } - int opt_int(const t_config_option_key &opt_key) const { return dynamic_cast(this->option(opt_key))->value; } - int& opt_int(const t_config_option_key &opt_key, unsigned int idx) { return this->option(opt_key)->get_at(idx); } - int opt_int(const t_config_option_key &opt_key, unsigned int idx) const { return dynamic_cast(this->option(opt_key))->get_at(idx); } + int& opt_int(const t_config_option_key& opt_key) { return this->option(opt_key)->value; } + int opt_int(const t_config_option_key& opt_key) const { return dynamic_cast(this->option(opt_key))->value; } + int& opt_int(const t_config_option_key& opt_key, unsigned int idx) { return this->option(opt_key)->get_at(idx); } + int opt_int(const t_config_option_key& opt_key, unsigned int idx) const + { + return dynamic_cast(this->option(opt_key))->get_at(idx); + } - // In ConfigManipulation::toggle_print_fff_options, it is called on option with type ConfigOptionEnumGeneric* and also ConfigOptionEnum*. - // Thus the virtual method getInt() is used to retrieve the enum value. - template - ENUM opt_enum(const t_config_option_key &opt_key) const { return static_cast(this->option(opt_key)->getInt()); } + // In ConfigManipulation::toggle_print_fff_options, it is called on option with type ConfigOptionEnumGeneric* and also + // ConfigOptionEnum*. Thus the virtual method getInt() is used to retrieve the enum value. + template ENUM opt_enum(const t_config_option_key& opt_key) const + { + return static_cast(this->option(opt_key)->getInt()); + } // BBS - int opt_enum(const t_config_option_key &opt_key, unsigned int idx) const { return dynamic_cast(this->option(opt_key))->get_at(idx); } + int opt_enum(const t_config_option_key& opt_key, unsigned int idx) const + { + return dynamic_cast(this->option(opt_key))->get_at(idx); + } - bool opt_bool(const t_config_option_key &opt_key) const { return this->option(opt_key)->value != 0; } - bool opt_bool(const t_config_option_key &opt_key, unsigned int idx) const { return this->option(opt_key)->get_at(idx) != 0; } + bool opt_bool(const t_config_option_key& opt_key) const { return this->option(opt_key)->value != 0; } + bool opt_bool(const t_config_option_key& opt_key, unsigned int idx) const + { + return this->option(opt_key)->get_at(idx) != 0; + } // Command line processing - bool read_cli(int argc, const char* const argv[], t_config_option_keys* extra, t_config_option_keys* keys = nullptr); + bool read_cli(int argc, const char* const argv[], t_config_option_keys* extra, t_config_option_keys* keys = nullptr); std::map>::const_iterator cbegin() const { return options.cbegin(); } - std::map>::const_iterator cend() const { return options.cend(); } - size_t size() const { return options.size(); } + std::map>::const_iterator cend() const { return options.cend(); } + size_t size() const { return options.size(); } /** * @brief Detailed information about the difference found for a single key. */ - struct KeyDifference { + struct KeyDifference + { std::optional left_value; std::optional right_value; - bool is_missing_key() const { - return !left_value.has_value() || !right_value.has_value(); - } - bool is_different_value() const { + bool is_missing_key() const { return !left_value.has_value() || !right_value.has_value(); } + bool is_different_value() const + { return left_value.has_value() && right_value.has_value() && (left_value.value() != right_value.value()); } }; @@ -2801,12 +3114,11 @@ public: /** * @brief The full report object containing all detected differences. */ - struct DynamicConfigDifference { + struct DynamicConfigDifference + { std::map differences; - bool is_different() const { - return !differences.empty(); - } + bool is_different() const { return !differences.empty(); } }; /** @@ -2820,8 +3132,8 @@ public: private: std::map> options; - friend class cereal::access; - template void serialize(Archive &ar) { ar(options); } + friend class cereal::access; + template void serialize(Archive& ar) { ar(options); } }; std::ostream& operator<<(std::ostream& os, const DynamicConfig::DynamicConfigDifference& diff); @@ -2842,6 +3154,6 @@ protected: void set_defaults(); }; -} +} // namespace Slic3r #endif