mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-01 04:41:32 +00:00
perf: speed up G-code export by 7-26% via typed config apply (#16026)
This commit is contained in:
@@ -2702,6 +2702,9 @@ public:
|
|||||||
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.
|
// 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;
|
||||||
|
// Set this config's options on target member by member, when target is of this config's static type or
|
||||||
|
// derives from it, and return true. apply() prefers this to looking every key up by name.
|
||||||
|
virtual bool apply_to(ConfigBase &/*target*/) const { return false; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Verify whether the opt_key has not been obsoleted or renamed.
|
// Verify whether the opt_key has not been obsoleted or renamed.
|
||||||
@@ -2753,7 +2756,8 @@ public:
|
|||||||
// Apply all keys of other ConfigBase defined by this->def() to this ConfigBase.
|
// 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(),
|
// 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.
|
// 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)
|
||||||
|
{ if (! other.apply_to(*this)) this->apply_only(other, other.keys(), ignore_nonexistent); }
|
||||||
// Apply explicitely enumerated keys of other ConfigBase defined by this->def() to this ConfigBase.
|
// 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(),
|
// 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.
|
// or this ConfigBase is of a StaticConfig type and it does not support some of the keys, and ignore_nonexistent is not set.
|
||||||
|
|||||||
@@ -11958,6 +11958,21 @@ PRINT_CONFIG_CACHE_INITIALIZE((
|
|||||||
SLAMaterialConfig, SLAPrintConfig, SLAPrintObjectConfig, SLAPrinterConfig, SLAFullPrintConfig))
|
SLAMaterialConfig, SLAPrintConfig, SLAPrintObjectConfig, SLAPrinterConfig, SLAFullPrintConfig))
|
||||||
static int print_config_static_initialized = print_config_static_initializer();
|
static int print_config_static_initialized = print_config_static_initializer();
|
||||||
|
|
||||||
|
// The same set() calls ConfigBase::apply_only() makes, without looking every key up by name. Out of line so the
|
||||||
|
// option list is expanded for this once, not in every file that includes PrintConfig.hpp.
|
||||||
|
#define PRINT_CONFIG_APPLY_TO_DEFINITION(r, data, CLASS_NAME) \
|
||||||
|
bool CLASS_NAME::apply_to(ConfigBase &target) const \
|
||||||
|
{ \
|
||||||
|
auto *dst = dynamic_cast<CLASS_NAME*>(&target); \
|
||||||
|
if (dst == nullptr) \
|
||||||
|
return false; \
|
||||||
|
visit_option_pairs(*dst, *this, [](const char*, ConfigOption &a, const ConfigOption &b) { a.set(&b); return true; }); \
|
||||||
|
return true; \
|
||||||
|
}
|
||||||
|
BOOST_PP_SEQ_FOR_EACH(PRINT_CONFIG_APPLY_TO_DEFINITION, _, (PrintObjectConfig)(PrintRegionConfig)(MachineEnvelopeConfig)(GCodeConfig)
|
||||||
|
(SLAMaterialConfig)(SLAPrintConfig)(SLAPrintObjectConfig)(SLAPrinterConfig))
|
||||||
|
#undef PRINT_CONFIG_APPLY_TO_DEFINITION
|
||||||
|
|
||||||
//BBS: remove unused command currently
|
//BBS: remove unused command currently
|
||||||
CLIActionsConfigDef::CLIActionsConfigDef()
|
CLIActionsConfigDef::CLIActionsConfigDef()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1033,9 +1033,10 @@ public: \
|
|||||||
|
|
||||||
#define PRINT_CONFIG_CLASS_ELEMENT_DEFINITION(r, data, elem) BOOST_PP_TUPLE_ELEM(0, elem) BOOST_PP_TUPLE_ELEM(1, elem);
|
#define PRINT_CONFIG_CLASS_ELEMENT_DEFINITION(r, data, elem) BOOST_PP_TUPLE_ELEM(0, elem) BOOST_PP_TUPLE_ELEM(1, elem);
|
||||||
#define PRINT_CONFIG_CLASS_ELEMENT_VISIT(r, data, elem) if (! f(BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(1, elem)), this->BOOST_PP_TUPLE_ELEM(1, elem), rhs.BOOST_PP_TUPLE_ELEM(1, elem))) return;
|
#define PRINT_CONFIG_CLASS_ELEMENT_VISIT(r, data, elem) if (! f(BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(1, elem)), this->BOOST_PP_TUPLE_ELEM(1, elem), rhs.BOOST_PP_TUPLE_ELEM(1, elem))) return;
|
||||||
|
#define PRINT_CONFIG_CLASS_ELEMENT_VISIT_SELF(r, data, elem) if (! f(BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(1, elem)), self.BOOST_PP_TUPLE_ELEM(1, elem), rhs.BOOST_PP_TUPLE_ELEM(1, elem))) return;
|
||||||
// Each option list is expanded into the members and again into for_each_option_pair(), which calls
|
// Each option list is expanded into the members and again into for_each_option_pair(), which calls
|
||||||
// f(key, this->option, rhs.option) in declaration order and stops when f returns false. hash(),
|
// f(key, this->option, rhs.option) in declaration order and stops when f returns false. hash(),
|
||||||
// operator==, operator< and initialize() iterate the options through that visitor.
|
// operator==, operator<, initialize() and apply_to() iterate the options through that visitor.
|
||||||
#define PRINT_CONFIG_CLASS_COMMON_BODY(CLASS_NAME) \
|
#define PRINT_CONFIG_CLASS_COMMON_BODY(CLASS_NAME) \
|
||||||
size_t hash() const throw() \
|
size_t hash() const throw() \
|
||||||
{ \
|
{ \
|
||||||
@@ -1067,11 +1068,16 @@ class CLASS_NAME : public StaticPrintConfig { \
|
|||||||
STATIC_PRINT_CONFIG_CACHE(CLASS_NAME) \
|
STATIC_PRINT_CONFIG_CACHE(CLASS_NAME) \
|
||||||
public: \
|
public: \
|
||||||
BOOST_PP_SEQ_FOR_EACH(PRINT_CONFIG_CLASS_ELEMENT_DEFINITION, _, PARAMETER_DEFINITION_SEQ) \
|
BOOST_PP_SEQ_FOR_EACH(PRINT_CONFIG_CLASS_ELEMENT_DEFINITION, _, PARAMETER_DEFINITION_SEQ) \
|
||||||
template<typename F> void for_each_option_pair(const CLASS_NAME &rhs, F &&f) const \
|
template<typename F> void for_each_option_pair(const CLASS_NAME &rhs, F &&f) const { visit_option_pairs(*this, rhs, f); } \
|
||||||
{ \
|
/* Defined in PrintConfig.cpp. */ \
|
||||||
BOOST_PP_SEQ_FOR_EACH(PRINT_CONFIG_CLASS_ELEMENT_VISIT, _, PARAMETER_DEFINITION_SEQ) \
|
bool apply_to(ConfigBase &target) const override; \
|
||||||
} \
|
|
||||||
PRINT_CONFIG_CLASS_COMMON_BODY(CLASS_NAME) \
|
PRINT_CONFIG_CLASS_COMMON_BODY(CLASS_NAME) \
|
||||||
|
private: \
|
||||||
|
/* The one expansion of the option list, for a const self and for apply_to()'s mutable target. */ \
|
||||||
|
template<typename Self, typename F> static void visit_option_pairs(Self &self, const CLASS_NAME &rhs, F &&f) \
|
||||||
|
{ \
|
||||||
|
BOOST_PP_SEQ_FOR_EACH(PRINT_CONFIG_CLASS_ELEMENT_VISIT_SELF, _, PARAMETER_DEFINITION_SEQ) \
|
||||||
|
} \
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PRINT_CONFIG_CLASS_DERIVED_CLASS_LIST_ITEM(r, data, i, elem) BOOST_PP_COMMA_IF(i) public elem
|
#define PRINT_CONFIG_CLASS_DERIVED_CLASS_LIST_ITEM(r, data, i, elem) BOOST_PP_COMMA_IF(i) public elem
|
||||||
@@ -1092,6 +1098,8 @@ class CLASS_NAME : PRINT_CONFIG_CLASS_DERIVED_CLASS_LIST(CLASSES_PARENTS_TUPLE)
|
|||||||
public: \
|
public: \
|
||||||
PARAMETER_DEFINITION \
|
PARAMETER_DEFINITION \
|
||||||
template<typename F> void for_each_option_pair(const CLASS_NAME &rhs, F &&f) const { PARAMETER_VISIT } \
|
template<typename F> void for_each_option_pair(const CLASS_NAME &rhs, F &&f) const { PARAMETER_VISIT } \
|
||||||
|
/* Its parents each apply themselves to a target member by member, so this one keeps the lookup by name. */ \
|
||||||
|
bool apply_to(ConfigBase &/*target*/) const override { return false; } \
|
||||||
size_t hash() const throw() \
|
size_t hash() const throw() \
|
||||||
{ \
|
{ \
|
||||||
size_t seed = 0; \
|
size_t seed = 0; \
|
||||||
@@ -2182,6 +2190,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE0(
|
|||||||
#undef STATIC_PRINT_CONFIG_CACHE_DERIVED
|
#undef STATIC_PRINT_CONFIG_CACHE_DERIVED
|
||||||
#undef PRINT_CONFIG_CLASS_ELEMENT_DEFINITION
|
#undef PRINT_CONFIG_CLASS_ELEMENT_DEFINITION
|
||||||
#undef PRINT_CONFIG_CLASS_ELEMENT_VISIT
|
#undef PRINT_CONFIG_CLASS_ELEMENT_VISIT
|
||||||
|
#undef PRINT_CONFIG_CLASS_ELEMENT_VISIT_SELF
|
||||||
#undef PRINT_CONFIG_CLASS_COMMON_BODY
|
#undef PRINT_CONFIG_CLASS_COMMON_BODY
|
||||||
#undef PRINT_CONFIG_CLASS_DEFINE
|
#undef PRINT_CONFIG_CLASS_DEFINE
|
||||||
#undef PRINT_CONFIG_CLASS_DERIVED_CLASS_LIST
|
#undef PRINT_CONFIG_CLASS_DERIVED_CLASS_LIST
|
||||||
|
|||||||
@@ -1289,3 +1289,73 @@ TEST_CASE("Static print configs compare, order and hash by their option values",
|
|||||||
REQUIRE(c.optptr("gcode_flavor") == &c.gcode_flavor);
|
REQUIRE(c.optptr("gcode_flavor") == &c.gcode_flavor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// Keys whose values differ between two full configs, compared as text so enum names count too.
|
||||||
|
std::vector<std::string> differing_keys(const FullPrintConfig &a, const FullPrintConfig &b)
|
||||||
|
{
|
||||||
|
std::vector<std::string> keys;
|
||||||
|
for (const std::string &key : a.keys())
|
||||||
|
if (a.opt_serialize(key) != b.opt_serialize(key))
|
||||||
|
keys.push_back(key);
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Applies source to one full config member by member and to another key by key, as apply() did before
|
||||||
|
// static configs could apply themselves.
|
||||||
|
template<class Source> void check_member_apply_matches_key_apply(const Source &source)
|
||||||
|
{
|
||||||
|
FullPrintConfig by_member;
|
||||||
|
FullPrintConfig by_key;
|
||||||
|
by_member.apply(source);
|
||||||
|
by_key.apply_only(source, source.keys());
|
||||||
|
CHECK(differing_keys(by_member, by_key).empty());
|
||||||
|
CHECK_FALSE(differing_keys(by_member, FullPrintConfig()).empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
TEST_CASE("A static config applies itself onto a config of its type as a lookup by name would", "[Config]")
|
||||||
|
{
|
||||||
|
SECTION("region config")
|
||||||
|
{
|
||||||
|
PrintRegionConfig region;
|
||||||
|
region.sparse_infill_pattern.value = ipGyroid;
|
||||||
|
region.outer_wall_speed.values = {37.};
|
||||||
|
region.sparse_infill_density.value = 35.;
|
||||||
|
FullPrintConfig full;
|
||||||
|
REQUIRE(region.apply_to(full));
|
||||||
|
check_member_apply_matches_key_apply(region);
|
||||||
|
}
|
||||||
|
SECTION("object config")
|
||||||
|
{
|
||||||
|
PrintObjectConfig object;
|
||||||
|
object.seam_position.value = spRear;
|
||||||
|
object.wall_generator.value = PerimeterGeneratorType::Arachne;
|
||||||
|
object.support_speed.values = {33.};
|
||||||
|
object.enable_support.value = true;
|
||||||
|
FullPrintConfig full;
|
||||||
|
REQUIRE(object.apply_to(full));
|
||||||
|
check_member_apply_matches_key_apply(object);
|
||||||
|
}
|
||||||
|
SECTION("G-code config, whose enum lists carry their names through a keys map")
|
||||||
|
{
|
||||||
|
GCodeConfig gcode;
|
||||||
|
gcode.z_hop_types.values = {int(zhtSpiral)};
|
||||||
|
gcode.retraction_length.values = {1.5};
|
||||||
|
FullPrintConfig full;
|
||||||
|
REQUIRE(gcode.apply_to(full));
|
||||||
|
check_member_apply_matches_key_apply(gcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("A static config applied onto a config of another type falls back to a lookup by name", "[Config]")
|
||||||
|
{
|
||||||
|
PrintRegionConfig region;
|
||||||
|
region.sparse_infill_pattern.value = ipGyroid;
|
||||||
|
DynamicPrintConfig dynamic;
|
||||||
|
REQUIRE_FALSE(region.apply_to(dynamic));
|
||||||
|
dynamic.apply(region);
|
||||||
|
CHECK(dynamic.opt_serialize("sparse_infill_pattern") == "gyroid");
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user