mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 13:50:40 +01:00

git ls-files | grep -e "\(\.h\|\.cc\)$" | grep -e "^rtc_base/" | xargs clang-format -i ; git cl format after landing: add to .git-blame-ignore-revs Bug: webrtc:15082 Change-Id: I152228f7c7926adf95d2f3fbbe4178556fd75d0d Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/302061 Reviewed-by: Florent Castelli <orphis@webrtc.org> Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org> Commit-Queue: Harald Alvestrand <hta@webrtc.org> Reviewed-by: Harald Alvestrand <hta@webrtc.org> Cr-Commit-Position: refs/heads/main@{#39914}
226 lines
7 KiB
C++
226 lines
7 KiB
C++
/*
|
|
* Copyright 2018 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_FIELD_TRIAL_LIST_H_
|
|
#define RTC_BASE_EXPERIMENTS_FIELD_TRIAL_LIST_H_
|
|
|
|
#include <initializer_list>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "absl/strings/string_view.h"
|
|
#include "rtc_base/experiments/field_trial_parser.h"
|
|
#include "rtc_base/string_encode.h"
|
|
|
|
// List support for field trial strings. FieldTrialList and FieldTrialStructList
|
|
// are used similarly to the other FieldTrialParameters, but take a variable
|
|
// number of parameters. A FieldTrialList<T> parses a |-delimeted string into a
|
|
// list of T, using ParseTypedParameter to parse the individual tokens.
|
|
// Example string: "my_list:1|2|3,empty_list,other_list:aardvark".
|
|
|
|
// A FieldTrialStructList combines multiple lists into a list-of-structs. It
|
|
// ensures that all its sublists parse correctly and have the same length, then
|
|
// uses user-supplied accessor functions to write those elements into structs of
|
|
// a user-supplied type.
|
|
|
|
// See the unit test for usage and behavior.
|
|
|
|
namespace webrtc {
|
|
|
|
class FieldTrialListBase : public FieldTrialParameterInterface {
|
|
protected:
|
|
friend class FieldTrialListWrapper;
|
|
explicit FieldTrialListBase(absl::string_view key);
|
|
|
|
bool Failed() const;
|
|
bool Used() const;
|
|
|
|
virtual int Size() = 0;
|
|
|
|
bool failed_;
|
|
bool parse_got_called_;
|
|
};
|
|
|
|
// This class represents a vector of type T. The elements are separated by a |
|
|
// and parsed using ParseTypedParameter.
|
|
template <typename T>
|
|
class FieldTrialList : public FieldTrialListBase {
|
|
public:
|
|
explicit FieldTrialList(absl::string_view key) : FieldTrialList(key, {}) {}
|
|
FieldTrialList(absl::string_view key, std::initializer_list<T> default_values)
|
|
: FieldTrialListBase(key), values_(default_values) {}
|
|
|
|
std::vector<T> Get() const { return values_; }
|
|
operator std::vector<T>() const { return Get(); }
|
|
typename std::vector<T>::const_reference operator[](size_t index) const {
|
|
return values_[index];
|
|
}
|
|
const std::vector<T>* operator->() const { return &values_; }
|
|
|
|
protected:
|
|
bool Parse(absl::optional<std::string> str_value) override {
|
|
parse_got_called_ = true;
|
|
|
|
if (!str_value) {
|
|
values_.clear();
|
|
return true;
|
|
}
|
|
|
|
std::vector<T> new_values_;
|
|
|
|
for (const absl::string_view token : rtc::split(str_value.value(), '|')) {
|
|
absl::optional<T> value = ParseTypedParameter<T>(token);
|
|
if (value) {
|
|
new_values_.push_back(*value);
|
|
} else {
|
|
failed_ = true;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
values_.swap(new_values_);
|
|
return true;
|
|
}
|
|
|
|
int Size() override { return values_.size(); }
|
|
|
|
private:
|
|
std::vector<T> values_;
|
|
};
|
|
|
|
class FieldTrialListWrapper {
|
|
public:
|
|
virtual ~FieldTrialListWrapper() = default;
|
|
|
|
// Takes the element at the given index in the wrapped list and writes it to
|
|
// the given struct.
|
|
virtual void WriteElement(void* struct_to_write, int index) = 0;
|
|
|
|
virtual FieldTrialListBase* GetList() = 0;
|
|
|
|
int Length();
|
|
|
|
// Returns true iff the wrapped list has failed to parse at least one token.
|
|
bool Failed();
|
|
|
|
bool Used();
|
|
|
|
protected:
|
|
FieldTrialListWrapper() = default;
|
|
};
|
|
|
|
namespace field_trial_list_impl {
|
|
// The LambdaTypeTraits struct provides type information about lambdas in the
|
|
// template expressions below.
|
|
template <typename T>
|
|
struct LambdaTypeTraits : public LambdaTypeTraits<decltype(&T::operator())> {};
|
|
|
|
template <typename ClassType, typename RetType, typename SourceType>
|
|
struct LambdaTypeTraits<RetType* (ClassType::*)(SourceType*) const> {
|
|
using ret = RetType;
|
|
using src = SourceType;
|
|
};
|
|
|
|
template <typename T>
|
|
struct TypedFieldTrialListWrapper : FieldTrialListWrapper {
|
|
public:
|
|
TypedFieldTrialListWrapper(absl::string_view key,
|
|
std::function<void(void*, T)> sink)
|
|
: list_(key), sink_(sink) {}
|
|
|
|
void WriteElement(void* struct_to_write, int index) override {
|
|
sink_(struct_to_write, list_[index]);
|
|
}
|
|
|
|
FieldTrialListBase* GetList() override { return &list_; }
|
|
|
|
private:
|
|
FieldTrialList<T> list_;
|
|
std::function<void(void*, T)> sink_;
|
|
};
|
|
|
|
} // namespace field_trial_list_impl
|
|
|
|
template <typename F,
|
|
typename Traits = typename field_trial_list_impl::LambdaTypeTraits<F>>
|
|
FieldTrialListWrapper* FieldTrialStructMember(absl::string_view key,
|
|
F accessor) {
|
|
return new field_trial_list_impl::TypedFieldTrialListWrapper<
|
|
typename Traits::ret>(key, [accessor](void* s, typename Traits::ret t) {
|
|
*accessor(static_cast<typename Traits::src*>(s)) = t;
|
|
});
|
|
}
|
|
|
|
// This base class is here to reduce the amount of code we have to generate for
|
|
// each type of FieldTrialStructList.
|
|
class FieldTrialStructListBase : public FieldTrialParameterInterface {
|
|
protected:
|
|
FieldTrialStructListBase(
|
|
std::initializer_list<FieldTrialListWrapper*> sub_lists)
|
|
: FieldTrialParameterInterface(""), sub_lists_() {
|
|
// Take ownership of the list wrappers generated by FieldTrialStructMember
|
|
// on the call site.
|
|
for (FieldTrialListWrapper* const* it = sub_lists.begin();
|
|
it != sub_lists.end(); it++) {
|
|
sub_parameters_.push_back((*it)->GetList());
|
|
sub_lists_.push_back(std::unique_ptr<FieldTrialListWrapper>(*it));
|
|
}
|
|
}
|
|
|
|
// Check that all of our sublists that were in the field trial string had the
|
|
// same number of elements. If they do, we return that length. If they had
|
|
// different lengths, any sublist had parse failures or no sublists had
|
|
// user-supplied values, we return -1.
|
|
int ValidateAndGetLength();
|
|
|
|
bool Parse(absl::optional<std::string> str_value) override;
|
|
|
|
std::vector<std::unique_ptr<FieldTrialListWrapper>> sub_lists_;
|
|
};
|
|
|
|
template <typename S>
|
|
class FieldTrialStructList : public FieldTrialStructListBase {
|
|
public:
|
|
FieldTrialStructList(std::initializer_list<FieldTrialListWrapper*> l,
|
|
std::initializer_list<S> default_list)
|
|
: FieldTrialStructListBase(l), values_(default_list) {}
|
|
|
|
std::vector<S> Get() const { return values_; }
|
|
operator std::vector<S>() const { return Get(); }
|
|
const S& operator[](size_t index) const { return values_[index]; }
|
|
const std::vector<S>* operator->() const { return &values_; }
|
|
|
|
protected:
|
|
void ParseDone() override {
|
|
int length = ValidateAndGetLength();
|
|
|
|
if (length == -1)
|
|
return;
|
|
|
|
std::vector<S> new_values(length, S());
|
|
|
|
for (std::unique_ptr<FieldTrialListWrapper>& li : sub_lists_) {
|
|
if (li->Used()) {
|
|
for (int i = 0; i < length; i++) {
|
|
li->WriteElement(&new_values[i], i);
|
|
}
|
|
}
|
|
}
|
|
|
|
values_.swap(new_values);
|
|
}
|
|
|
|
private:
|
|
std::vector<S> values_;
|
|
};
|
|
|
|
} // namespace webrtc
|
|
|
|
#endif // RTC_BASE_EXPERIMENTS_FIELD_TRIAL_LIST_H_
|