blob: 822895e70b0a34b3cd3b4f7dae6d17f46bb8ea24 [file] [log] [blame]
Sebastian Jansson9eb38862018-06-14 14:47:421/*
2 * Copyright 2018 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10#ifndef RTC_BASE_EXPERIMENTS_FIELD_TRIAL_PARSER_H_
11#define RTC_BASE_EXPERIMENTS_FIELD_TRIAL_PARSER_H_
12
13#include <stdint.h>
Jonas Olsson97d84ef2019-04-11 09:53:2614
Sebastian Jansson9eb38862018-06-14 14:47:4215#include <initializer_list>
Sebastian Jansson2c74d852018-06-26 08:30:1616#include <map>
17#include <set>
Sebastian Jansson9eb38862018-06-14 14:47:4218#include <string>
Jonas Olsson97d84ef2019-04-11 09:53:2619#include <vector>
20
Danil Chapovalov1b320f82021-11-09 10:41:5421#include "absl/strings/string_view.h"
Danil Chapovalov0a1d1892018-06-21 09:48:2522#include "absl/types/optional.h"
Sebastian Jansson9eb38862018-06-14 14:47:4223
24// Field trial parser functionality. Provides funcitonality to parse field trial
25// argument strings in key:value format. Each parameter is described using
26// key:value, parameters are separated with a ,. Values can't include the comma
27// character, since there's no quote facility. For most types, white space is
28// ignored. Parameters are declared with a given type for which an
29// implementation of ParseTypedParameter should be provided. The
30// ParseTypedParameter implementation is given whatever is between the : and the
Jonas Olsson97d84ef2019-04-11 09:53:2631// ,. If the key is provided without : a FieldTrialOptional will use nullopt.
Sebastian Jansson9eb38862018-06-14 14:47:4232
33// Example string: "my_optional,my_int:3,my_string:hello"
34
35// For further description of usage and behavior, see the examples in the unit
36// tests.
37
38namespace webrtc {
39class FieldTrialParameterInterface {
40 public:
41 virtual ~FieldTrialParameterInterface();
Sebastian Janssone670fd92019-04-25 12:44:0742 std::string key() const { return key_; }
Sebastian Jansson9eb38862018-06-14 14:47:4243
44 protected:
Sebastian Jansson343f4142018-10-05 17:44:4645 // Protected to allow implementations to provide assignment and copy.
46 FieldTrialParameterInterface(const FieldTrialParameterInterface&) = default;
47 FieldTrialParameterInterface& operator=(const FieldTrialParameterInterface&) =
48 default;
Ali Tofigh7fa90572022-03-17 14:47:4949 explicit FieldTrialParameterInterface(absl::string_view key);
Sebastian Jansson9eb38862018-06-14 14:47:4250 friend void ParseFieldTrial(
51 std::initializer_list<FieldTrialParameterInterface*> fields,
Danil Chapovalov1b320f82021-11-09 10:41:5452 absl::string_view trial_string);
Sebastian Janssonfea46372018-09-03 08:15:1353 void MarkAsUsed() { used_ = true; }
Danil Chapovalov0a1d1892018-06-21 09:48:2554 virtual bool Parse(absl::optional<std::string> str_value) = 0;
Jonas Olsson97d84ef2019-04-11 09:53:2655
56 virtual void ParseDone() {}
57
58 std::vector<FieldTrialParameterInterface*> sub_parameters_;
59
Sebastian Jansson9eb38862018-06-14 14:47:4260 private:
Sebastian Janssone670fd92019-04-25 12:44:0761 std::string key_;
Sebastian Janssonfea46372018-09-03 08:15:1362 bool used_ = false;
Sebastian Jansson9eb38862018-06-14 14:47:4263};
64
65// ParseFieldTrial function parses the given string and fills the given fields
Sebastian Janssond69998a2018-12-20 11:25:1966// with extracted values if available.
Sebastian Jansson9eb38862018-06-14 14:47:4267void ParseFieldTrial(
68 std::initializer_list<FieldTrialParameterInterface*> fields,
Danil Chapovalov1b320f82021-11-09 10:41:5469 absl::string_view trial_string);
Sebastian Jansson9eb38862018-06-14 14:47:4270
Danil Chapovalov0a1d1892018-06-21 09:48:2571// Specialize this in code file for custom types. Should return absl::nullopt if
Sebastian Jansson9eb38862018-06-14 14:47:4272// the given string cannot be properly parsed.
73template <typename T>
Ali Tofigh7fa90572022-03-17 14:47:4974absl::optional<T> ParseTypedParameter(absl::string_view);
Sebastian Jansson9eb38862018-06-14 14:47:4275
76// This class uses the ParseTypedParameter function to implement a parameter
77// implementation with an enforced default value.
78template <typename T>
79class FieldTrialParameter : public FieldTrialParameterInterface {
80 public:
Ali Tofigh7fa90572022-03-17 14:47:4981 FieldTrialParameter(absl::string_view key, T default_value)
Sebastian Jansson9eb38862018-06-14 14:47:4282 : FieldTrialParameterInterface(key), value_(default_value) {}
83 T Get() const { return value_; }
84 operator T() const { return Get(); }
Sebastian Janssonfea46372018-09-03 08:15:1385 const T* operator->() const { return &value_; }
Sebastian Jansson9eb38862018-06-14 14:47:4286
Sebastian Jansson1c4547d2019-04-01 11:26:4487 void SetForTest(T value) { value_ = value; }
88
Sebastian Jansson9eb38862018-06-14 14:47:4289 protected:
Danil Chapovalov0a1d1892018-06-21 09:48:2590 bool Parse(absl::optional<std::string> str_value) override {
Sebastian Jansson9eb38862018-06-14 14:47:4291 if (str_value) {
Danil Chapovalov0a1d1892018-06-21 09:48:2592 absl::optional<T> value = ParseTypedParameter<T>(*str_value);
Sebastian Jansson9eb38862018-06-14 14:47:4293 if (value.has_value()) {
94 value_ = value.value();
95 return true;
96 }
97 }
98 return false;
99 }
100
101 private:
102 T value_;
103};
104
Sebastian Janssonb22f0772018-11-19 16:44:33105// This class uses the ParseTypedParameter function to implement a parameter
106// implementation with an enforced default value and a range constraint. Values
107// outside the configured range will be ignored.
108template <typename T>
109class FieldTrialConstrained : public FieldTrialParameterInterface {
110 public:
Ali Tofigh7fa90572022-03-17 14:47:49111 FieldTrialConstrained(absl::string_view key,
Sebastian Janssonb22f0772018-11-19 16:44:33112 T default_value,
113 absl::optional<T> lower_limit,
114 absl::optional<T> upper_limit)
115 : FieldTrialParameterInterface(key),
116 value_(default_value),
117 lower_limit_(lower_limit),
118 upper_limit_(upper_limit) {}
119 T Get() const { return value_; }
120 operator T() const { return Get(); }
121 const T* operator->() const { return &value_; }
122
123 protected:
124 bool Parse(absl::optional<std::string> str_value) override {
125 if (str_value) {
126 absl::optional<T> value = ParseTypedParameter<T>(*str_value);
127 if (value && (!lower_limit_ || *value >= *lower_limit_) &&
128 (!upper_limit_ || *value <= *upper_limit_)) {
129 value_ = *value;
130 return true;
131 }
132 }
133 return false;
134 }
135
136 private:
137 T value_;
138 absl::optional<T> lower_limit_;
139 absl::optional<T> upper_limit_;
140};
141
Sebastian Jansson2c74d852018-06-26 08:30:16142class AbstractFieldTrialEnum : public FieldTrialParameterInterface {
143 public:
Ali Tofigh7fa90572022-03-17 14:47:49144 AbstractFieldTrialEnum(absl::string_view key,
Sebastian Jansson2c74d852018-06-26 08:30:16145 int default_value,
146 std::map<std::string, int> mapping);
147 ~AbstractFieldTrialEnum() override;
148 AbstractFieldTrialEnum(const AbstractFieldTrialEnum&);
149
150 protected:
151 bool Parse(absl::optional<std::string> str_value) override;
152
153 protected:
154 int value_;
155 std::map<std::string, int> enum_mapping_;
156 std::set<int> valid_values_;
157};
158
159// The FieldTrialEnum class can be used to quickly define a parser for a
160// specific enum. It handles values provided as integers and as strings if a
161// mapping is provided.
162template <typename T>
163class FieldTrialEnum : public AbstractFieldTrialEnum {
164 public:
Ali Tofigh7fa90572022-03-17 14:47:49165 FieldTrialEnum(absl::string_view key,
Sebastian Jansson2c74d852018-06-26 08:30:16166 T default_value,
167 std::map<std::string, T> mapping)
168 : AbstractFieldTrialEnum(key,
169 static_cast<int>(default_value),
170 ToIntMap(mapping)) {}
171 T Get() const { return static_cast<T>(value_); }
172 operator T() const { return Get(); }
173
174 private:
175 static std::map<std::string, int> ToIntMap(std::map<std::string, T> mapping) {
176 std::map<std::string, int> res;
177 for (const auto& it : mapping)
178 res[it.first] = static_cast<int>(it.second);
179 return res;
180 }
181};
182
Sebastian Jansson9eb38862018-06-14 14:47:42183// This class uses the ParseTypedParameter function to implement an optional
Danil Chapovalov0a1d1892018-06-21 09:48:25184// parameter implementation that can default to absl::nullopt.
Sebastian Jansson9eb38862018-06-14 14:47:42185template <typename T>
186class FieldTrialOptional : public FieldTrialParameterInterface {
187 public:
Ali Tofigh7fa90572022-03-17 14:47:49188 explicit FieldTrialOptional(absl::string_view key)
Sebastian Jansson9eb38862018-06-14 14:47:42189 : FieldTrialParameterInterface(key) {}
Ali Tofigh7fa90572022-03-17 14:47:49190 FieldTrialOptional(absl::string_view key, absl::optional<T> default_value)
Sebastian Jansson9eb38862018-06-14 14:47:42191 : FieldTrialParameterInterface(key), value_(default_value) {}
Sebastian Janssonfea46372018-09-03 08:15:13192 absl::optional<T> GetOptional() const { return value_; }
193 const T& Value() const { return value_.value(); }
194 const T& operator*() const { return value_.value(); }
195 const T* operator->() const { return &value_.value(); }
Jonas Olssoncb968092019-03-12 12:57:15196 explicit operator bool() const { return value_.has_value(); }
Sebastian Jansson9eb38862018-06-14 14:47:42197
198 protected:
Danil Chapovalov0a1d1892018-06-21 09:48:25199 bool Parse(absl::optional<std::string> str_value) override {
Sebastian Jansson9eb38862018-06-14 14:47:42200 if (str_value) {
Danil Chapovalov0a1d1892018-06-21 09:48:25201 absl::optional<T> value = ParseTypedParameter<T>(*str_value);
Sebastian Jansson9eb38862018-06-14 14:47:42202 if (!value.has_value())
203 return false;
204 value_ = value.value();
205 } else {
Danil Chapovalov0a1d1892018-06-21 09:48:25206 value_ = absl::nullopt;
Sebastian Jansson9eb38862018-06-14 14:47:42207 }
208 return true;
209 }
210
211 private:
Danil Chapovalov0a1d1892018-06-21 09:48:25212 absl::optional<T> value_;
Sebastian Jansson9eb38862018-06-14 14:47:42213};
214
215// Equivalent to a FieldTrialParameter<bool> in the case that both key and value
216// are present. If key is missing, evaluates to false. If key is present, but no
217// explicit value is provided, the flag evaluates to true.
218class FieldTrialFlag : public FieldTrialParameterInterface {
219 public:
Ali Tofigh7fa90572022-03-17 14:47:49220 explicit FieldTrialFlag(absl::string_view key);
221 FieldTrialFlag(absl::string_view key, bool default_value);
Sebastian Jansson9eb38862018-06-14 14:47:42222 bool Get() const;
Niels Möllerb02220d2022-02-04 15:13:37223 explicit operator bool() const;
Sebastian Jansson9eb38862018-06-14 14:47:42224
225 protected:
Danil Chapovalov0a1d1892018-06-21 09:48:25226 bool Parse(absl::optional<std::string> str_value) override;
Sebastian Jansson9eb38862018-06-14 14:47:42227
228 private:
229 bool value_;
230};
231
Sebastian Jansson55251c32019-08-08 09:14:51232template <typename T>
Ali Tofigh7fa90572022-03-17 14:47:49233absl::optional<absl::optional<T>> ParseOptionalParameter(
234 absl::string_view str) {
Sebastian Jansson55251c32019-08-08 09:14:51235 if (str.empty())
236 return absl::optional<T>();
237 auto parsed = ParseTypedParameter<T>(str);
238 if (parsed.has_value())
239 return parsed;
240 return absl::nullopt;
241}
242
243template <>
Ali Tofigh7fa90572022-03-17 14:47:49244absl::optional<bool> ParseTypedParameter<bool>(absl::string_view str);
Sebastian Jansson55251c32019-08-08 09:14:51245template <>
Ali Tofigh7fa90572022-03-17 14:47:49246absl::optional<double> ParseTypedParameter<double>(absl::string_view str);
Sebastian Jansson55251c32019-08-08 09:14:51247template <>
Ali Tofigh7fa90572022-03-17 14:47:49248absl::optional<int> ParseTypedParameter<int>(absl::string_view str);
Sebastian Jansson0ee80082019-08-14 11:16:26249template <>
Ali Tofigh7fa90572022-03-17 14:47:49250absl::optional<unsigned> ParseTypedParameter<unsigned>(absl::string_view str);
Bjorn Terelius9f00f0e2019-08-30 07:39:31251template <>
Ali Tofigh7fa90572022-03-17 14:47:49252absl::optional<std::string> ParseTypedParameter<std::string>(
253 absl::string_view str);
Philip Eliasson29ab4872019-09-10 14:05:43254
255template <>
Sebastian Jansson55251c32019-08-08 09:14:51256absl::optional<absl::optional<bool>> ParseTypedParameter<absl::optional<bool>>(
Ali Tofigh7fa90572022-03-17 14:47:49257 absl::string_view str);
Sebastian Jansson55251c32019-08-08 09:14:51258template <>
259absl::optional<absl::optional<int>> ParseTypedParameter<absl::optional<int>>(
Ali Tofigh7fa90572022-03-17 14:47:49260 absl::string_view str);
Sebastian Jansson55251c32019-08-08 09:14:51261template <>
Bjorn Terelius9f00f0e2019-08-30 07:39:31262absl::optional<absl::optional<unsigned>>
Ali Tofigh7fa90572022-03-17 14:47:49263ParseTypedParameter<absl::optional<unsigned>>(absl::string_view str);
Bjorn Terelius9f00f0e2019-08-30 07:39:31264template <>
Sebastian Jansson55251c32019-08-08 09:14:51265absl::optional<absl::optional<double>>
Ali Tofigh7fa90572022-03-17 14:47:49266ParseTypedParameter<absl::optional<double>>(absl::string_view str);
Sebastian Jansson55251c32019-08-08 09:14:51267
Sebastian Jansson9eb38862018-06-14 14:47:42268// Accepts true, false, else parsed with sscanf %i, true if != 0.
269extern template class FieldTrialParameter<bool>;
270// Interpreted using sscanf %lf.
271extern template class FieldTrialParameter<double>;
272// Interpreted using sscanf %i.
273extern template class FieldTrialParameter<int>;
Bjorn Terelius9f00f0e2019-08-30 07:39:31274// Interpreted using sscanf %u.
275extern template class FieldTrialParameter<unsigned>;
Philip Eliasson29ab4872019-09-10 14:05:43276// Using the given value as is.
277extern template class FieldTrialParameter<std::string>;
Sebastian Jansson9eb38862018-06-14 14:47:42278
Sebastian Janssonb22f0772018-11-19 16:44:33279extern template class FieldTrialConstrained<double>;
280extern template class FieldTrialConstrained<int>;
Bjorn Terelius9f00f0e2019-08-30 07:39:31281extern template class FieldTrialConstrained<unsigned>;
Sebastian Janssonb22f0772018-11-19 16:44:33282
Sebastian Jansson9eb38862018-06-14 14:47:42283extern template class FieldTrialOptional<double>;
284extern template class FieldTrialOptional<int>;
Bjorn Terelius9f00f0e2019-08-30 07:39:31285extern template class FieldTrialOptional<unsigned>;
Sebastian Jansson9eb38862018-06-14 14:47:42286extern template class FieldTrialOptional<bool>;
Philip Eliasson29ab4872019-09-10 14:05:43287extern template class FieldTrialOptional<std::string>;
Sebastian Jansson9eb38862018-06-14 14:47:42288
289} // namespace webrtc
290
291#endif // RTC_BASE_EXPERIMENTS_FIELD_TRIAL_PARSER_H_