aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpiegames <git@piegames.de>2024-08-18 14:43:12 +0200
committerpiegames <git@piegames.de>2024-08-18 16:56:49 +0000
commit007211e7a27a512cb343060e8b363c9f66ef67af (patch)
treef5d127d61e182049e2c1534d1ded45bc2ef265f3
parent7506d680ac540f39944c2a9f573900c5b1e4a023 (diff)
libutil: Optimize feature checks
Instead of doing a linear search on an std::set, we use a bitset enum. Change-Id: Ide537f6cffdd16d06e59aaeb2e4ac0acb6493421
-rw-r--r--src/libutil/config-impl.hh12
-rw-r--r--src/libutil/config.cc50
-rw-r--r--src/libutil/config.hh5
-rw-r--r--src/libutil/deprecated-features.cc6
-rw-r--r--src/libutil/deprecated-features.hh18
-rw-r--r--src/libutil/experimental-features.cc6
-rw-r--r--src/libutil/experimental-features.hh16
-rw-r--r--src/nix/main.cc9
8 files changed, 77 insertions, 45 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)
diff --git a/src/nix/main.cc b/src/nix/main.cc
index 5356a0d04..e84e4f310 100644
--- a/src/nix/main.cc
+++ b/src/nix/main.cc
@@ -378,11 +378,10 @@ void mainWrapped(int argc, char * * argv)
}
if (argc == 2 && std::string(argv[1]) == "__dump-language") {
- experimentalFeatureSettings.experimentalFeatures = {
- Xp::Flakes,
- Xp::FetchClosure,
- Xp::DynamicDerivations,
- };
+ experimentalFeatureSettings.experimentalFeatures = ExperimentalFeatures{}
+ | Xp::Flakes
+ | Xp::FetchClosure
+ | Xp::DynamicDerivations;
evalSettings.pureEval = false;
EvalState state({}, openStore("dummy://"));
auto res = nlohmann::json::object();