field_trial_parser.h 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. /*
  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. #include <stdint.h>
  13. #include <initializer_list>
  14. #include <map>
  15. #include <set>
  16. #include <string>
  17. #include <vector>
  18. #include "absl/types/optional.h"
  19. // Field trial parser functionality. Provides funcitonality to parse field trial
  20. // argument strings in key:value format. Each parameter is described using
  21. // key:value, parameters are separated with a ,. Values can't include the comma
  22. // character, since there's no quote facility. For most types, white space is
  23. // ignored. Parameters are declared with a given type for which an
  24. // implementation of ParseTypedParameter should be provided. The
  25. // ParseTypedParameter implementation is given whatever is between the : and the
  26. // ,. If the key is provided without : a FieldTrialOptional will use nullopt.
  27. // Example string: "my_optional,my_int:3,my_string:hello"
  28. // For further description of usage and behavior, see the examples in the unit
  29. // tests.
  30. namespace webrtc {
  31. class FieldTrialParameterInterface {
  32. public:
  33. virtual ~FieldTrialParameterInterface();
  34. std::string key() const { return key_; }
  35. protected:
  36. // Protected to allow implementations to provide assignment and copy.
  37. FieldTrialParameterInterface(const FieldTrialParameterInterface&) = default;
  38. FieldTrialParameterInterface& operator=(const FieldTrialParameterInterface&) =
  39. default;
  40. explicit FieldTrialParameterInterface(std::string key);
  41. friend void ParseFieldTrial(
  42. std::initializer_list<FieldTrialParameterInterface*> fields,
  43. std::string raw_string);
  44. void MarkAsUsed() { used_ = true; }
  45. virtual bool Parse(absl::optional<std::string> str_value) = 0;
  46. virtual void ParseDone() {}
  47. std::vector<FieldTrialParameterInterface*> sub_parameters_;
  48. private:
  49. std::string key_;
  50. bool used_ = false;
  51. };
  52. // ParseFieldTrial function parses the given string and fills the given fields
  53. // with extracted values if available.
  54. void ParseFieldTrial(
  55. std::initializer_list<FieldTrialParameterInterface*> fields,
  56. std::string raw_string);
  57. // Specialize this in code file for custom types. Should return absl::nullopt if
  58. // the given string cannot be properly parsed.
  59. template <typename T>
  60. absl::optional<T> ParseTypedParameter(std::string);
  61. // This class uses the ParseTypedParameter function to implement a parameter
  62. // implementation with an enforced default value.
  63. template <typename T>
  64. class FieldTrialParameter : public FieldTrialParameterInterface {
  65. public:
  66. FieldTrialParameter(std::string key, T default_value)
  67. : FieldTrialParameterInterface(key), value_(default_value) {}
  68. T Get() const { return value_; }
  69. operator T() const { return Get(); }
  70. const T* operator->() const { return &value_; }
  71. void SetForTest(T value) { value_ = value; }
  72. protected:
  73. bool Parse(absl::optional<std::string> str_value) override {
  74. if (str_value) {
  75. absl::optional<T> value = ParseTypedParameter<T>(*str_value);
  76. if (value.has_value()) {
  77. value_ = value.value();
  78. return true;
  79. }
  80. }
  81. return false;
  82. }
  83. private:
  84. T value_;
  85. };
  86. // This class uses the ParseTypedParameter function to implement a parameter
  87. // implementation with an enforced default value and a range constraint. Values
  88. // outside the configured range will be ignored.
  89. template <typename T>
  90. class FieldTrialConstrained : public FieldTrialParameterInterface {
  91. public:
  92. FieldTrialConstrained(std::string key,
  93. T default_value,
  94. absl::optional<T> lower_limit,
  95. absl::optional<T> upper_limit)
  96. : FieldTrialParameterInterface(key),
  97. value_(default_value),
  98. lower_limit_(lower_limit),
  99. upper_limit_(upper_limit) {}
  100. T Get() const { return value_; }
  101. operator T() const { return Get(); }
  102. const T* operator->() const { return &value_; }
  103. protected:
  104. bool Parse(absl::optional<std::string> str_value) override {
  105. if (str_value) {
  106. absl::optional<T> value = ParseTypedParameter<T>(*str_value);
  107. if (value && (!lower_limit_ || *value >= *lower_limit_) &&
  108. (!upper_limit_ || *value <= *upper_limit_)) {
  109. value_ = *value;
  110. return true;
  111. }
  112. }
  113. return false;
  114. }
  115. private:
  116. T value_;
  117. absl::optional<T> lower_limit_;
  118. absl::optional<T> upper_limit_;
  119. };
  120. class AbstractFieldTrialEnum : public FieldTrialParameterInterface {
  121. public:
  122. AbstractFieldTrialEnum(std::string key,
  123. int default_value,
  124. std::map<std::string, int> mapping);
  125. ~AbstractFieldTrialEnum() override;
  126. AbstractFieldTrialEnum(const AbstractFieldTrialEnum&);
  127. protected:
  128. bool Parse(absl::optional<std::string> str_value) override;
  129. protected:
  130. int value_;
  131. std::map<std::string, int> enum_mapping_;
  132. std::set<int> valid_values_;
  133. };
  134. // The FieldTrialEnum class can be used to quickly define a parser for a
  135. // specific enum. It handles values provided as integers and as strings if a
  136. // mapping is provided.
  137. template <typename T>
  138. class FieldTrialEnum : public AbstractFieldTrialEnum {
  139. public:
  140. FieldTrialEnum(std::string key,
  141. T default_value,
  142. std::map<std::string, T> mapping)
  143. : AbstractFieldTrialEnum(key,
  144. static_cast<int>(default_value),
  145. ToIntMap(mapping)) {}
  146. T Get() const { return static_cast<T>(value_); }
  147. operator T() const { return Get(); }
  148. private:
  149. static std::map<std::string, int> ToIntMap(std::map<std::string, T> mapping) {
  150. std::map<std::string, int> res;
  151. for (const auto& it : mapping)
  152. res[it.first] = static_cast<int>(it.second);
  153. return res;
  154. }
  155. };
  156. // This class uses the ParseTypedParameter function to implement an optional
  157. // parameter implementation that can default to absl::nullopt.
  158. template <typename T>
  159. class FieldTrialOptional : public FieldTrialParameterInterface {
  160. public:
  161. explicit FieldTrialOptional(std::string key)
  162. : FieldTrialParameterInterface(key) {}
  163. FieldTrialOptional(std::string key, absl::optional<T> default_value)
  164. : FieldTrialParameterInterface(key), value_(default_value) {}
  165. absl::optional<T> GetOptional() const { return value_; }
  166. const T& Value() const { return value_.value(); }
  167. const T& operator*() const { return value_.value(); }
  168. const T* operator->() const { return &value_.value(); }
  169. explicit operator bool() const { return value_.has_value(); }
  170. protected:
  171. bool Parse(absl::optional<std::string> str_value) override {
  172. if (str_value) {
  173. absl::optional<T> value = ParseTypedParameter<T>(*str_value);
  174. if (!value.has_value())
  175. return false;
  176. value_ = value.value();
  177. } else {
  178. value_ = absl::nullopt;
  179. }
  180. return true;
  181. }
  182. private:
  183. absl::optional<T> value_;
  184. };
  185. // Equivalent to a FieldTrialParameter<bool> in the case that both key and value
  186. // are present. If key is missing, evaluates to false. If key is present, but no
  187. // explicit value is provided, the flag evaluates to true.
  188. class FieldTrialFlag : public FieldTrialParameterInterface {
  189. public:
  190. explicit FieldTrialFlag(std::string key);
  191. FieldTrialFlag(std::string key, bool default_value);
  192. bool Get() const;
  193. operator bool() const;
  194. protected:
  195. bool Parse(absl::optional<std::string> str_value) override;
  196. private:
  197. bool value_;
  198. };
  199. template <typename T>
  200. absl::optional<absl::optional<T>> ParseOptionalParameter(std::string str) {
  201. if (str.empty())
  202. return absl::optional<T>();
  203. auto parsed = ParseTypedParameter<T>(str);
  204. if (parsed.has_value())
  205. return parsed;
  206. return absl::nullopt;
  207. }
  208. template <>
  209. absl::optional<bool> ParseTypedParameter<bool>(std::string str);
  210. template <>
  211. absl::optional<double> ParseTypedParameter<double>(std::string str);
  212. template <>
  213. absl::optional<int> ParseTypedParameter<int>(std::string str);
  214. template <>
  215. absl::optional<unsigned> ParseTypedParameter<unsigned>(std::string str);
  216. template <>
  217. absl::optional<std::string> ParseTypedParameter<std::string>(std::string str);
  218. template <>
  219. absl::optional<absl::optional<bool>> ParseTypedParameter<absl::optional<bool>>(
  220. std::string str);
  221. template <>
  222. absl::optional<absl::optional<int>> ParseTypedParameter<absl::optional<int>>(
  223. std::string str);
  224. template <>
  225. absl::optional<absl::optional<unsigned>>
  226. ParseTypedParameter<absl::optional<unsigned>>(std::string str);
  227. template <>
  228. absl::optional<absl::optional<double>>
  229. ParseTypedParameter<absl::optional<double>>(std::string str);
  230. // Accepts true, false, else parsed with sscanf %i, true if != 0.
  231. extern template class FieldTrialParameter<bool>;
  232. // Interpreted using sscanf %lf.
  233. extern template class FieldTrialParameter<double>;
  234. // Interpreted using sscanf %i.
  235. extern template class FieldTrialParameter<int>;
  236. // Interpreted using sscanf %u.
  237. extern template class FieldTrialParameter<unsigned>;
  238. // Using the given value as is.
  239. extern template class FieldTrialParameter<std::string>;
  240. extern template class FieldTrialConstrained<double>;
  241. extern template class FieldTrialConstrained<int>;
  242. extern template class FieldTrialConstrained<unsigned>;
  243. extern template class FieldTrialOptional<double>;
  244. extern template class FieldTrialOptional<int>;
  245. extern template class FieldTrialOptional<unsigned>;
  246. extern template class FieldTrialOptional<bool>;
  247. extern template class FieldTrialOptional<std::string>;
  248. } // namespace webrtc
  249. #endif // RTC_BASE_EXPERIMENTS_FIELD_TRIAL_PARSER_H_