blob: a63cb20ef04def33273a230bdea0ad2ae2ed9b56 [file] [log] [blame]
Sebastian Jansson9eb38862018-06-14 16:47:42 +02001/*
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 11:53:26 +020014
Sebastian Jansson9eb38862018-06-14 16:47:42 +020015#include <initializer_list>
Sebastian Jansson2c74d852018-06-26 10:30:16 +020016#include <map>
17#include <set>
Sebastian Jansson9eb38862018-06-14 16:47:42 +020018#include <string>
Jonas Olsson97d84ef2019-04-11 11:53:26 +020019#include <vector>
20
Danil Chapovalov0a1d1892018-06-21 11:48:25 +020021#include "absl/types/optional.h"
Sebastian Jansson9eb38862018-06-14 16:47:42 +020022
23// Field trial parser functionality. Provides funcitonality to parse field trial
24// argument strings in key:value format. Each parameter is described using
25// key:value, parameters are separated with a ,. Values can't include the comma
26// character, since there's no quote facility. For most types, white space is
27// ignored. Parameters are declared with a given type for which an
28// implementation of ParseTypedParameter should be provided. The
29// ParseTypedParameter implementation is given whatever is between the : and the
Jonas Olsson97d84ef2019-04-11 11:53:26 +020030// ,. If the key is provided without : a FieldTrialOptional will use nullopt.
Sebastian Jansson9eb38862018-06-14 16:47:42 +020031
32// Example string: "my_optional,my_int:3,my_string:hello"
33
34// For further description of usage and behavior, see the examples in the unit
35// tests.
36
37namespace webrtc {
38class FieldTrialParameterInterface {
39 public:
40 virtual ~FieldTrialParameterInterface();
41
42 protected:
Sebastian Jansson343f4142018-10-05 19:44:46 +020043 // Protected to allow implementations to provide assignment and copy.
44 FieldTrialParameterInterface(const FieldTrialParameterInterface&) = default;
45 FieldTrialParameterInterface& operator=(const FieldTrialParameterInterface&) =
46 default;
Sebastian Jansson9eb38862018-06-14 16:47:42 +020047 explicit FieldTrialParameterInterface(std::string key);
48 friend void ParseFieldTrial(
49 std::initializer_list<FieldTrialParameterInterface*> fields,
50 std::string raw_string);
Sebastian Janssonfea46372018-09-03 10:15:13 +020051 void MarkAsUsed() { used_ = true; }
Danil Chapovalov0a1d1892018-06-21 11:48:25 +020052 virtual bool Parse(absl::optional<std::string> str_value) = 0;
Jonas Olsson97d84ef2019-04-11 11:53:26 +020053
54 virtual void ParseDone() {}
55
56 std::vector<FieldTrialParameterInterface*> sub_parameters_;
57
58 std::string key_;
Sebastian Jansson9eb38862018-06-14 16:47:42 +020059
60 private:
Sebastian Janssonfea46372018-09-03 10:15:13 +020061 bool used_ = false;
Sebastian Jansson9eb38862018-06-14 16:47:42 +020062};
63
64// ParseFieldTrial function parses the given string and fills the given fields
Sebastian Janssond69998a2018-12-20 12:25:19 +010065// with extracted values if available.
Sebastian Jansson9eb38862018-06-14 16:47:42 +020066void ParseFieldTrial(
67 std::initializer_list<FieldTrialParameterInterface*> fields,
68 std::string raw_string);
69
Danil Chapovalov0a1d1892018-06-21 11:48:25 +020070// Specialize this in code file for custom types. Should return absl::nullopt if
Sebastian Jansson9eb38862018-06-14 16:47:42 +020071// the given string cannot be properly parsed.
72template <typename T>
Danil Chapovalov0a1d1892018-06-21 11:48:25 +020073absl::optional<T> ParseTypedParameter(std::string);
Sebastian Jansson9eb38862018-06-14 16:47:42 +020074
75// This class uses the ParseTypedParameter function to implement a parameter
76// implementation with an enforced default value.
77template <typename T>
78class FieldTrialParameter : public FieldTrialParameterInterface {
79 public:
80 FieldTrialParameter(std::string key, T default_value)
81 : FieldTrialParameterInterface(key), value_(default_value) {}
82 T Get() const { return value_; }
83 operator T() const { return Get(); }
Sebastian Janssonfea46372018-09-03 10:15:13 +020084 const T* operator->() const { return &value_; }
Sebastian Jansson9eb38862018-06-14 16:47:42 +020085
Sebastian Jansson1c4547d2019-04-01 13:26:44 +020086 void SetForTest(T value) { value_ = value; }
87
Sebastian Jansson9eb38862018-06-14 16:47:42 +020088 protected:
Danil Chapovalov0a1d1892018-06-21 11:48:25 +020089 bool Parse(absl::optional<std::string> str_value) override {
Sebastian Jansson9eb38862018-06-14 16:47:42 +020090 if (str_value) {
Danil Chapovalov0a1d1892018-06-21 11:48:25 +020091 absl::optional<T> value = ParseTypedParameter<T>(*str_value);
Sebastian Jansson9eb38862018-06-14 16:47:42 +020092 if (value.has_value()) {
93 value_ = value.value();
94 return true;
95 }
96 }
97 return false;
98 }
99
100 private:
101 T value_;
102};
103
Sebastian Janssonb22f0772018-11-19 17:44:33 +0100104// This class uses the ParseTypedParameter function to implement a parameter
105// implementation with an enforced default value and a range constraint. Values
106// outside the configured range will be ignored.
107template <typename T>
108class FieldTrialConstrained : public FieldTrialParameterInterface {
109 public:
110 FieldTrialConstrained(std::string key,
111 T default_value,
112 absl::optional<T> lower_limit,
113 absl::optional<T> upper_limit)
114 : FieldTrialParameterInterface(key),
115 value_(default_value),
116 lower_limit_(lower_limit),
117 upper_limit_(upper_limit) {}
118 T Get() const { return value_; }
119 operator T() const { return Get(); }
120 const T* operator->() const { return &value_; }
121
122 protected:
123 bool Parse(absl::optional<std::string> str_value) override {
124 if (str_value) {
125 absl::optional<T> value = ParseTypedParameter<T>(*str_value);
126 if (value && (!lower_limit_ || *value >= *lower_limit_) &&
127 (!upper_limit_ || *value <= *upper_limit_)) {
128 value_ = *value;
129 return true;
130 }
131 }
132 return false;
133 }
134
135 private:
136 T value_;
137 absl::optional<T> lower_limit_;
138 absl::optional<T> upper_limit_;
139};
140
Sebastian Jansson2c74d852018-06-26 10:30:16 +0200141class AbstractFieldTrialEnum : public FieldTrialParameterInterface {
142 public:
143 AbstractFieldTrialEnum(std::string key,
144 int default_value,
145 std::map<std::string, int> mapping);
146 ~AbstractFieldTrialEnum() override;
147 AbstractFieldTrialEnum(const AbstractFieldTrialEnum&);
148
149 protected:
150 bool Parse(absl::optional<std::string> str_value) override;
151
152 protected:
153 int value_;
154 std::map<std::string, int> enum_mapping_;
155 std::set<int> valid_values_;
156};
157
158// The FieldTrialEnum class can be used to quickly define a parser for a
159// specific enum. It handles values provided as integers and as strings if a
160// mapping is provided.
161template <typename T>
162class FieldTrialEnum : public AbstractFieldTrialEnum {
163 public:
164 FieldTrialEnum(std::string key,
165 T default_value,
166 std::map<std::string, T> mapping)
167 : AbstractFieldTrialEnum(key,
168 static_cast<int>(default_value),
169 ToIntMap(mapping)) {}
170 T Get() const { return static_cast<T>(value_); }
171 operator T() const { return Get(); }
172
173 private:
174 static std::map<std::string, int> ToIntMap(std::map<std::string, T> mapping) {
175 std::map<std::string, int> res;
176 for (const auto& it : mapping)
177 res[it.first] = static_cast<int>(it.second);
178 return res;
179 }
180};
181
Sebastian Jansson9eb38862018-06-14 16:47:42 +0200182// This class uses the ParseTypedParameter function to implement an optional
Danil Chapovalov0a1d1892018-06-21 11:48:25 +0200183// parameter implementation that can default to absl::nullopt.
Sebastian Jansson9eb38862018-06-14 16:47:42 +0200184template <typename T>
185class FieldTrialOptional : public FieldTrialParameterInterface {
186 public:
187 explicit FieldTrialOptional(std::string key)
188 : FieldTrialParameterInterface(key) {}
Danil Chapovalov0a1d1892018-06-21 11:48:25 +0200189 FieldTrialOptional(std::string key, absl::optional<T> default_value)
Sebastian Jansson9eb38862018-06-14 16:47:42 +0200190 : FieldTrialParameterInterface(key), value_(default_value) {}
Sebastian Janssonfea46372018-09-03 10:15:13 +0200191 absl::optional<T> GetOptional() const { return value_; }
192 const T& Value() const { return value_.value(); }
193 const T& operator*() const { return value_.value(); }
194 const T* operator->() const { return &value_.value(); }
Jonas Olssoncb968092019-03-12 13:57:15 +0100195 explicit operator bool() const { return value_.has_value(); }
Sebastian Jansson9eb38862018-06-14 16:47:42 +0200196
197 protected:
Danil Chapovalov0a1d1892018-06-21 11:48:25 +0200198 bool Parse(absl::optional<std::string> str_value) override {
Sebastian Jansson9eb38862018-06-14 16:47:42 +0200199 if (str_value) {
Danil Chapovalov0a1d1892018-06-21 11:48:25 +0200200 absl::optional<T> value = ParseTypedParameter<T>(*str_value);
Sebastian Jansson9eb38862018-06-14 16:47:42 +0200201 if (!value.has_value())
202 return false;
203 value_ = value.value();
204 } else {
Danil Chapovalov0a1d1892018-06-21 11:48:25 +0200205 value_ = absl::nullopt;
Sebastian Jansson9eb38862018-06-14 16:47:42 +0200206 }
207 return true;
208 }
209
210 private:
Danil Chapovalov0a1d1892018-06-21 11:48:25 +0200211 absl::optional<T> value_;
Sebastian Jansson9eb38862018-06-14 16:47:42 +0200212};
213
214// Equivalent to a FieldTrialParameter<bool> in the case that both key and value
215// are present. If key is missing, evaluates to false. If key is present, but no
216// explicit value is provided, the flag evaluates to true.
217class FieldTrialFlag : public FieldTrialParameterInterface {
218 public:
219 explicit FieldTrialFlag(std::string key);
220 FieldTrialFlag(std::string key, bool default_value);
221 bool Get() const;
Sebastian Janssonfea46372018-09-03 10:15:13 +0200222 operator bool() const;
Sebastian Jansson9eb38862018-06-14 16:47:42 +0200223
224 protected:
Danil Chapovalov0a1d1892018-06-21 11:48:25 +0200225 bool Parse(absl::optional<std::string> str_value) override;
Sebastian Jansson9eb38862018-06-14 16:47:42 +0200226
227 private:
228 bool value_;
229};
230
231// Accepts true, false, else parsed with sscanf %i, true if != 0.
232extern template class FieldTrialParameter<bool>;
233// Interpreted using sscanf %lf.
234extern template class FieldTrialParameter<double>;
235// Interpreted using sscanf %i.
236extern template class FieldTrialParameter<int>;
237// Using the given value as is.
238extern template class FieldTrialParameter<std::string>;
239
Sebastian Janssonb22f0772018-11-19 17:44:33 +0100240extern template class FieldTrialConstrained<double>;
241extern template class FieldTrialConstrained<int>;
242
Sebastian Jansson9eb38862018-06-14 16:47:42 +0200243extern template class FieldTrialOptional<double>;
244extern template class FieldTrialOptional<int>;
245extern template class FieldTrialOptional<bool>;
246extern template class FieldTrialOptional<std::string>;
247
248} // namespace webrtc
249
250#endif // RTC_BASE_EXPERIMENTS_FIELD_TRIAL_PARSER_H_