libutil: Optimize feature checks
Instead of doing a linear search on an std::set, we use a bitset enum. Change-Id: Ide537f6cffdd16d06e59aaeb2e4ac0acb6493421
This commit is contained in:
parent
7506d680ac
commit
007211e7a2
8 changed files with 77 additions and 45 deletions
|
@ -30,11 +30,11 @@ template<> struct BaseSetting<StringMap>::trait
|
||||||
{
|
{
|
||||||
static constexpr bool appendable = true;
|
static constexpr bool appendable = true;
|
||||||
};
|
};
|
||||||
template<> struct BaseSetting<std::set<ExperimentalFeature>>::trait
|
template<> struct BaseSetting<ExperimentalFeatures>::trait
|
||||||
{
|
{
|
||||||
static constexpr bool appendable = true;
|
static constexpr bool appendable = true;
|
||||||
};
|
};
|
||||||
template<> struct BaseSetting<std::set<DeprecatedFeature>>::trait
|
template<> struct BaseSetting<DeprecatedFeatures>::trait
|
||||||
{
|
{
|
||||||
static constexpr bool appendable = true;
|
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<Strings>::appendOrSet(Strings newValue, bool append);
|
||||||
template<> void BaseSetting<StringSet>::appendOrSet(StringSet newValue, bool append);
|
template<> void BaseSetting<StringSet>::appendOrSet(StringSet newValue, bool append);
|
||||||
template<> void BaseSetting<StringMap>::appendOrSet(StringMap 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<ExperimentalFeatures>::appendOrSet(ExperimentalFeatures newValue, bool append);
|
||||||
template<> void BaseSetting<std::set<DeprecatedFeature>>::appendOrSet(std::set<DeprecatedFeature> newValue, bool append);
|
template<> void BaseSetting<DeprecatedFeatures>::appendOrSet(DeprecatedFeatures newValue, bool append);
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void BaseSetting<T>::appendOrSet(T newValue, bool append)
|
void BaseSetting<T>::appendOrSet(T newValue, bool append)
|
||||||
|
@ -120,8 +120,8 @@ DECLARE_CONFIG_SERIALISER(bool)
|
||||||
DECLARE_CONFIG_SERIALISER(Strings)
|
DECLARE_CONFIG_SERIALISER(Strings)
|
||||||
DECLARE_CONFIG_SERIALISER(StringSet)
|
DECLARE_CONFIG_SERIALISER(StringSet)
|
||||||
DECLARE_CONFIG_SERIALISER(StringMap)
|
DECLARE_CONFIG_SERIALISER(StringMap)
|
||||||
DECLARE_CONFIG_SERIALISER(std::set<ExperimentalFeature>)
|
DECLARE_CONFIG_SERIALISER(ExperimentalFeatures)
|
||||||
DECLARE_CONFIG_SERIALISER(std::set<DeprecatedFeature>)
|
DECLARE_CONFIG_SERIALISER(DeprecatedFeatures)
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T BaseSetting<T>::parse(const std::string & str) const
|
T BaseSetting<T>::parse(const std::string & str) const
|
||||||
|
|
|
@ -330,55 +330,61 @@ template<> std::string BaseSetting<StringSet>::to_string() const
|
||||||
return concatStringsSep(" ", value);
|
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)) {
|
for (auto & s : tokenizeString<StringSet>(str)) {
|
||||||
if (auto thisXpFeature = parseExperimentalFeature(s); thisXpFeature)
|
if (auto thisXpFeature = parseExperimentalFeature(s); thisXpFeature)
|
||||||
res.insert(thisXpFeature.value());
|
res = res | thisXpFeature.value();
|
||||||
else
|
else
|
||||||
warn("unknown experimental feature '%s'", s);
|
warn("unknown experimental feature '%s'", s);
|
||||||
}
|
}
|
||||||
return res;
|
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();
|
if (append)
|
||||||
value.insert(std::make_move_iterator(newValue.begin()), std::make_move_iterator(newValue.end()));
|
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;
|
StringSet stringifiedXpFeatures;
|
||||||
for (const auto & feature : value)
|
for (size_t tag = 0; tag < sizeof(ExperimentalFeatures) * CHAR_BIT; tag++)
|
||||||
stringifiedXpFeatures.insert(std::string(showExperimentalFeature(feature)));
|
if ((value & ExperimentalFeature(tag)) != ExperimentalFeatures{})
|
||||||
|
stringifiedXpFeatures.insert(std::string(showExperimentalFeature(ExperimentalFeature(tag))));
|
||||||
return concatStringsSep(" ", stringifiedXpFeatures);
|
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)) {
|
for (auto & s : tokenizeString<StringSet>(str)) {
|
||||||
if (auto thisDpFeature = parseDeprecatedFeature(s); thisDpFeature)
|
if (auto thisDpFeature = parseDeprecatedFeature(s); thisDpFeature)
|
||||||
res.insert(thisDpFeature.value());
|
res = res | thisDpFeature.value();
|
||||||
else
|
else
|
||||||
warn("unknown deprecated feature '%s'", s);
|
warn("unknown deprecated feature '%s'", s);
|
||||||
}
|
}
|
||||||
return res;
|
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();
|
if (append)
|
||||||
value.insert(std::make_move_iterator(newValue.begin()), std::make_move_iterator(newValue.end()));
|
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;
|
StringSet stringifiedDpFeatures;
|
||||||
for (const auto & feature : value)
|
for (size_t tag = 0; tag < sizeof(DeprecatedFeatures) * CHAR_BIT; tag++)
|
||||||
stringifiedDpFeatures.insert(std::string(showDeprecatedFeature(feature)));
|
if ((value & DeprecatedFeature(tag)) != DeprecatedFeatures{})
|
||||||
|
stringifiedDpFeatures.insert(std::string(showDeprecatedFeature(DeprecatedFeature(tag))));
|
||||||
return concatStringsSep(" ", stringifiedDpFeatures);
|
return concatStringsSep(" ", stringifiedDpFeatures);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,8 +423,8 @@ template class BaseSetting<std::string>;
|
||||||
template class BaseSetting<Strings>;
|
template class BaseSetting<Strings>;
|
||||||
template class BaseSetting<StringSet>;
|
template class BaseSetting<StringSet>;
|
||||||
template class BaseSetting<StringMap>;
|
template class BaseSetting<StringMap>;
|
||||||
template class BaseSetting<std::set<ExperimentalFeature>>;
|
template class BaseSetting<ExperimentalFeatures>;
|
||||||
template class BaseSetting<std::set<DeprecatedFeature>>;
|
template class BaseSetting<DeprecatedFeatures>;
|
||||||
|
|
||||||
static Path parsePath(const AbstractSetting & s, const std::string & str)
|
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
|
bool FeatureSettings::isEnabled(const ExperimentalFeature & feature) const
|
||||||
{
|
{
|
||||||
auto & f = experimentalFeatures.get();
|
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
|
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
|
bool FeatureSettings::isEnabled(const DeprecatedFeature & feature) const
|
||||||
{
|
{
|
||||||
auto & f = deprecatedFeatures.get();
|
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
|
void FeatureSettings::require(const DeprecatedFeature & feature) const
|
||||||
|
|
|
@ -444,7 +444,7 @@ extern GlobalConfig globalConfig;
|
||||||
|
|
||||||
struct FeatureSettings : Config {
|
struct FeatureSettings : Config {
|
||||||
|
|
||||||
Setting<std::set<ExperimentalFeature>> experimentalFeatures{
|
Setting<ExperimentalFeatures> experimentalFeatures{
|
||||||
this, {}, "experimental-features",
|
this, {}, "experimental-features",
|
||||||
R"(
|
R"(
|
||||||
Experimental features that are enabled.
|
Experimental features that are enabled.
|
||||||
|
@ -484,8 +484,7 @@ struct FeatureSettings : Config {
|
||||||
* disabled, and so the function does nothing in that case.
|
* disabled, and so the function does nothing in that case.
|
||||||
*/
|
*/
|
||||||
void require(const std::optional<ExperimentalFeature> &) const;
|
void require(const std::optional<ExperimentalFeature> &) const;
|
||||||
|
Setting<DeprecatedFeatures> deprecatedFeatures{
|
||||||
Setting<std::set<DeprecatedFeature>> deprecatedFeatures{
|
|
||||||
this, {}, "deprecated-features",
|
this, {}, "deprecated-features",
|
||||||
R"(
|
R"(
|
||||||
Deprecated features that are allowed.
|
Deprecated features that are allowed.
|
||||||
|
|
|
@ -77,12 +77,12 @@ nlohmann::json documentDeprecatedFeatures()
|
||||||
return (nlohmann::json) res;
|
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)
|
for (auto & rawFeature : rawFeatures)
|
||||||
if (auto feature = parseDeprecatedFeature(rawFeature))
|
if (auto feature = parseDeprecatedFeature(rawFeature))
|
||||||
res.insert(*feature);
|
res = res | *feature;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,9 +18,23 @@ namespace nix {
|
||||||
*/
|
*/
|
||||||
enum struct DeprecatedFeature
|
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
|
* 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
|
* Parse a set of strings to the corresponding set of deprecated
|
||||||
* features, ignoring (but warning for) any unknown feature.
|
* 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
|
* A deprecated feature used for some
|
||||||
|
|
|
@ -293,12 +293,12 @@ nlohmann::json documentExperimentalFeatures()
|
||||||
return (nlohmann::json) res;
|
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)
|
for (auto & rawFeature : rawFeatures)
|
||||||
if (auto feature = parseExperimentalFeature(rawFeature))
|
if (auto feature = parseExperimentalFeature(rawFeature))
|
||||||
res.insert(*feature);
|
res = res | *feature;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,20 @@ enum struct ExperimentalFeature
|
||||||
ReplAutomation,
|
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
|
* 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
|
* Parse a set of strings to the corresponding set of experimental
|
||||||
* features, ignoring (but warning for) any unknown feature.
|
* 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)
|
* An experimental feature was required for some (experimental)
|
||||||
|
|
|
@ -378,11 +378,10 @@ void mainWrapped(int argc, char * * argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc == 2 && std::string(argv[1]) == "__dump-language") {
|
if (argc == 2 && std::string(argv[1]) == "__dump-language") {
|
||||||
experimentalFeatureSettings.experimentalFeatures = {
|
experimentalFeatureSettings.experimentalFeatures = ExperimentalFeatures{}
|
||||||
Xp::Flakes,
|
| Xp::Flakes
|
||||||
Xp::FetchClosure,
|
| Xp::FetchClosure
|
||||||
Xp::DynamicDerivations,
|
| Xp::DynamicDerivations;
|
||||||
};
|
|
||||||
evalSettings.pureEval = false;
|
evalSettings.pureEval = false;
|
||||||
EvalState state({}, openStore("dummy://"));
|
EvalState state({}, openStore("dummy://"));
|
||||||
auto res = nlohmann::json::object();
|
auto res = nlohmann::json::object();
|
||||||
|
|
Loading…
Reference in a new issue