blob: e6ae4c52a642c949471cfe067f85fbaf7669c063 [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>
14#include <initializer_list>
Sebastian Jansson2c74d852018-06-26 10:30:16 +020015#include <map>
16#include <set>
Sebastian Jansson9eb38862018-06-14 16:47:42 +020017#include <string>
Danil Chapovalov0a1d1892018-06-21 11:48:25 +020018#include "absl/types/optional.h"
Sebastian Jansson9eb38862018-06-14 16:47:42 +020019
20// Field trial parser functionality. Provides funcitonality to parse field trial
21// argument strings in key:value format. Each parameter is described using
22// key:value, parameters are separated with a ,. Values can't include the comma
23// character, since there's no quote facility. For most types, white space is
24// ignored. Parameters are declared with a given type for which an
25// implementation of ParseTypedParameter should be provided. The
26// ParseTypedParameter implementation is given whatever is between the : and the
27// ,. FieldTrialOptional will use nullopt if the key is provided without :.
28
29// Example string: "my_optional,my_int:3,my_string:hello"
30
31// For further description of usage and behavior, see the examples in the unit
32// tests.
33
34namespace webrtc {
35class FieldTrialParameterInterface {
36 public:
37 virtual ~FieldTrialParameterInterface();
38
39 protected:
Sebastian Jansson343f4142018-10-05 19:44:46 +020040 // Protected to allow implementations to provide assignment and copy.
41 FieldTrialParameterInterface(const FieldTrialParameterInterface&) = default;
42 FieldTrialParameterInterface& operator=(const FieldTrialParameterInterface&) =
43 default;
Sebastian Jansson9eb38862018-06-14 16:47:42 +020044 explicit FieldTrialParameterInterface(std::string key);
45 friend void ParseFieldTrial(
46 std::initializer_list<FieldTrialParameterInterface*> fields,
47 std::string raw_string);
Sebastian Janssonfea46372018-09-03 10:15:13 +020048 void MarkAsUsed() { used_ = true; }
Danil Chapovalov0a1d1892018-06-21 11:48:25 +020049 virtual bool Parse(absl::optional<std::string> str_value) = 0;
Sebastian Jansson9eb38862018-06-14 16:47:42 +020050 std::string Key() const;
51
52 private:
Sebastian Jansson343f4142018-10-05 19:44:46 +020053 std::string key_;
Sebastian Janssonfea46372018-09-03 10:15:13 +020054 bool used_ = false;
Sebastian Jansson9eb38862018-06-14 16:47:42 +020055};
56
57// ParseFieldTrial function parses the given string and fills the given fields
Sebastian Janssond69998a2018-12-20 12:25:19 +010058// with extracted values if available.
Sebastian Jansson9eb38862018-06-14 16:47:42 +020059void ParseFieldTrial(
60 std::initializer_list<FieldTrialParameterInterface*> fields,
61 std::string raw_string);
62
Danil Chapovalov0a1d1892018-06-21 11:48:25 +020063// Specialize this in code file for custom types. Should return absl::nullopt if
Sebastian Jansson9eb38862018-06-14 16:47:42 +020064// the given string cannot be properly parsed.
65template <typename T>
Danil Chapovalov0a1d1892018-06-21 11:48:25 +020066absl::optional<T> ParseTypedParameter(std::string);
Sebastian Jansson9eb38862018-06-14 16:47:42 +020067
68// This class uses the ParseTypedParameter function to implement a parameter
69// implementation with an enforced default value.
70template <typename T>
71class FieldTrialParameter : public FieldTrialParameterInterface {
72 public:
73 FieldTrialParameter(std::string key, T default_value)
74 : FieldTrialParameterInterface(key), value_(default_value) {}
75 T Get() const { return value_; }
76 operator T() const { return Get(); }
Sebastian Janssonfea46372018-09-03 10:15:13 +020077 const T* operator->() const { return &value_; }
Sebastian Jansson9eb38862018-06-14 16:47:42 +020078
Sebastian Jansson1c4547d2019-04-01 13:26:44 +020079 void SetForTest(T value) { value_ = value; }
80
Sebastian Jansson9eb38862018-06-14 16:47:42 +020081 protected:
Danil Chapovalov0a1d1892018-06-21 11:48:25 +020082 bool Parse(absl::optional<std::string> str_value) override {
Sebastian Jansson9eb38862018-06-14 16:47:42 +020083 if (str_value) {
Danil Chapovalov0a1d1892018-06-21 11:48:25 +020084 absl::optional<T> value = ParseTypedParameter<T>(*str_value);
Sebastian Jansson9eb38862018-06-14 16:47:42 +020085 if (value.has_value()) {
86 value_ = value.value();
87 return true;
88 }
89 }
90 return false;
91 }
92
93 private:
94 T value_;
95};
96
Sebastian Janssonb22f0772018-11-19 17:44:33 +010097// This class uses the ParseTypedParameter function to implement a parameter
98// implementation with an enforced default value and a range constraint. Values
99// outside the configured range will be ignored.
100template <typename T>
101class FieldTrialConstrained : public FieldTrialParameterInterface {
102 public:
103 FieldTrialConstrained(std::string key,
104 T default_value,
105 absl::optional<T> lower_limit,
106 absl::optional<T> upper_limit)
107 : FieldTrialParameterInterface(key),
108 value_(default_value),
109 lower_limit_(lower_limit),
110 upper_limit_(upper_limit) {}
111 T Get() const { return value_; }
112 operator T() const { return Get(); }
113 const T* operator->() const { return &value_; }
114
115 protected:
116 bool Parse(absl::optional<std::string> str_value) override {
117 if (str_value) {
118 absl::optional<T> value = ParseTypedParameter<T>(*str_value);
119 if (value && (!lower_limit_ || *value >= *lower_limit_) &&
120 (!upper_limit_ || *value <= *upper_limit_)) {
121 value_ = *value;
122 return true;
123 }
124 }
125 return false;
126 }
127
128 private:
129 T value_;
130 absl::optional<T> lower_limit_;
131 absl::optional<T> upper_limit_;
132};
133
Sebastian Jansson2c74d852018-06-26 10:30:16 +0200134class AbstractFieldTrialEnum : public FieldTrialParameterInterface {
135 public:
136 AbstractFieldTrialEnum(std::string key,
137 int default_value,
138 std::map<std::string, int> mapping);
139 ~AbstractFieldTrialEnum() override;
140 AbstractFieldTrialEnum(const AbstractFieldTrialEnum&);
141
142 protected:
143 bool Parse(absl::optional<std::string> str_value) override;
144
145 protected:
146 int value_;
147 std::map<std::string, int> enum_mapping_;
148 std::set<int> valid_values_;
149};
150
151// The FieldTrialEnum class can be used to quickly define a parser for a
152// specific enum. It handles values provided as integers and as strings if a
153// mapping is provided.
154template <typename T>
155class FieldTrialEnum : public AbstractFieldTrialEnum {
156 public:
157 FieldTrialEnum(std::string key,
158 T default_value,
159 std::map<std::string, T> mapping)
160 : AbstractFieldTrialEnum(key,
161 static_cast<int>(default_value),
162 ToIntMap(mapping)) {}
163 T Get() const { return static_cast<T>(value_); }
164 operator T() const { return Get(); }
165
166 private:
167 static std::map<std::string, int> ToIntMap(std::map<std::string, T> mapping) {
168 std::map<std::string, int> res;
169 for (const auto& it : mapping)
170 res[it.first] = static_cast<int>(it.second);
171 return res;
172 }
173};
174
Sebastian Jansson9eb38862018-06-14 16:47:42 +0200175// This class uses the ParseTypedParameter function to implement an optional
Danil Chapovalov0a1d1892018-06-21 11:48:25 +0200176// parameter implementation that can default to absl::nullopt.
Sebastian Jansson9eb38862018-06-14 16:47:42 +0200177template <typename T>
178class FieldTrialOptional : public FieldTrialParameterInterface {
179 public:
180 explicit FieldTrialOptional(std::string key)
181 : FieldTrialParameterInterface(key) {}
Danil Chapovalov0a1d1892018-06-21 11:48:25 +0200182 FieldTrialOptional(std::string key, absl::optional<T> default_value)
Sebastian Jansson9eb38862018-06-14 16:47:42 +0200183 : FieldTrialParameterInterface(key), value_(default_value) {}
Sebastian Janssonfea46372018-09-03 10:15:13 +0200184 absl::optional<T> GetOptional() const { return value_; }
185 const T& Value() const { return value_.value(); }
186 const T& operator*() const { return value_.value(); }
187 const T* operator->() const { return &value_.value(); }
Jonas Olssoncb968092019-03-12 13:57:15 +0100188 explicit operator bool() const { return value_.has_value(); }
Sebastian Jansson9eb38862018-06-14 16:47:42 +0200189
190 protected:
Danil Chapovalov0a1d1892018-06-21 11:48:25 +0200191 bool Parse(absl::optional<std::string> str_value) override {
Sebastian Jansson9eb38862018-06-14 16:47:42 +0200192 if (str_value) {
Danil Chapovalov0a1d1892018-06-21 11:48:25 +0200193 absl::optional<T> value = ParseTypedParameter<T>(*str_value);
Sebastian Jansson9eb38862018-06-14 16:47:42 +0200194 if (!value.has_value())
195 return false;
196 value_ = value.value();
197 } else {
Danil Chapovalov0a1d1892018-06-21 11:48:25 +0200198 value_ = absl::nullopt;
Sebastian Jansson9eb38862018-06-14 16:47:42 +0200199 }
200 return true;
201 }
202
203 private:
Danil Chapovalov0a1d1892018-06-21 11:48:25 +0200204 absl::optional<T> value_;
Sebastian Jansson9eb38862018-06-14 16:47:42 +0200205};
206
207// Equivalent to a FieldTrialParameter<bool> in the case that both key and value
208// are present. If key is missing, evaluates to false. If key is present, but no
209// explicit value is provided, the flag evaluates to true.
210class FieldTrialFlag : public FieldTrialParameterInterface {
211 public:
212 explicit FieldTrialFlag(std::string key);
213 FieldTrialFlag(std::string key, bool default_value);
214 bool Get() const;
Sebastian Janssonfea46372018-09-03 10:15:13 +0200215 operator bool() const;
Sebastian Jansson9eb38862018-06-14 16:47:42 +0200216
217 protected:
Danil Chapovalov0a1d1892018-06-21 11:48:25 +0200218 bool Parse(absl::optional<std::string> str_value) override;
Sebastian Jansson9eb38862018-06-14 16:47:42 +0200219
220 private:
221 bool value_;
222};
223
224// Accepts true, false, else parsed with sscanf %i, true if != 0.
225extern template class FieldTrialParameter<bool>;
226// Interpreted using sscanf %lf.
227extern template class FieldTrialParameter<double>;
228// Interpreted using sscanf %i.
229extern template class FieldTrialParameter<int>;
230// Using the given value as is.
231extern template class FieldTrialParameter<std::string>;
232
Sebastian Janssonb22f0772018-11-19 17:44:33 +0100233extern template class FieldTrialConstrained<double>;
234extern template class FieldTrialConstrained<int>;
235
Sebastian Jansson9eb38862018-06-14 16:47:42 +0200236extern template class FieldTrialOptional<double>;
237extern template class FieldTrialOptional<int>;
238extern template class FieldTrialOptional<bool>;
239extern template class FieldTrialOptional<std::string>;
240
241} // namespace webrtc
242
243#endif // RTC_BASE_EXPERIMENTS_FIELD_TRIAL_PARSER_H_