289 lines
9.6 KiB
C
289 lines
9.6 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_PARSER_H_
|
||
|
#define RTC_BASE_EXPERIMENTS_FIELD_TRIAL_PARSER_H_
|
||
|
|
||
|
#include <stdint.h>
|
||
|
|
||
|
#include <initializer_list>
|
||
|
#include <map>
|
||
|
#include <set>
|
||
|
#include <string>
|
||
|
#include <vector>
|
||
|
|
||
|
#include "absl/types/optional.h"
|
||
|
|
||
|
// Field trial parser functionality. Provides funcitonality to parse field trial
|
||
|
// argument strings in key:value format. Each parameter is described using
|
||
|
// key:value, parameters are separated with a ,. Values can't include the comma
|
||
|
// character, since there's no quote facility. For most types, white space is
|
||
|
// ignored. Parameters are declared with a given type for which an
|
||
|
// implementation of ParseTypedParameter should be provided. The
|
||
|
// ParseTypedParameter implementation is given whatever is between the : and the
|
||
|
// ,. If the key is provided without : a FieldTrialOptional will use nullopt.
|
||
|
|
||
|
// Example string: "my_optional,my_int:3,my_string:hello"
|
||
|
|
||
|
// For further description of usage and behavior, see the examples in the unit
|
||
|
// tests.
|
||
|
|
||
|
namespace webrtc {
|
||
|
class FieldTrialParameterInterface {
|
||
|
public:
|
||
|
virtual ~FieldTrialParameterInterface();
|
||
|
std::string key() const { return key_; }
|
||
|
|
||
|
protected:
|
||
|
// Protected to allow implementations to provide assignment and copy.
|
||
|
FieldTrialParameterInterface(const FieldTrialParameterInterface&) = default;
|
||
|
FieldTrialParameterInterface& operator=(const FieldTrialParameterInterface&) =
|
||
|
default;
|
||
|
explicit FieldTrialParameterInterface(std::string key);
|
||
|
friend void ParseFieldTrial(
|
||
|
std::initializer_list<FieldTrialParameterInterface*> fields,
|
||
|
std::string raw_string);
|
||
|
void MarkAsUsed() { used_ = true; }
|
||
|
virtual bool Parse(absl::optional<std::string> str_value) = 0;
|
||
|
|
||
|
virtual void ParseDone() {}
|
||
|
|
||
|
std::vector<FieldTrialParameterInterface*> sub_parameters_;
|
||
|
|
||
|
private:
|
||
|
std::string key_;
|
||
|
bool used_ = false;
|
||
|
};
|
||
|
|
||
|
// ParseFieldTrial function parses the given string and fills the given fields
|
||
|
// with extracted values if available.
|
||
|
void ParseFieldTrial(
|
||
|
std::initializer_list<FieldTrialParameterInterface*> fields,
|
||
|
std::string raw_string);
|
||
|
|
||
|
// Specialize this in code file for custom types. Should return absl::nullopt if
|
||
|
// the given string cannot be properly parsed.
|
||
|
template <typename T>
|
||
|
absl::optional<T> ParseTypedParameter(std::string);
|
||
|
|
||
|
// This class uses the ParseTypedParameter function to implement a parameter
|
||
|
// implementation with an enforced default value.
|
||
|
template <typename T>
|
||
|
class FieldTrialParameter : public FieldTrialParameterInterface {
|
||
|
public:
|
||
|
FieldTrialParameter(std::string key, T default_value)
|
||
|
: FieldTrialParameterInterface(key), value_(default_value) {}
|
||
|
T Get() const { return value_; }
|
||
|
operator T() const { return Get(); }
|
||
|
const T* operator->() const { return &value_; }
|
||
|
|
||
|
void SetForTest(T value) { value_ = value; }
|
||
|
|
||
|
protected:
|
||
|
bool Parse(absl::optional<std::string> str_value) override {
|
||
|
if (str_value) {
|
||
|
absl::optional<T> value = ParseTypedParameter<T>(*str_value);
|
||
|
if (value.has_value()) {
|
||
|
value_ = value.value();
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
T value_;
|
||
|
};
|
||
|
|
||
|
// This class uses the ParseTypedParameter function to implement a parameter
|
||
|
// implementation with an enforced default value and a range constraint. Values
|
||
|
// outside the configured range will be ignored.
|
||
|
template <typename T>
|
||
|
class FieldTrialConstrained : public FieldTrialParameterInterface {
|
||
|
public:
|
||
|
FieldTrialConstrained(std::string key,
|
||
|
T default_value,
|
||
|
absl::optional<T> lower_limit,
|
||
|
absl::optional<T> upper_limit)
|
||
|
: FieldTrialParameterInterface(key),
|
||
|
value_(default_value),
|
||
|
lower_limit_(lower_limit),
|
||
|
upper_limit_(upper_limit) {}
|
||
|
T Get() const { return value_; }
|
||
|
operator T() const { return Get(); }
|
||
|
const T* operator->() const { return &value_; }
|
||
|
|
||
|
protected:
|
||
|
bool Parse(absl::optional<std::string> str_value) override {
|
||
|
if (str_value) {
|
||
|
absl::optional<T> value = ParseTypedParameter<T>(*str_value);
|
||
|
if (value && (!lower_limit_ || *value >= *lower_limit_) &&
|
||
|
(!upper_limit_ || *value <= *upper_limit_)) {
|
||
|
value_ = *value;
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
T value_;
|
||
|
absl::optional<T> lower_limit_;
|
||
|
absl::optional<T> upper_limit_;
|
||
|
};
|
||
|
|
||
|
class AbstractFieldTrialEnum : public FieldTrialParameterInterface {
|
||
|
public:
|
||
|
AbstractFieldTrialEnum(std::string key,
|
||
|
int default_value,
|
||
|
std::map<std::string, int> mapping);
|
||
|
~AbstractFieldTrialEnum() override;
|
||
|
AbstractFieldTrialEnum(const AbstractFieldTrialEnum&);
|
||
|
|
||
|
protected:
|
||
|
bool Parse(absl::optional<std::string> str_value) override;
|
||
|
|
||
|
protected:
|
||
|
int value_;
|
||
|
std::map<std::string, int> enum_mapping_;
|
||
|
std::set<int> valid_values_;
|
||
|
};
|
||
|
|
||
|
// The FieldTrialEnum class can be used to quickly define a parser for a
|
||
|
// specific enum. It handles values provided as integers and as strings if a
|
||
|
// mapping is provided.
|
||
|
template <typename T>
|
||
|
class FieldTrialEnum : public AbstractFieldTrialEnum {
|
||
|
public:
|
||
|
FieldTrialEnum(std::string key,
|
||
|
T default_value,
|
||
|
std::map<std::string, T> mapping)
|
||
|
: AbstractFieldTrialEnum(key,
|
||
|
static_cast<int>(default_value),
|
||
|
ToIntMap(mapping)) {}
|
||
|
T Get() const { return static_cast<T>(value_); }
|
||
|
operator T() const { return Get(); }
|
||
|
|
||
|
private:
|
||
|
static std::map<std::string, int> ToIntMap(std::map<std::string, T> mapping) {
|
||
|
std::map<std::string, int> res;
|
||
|
for (const auto& it : mapping)
|
||
|
res[it.first] = static_cast<int>(it.second);
|
||
|
return res;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// This class uses the ParseTypedParameter function to implement an optional
|
||
|
// parameter implementation that can default to absl::nullopt.
|
||
|
template <typename T>
|
||
|
class FieldTrialOptional : public FieldTrialParameterInterface {
|
||
|
public:
|
||
|
explicit FieldTrialOptional(std::string key)
|
||
|
: FieldTrialParameterInterface(key) {}
|
||
|
FieldTrialOptional(std::string key, absl::optional<T> default_value)
|
||
|
: FieldTrialParameterInterface(key), value_(default_value) {}
|
||
|
absl::optional<T> GetOptional() const { return value_; }
|
||
|
const T& Value() const { return value_.value(); }
|
||
|
const T& operator*() const { return value_.value(); }
|
||
|
const T* operator->() const { return &value_.value(); }
|
||
|
explicit operator bool() const { return value_.has_value(); }
|
||
|
|
||
|
protected:
|
||
|
bool Parse(absl::optional<std::string> str_value) override {
|
||
|
if (str_value) {
|
||
|
absl::optional<T> value = ParseTypedParameter<T>(*str_value);
|
||
|
if (!value.has_value())
|
||
|
return false;
|
||
|
value_ = value.value();
|
||
|
} else {
|
||
|
value_ = absl::nullopt;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
absl::optional<T> value_;
|
||
|
};
|
||
|
|
||
|
// Equivalent to a FieldTrialParameter<bool> in the case that both key and value
|
||
|
// are present. If key is missing, evaluates to false. If key is present, but no
|
||
|
// explicit value is provided, the flag evaluates to true.
|
||
|
class FieldTrialFlag : public FieldTrialParameterInterface {
|
||
|
public:
|
||
|
explicit FieldTrialFlag(std::string key);
|
||
|
FieldTrialFlag(std::string key, bool default_value);
|
||
|
bool Get() const;
|
||
|
operator bool() const;
|
||
|
|
||
|
protected:
|
||
|
bool Parse(absl::optional<std::string> str_value) override;
|
||
|
|
||
|
private:
|
||
|
bool value_;
|
||
|
};
|
||
|
|
||
|
template <typename T>
|
||
|
absl::optional<absl::optional<T>> ParseOptionalParameter(std::string str) {
|
||
|
if (str.empty())
|
||
|
return absl::optional<T>();
|
||
|
auto parsed = ParseTypedParameter<T>(str);
|
||
|
if (parsed.has_value())
|
||
|
return parsed;
|
||
|
return absl::nullopt;
|
||
|
}
|
||
|
|
||
|
template <>
|
||
|
absl::optional<bool> ParseTypedParameter<bool>(std::string str);
|
||
|
template <>
|
||
|
absl::optional<double> ParseTypedParameter<double>(std::string str);
|
||
|
template <>
|
||
|
absl::optional<int> ParseTypedParameter<int>(std::string str);
|
||
|
template <>
|
||
|
absl::optional<unsigned> ParseTypedParameter<unsigned>(std::string str);
|
||
|
template <>
|
||
|
absl::optional<std::string> ParseTypedParameter<std::string>(std::string str);
|
||
|
|
||
|
template <>
|
||
|
absl::optional<absl::optional<bool>> ParseTypedParameter<absl::optional<bool>>(
|
||
|
std::string str);
|
||
|
template <>
|
||
|
absl::optional<absl::optional<int>> ParseTypedParameter<absl::optional<int>>(
|
||
|
std::string str);
|
||
|
template <>
|
||
|
absl::optional<absl::optional<unsigned>>
|
||
|
ParseTypedParameter<absl::optional<unsigned>>(std::string str);
|
||
|
template <>
|
||
|
absl::optional<absl::optional<double>>
|
||
|
ParseTypedParameter<absl::optional<double>>(std::string str);
|
||
|
|
||
|
// Accepts true, false, else parsed with sscanf %i, true if != 0.
|
||
|
extern template class FieldTrialParameter<bool>;
|
||
|
// Interpreted using sscanf %lf.
|
||
|
extern template class FieldTrialParameter<double>;
|
||
|
// Interpreted using sscanf %i.
|
||
|
extern template class FieldTrialParameter<int>;
|
||
|
// Interpreted using sscanf %u.
|
||
|
extern template class FieldTrialParameter<unsigned>;
|
||
|
// Using the given value as is.
|
||
|
extern template class FieldTrialParameter<std::string>;
|
||
|
|
||
|
extern template class FieldTrialConstrained<double>;
|
||
|
extern template class FieldTrialConstrained<int>;
|
||
|
extern template class FieldTrialConstrained<unsigned>;
|
||
|
|
||
|
extern template class FieldTrialOptional<double>;
|
||
|
extern template class FieldTrialOptional<int>;
|
||
|
extern template class FieldTrialOptional<unsigned>;
|
||
|
extern template class FieldTrialOptional<bool>;
|
||
|
extern template class FieldTrialOptional<std::string>;
|
||
|
|
||
|
} // namespace webrtc
|
||
|
|
||
|
#endif // RTC_BASE_EXPERIMENTS_FIELD_TRIAL_PARSER_H_
|