field_trials.cc (3577B)
1 /* 2 * Copyright (c) 2020 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 11 #include "api/field_trials.h" 12 13 #include <memory> 14 #include <string> 15 #include <utility> 16 17 #include "absl/base/nullability.h" 18 #include "absl/memory/memory.h" 19 #include "absl/strings/string_view.h" 20 #include "api/field_trials_registry.h" 21 #include "rtc_base/checks.h" 22 #include "rtc_base/containers/flat_map.h" 23 24 namespace webrtc { 25 namespace { 26 27 absl::string_view NextKeyOrValue(absl::string_view& s) { 28 absl::string_view::size_type separator_pos = s.find('/'); 29 if (separator_pos == absl::string_view::npos) { 30 // Missing separator '/' after field trial key or value. 31 return ""; 32 } 33 absl::string_view result = s.substr(0, separator_pos); 34 s.remove_prefix(separator_pos + 1); 35 return result; 36 } 37 38 bool Parse(absl::string_view s, 39 flat_map<std::string, std::string>& key_value_map) { 40 while (!s.empty()) { 41 absl::string_view key = NextKeyOrValue(s); 42 absl::string_view value = NextKeyOrValue(s); 43 if (key.empty() || value.empty()) { 44 return false; 45 } 46 47 auto it = key_value_map.emplace(key, value).first; 48 if (it->second != value) { 49 // Duplicate trials with different values is not fine. 50 return false; 51 } 52 } 53 return true; 54 } 55 56 } // namespace 57 58 absl_nullable std::unique_ptr<FieldTrials> FieldTrials::Create( 59 absl::string_view s) { 60 flat_map<std::string, std::string> key_value_map; 61 if (!Parse(s, key_value_map)) { 62 return nullptr; 63 } 64 // Using `new` to access a private constructor. 65 return absl::WrapUnique(new FieldTrials(std::move(key_value_map))); 66 } 67 68 FieldTrials::FieldTrials(absl::string_view s) { 69 RTC_CHECK(Parse(s, key_value_map_)); 70 } 71 72 FieldTrials::FieldTrials(const FieldTrials& other) 73 : FieldTrialsRegistry(other) { 74 key_value_map_ = other.key_value_map_; 75 } 76 77 FieldTrials::FieldTrials(FieldTrials&& other) : FieldTrialsRegistry(other) { 78 key_value_map_ = std::move(other.key_value_map_); 79 } 80 81 FieldTrials& FieldTrials::operator=(const FieldTrials& other) { 82 if (this != &other) { 83 AssertGetValueNotCalled(); 84 FieldTrialsRegistry::operator=(other); 85 key_value_map_ = other.key_value_map_; 86 } 87 return *this; 88 } 89 90 FieldTrials& FieldTrials::operator=(FieldTrials&& other) { 91 if (this != &other) { 92 AssertGetValueNotCalled(); 93 FieldTrialsRegistry::operator=(other); 94 key_value_map_ = std::move(other.key_value_map_); 95 } 96 return *this; 97 } 98 99 void FieldTrials::Merge(const FieldTrials& other) { 100 AssertGetValueNotCalled(); 101 for (const auto& [trial, group] : other.key_value_map_) { 102 key_value_map_.insert_or_assign(trial, group); 103 } 104 } 105 106 void FieldTrials::Set(absl::string_view trial, absl::string_view group) { 107 AssertGetValueNotCalled(); 108 RTC_CHECK(!trial.empty()); 109 RTC_CHECK_EQ(trial.find('/'), absl::string_view::npos); 110 RTC_CHECK_EQ(group.find('/'), absl::string_view::npos); 111 if (group.empty()) { 112 key_value_map_.erase(trial); 113 } else { 114 key_value_map_.insert_or_assign(trial, group); 115 } 116 } 117 118 std::string FieldTrials::GetValue(absl::string_view key) const { 119 #if RTC_DCHECK_IS_ON 120 get_value_called_ = true; 121 #endif 122 auto it = key_value_map_.find(key); 123 if (it != key_value_map_.end()) { 124 return it->second; 125 } 126 127 return ""; 128 } 129 130 } // namespace webrtc