| /* | 
 |  *  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 "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(std::string 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(std::string key) : FieldTrialList(key, {}) {} | 
 |   FieldTrialList(std::string 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(); } | 
 |   const T& 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<std::string> tokens; | 
 |     std::vector<T> new_values_; | 
 |     rtc::split(str_value.value(), '|', &tokens); | 
 |  | 
 |     for (std::string token : tokens) { | 
 |       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(std::string 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(std::string 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_ |