/* * Copyright (c) 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. */ #ifndef RTC_BASE_EXPERIMENTS_STRUCT_PARAMETERS_PARSER_H_ #define RTC_BASE_EXPERIMENTS_STRUCT_PARAMETERS_PARSER_H_ #include #include #include #include #include #include #include "absl/memory/memory.h" #include "absl/strings/string_view.h" #include "absl/types/optional.h" #include "rtc_base/experiments/field_trial_parser.h" #include "rtc_base/experiments/field_trial_units.h" #include "rtc_base/string_encode.h" namespace webrtc { namespace struct_parser_impl { inline std::string StringEncode(bool val) { return rtc::ToString(val); } inline std::string StringEncode(double val) { return rtc::ToString(val); } inline std::string StringEncode(int val) { return rtc::ToString(val); } inline std::string StringEncode(std::string val) { return val; } inline std::string StringEncode(DataRate val) { return ToString(val); } inline std::string StringEncode(DataSize val) { return ToString(val); } inline std::string StringEncode(TimeDelta val) { return ToString(val); } template inline std::string StringEncode(absl::optional val) { if (val) return StringEncode(*val); return ""; } template struct LambdaTraits : public LambdaTraits {}; template struct LambdaTraits { using ret = RetType; using src = SourceType; }; void ParseConfigParams( absl::string_view config_str, std::map> field_map); std::string EncodeStringStringMap(std::map mapping); template class StructParameterParser { public: virtual bool Parse(absl::string_view src, StructType* target) const = 0; virtual bool Changed(const StructType& src, const StructType& base) const = 0; virtual std::string Encode(const StructType& src) const = 0; virtual ~StructParameterParser() = default; }; template class StructParameterImpl : public StructParameterParser { public: explicit StructParameterImpl(std::function field_getter) : field_getter_(std::move(field_getter)) {} bool Parse(absl::string_view src, StructType* target) const override { auto parsed = ParseTypedParameter(std::string(src)); if (parsed.has_value()) *field_getter_(target) = *parsed; return parsed.has_value(); } bool Changed(const StructType& src, const StructType& base) const override { T base_value = *field_getter_(const_cast(&base)); T value = *field_getter_(const_cast(&src)); return value != base_value; } std::string Encode(const StructType& src) const override { T value = *field_getter_(const_cast(&src)); return struct_parser_impl::StringEncode(value); } private: const std::function field_getter_; }; template struct StructParameter { std::string key; StructParameterParser* parser; }; template ::ret> void AddParameters(std::vector>* out, std::string key, Closure getter) { auto* parser = new StructParameterImpl(getter); out->push_back(StructParameter{std::move(key), parser}); } template ::ret, typename... Args> void AddParameters(std::vector>* out, std::string key, Closure getter, Args... args) { AddParameters(out, key, getter); AddParameters(out, args...); } } // namespace struct_parser_impl template class StructParametersParser { public: ~StructParametersParser() { for (auto& param : parameters_) { delete param.parser; } } void Parse(StructType* target, absl::string_view src) { std::map> field_parsers; for (const auto& param : parameters_) { field_parsers.emplace(param.key, [target, param](absl::string_view src) { return param.parser->Parse(src, target); }); } struct_parser_impl::ParseConfigParams(src, std::move(field_parsers)); } StructType Parse(absl::string_view src) { StructType res; Parse(&res, src); return res; } std::string EncodeChanged(const StructType& src) { static StructType base; std::map pairs; for (const auto& param : parameters_) { if (param.parser->Changed(src, base)) pairs[param.key] = param.parser->Encode(src); } return struct_parser_impl::EncodeStringStringMap(pairs); } std::string EncodeAll(const StructType& src) { std::map pairs; for (const auto& param : parameters_) { pairs[param.key] = param.parser->Encode(src); } return struct_parser_impl::EncodeStringStringMap(pairs); } private: template friend std::unique_ptr> CreateStructParametersParser(std::string, C, Args...); explicit StructParametersParser( std::vector> parameters) : parameters_(parameters) {} std::vector> parameters_; }; // Creates a struct parameters parser based on interleaved key and field // accessor arguments, where the field accessor converts a struct pointer to a // member pointer: FieldType*(StructType*). See the unit tests for example // usage. Note that the struct type is inferred from the field getters. Beware // of providing incorrect arguments to this, such as mixing the struct type or // incorrect return values, as this will cause very confusing compile errors. template ::src, typename... Args> std::unique_ptr> CreateStructParametersParser( std::string first_key, Closure first_getter, Args... args) { std::vector> parameters; struct_parser_impl::AddParameters(¶meters, std::move(first_key), first_getter, args...); // absl::make_unique can't be used since the StructParametersParser // constructor is only visible to this create function. return absl::WrapUnique(new StructParametersParser(std::move(parameters))); } } // namespace webrtc #endif // RTC_BASE_EXPERIMENTS_STRUCT_PARAMETERS_PARSER_H_