diff --git a/rtc_base/experiments/field_trial_parser.cc b/rtc_base/experiments/field_trial_parser.cc index 4ea603f931..55299adbb6 100644 --- a/rtc_base/experiments/field_trial_parser.cc +++ b/rtc_base/experiments/field_trial_parser.cc @@ -121,6 +121,37 @@ bool FieldTrialFlag::Parse(absl::optional str_value) { return true; } +AbstractFieldTrialEnum::AbstractFieldTrialEnum( + std::string key, + int default_value, + std::map mapping) + : FieldTrialParameterInterface(key), + value_(default_value), + enum_mapping_(mapping) { + for (auto& key_val : enum_mapping_) + valid_values_.insert(key_val.second); +} +AbstractFieldTrialEnum::AbstractFieldTrialEnum(const AbstractFieldTrialEnum&) = + default; +AbstractFieldTrialEnum::~AbstractFieldTrialEnum() = default; + +bool AbstractFieldTrialEnum::Parse(absl::optional str_value) { + if (str_value) { + auto it = enum_mapping_.find(*str_value); + if (it != enum_mapping_.end()) { + value_ = it->second; + return true; + } + absl::optional value = ParseTypedParameter(*str_value); + if (value.has_value() && + (valid_values_.find(*value) != valid_values_.end())) { + value_ = *value; + return true; + } + } + return false; +} + template class FieldTrialParameter; template class FieldTrialParameter; template class FieldTrialParameter; diff --git a/rtc_base/experiments/field_trial_parser.h b/rtc_base/experiments/field_trial_parser.h index ff00b90f36..a385ccfc16 100644 --- a/rtc_base/experiments/field_trial_parser.h +++ b/rtc_base/experiments/field_trial_parser.h @@ -12,6 +12,8 @@ #include #include +#include +#include #include #include "absl/types/optional.h" @@ -83,6 +85,47 @@ class FieldTrialParameter : public FieldTrialParameterInterface { T value_; }; +class AbstractFieldTrialEnum : public FieldTrialParameterInterface { + public: + AbstractFieldTrialEnum(std::string key, + int default_value, + std::map mapping); + ~AbstractFieldTrialEnum() override; + AbstractFieldTrialEnum(const AbstractFieldTrialEnum&); + + protected: + bool Parse(absl::optional str_value) override; + + protected: + int value_; + std::map enum_mapping_; + std::set valid_values_; +}; + +// The FieldTrialEnum class can be used to quickly define a parser for a +// specific enum. It handles values provided as integers and as strings if a +// mapping is provided. +template +class FieldTrialEnum : public AbstractFieldTrialEnum { + public: + FieldTrialEnum(std::string key, + T default_value, + std::map mapping) + : AbstractFieldTrialEnum(key, + static_cast(default_value), + ToIntMap(mapping)) {} + T Get() const { return static_cast(value_); } + operator T() const { return Get(); } + + private: + static std::map ToIntMap(std::map mapping) { + std::map res; + for (const auto& it : mapping) + res[it.first] = static_cast(it.second); + return res; + } +}; + // This class uses the ParseTypedParameter function to implement an optional // parameter implementation that can default to absl::nullopt. template diff --git a/rtc_base/experiments/field_trial_parser_unittest.cc b/rtc_base/experiments/field_trial_parser_unittest.cc index 73bddfdee0..69f35bd647 100644 --- a/rtc_base/experiments/field_trial_parser_unittest.cc +++ b/rtc_base/experiments/field_trial_parser_unittest.cc @@ -34,25 +34,12 @@ struct DummyExperiment { }; enum class CustomEnum { - kDefault, - kRed, - kBlue, + kDefault = 0, + kRed = 1, + kBlue = 2, }; } // namespace -// Providing a custom parser for an enum can make the trial string easier to -// read, but also adds more code and makes the string more verbose. -template <> -absl::optional ParseTypedParameter(std::string str) { - if (str == "default") - return CustomEnum::kDefault; - else if (str == "red") - return CustomEnum::kRed; - else if (str == "blue") - return CustomEnum::kBlue; - return absl::nullopt; -} - TEST(FieldTrialParserTest, ParsesValidParameters) { DummyExperiment exp("Enabled,f:-1.7,r:2,p:1,h:x7c"); EXPECT_TRUE(exp.enabled.Get()); @@ -122,10 +109,17 @@ TEST(FieldTrialParserTest, ParsesOptionalParameters) { EXPECT_FALSE(optional_string.Get().has_value()); } TEST(FieldTrialParserTest, ParsesCustomEnumParameter) { - FieldTrialParameter my_enum("e", CustomEnum::kDefault); + FieldTrialEnum my_enum("e", CustomEnum::kDefault, + {{"default", CustomEnum::kDefault}, + {"red", CustomEnum::kRed}, + {"blue", CustomEnum::kBlue}}); ParseFieldTrial({&my_enum}, ""); EXPECT_EQ(my_enum.Get(), CustomEnum::kDefault); ParseFieldTrial({&my_enum}, "e:red"); EXPECT_EQ(my_enum.Get(), CustomEnum::kRed); + ParseFieldTrial({&my_enum}, "e:2"); + EXPECT_EQ(my_enum.Get(), CustomEnum::kBlue); + ParseFieldTrial({&my_enum}, "e:5"); + EXPECT_EQ(my_enum.Get(), CustomEnum::kBlue); } } // namespace webrtc