From 781a5d851616cbe59f51a678715033cbd5435c5e Mon Sep 17 00:00:00 2001 From: raistlin7447 Date: Wed, 23 Sep 2026 07:11:14 -0500 Subject: [PATCH] libslic3r: compare preset json keys without the locale Reading one preset file tries a dozen key names against every key in it with boost::iequals, which compares through std::locale(). Constructing that takes a lock the whole process shares in the MSVC runtime, so it is both the bulk of the work in a preset file's parse and the reason two threads cannot do it at once. Comparing the bytes instead takes loading 328 user presets from 129 to 105 ms one at a time, and the same files spread across threads from 132 to 27 ms. The first launch after an update, when the system profiles are parsed from JSON rather than served from their cache, goes through the same function. --- src/libslic3r/Config.cpp | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp index 42d6970ad1..427f6e66c9 100644 --- a/src/libslic3r/Config.cpp +++ b/src/libslic3r/Config.cpp @@ -849,6 +849,19 @@ ConfigSubstitutions ConfigBase::load_from_json(const std::string &file, ForwardC return std::move(substitutions_ctxt.substitutions); } +// Case-insensitive compare of a JSON key against a fixed ASCII one, without +// boost::iequals, whose std::locale() takes a lock the whole process shares in the +// MSVC runtime. +static bool ascii_iequals(const std::string &key, const char *literal) +{ + auto lower = [](char c) { return (c >= 'A' && c <= 'Z') ? char(c - 'A' + 'a') : c; }; + size_t i = 0; + for (; i < key.size() && literal[i] != '\0'; ++ i) + if (lower(key[i]) != lower(literal[i])) + return false; + return i == key.size() && literal[i] == '\0'; +} + 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; @@ -916,44 +929,44 @@ int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContex } //parse the json elements for (auto it = j.begin(); it != j.end(); it++) { - if (boost::iequals(it.key(),BBL_JSON_KEY_VERSION)) { + if (ascii_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)) { + else if (ascii_iequals(it.key(), BBL_JSON_KEY_IS_CUSTOM)) { //skip it } - else if (boost::iequals(it.key(), BBL_JSON_KEY_NAME)) { + else if (ascii_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 (ascii_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 (ascii_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 (ascii_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 (ascii_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 (ascii_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 (ascii_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 (ascii_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 && ascii_iequals(it.key(), BBL_JSON_KEY_INHERITS)) { key_values.emplace(BBL_JSON_KEY_INHERITS, it.value()); } - else if (!load_inherits_to_config && boost::iequals(it.key(), BBL_JSON_KEY_INCLUDES)) { + else if (!load_inherits_to_config && ascii_iequals(it.key(), BBL_JSON_KEY_INCLUDES)) { key_values.emplace(BBL_JSON_KEY_INCLUDES, it.value().dump()); - } else if (boost::iequals(it.key(), ORCA_JSON_KEY_RENAMED_FROM)) { + } else if (ascii_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();