blob: f6728f6ea5a1e0c3933fa3fd8dccc64534f0d9a7 [file] [log] [blame]
Sebastian Jansson55251c32019-08-08 11:14:51 +02001/*
2 * Copyright (c) 2019 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_STRUCT_PARAMETERS_PARSER_H_
11#define RTC_BASE_EXPERIMENTS_STRUCT_PARAMETERS_PARSER_H_
12
13#include <functional>
14#include <map>
15#include <memory>
16#include <string>
17#include <utility>
18#include <vector>
19
20#include "absl/memory/memory.h"
21#include "absl/strings/string_view.h"
22#include "absl/types/optional.h"
23#include "rtc_base/experiments/field_trial_parser.h"
24#include "rtc_base/experiments/field_trial_units.h"
25#include "rtc_base/string_encode.h"
26
27namespace webrtc {
28namespace struct_parser_impl {
29inline std::string StringEncode(bool val) {
30 return rtc::ToString(val);
31}
32inline std::string StringEncode(double val) {
33 return rtc::ToString(val);
34}
35inline std::string StringEncode(int val) {
36 return rtc::ToString(val);
37}
38inline std::string StringEncode(std::string val) {
39 return val;
40}
41inline std::string StringEncode(DataRate val) {
42 return ToString(val);
43}
44inline std::string StringEncode(DataSize val) {
45 return ToString(val);
46}
47inline std::string StringEncode(TimeDelta val) {
48 return ToString(val);
49}
50
51template <typename T>
52inline std::string StringEncode(absl::optional<T> val) {
53 if (val)
54 return StringEncode(*val);
55 return "";
56}
57
58template <typename T>
59struct LambdaTraits : public LambdaTraits<decltype(&T::operator())> {};
60
61template <typename ClassType, typename RetType, typename SourceType>
62struct LambdaTraits<RetType* (ClassType::*)(SourceType*)const> {
63 using ret = RetType;
64 using src = SourceType;
65};
66
67void ParseConfigParams(
68 absl::string_view config_str,
69 std::map<std::string, std::function<bool(absl::string_view)>> field_map);
70
71std::string EncodeStringStringMap(std::map<std::string, std::string> mapping);
72
73template <typename StructType>
74class StructParameterParser {
75 public:
76 virtual bool Parse(absl::string_view src, StructType* target) const = 0;
77 virtual bool Changed(const StructType& src, const StructType& base) const = 0;
78 virtual std::string Encode(const StructType& src) const = 0;
79 virtual ~StructParameterParser() = default;
80};
81
82template <typename StructType, typename T>
83class StructParameterImpl : public StructParameterParser<StructType> {
84 public:
85 explicit StructParameterImpl(std::function<T*(StructType*)> field_getter)
86 : field_getter_(std::move(field_getter)) {}
87 bool Parse(absl::string_view src, StructType* target) const override {
88 auto parsed = ParseTypedParameter<T>(std::string(src));
89 if (parsed.has_value())
90 *field_getter_(target) = *parsed;
91 return parsed.has_value();
92 }
93 bool Changed(const StructType& src, const StructType& base) const override {
94 T base_value = *field_getter_(const_cast<StructType*>(&base));
95 T value = *field_getter_(const_cast<StructType*>(&src));
96 return value != base_value;
97 }
98 std::string Encode(const StructType& src) const override {
99 T value = *field_getter_(const_cast<StructType*>(&src));
100 return struct_parser_impl::StringEncode(value);
101 }
102
103 private:
104 const std::function<T*(StructType*)> field_getter_;
105};
106
107template <typename StructType>
108struct StructParameter {
109 std::string key;
110 StructParameterParser<StructType>* parser;
111};
112
113template <typename S,
114 typename Closure,
115 typename T = typename LambdaTraits<Closure>::ret>
116void AddParameters(std::vector<StructParameter<S>>* out,
117 std::string key,
118 Closure getter) {
119 auto* parser = new StructParameterImpl<S, T>(getter);
120 out->push_back(StructParameter<S>{std::move(key), parser});
121}
122
123template <typename S,
124 typename Closure,
125 typename T = typename LambdaTraits<Closure>::ret,
126 typename... Args>
127void AddParameters(std::vector<StructParameter<S>>* out,
128 std::string key,
129 Closure getter,
130 Args... args) {
131 AddParameters(out, key, getter);
132 AddParameters<S>(out, args...);
133}
134
135} // namespace struct_parser_impl
136
137template <typename StructType>
138class StructParametersParser {
139 public:
140 ~StructParametersParser() {
141 for (auto& param : parameters_) {
142 delete param.parser;
143 }
144 }
145
146 void Parse(StructType* target, absl::string_view src) {
147 std::map<std::string, std::function<bool(absl::string_view)>> field_parsers;
148 for (const auto& param : parameters_) {
149 field_parsers.emplace(param.key, [target, param](absl::string_view src) {
150 return param.parser->Parse(src, target);
151 });
152 }
153 struct_parser_impl::ParseConfigParams(src, std::move(field_parsers));
154 }
155
156 StructType Parse(absl::string_view src) {
157 StructType res;
158 Parse(&res, src);
159 return res;
160 }
161
162 std::string EncodeChanged(const StructType& src) {
163 static StructType base;
164 std::map<std::string, std::string> pairs;
165 for (const auto& param : parameters_) {
166 if (param.parser->Changed(src, base))
167 pairs[param.key] = param.parser->Encode(src);
168 }
169 return struct_parser_impl::EncodeStringStringMap(pairs);
170 }
171
172 std::string EncodeAll(const StructType& src) {
173 std::map<std::string, std::string> pairs;
174 for (const auto& param : parameters_) {
175 pairs[param.key] = param.parser->Encode(src);
176 }
177 return struct_parser_impl::EncodeStringStringMap(pairs);
178 }
179
180 private:
181 template <typename C, typename S, typename... Args>
182 friend std::unique_ptr<StructParametersParser<S>>
183 CreateStructParametersParser(std::string, C, Args...);
184
185 explicit StructParametersParser(
186 std::vector<struct_parser_impl::StructParameter<StructType>> parameters)
187 : parameters_(parameters) {}
188
189 std::vector<struct_parser_impl::StructParameter<StructType>> parameters_;
190};
191
192// Creates a struct parameters parser based on interleaved key and field
193// accessor arguments, where the field accessor converts a struct pointer to a
194// member pointer: FieldType*(StructType*). See the unit tests for example
195// usage. Note that the struct type is inferred from the field getters. Beware
196// of providing incorrect arguments to this, such as mixing the struct type or
197// incorrect return values, as this will cause very confusing compile errors.
198template <typename Closure,
199 typename S = typename struct_parser_impl::LambdaTraits<Closure>::src,
200 typename... Args>
201std::unique_ptr<StructParametersParser<S>> CreateStructParametersParser(
202 std::string first_key,
203 Closure first_getter,
204 Args... args) {
205 std::vector<struct_parser_impl::StructParameter<S>> parameters;
206 struct_parser_impl::AddParameters<S>(&parameters, std::move(first_key),
207 first_getter, args...);
208 // absl::make_unique can't be used since the StructParametersParser
209 // constructor is only visible to this create function.
210 return absl::WrapUnique(new StructParametersParser<S>(std::move(parameters)));
211}
212} // namespace webrtc
213
214#endif // RTC_BASE_EXPERIMENTS_STRUCT_PARAMETERS_PARSER_H_