blob: 55299adbb618baaa2901524416bece9e75880417 [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#include "rtc_base/experiments/field_trial_parser.h"
11
12#include <algorithm>
13#include <map>
14#include <type_traits>
15#include <utility>
16
17#include "rtc_base/logging.h"
18
19namespace webrtc {
20namespace {
21
22int FindOrEnd(std::string str, size_t start, char delimiter) {
23 size_t pos = str.find(delimiter, start);
24 pos = (pos == std::string::npos) ? str.length() : pos;
25 return static_cast<int>(pos);
26}
27} // namespace
28
29FieldTrialParameterInterface::FieldTrialParameterInterface(std::string key)
30 : key_(key) {}
31FieldTrialParameterInterface::~FieldTrialParameterInterface() = default;
32std::string FieldTrialParameterInterface::Key() const {
33 return key_;
34}
35
36void ParseFieldTrial(
37 std::initializer_list<FieldTrialParameterInterface*> fields,
38 std::string trial_string) {
39 std::map<std::string, FieldTrialParameterInterface*> field_map;
40 for (FieldTrialParameterInterface* field : fields) {
41 field_map[field->Key()] = field;
42 }
43 size_t i = 0;
44 while (i < trial_string.length()) {
45 int val_end = FindOrEnd(trial_string, i, ',');
46 int colon_pos = FindOrEnd(trial_string, i, ':');
47 int key_end = std::min(val_end, colon_pos);
48 int val_begin = key_end + 1;
49 std::string key = trial_string.substr(i, key_end - i);
Danil Chapovalov0a1d1892018-06-21 11:48:25 +020050 absl::optional<std::string> opt_value;
Sebastian Jansson9eb38862018-06-14 16:47:42 +020051 if (val_end >= val_begin)
52 opt_value = trial_string.substr(val_begin, val_end - val_begin);
53 i = val_end + 1;
54 auto field = field_map.find(key);
55 if (field != field_map.end()) {
56 if (!field->second->Parse(std::move(opt_value))) {
57 RTC_LOG(LS_WARNING) << "Failed to read field with key: '" << key
58 << "' in trial: \"" << trial_string << "\"";
59 }
60 } else {
61 RTC_LOG(LS_INFO) << "No field with key: '" << key
62 << "' (found in trial: \"" << trial_string << "\")";
63 }
64 }
65}
66
67template <>
Danil Chapovalov0a1d1892018-06-21 11:48:25 +020068absl::optional<bool> ParseTypedParameter<bool>(std::string str) {
Sebastian Jansson9eb38862018-06-14 16:47:42 +020069 if (str == "true" || str == "1") {
70 return true;
71 } else if (str == "false" || str == "0") {
72 return false;
73 }
Danil Chapovalov0a1d1892018-06-21 11:48:25 +020074 return absl::nullopt;
Sebastian Jansson9eb38862018-06-14 16:47:42 +020075}
76
77template <>
Danil Chapovalov0a1d1892018-06-21 11:48:25 +020078absl::optional<double> ParseTypedParameter<double>(std::string str) {
Sebastian Jansson9eb38862018-06-14 16:47:42 +020079 double value;
80 if (sscanf(str.c_str(), "%lf", &value) == 1) {
81 return value;
82 } else {
Danil Chapovalov0a1d1892018-06-21 11:48:25 +020083 return absl::nullopt;
Sebastian Jansson9eb38862018-06-14 16:47:42 +020084 }
85}
86
87template <>
Danil Chapovalov0a1d1892018-06-21 11:48:25 +020088absl::optional<int> ParseTypedParameter<int>(std::string str) {
Sebastian Jansson9eb38862018-06-14 16:47:42 +020089 int value;
90 if (sscanf(str.c_str(), "%i", &value) == 1) {
91 return value;
92 } else {
Danil Chapovalov0a1d1892018-06-21 11:48:25 +020093 return absl::nullopt;
Sebastian Jansson9eb38862018-06-14 16:47:42 +020094 }
95}
96
97template <>
Danil Chapovalov0a1d1892018-06-21 11:48:25 +020098absl::optional<std::string> ParseTypedParameter<std::string>(std::string str) {
Sebastian Jansson9eb38862018-06-14 16:47:42 +020099 return std::move(str);
100}
101
102FieldTrialFlag::FieldTrialFlag(std::string key) : FieldTrialFlag(key, false) {}
103
104FieldTrialFlag::FieldTrialFlag(std::string key, bool default_value)
105 : FieldTrialParameterInterface(key), value_(default_value) {}
106
107bool FieldTrialFlag::Get() const {
108 return value_;
109}
110
Danil Chapovalov0a1d1892018-06-21 11:48:25 +0200111bool FieldTrialFlag::Parse(absl::optional<std::string> str_value) {
Sebastian Jansson9eb38862018-06-14 16:47:42 +0200112 // Only set the flag if there is no argument provided.
113 if (str_value) {
Danil Chapovalov0a1d1892018-06-21 11:48:25 +0200114 absl::optional<bool> opt_value = ParseTypedParameter<bool>(*str_value);
Sebastian Jansson9eb38862018-06-14 16:47:42 +0200115 if (!opt_value)
116 return false;
117 value_ = *opt_value;
118 } else {
119 value_ = true;
120 }
121 return true;
122}
123
Sebastian Jansson2c74d852018-06-26 10:30:16 +0200124AbstractFieldTrialEnum::AbstractFieldTrialEnum(
125 std::string key,
126 int default_value,
127 std::map<std::string, int> mapping)
128 : FieldTrialParameterInterface(key),
129 value_(default_value),
130 enum_mapping_(mapping) {
131 for (auto& key_val : enum_mapping_)
132 valid_values_.insert(key_val.second);
133}
134AbstractFieldTrialEnum::AbstractFieldTrialEnum(const AbstractFieldTrialEnum&) =
135 default;
136AbstractFieldTrialEnum::~AbstractFieldTrialEnum() = default;
137
138bool AbstractFieldTrialEnum::Parse(absl::optional<std::string> str_value) {
139 if (str_value) {
140 auto it = enum_mapping_.find(*str_value);
141 if (it != enum_mapping_.end()) {
142 value_ = it->second;
143 return true;
144 }
145 absl::optional<int> value = ParseTypedParameter<int>(*str_value);
146 if (value.has_value() &&
147 (valid_values_.find(*value) != valid_values_.end())) {
148 value_ = *value;
149 return true;
150 }
151 }
152 return false;
153}
154
Sebastian Jansson9eb38862018-06-14 16:47:42 +0200155template class FieldTrialParameter<bool>;
156template class FieldTrialParameter<double>;
157template class FieldTrialParameter<int>;
158template class FieldTrialParameter<std::string>;
159
160template class FieldTrialOptional<double>;
161template class FieldTrialOptional<int>;
162template class FieldTrialOptional<bool>;
163template class FieldTrialOptional<std::string>;
164
165} // namespace webrtc