1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_METRICS_FIELD_TRIAL_PARAMS_H_
6 #define BASE_METRICS_FIELD_TRIAL_PARAMS_H_
7 
8 #include <map>
9 #include <string>
10 
11 #include "base/base_export.h"
12 
13 namespace base {
14 
15 struct Feature;
16 
17 // Associates the specified set of key-value |params| with the field trial
18 // specified by |trial_name| and |group_name|. Fails and returns false if the
19 // specified field trial already has params associated with it or the trial
20 // is already active (group() has been called on it). Thread safe.
21 BASE_EXPORT bool AssociateFieldTrialParams(
22     const std::string& trial_name,
23     const std::string& group_name,
24     const std::map<std::string, std::string>& params);
25 
26 // Retrieves the set of key-value |params| for the specified field trial, based
27 // on its selected group. If the field trial does not exist or its selected
28 // group does not have any parameters associated with it, returns false and
29 // does not modify |params|. Calling this function will result in the field
30 // trial being marked as active if found (i.e. group() will be called on it),
31 // if it wasn't already. Thread safe.
32 BASE_EXPORT bool GetFieldTrialParams(
33     const std::string& trial_name,
34     std::map<std::string, std::string>* params);
35 
36 // Retrieves the set of key-value |params| for the field trial associated with
37 // the specified |feature|. A feature is associated with at most one field
38 // trial and selected group. See  base/feature_list.h for more information on
39 // features. If the feature is not enabled, or if there's no associated params,
40 // returns false and does not modify |params|. Calling this function will
41 // result in the associated field trial being marked as active if found (i.e.
42 // group() will be called on it), if it wasn't already. Thread safe.
43 BASE_EXPORT bool GetFieldTrialParamsByFeature(
44     const base::Feature& feature,
45     std::map<std::string, std::string>* params);
46 
47 // Retrieves a specific parameter value corresponding to |param_name| for the
48 // specified field trial, based on its selected group. If the field trial does
49 // not exist or the specified parameter does not exist, returns an empty
50 // string. Calling this function will result in the field trial being marked as
51 // active if found (i.e. group() will be called on it), if it wasn't already.
52 // Thread safe.
53 BASE_EXPORT std::string GetFieldTrialParamValue(const std::string& trial_name,
54                                                 const std::string& param_name);
55 
56 // Retrieves a specific parameter value corresponding to |param_name| for the
57 // field trial associated with the specified |feature|. A feature is associated
58 // with at most one field trial and selected group. See base/feature_list.h for
59 // more information on features. If the feature is not enabled, or the
60 // specified parameter does not exist, returns an empty string. Calling this
61 // function will result in the associated field trial being marked as active if
62 // found (i.e. group() will be called on it), if it wasn't already. Thread safe.
63 BASE_EXPORT std::string GetFieldTrialParamValueByFeature(
64     const base::Feature& feature,
65     const std::string& param_name);
66 
67 // Same as GetFieldTrialParamValueByFeature(). On top of that, it converts the
68 // string value into an int using base::StringToInt() and returns it, if
69 // successful. Otherwise, it returns |default_value|. If the string value is not
70 // empty and the conversion does not succeed, it produces a warning to LOG.
71 BASE_EXPORT int GetFieldTrialParamByFeatureAsInt(const base::Feature& feature,
72                                                  const std::string& param_name,
73                                                  int default_value);
74 
75 // Same as GetFieldTrialParamValueByFeature(). On top of that, it converts the
76 // string value into a double using base::StringToDouble() and returns it, if
77 // successful. Otherwise, it returns |default_value|. If the string value is not
78 // empty and the conversion does not succeed, it produces a warning to LOG.
79 BASE_EXPORT double GetFieldTrialParamByFeatureAsDouble(
80     const base::Feature& feature,
81     const std::string& param_name,
82     double default_value);
83 
84 // Same as GetFieldTrialParamValueByFeature(). On top of that, it converts the
85 // string value into a boolean and returns it, if successful. Otherwise, it
86 // returns |default_value|. The only string representations accepted here are
87 // "true" and "false". If the string value is not empty and the conversion does
88 // not succeed, it produces a warning to LOG.
89 BASE_EXPORT bool GetFieldTrialParamByFeatureAsBool(
90     const base::Feature& feature,
91     const std::string& param_name,
92     bool default_value);
93 
94 // Shared declaration for various FeatureParam<T> types.
95 //
96 // This template is defined for the following types T:
97 //   bool
98 //   int
99 //   double
100 //   std::string
101 //   enum types
102 //
103 // See the individual definitions below for the appropriate interfaces.
104 // Attempting to use it with any other type is a compile error.
105 template <typename T, bool IsEnum = std::is_enum<T>::value>
106 struct FeatureParam {
107   // Prevent use of FeatureParam<> with unsupported types (e.g. void*). Uses T
108   // in its definition so that evaluation is deferred until the template is
109   // instantiated.
110   static_assert(!std::is_same<T, T>::value, "unsupported FeatureParam<> type");
111 };
112 
113 // Declares a string-valued parameter. Example:
114 //
115 //     constexpr FeatureParam<string> kAssistantName{
116 //         &kAssistantFeature, "assistant_name", "HAL"};
117 //
118 // If the feature is not set, or set to the empty string, then Get() will return
119 // the default value.
120 template <>
121 struct FeatureParam<std::string> {
122   constexpr FeatureParam(const Feature* feature,
123                          const char* name,
124                          const char* default_value)
125       : feature(feature), name(name), default_value(default_value) {}
126 
127   BASE_EXPORT std::string Get() const;
128 
129   const Feature* const feature;
130   const char* const name;
131   const char* const default_value;
132 };
133 
134 // Declares a double-valued parameter. Example:
135 //
136 //     constexpr FeatureParam<double> kAssistantTriggerThreshold{
137 //         &kAssistantFeature, "trigger_threshold", 0.10};
138 //
139 // If the feature is not set, or set to an invalid double value, then Get() will
140 // return the default value.
141 template <>
142 struct FeatureParam<double> {
143   constexpr FeatureParam(const Feature* feature,
144                          const char* name,
145                          double default_value)
146       : feature(feature), name(name), default_value(default_value) {}
147 
148   BASE_EXPORT double Get() const;
149 
150   const Feature* const feature;
151   const char* const name;
152   const double default_value;
153 };
154 
155 // Declares an int-valued parameter. Example:
156 //
157 //     constexpr FeatureParam<int> kAssistantParallelism{
158 //         &kAssistantFeature, "parallelism", 4};
159 //
160 // If the feature is not set, or set to an invalid int value, then Get() will
161 // return the default value.
162 template <>
163 struct FeatureParam<int> {
164   constexpr FeatureParam(const Feature* feature,
165                          const char* name,
166                          int default_value)
167       : feature(feature), name(name), default_value(default_value) {}
168 
169   BASE_EXPORT int Get() const;
170 
171   const Feature* const feature;
172   const char* const name;
173   const int default_value;
174 };
175 
176 // Declares a bool-valued parameter. Example:
177 //
178 //     constexpr FeatureParam<int> kAssistantIsHelpful{
179 //         &kAssistantFeature, "is_helpful", true};
180 //
181 // If the feature is not set, or set to value other than "true" or "false", then
182 // Get() will return the default value.
183 template <>
184 struct FeatureParam<bool> {
185   constexpr FeatureParam(const Feature* feature,
186                          const char* name,
187                          bool default_value)
188       : feature(feature), name(name), default_value(default_value) {}
189 
190   BASE_EXPORT bool Get() const;
191 
192   const Feature* const feature;
193   const char* const name;
194   const bool default_value;
195 };
196 
197 BASE_EXPORT void LogInvalidEnumValue(const Feature& feature,
198                                      const std::string& param_name,
199                                      const std::string& value_as_string,
200                                      int default_value_as_int);
201 
202 // Feature param declaration for an enum, with associated options. Example:
203 //
204 //     constexpr FeatureParam<ShapeEnum>::Option[] kShapeParamOptions[] = {
205 //         {SHAPE_CIRCLE, "circle"},
206 //         {SHAPE_CYLINDER, "cylinder"},
207 //         {SHAPE_PAPERCLIP, "paperclip"}};
208 //     constexpr FeatureParam<ShapeEnum> kAssistantShapeParam{
209 //         &kAssistantFeature, "shape", SHAPE_CIRCLE, &kShapeParamOptions};
210 //
211 // With this declaration, the parameter may be set to "circle", "cylinder", or
212 // "paperclip", and that will be translated to one of the three enum values. By
213 // default, or if the param is set to an unknown value, the parameter will be
214 // assumed to be SHAPE_CIRCLE.
215 template <typename Enum>
216 struct FeatureParam<Enum, true> {
217   struct Option {
218     constexpr Option(Enum value, const char* name) : value(value), name(name) {}
219 
220     const Enum value;
221     const char* const name;
222   };
223 
224   template <size_t option_count>
225   constexpr FeatureParam(const Feature* feature,
226                          const char* name,
227                          const Enum default_value,
228                          const Option (*options)[option_count])
229       : feature(feature),
230         name(name),
231         default_value(default_value),
232         options(*options),
233         option_count(option_count) {
234     static_assert(option_count >= 1, "FeatureParam<enum> has no options");
235   }
236 
237   Enum Get() const {
238     std::string value = GetFieldTrialParamValueByFeature(*feature, name);
239     if (value.empty())
240       return default_value;
241     for (size_t i = 0; i < option_count; ++i) {
242       if (value == options[i].name)
243         return options[i].value;
244     }
245     LogInvalidEnumValue(*feature, name, value, static_cast<int>(default_value));
246     return default_value;
247   }
248 
249   const base::Feature* const feature;
250   const char* const name;
251   const Enum default_value;
252   const Option* const options;
253   const size_t option_count;
254 };
255 
256 }  // namespace base
257 
258 #endif  // BASE_METRICS_FIELD_TRIAL_PARAMS_H_
259