diff options
author | piegames <git@piegames.de> | 2024-08-18 14:43:12 +0200 |
---|---|---|
committer | piegames <git@piegames.de> | 2024-08-18 16:56:49 +0000 |
commit | 007211e7a27a512cb343060e8b363c9f66ef67af (patch) | |
tree | f5d127d61e182049e2c1534d1ded45bc2ef265f3 /src/libutil | |
parent | 7506d680ac540f39944c2a9f573900c5b1e4a023 (diff) |
libutil: Optimize feature checks
Instead of doing a linear search on an std::set, we use a bitset enum.
Change-Id: Ide537f6cffdd16d06e59aaeb2e4ac0acb6493421
Diffstat (limited to 'src/libutil')
-rw-r--r-- | src/libutil/config-impl.hh | 12 | ||||
-rw-r--r-- | src/libutil/config.cc | 50 | ||||
-rw-r--r-- | src/libutil/config.hh | 5 | ||||
-rw-r--r-- | src/libutil/deprecated-features.cc | 6 | ||||
-rw-r--r-- | src/libutil/deprecated-features.hh | 18 | ||||
-rw-r--r-- | src/libutil/experimental-features.cc | 6 | ||||
-rw-r--r-- | src/libutil/experimental-features.hh | 16 |
7 files changed, 73 insertions, 40 deletions
diff --git a/src/libutil/config-impl.hh b/src/libutil/config-impl.hh index bc88b5504..024018e00 100644 --- a/src/libutil/config-impl.hh +++ b/src/libutil/config-impl.hh @@ -30,11 +30,11 @@ template<> struct BaseSetting<StringMap>::trait { static constexpr bool appendable = true; }; -template<> struct BaseSetting<std::set<ExperimentalFeature>>::trait +template<> struct BaseSetting<ExperimentalFeatures>::trait { static constexpr bool appendable = true; }; -template<> struct BaseSetting<std::set<DeprecatedFeature>>::trait +template<> struct BaseSetting<DeprecatedFeatures>::trait { static constexpr bool appendable = true; }; @@ -54,8 +54,8 @@ bool BaseSetting<T>::isAppendable() template<> void BaseSetting<Strings>::appendOrSet(Strings newValue, bool append); template<> void BaseSetting<StringSet>::appendOrSet(StringSet newValue, bool append); template<> void BaseSetting<StringMap>::appendOrSet(StringMap newValue, bool append); -template<> void BaseSetting<std::set<ExperimentalFeature>>::appendOrSet(std::set<ExperimentalFeature> newValue, bool append); -template<> void BaseSetting<std::set<DeprecatedFeature>>::appendOrSet(std::set<DeprecatedFeature> newValue, bool append); +template<> void BaseSetting<ExperimentalFeatures>::appendOrSet(ExperimentalFeatures newValue, bool append); +template<> void BaseSetting<DeprecatedFeatures>::appendOrSet(DeprecatedFeatures newValue, bool append); template<typename T> void BaseSetting<T>::appendOrSet(T newValue, bool append) @@ -120,8 +120,8 @@ DECLARE_CONFIG_SERIALISER(bool) DECLARE_CONFIG_SERIALISER(Strings) DECLARE_CONFIG_SERIALISER(StringSet) DECLARE_CONFIG_SERIALISER(StringMap) -DECLARE_CONFIG_SERIALISER(std::set<ExperimentalFeature>) -DECLARE_CONFIG_SERIALISER(std::set<DeprecatedFeature>) +DECLARE_CONFIG_SERIALISER(ExperimentalFeatures) +DECLARE_CONFIG_SERIALISER(DeprecatedFeatures) template<typename T> T BaseSetting<T>::parse(const std::string & str) const diff --git a/src/libutil/config.cc b/src/libutil/config.cc index 3371e0bb3..3c4f4798b 100644 --- a/src/libutil/config.cc +++ b/src/libutil/config.cc @@ -330,55 +330,61 @@ template<> std::string BaseSetting<StringSet>::to_string() const return concatStringsSep(" ", value); } -template<> std::set<ExperimentalFeature> BaseSetting<std::set<ExperimentalFeature>>::parse(const std::string & str) const +template<> ExperimentalFeatures BaseSetting<ExperimentalFeatures>::parse(const std::string & str) const { - std::set<ExperimentalFeature> res; + ExperimentalFeatures res{}; for (auto & s : tokenizeString<StringSet>(str)) { if (auto thisXpFeature = parseExperimentalFeature(s); thisXpFeature) - res.insert(thisXpFeature.value()); + res = res | thisXpFeature.value(); else warn("unknown experimental feature '%s'", s); } return res; } -template<> void BaseSetting<std::set<ExperimentalFeature>>::appendOrSet(std::set<ExperimentalFeature> newValue, bool append) +template<> void BaseSetting<ExperimentalFeatures>::appendOrSet(ExperimentalFeatures newValue, bool append) { - if (!append) value.clear(); - value.insert(std::make_move_iterator(newValue.begin()), std::make_move_iterator(newValue.end())); + if (append) + value = value | newValue; + else + value = newValue; } -template<> std::string BaseSetting<std::set<ExperimentalFeature>>::to_string() const +template<> std::string BaseSetting<ExperimentalFeatures>::to_string() const { StringSet stringifiedXpFeatures; - for (const auto & feature : value) - stringifiedXpFeatures.insert(std::string(showExperimentalFeature(feature))); + for (size_t tag = 0; tag < sizeof(ExperimentalFeatures) * CHAR_BIT; tag++) + if ((value & ExperimentalFeature(tag)) != ExperimentalFeatures{}) + stringifiedXpFeatures.insert(std::string(showExperimentalFeature(ExperimentalFeature(tag)))); return concatStringsSep(" ", stringifiedXpFeatures); } -template<> std::set<DeprecatedFeature> BaseSetting<std::set<DeprecatedFeature>>::parse(const std::string & str) const +template<> DeprecatedFeatures BaseSetting<DeprecatedFeatures>::parse(const std::string & str) const { - std::set<DeprecatedFeature> res; + DeprecatedFeatures res{}; for (auto & s : tokenizeString<StringSet>(str)) { if (auto thisDpFeature = parseDeprecatedFeature(s); thisDpFeature) - res.insert(thisDpFeature.value()); + res = res | thisDpFeature.value(); else warn("unknown deprecated feature '%s'", s); } return res; } -template<> void BaseSetting<std::set<DeprecatedFeature>>::appendOrSet(std::set<DeprecatedFeature> newValue, bool append) +template<> void BaseSetting<DeprecatedFeatures>::appendOrSet(DeprecatedFeatures newValue, bool append) { - if (!append) value.clear(); - value.insert(std::make_move_iterator(newValue.begin()), std::make_move_iterator(newValue.end())); + if (append) + value = value | newValue; + else + value = newValue; } -template<> std::string BaseSetting<std::set<DeprecatedFeature>>::to_string() const +template<> std::string BaseSetting<DeprecatedFeatures>::to_string() const { StringSet stringifiedDpFeatures; - for (const auto & feature : value) - stringifiedDpFeatures.insert(std::string(showDeprecatedFeature(feature))); + for (size_t tag = 0; tag < sizeof(DeprecatedFeatures) * CHAR_BIT; tag++) + if ((value & DeprecatedFeature(tag)) != DeprecatedFeatures{}) + stringifiedDpFeatures.insert(std::string(showDeprecatedFeature(DeprecatedFeature(tag)))); return concatStringsSep(" ", stringifiedDpFeatures); } @@ -417,8 +423,8 @@ template class BaseSetting<std::string>; template class BaseSetting<Strings>; template class BaseSetting<StringSet>; template class BaseSetting<StringMap>; -template class BaseSetting<std::set<ExperimentalFeature>>; -template class BaseSetting<std::set<DeprecatedFeature>>; +template class BaseSetting<ExperimentalFeatures>; +template class BaseSetting<DeprecatedFeatures>; static Path parsePath(const AbstractSetting & s, const std::string & str) { @@ -562,7 +568,7 @@ static GlobalConfig::Register rSettings(&experimentalFeatureSettings); bool FeatureSettings::isEnabled(const ExperimentalFeature & feature) const { auto & f = experimentalFeatures.get(); - return std::find(f.begin(), f.end(), feature) != f.end(); + return (f & feature) != ExperimentalFeatures{}; } void FeatureSettings::require(const ExperimentalFeature & feature) const @@ -584,7 +590,7 @@ void FeatureSettings::require(const std::optional<ExperimentalFeature> & feature bool FeatureSettings::isEnabled(const DeprecatedFeature & feature) const { auto & f = deprecatedFeatures.get(); - return std::find(f.begin(), f.end(), feature) != f.end(); + return (f & feature) != DeprecatedFeatures{}; } void FeatureSettings::require(const DeprecatedFeature & feature) const diff --git a/src/libutil/config.hh b/src/libutil/config.hh index 36e42fe63..d1812f47e 100644 --- a/src/libutil/config.hh +++ b/src/libutil/config.hh @@ -444,7 +444,7 @@ extern GlobalConfig globalConfig; struct FeatureSettings : Config { - Setting<std::set<ExperimentalFeature>> experimentalFeatures{ + Setting<ExperimentalFeatures> experimentalFeatures{ this, {}, "experimental-features", R"( Experimental features that are enabled. @@ -484,8 +484,7 @@ struct FeatureSettings : Config { * disabled, and so the function does nothing in that case. */ void require(const std::optional<ExperimentalFeature> &) const; - - Setting<std::set<DeprecatedFeature>> deprecatedFeatures{ + Setting<DeprecatedFeatures> deprecatedFeatures{ this, {}, "deprecated-features", R"( Deprecated features that are allowed. diff --git a/src/libutil/deprecated-features.cc b/src/libutil/deprecated-features.cc index 11b6c42bd..877d69da0 100644 --- a/src/libutil/deprecated-features.cc +++ b/src/libutil/deprecated-features.cc @@ -77,12 +77,12 @@ nlohmann::json documentDeprecatedFeatures() return (nlohmann::json) res; } -std::set<DeprecatedFeature> parseDeprecatedFeatures(const std::set<std::string> & rawFeatures) +DeprecatedFeatures parseDeprecatedFeatures(const std::set<std::string> & rawFeatures) { - std::set<DeprecatedFeature> res; + DeprecatedFeatures res{}; for (auto & rawFeature : rawFeatures) if (auto feature = parseDeprecatedFeature(rawFeature)) - res.insert(*feature); + res = res | *feature; return res; } diff --git a/src/libutil/deprecated-features.hh b/src/libutil/deprecated-features.hh index c00a5d7bd..3776e6c29 100644 --- a/src/libutil/deprecated-features.hh +++ b/src/libutil/deprecated-features.hh @@ -18,9 +18,23 @@ namespace nix { */ enum struct DeprecatedFeature { - UrlLiterals + UrlLiterals, }; +enum struct DeprecatedFeatures {}; + +inline DeprecatedFeatures operator| (DeprecatedFeatures a, DeprecatedFeatures b) { + return static_cast<DeprecatedFeatures>(static_cast<size_t>(a) | static_cast<size_t>(b)); +} + +inline DeprecatedFeatures operator| (DeprecatedFeatures a, DeprecatedFeature b) { + return a | static_cast<DeprecatedFeatures>(1 << static_cast<size_t>(b)); +} + +inline DeprecatedFeatures operator& (DeprecatedFeatures a, DeprecatedFeature b) { + return static_cast<DeprecatedFeatures>(static_cast<size_t>(a) & (1 << static_cast<size_t>(b))); +} + /** * Just because writing `DeprecatedFeature::UrlLiterals` is way too long */ @@ -50,7 +64,7 @@ std::ostream & operator<<( * Parse a set of strings to the corresponding set of deprecated * features, ignoring (but warning for) any unknown feature. */ -std::set<DeprecatedFeature> parseDeprecatedFeatures(const std::set<std::string> &); +DeprecatedFeatures parseDeprecatedFeatures(const std::set<std::string> &); /** * A deprecated feature used for some diff --git a/src/libutil/experimental-features.cc b/src/libutil/experimental-features.cc index 15a18c770..35982c28c 100644 --- a/src/libutil/experimental-features.cc +++ b/src/libutil/experimental-features.cc @@ -293,12 +293,12 @@ nlohmann::json documentExperimentalFeatures() return (nlohmann::json) res; } -std::set<ExperimentalFeature> parseFeatures(const std::set<std::string> & rawFeatures) +ExperimentalFeatures parseFeatures(const std::set<std::string> & rawFeatures) { - std::set<ExperimentalFeature> res; + ExperimentalFeatures res {}; for (auto & rawFeature : rawFeatures) if (auto feature = parseExperimentalFeature(rawFeature)) - res.insert(*feature); + res = res | *feature; return res; } diff --git a/src/libutil/experimental-features.hh b/src/libutil/experimental-features.hh index 121318d23..c45f05d78 100644 --- a/src/libutil/experimental-features.hh +++ b/src/libutil/experimental-features.hh @@ -33,6 +33,20 @@ enum struct ExperimentalFeature ReplAutomation, }; +enum struct ExperimentalFeatures {}; + +inline ExperimentalFeatures operator| (ExperimentalFeatures a, ExperimentalFeatures b) { + return static_cast<ExperimentalFeatures>(static_cast<size_t>(a) | static_cast<size_t>(b)); +} + +inline ExperimentalFeatures operator| (ExperimentalFeatures a, ExperimentalFeature b) { + return a | static_cast<ExperimentalFeatures>(1 << static_cast<size_t>(b)); +} + +inline ExperimentalFeatures operator& (ExperimentalFeatures a, ExperimentalFeature b) { + return static_cast<ExperimentalFeatures>(static_cast<size_t>(a) & (1 << static_cast<size_t>(b))); +} + /** * Just because writing `ExperimentalFeature::CaDerivations` is way too long */ @@ -62,7 +76,7 @@ std::ostream & operator<<( * Parse a set of strings to the corresponding set of experimental * features, ignoring (but warning for) any unknown feature. */ -std::set<ExperimentalFeature> parseFeatures(const std::set<std::string> &); +ExperimentalFeatures parseFeatures(const std::set<std::string> &); /** * An experimental feature was required for some (experimental) |