summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/rtc_base/experiments/field_trial_parser.cc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/libwebrtc/rtc_base/experiments/field_trial_parser.cc
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/libwebrtc/rtc_base/experiments/field_trial_parser.cc')
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/field_trial_parser.cc260
1 files changed, 260 insertions, 0 deletions
diff --git a/third_party/libwebrtc/rtc_base/experiments/field_trial_parser.cc b/third_party/libwebrtc/rtc_base/experiments/field_trial_parser.cc
new file mode 100644
index 0000000000..78d5489f5e
--- /dev/null
+++ b/third_party/libwebrtc/rtc_base/experiments/field_trial_parser.cc
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#include "rtc_base/experiments/field_trial_parser.h"
+
+#include <inttypes.h>
+
+#include <algorithm>
+#include <map>
+#include <type_traits>
+#include <utility>
+
+#include "absl/strings/string_view.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/numerics/safe_conversions.h"
+
+namespace webrtc {
+
+FieldTrialParameterInterface::FieldTrialParameterInterface(
+ absl::string_view key)
+ : key_(key) {}
+FieldTrialParameterInterface::~FieldTrialParameterInterface() {
+ RTC_DCHECK(used_) << "Field trial parameter with key: '" << key_
+ << "' never used.";
+}
+
+void ParseFieldTrial(
+ std::initializer_list<FieldTrialParameterInterface*> fields,
+ absl::string_view trial_string) {
+ std::map<absl::string_view, FieldTrialParameterInterface*> field_map;
+ FieldTrialParameterInterface* keyless_field = nullptr;
+ for (FieldTrialParameterInterface* field : fields) {
+ field->MarkAsUsed();
+ if (!field->sub_parameters_.empty()) {
+ for (FieldTrialParameterInterface* sub_field : field->sub_parameters_) {
+ RTC_DCHECK(!sub_field->key_.empty());
+ sub_field->MarkAsUsed();
+ field_map[sub_field->key_] = sub_field;
+ }
+ continue;
+ }
+
+ if (field->key_.empty()) {
+ RTC_DCHECK(!keyless_field);
+ keyless_field = field;
+ } else {
+ field_map[field->key_] = field;
+ }
+ }
+ bool logged_unknown_key = false;
+
+ absl::string_view tail = trial_string;
+ while (!tail.empty()) {
+ size_t key_end = tail.find_first_of(",:");
+ absl::string_view key = tail.substr(0, key_end);
+ absl::optional<std::string> opt_value;
+ if (key_end == absl::string_view::npos) {
+ tail = "";
+ } else if (tail[key_end] == ':') {
+ tail = tail.substr(key_end + 1);
+ size_t value_end = tail.find(',');
+ opt_value.emplace(tail.substr(0, value_end));
+ if (value_end == absl::string_view::npos) {
+ tail = "";
+ } else {
+ tail = tail.substr(value_end + 1);
+ }
+ } else {
+ RTC_DCHECK_EQ(tail[key_end], ',');
+ tail = tail.substr(key_end + 1);
+ }
+
+ auto field = field_map.find(key);
+ if (field != field_map.end()) {
+ if (!field->second->Parse(std::move(opt_value))) {
+ RTC_LOG(LS_WARNING) << "Failed to read field with key: '" << key
+ << "' in trial: \"" << trial_string << "\"";
+ }
+ } else if (!opt_value && keyless_field && !key.empty()) {
+ if (!keyless_field->Parse(std::string(key))) {
+ RTC_LOG(LS_WARNING) << "Failed to read empty key field with value '"
+ << key << "' in trial: \"" << trial_string << "\"";
+ }
+ } else if (key.empty() || key[0] != '_') {
+ // "_" is be used to prefix keys that are part of the string for
+ // debugging purposes but not neccessarily used.
+ // e.g. WebRTC-Experiment/param: value, _DebuggingString
+ if (!logged_unknown_key) {
+ RTC_LOG(LS_INFO) << "No field with key: '" << key
+ << "' (found in trial: \"" << trial_string << "\")";
+ std::string valid_keys;
+ for (const auto& f : field_map) {
+ valid_keys.append(f.first.data(), f.first.size());
+ valid_keys += ", ";
+ }
+ RTC_LOG(LS_INFO) << "Valid keys are: " << valid_keys;
+ logged_unknown_key = true;
+ }
+ }
+ }
+
+ for (FieldTrialParameterInterface* field : fields) {
+ field->ParseDone();
+ }
+}
+
+template <>
+absl::optional<bool> ParseTypedParameter<bool>(absl::string_view str) {
+ if (str == "true" || str == "1") {
+ return true;
+ } else if (str == "false" || str == "0") {
+ return false;
+ }
+ return absl::nullopt;
+}
+
+template <>
+absl::optional<double> ParseTypedParameter<double>(absl::string_view str) {
+ double value;
+ char unit[2]{0, 0};
+ if (sscanf(std::string(str).c_str(), "%lf%1s", &value, unit) >= 1) {
+ if (unit[0] == '%')
+ return value / 100;
+ return value;
+ } else {
+ return absl::nullopt;
+ }
+}
+
+template <>
+absl::optional<int> ParseTypedParameter<int>(absl::string_view str) {
+ int64_t value;
+ if (sscanf(std::string(str).c_str(), "%" SCNd64, &value) == 1) {
+ if (rtc::IsValueInRangeForNumericType<int, int64_t>(value)) {
+ return static_cast<int>(value);
+ }
+ }
+ return absl::nullopt;
+}
+
+template <>
+absl::optional<unsigned> ParseTypedParameter<unsigned>(absl::string_view str) {
+ int64_t value;
+ if (sscanf(std::string(str).c_str(), "%" SCNd64, &value) == 1) {
+ if (rtc::IsValueInRangeForNumericType<unsigned, int64_t>(value)) {
+ return static_cast<unsigned>(value);
+ }
+ }
+ return absl::nullopt;
+}
+
+template <>
+absl::optional<std::string> ParseTypedParameter<std::string>(
+ absl::string_view str) {
+ return std::string(str);
+}
+
+template <>
+absl::optional<absl::optional<bool>> ParseTypedParameter<absl::optional<bool>>(
+ absl::string_view str) {
+ return ParseOptionalParameter<bool>(str);
+}
+template <>
+absl::optional<absl::optional<int>> ParseTypedParameter<absl::optional<int>>(
+ absl::string_view str) {
+ return ParseOptionalParameter<int>(str);
+}
+template <>
+absl::optional<absl::optional<unsigned>>
+ParseTypedParameter<absl::optional<unsigned>>(absl::string_view str) {
+ return ParseOptionalParameter<unsigned>(str);
+}
+template <>
+absl::optional<absl::optional<double>>
+ParseTypedParameter<absl::optional<double>>(absl::string_view str) {
+ return ParseOptionalParameter<double>(str);
+}
+
+FieldTrialFlag::FieldTrialFlag(absl::string_view key)
+ : FieldTrialFlag(key, false) {}
+
+FieldTrialFlag::FieldTrialFlag(absl::string_view key, bool default_value)
+ : FieldTrialParameterInterface(key), value_(default_value) {}
+
+bool FieldTrialFlag::Get() const {
+ return value_;
+}
+
+webrtc::FieldTrialFlag::operator bool() const {
+ return value_;
+}
+
+bool FieldTrialFlag::Parse(absl::optional<std::string> str_value) {
+ // Only set the flag if there is no argument provided.
+ if (str_value) {
+ absl::optional<bool> opt_value = ParseTypedParameter<bool>(*str_value);
+ if (!opt_value)
+ return false;
+ value_ = *opt_value;
+ } else {
+ value_ = true;
+ }
+ return true;
+}
+
+AbstractFieldTrialEnum::AbstractFieldTrialEnum(
+ absl::string_view key,
+ int default_value,
+ std::map<std::string, int> mapping)
+ : FieldTrialParameterInterface(key),
+ value_(default_value),
+ enum_mapping_(mapping) {
+ for (auto& key_val : enum_mapping_)
+ valid_values_.insert(key_val.second);
+}
+AbstractFieldTrialEnum::AbstractFieldTrialEnum(const AbstractFieldTrialEnum&) =
+ default;
+AbstractFieldTrialEnum::~AbstractFieldTrialEnum() = default;
+
+bool AbstractFieldTrialEnum::Parse(absl::optional<std::string> str_value) {
+ if (str_value) {
+ auto it = enum_mapping_.find(*str_value);
+ if (it != enum_mapping_.end()) {
+ value_ = it->second;
+ return true;
+ }
+ absl::optional<int> value = ParseTypedParameter<int>(*str_value);
+ if (value.has_value() &&
+ (valid_values_.find(*value) != valid_values_.end())) {
+ value_ = *value;
+ return true;
+ }
+ }
+ return false;
+}
+
+template class FieldTrialParameter<bool>;
+template class FieldTrialParameter<double>;
+template class FieldTrialParameter<int>;
+template class FieldTrialParameter<unsigned>;
+template class FieldTrialParameter<std::string>;
+
+template class FieldTrialConstrained<double>;
+template class FieldTrialConstrained<int>;
+template class FieldTrialConstrained<unsigned>;
+
+template class FieldTrialOptional<double>;
+template class FieldTrialOptional<int>;
+template class FieldTrialOptional<unsigned>;
+template class FieldTrialOptional<bool>;
+template class FieldTrialOptional<std::string>;
+
+} // namespace webrtc