xref: /aosp_15_r20/external/cronet/base/metrics/field_trial_params.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2017 The Chromium Authors
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 #include "base/feature_list.h"
13 #include "base/logging.h"
14 #include "base/memory/raw_ptr_exclusion.h"
15 #include "base/notreached.h"
16 #include "base/time/time.h"
17 
18 namespace base {
19 
20 // Key-value mapping type for field trial parameters.
21 typedef std::map<std::string, std::string> FieldTrialParams;
22 
23 // Param string decoding function for AssociateFieldTrialParamsFromString().
24 typedef std::string (*FieldTrialParamsDecodeStringFunc)(const std::string& str);
25 
26 // Unescapes special characters from the given string. Used in
27 // AssociateFieldTrialParamsFromString() as one of the feature params decoding
28 // functions.
29 BASE_EXPORT std::string UnescapeValue(const std::string& value);
30 
31 // Associates the specified set of key-value |params| with the field trial
32 // specified by |trial_name| and |group_name|. Fails and returns false if the
33 // specified field trial already has params associated with it or the trial
34 // is already active (group() has been called on it). Thread safe.
35 BASE_EXPORT bool AssociateFieldTrialParams(const std::string& trial_name,
36                                            const std::string& group_name,
37                                            const FieldTrialParams& params);
38 
39 // Provides a mechanism to associate multiple set of params to multiple groups
40 // with a formatted string as returned by FieldTrialList::AllParamsToString().
41 // |decode_data_func| allows specifying a custom decoding function.
42 BASE_EXPORT bool AssociateFieldTrialParamsFromString(
43     const std::string& params_string,
44     FieldTrialParamsDecodeStringFunc decode_data_func);
45 
46 // Retrieves the set of key-value |params| for the specified field trial, based
47 // on its selected group. If the field trial does not exist or its selected
48 // group does not have any parameters associated with it, returns false and
49 // does not modify |params|. Calling this function will result in the field
50 // trial being marked as active if found (i.e. group() will be called on it),
51 // if it wasn't already. Thread safe.
52 BASE_EXPORT bool GetFieldTrialParams(const std::string& trial_name,
53                                      FieldTrialParams* params);
54 
55 // Retrieves the set of key-value |params| for the field trial associated with
56 // the specified |feature|. A feature is associated with at most one field
57 // trial and selected group. See  base/feature_list.h for more information on
58 // features. If the feature is not enabled, or if there's no associated params,
59 // returns false and does not modify |params|. Calling this function will
60 // result in the associated field trial being marked as active if found (i.e.
61 // group() will be called on it), if it wasn't already. Thread safe.
62 BASE_EXPORT bool GetFieldTrialParamsByFeature(const base::Feature& feature,
63                                               FieldTrialParams* params);
64 
65 // Retrieves a specific parameter value corresponding to |param_name| for the
66 // specified field trial, based on its selected group. If the field trial does
67 // not exist or the specified parameter does not exist, returns an empty
68 // string. Calling this function will result in the field trial being marked as
69 // active if found (i.e. group() will be called on it), if it wasn't already.
70 // Thread safe.
71 BASE_EXPORT std::string GetFieldTrialParamValue(const std::string& trial_name,
72                                                 const std::string& param_name);
73 
74 // Retrieves a specific parameter value corresponding to |param_name| for the
75 // field trial associated with the specified |feature|. A feature is associated
76 // with at most one field trial and selected group. See base/feature_list.h for
77 // more information on features. If the feature is not enabled, or the
78 // specified parameter does not exist, returns an empty string. Calling this
79 // function will result in the associated field trial being marked as active if
80 // found (i.e. group() will be called on it), if it wasn't already. Thread safe.
81 BASE_EXPORT std::string GetFieldTrialParamValueByFeature(
82     const base::Feature& feature,
83     const std::string& param_name);
84 
85 // Same as GetFieldTrialParamValueByFeature(). On top of that, it converts the
86 // string value into an int using base::StringToInt() and returns it, if
87 // successful. Otherwise, it returns |default_value|. If the string value is not
88 // empty and the conversion does not succeed, it produces a warning to LOG.
89 BASE_EXPORT int GetFieldTrialParamByFeatureAsInt(const base::Feature& feature,
90                                                  const std::string& param_name,
91                                                  int default_value);
92 
93 // Same as GetFieldTrialParamValueByFeature(). On top of that, it converts the
94 // string value into a double using base::StringToDouble() and returns it, if
95 // successful. Otherwise, it returns |default_value|. If the string value is not
96 // empty and the conversion does not succeed, it produces a warning to LOG.
97 BASE_EXPORT double GetFieldTrialParamByFeatureAsDouble(
98     const base::Feature& feature,
99     const std::string& param_name,
100     double default_value);
101 
102 // Same as GetFieldTrialParamValueByFeature(). On top of that, it converts the
103 // string value into a boolean and returns it, if successful. Otherwise, it
104 // returns |default_value|. The only string representations accepted here are
105 // "true" and "false". If the string value is not empty and the conversion does
106 // not succeed, it produces a warning to LOG.
107 BASE_EXPORT bool GetFieldTrialParamByFeatureAsBool(
108     const base::Feature& feature,
109     const std::string& param_name,
110     bool default_value);
111 
112 // Same as GetFieldTrialParamValueByFeature(). On top of that, it converts the
113 // string value into a base::TimeDelta and returns it, if successful. Otherwise,
114 // it returns `default_value`. If the string value is not empty and the
115 // conversion does not succeed, it produces a warning to LOG.
116 BASE_EXPORT base::TimeDelta GetFieldTrialParamByFeatureAsTimeDelta(
117     const Feature& feature,
118     const std::string& param_name,
119     base::TimeDelta default_value);
120 
121 // Shared declaration for various FeatureParam<T> types.
122 //
123 // This template is defined for the following types T:
124 //   bool
125 //   int
126 //   double
127 //   std::string
128 //   enum types
129 //   base::TimeDelta
130 //
131 // See the individual definitions below for the appropriate interfaces.
132 // Attempting to use it with any other type is a compile error.
133 //
134 // Getting a param value from a FeatureParam<T> will have the same semantics as
135 // GetFieldTrialParamValueByFeature(), see that function's comments for details.
136 template <typename T, bool IsEnum = std::is_enum_v<T>>
137 struct FeatureParam {
138   // Prevent use of FeatureParam<> with unsupported types (e.g. void*). Uses T
139   // in its definition so that evaluation is deferred until the template is
140   // instantiated.
141   static_assert(!std::is_same_v<T, T>, "unsupported FeatureParam<> type");
142 };
143 
144 // Declares a string-valued parameter. Example:
145 //
146 //     constexpr FeatureParam<string> kAssistantName{
147 //         &kAssistantFeature, "assistant_name", "HAL"};
148 //
149 // If the feature is not enabled, the parameter is not set, or set to the empty
150 // string, then Get() will return the default value.
151 template <>
152 struct FeatureParam<std::string> {
153   constexpr FeatureParam(const Feature* feature,
154                          const char* name,
155                          const char* default_value)
156       : feature(feature), name(name), default_value(default_value) {}
157 
158   // Calling Get() will activate the field trial associated with |feature|. See
159   // GetFieldTrialParamValueByFeature() for more details.
160   BASE_EXPORT std::string Get() const;
161 
162   // This field is not a raw_ptr<> because it was filtered by the rewriter for:
163   // #global-scope, #constexpr-ctor-field-initializer
164   RAW_PTR_EXCLUSION const Feature* const feature;
165   const char* const name;
166   const char* const default_value;
167 };
168 
169 // Declares a double-valued parameter. Example:
170 //
171 //     constexpr FeatureParam<double> kAssistantTriggerThreshold{
172 //         &kAssistantFeature, "trigger_threshold", 0.10};
173 //
174 // If the feature is not enabled, the parameter is not set, or set to an invalid
175 // double value, then Get() will return the default value.
176 template <>
177 struct FeatureParam<double> {
178   constexpr FeatureParam(const Feature* feature,
179                          const char* name,
180                          double default_value)
181       : feature(feature), name(name), default_value(default_value) {}
182 
183   // Calling Get() will activate the field trial associated with |feature|. See
184   // GetFieldTrialParamValueByFeature() for more details.
185   BASE_EXPORT double Get() const;
186 
187   // This field is not a raw_ptr<> because it was filtered by the rewriter for:
188   // #global-scope, #constexpr-ctor-field-initializer
189   RAW_PTR_EXCLUSION const Feature* const feature;
190   const char* const name;
191   const double default_value;
192 };
193 
194 // Declares an int-valued parameter. Example:
195 //
196 //     constexpr FeatureParam<int> kAssistantParallelism{
197 //         &kAssistantFeature, "parallelism", 4};
198 //
199 // If the feature is not enabled, the parameter is not set, or set to an invalid
200 // int value, then Get() will return the default value.
201 template <>
202 struct FeatureParam<int> {
203   constexpr FeatureParam(const Feature* feature,
204                          const char* name,
205                          int default_value)
206       : feature(feature), name(name), default_value(default_value) {}
207 
208   // Calling Get() will activate the field trial associated with |feature|. See
209   // GetFieldTrialParamValueByFeature() for more details.
210   BASE_EXPORT int Get() const;
211 
212   // This field is not a raw_ptr<> because it was filtered by the rewriter for:
213   // #global-scope, #constexpr-ctor-field-initializer
214   RAW_PTR_EXCLUSION const Feature* const feature;
215   const char* const name;
216   const int default_value;
217 };
218 
219 // Declares a bool-valued parameter. Example:
220 //
221 //     constexpr FeatureParam<int> kAssistantIsHelpful{
222 //         &kAssistantFeature, "is_helpful", true};
223 //
224 // If the feature is not enabled, the parameter is not set, or set to value
225 // other than "true" or "false", then Get() will return the default value.
226 template <>
227 struct FeatureParam<bool> {
228   constexpr FeatureParam(const Feature* feature,
229                          const char* name,
230                          bool default_value)
231       : feature(feature), name(name), default_value(default_value) {}
232 
233   // Calling Get() will activate the field trial associated with |feature|. See
234   // GetFieldTrialParamValueByFeature() for more details.
235   BASE_EXPORT bool Get() const;
236 
237   // This field is not a raw_ptr<> because it was filtered by the rewriter for:
238   // #global-scope, #constexpr-ctor-field-initializer
239   RAW_PTR_EXCLUSION const Feature* const feature;
240   const char* const name;
241   const bool default_value;
242 };
243 
244 // Declares an TimeDelta-valued parameter. Example:
245 //
246 //     constexpr base::FeatureParam<base::TimeDelta> kPerAgentDelay{
247 //         &kPerAgentSchedulingExperiments, "delay", base::TimeDelta()};
248 //
249 // If the feature is not enabled, the parameter is not set, or set to an
250 // invalid value (as defined by base::TimeDeltaFromString()), then Get() will
251 // return the default value.
252 template <>
253 struct FeatureParam<base::TimeDelta> {
254   constexpr FeatureParam(const Feature* feature,
255                          const char* name,
256                          base::TimeDelta default_value)
257       : feature(feature), name(name), default_value(default_value) {}
258 
259   // Calling Get() will activate the field trial associated with |feature|. See
260   // GetFieldTrialParamValueByFeature() for more details.
261   BASE_EXPORT base::TimeDelta Get() const;
262 
263   // This field is not a raw_ptr<> because it was filtered by the rewriter for:
264   // #global-scope, #constexpr-ctor-field-initializer
265   RAW_PTR_EXCLUSION const Feature* const feature;
266   const char* const name;
267   const base::TimeDelta default_value;
268 };
269 
270 BASE_EXPORT void LogInvalidEnumValue(const Feature& feature,
271                                      const std::string& param_name,
272                                      const std::string& value_as_string,
273                                      int default_value_as_int);
274 
275 // Feature param declaration for an enum, with associated options. Example:
276 //
277 //     constexpr FeatureParam<ShapeEnum>::Option kShapeParamOptions[] = {
278 //         {SHAPE_CIRCLE, "circle"},
279 //         {SHAPE_CYLINDER, "cylinder"},
280 //         {SHAPE_PAPERCLIP, "paperclip"}};
281 //     constexpr FeatureParam<ShapeEnum> kAssistantShapeParam{
282 //         &kAssistantFeature, "shape", SHAPE_CIRCLE, &kShapeParamOptions};
283 //
284 // With this declaration, the parameter may be set to "circle", "cylinder", or
285 // "paperclip", and that will be translated to one of the three enum values. By
286 // default, or if the param is set to an unknown value, the parameter will be
287 // assumed to be SHAPE_CIRCLE.
288 template <typename Enum>
289 struct FeatureParam<Enum, true> {
290   struct Option {
291     constexpr Option(Enum value, const char* name) : value(value), name(name) {}
292 
293     const Enum value;
294     const char* const name;
295   };
296 
297   template <size_t option_count>
298   constexpr FeatureParam(const Feature* feature,
299                          const char* name,
300                          const Enum default_value,
301                          const Option (*options)[option_count])
302       : feature(feature),
303         name(name),
304         default_value(default_value),
305         options(*options),
306         option_count(option_count) {
307     static_assert(option_count >= 1, "FeatureParam<enum> has no options");
308   }
309 
310   // Calling Get() will activate the field trial associated with |feature|. See
311   // GetFieldTrialParamValueByFeature() for more details.
312   Enum Get() const {
313     std::string value = GetFieldTrialParamValueByFeature(*feature, name);
314     if (value.empty())
315       return default_value;
316     for (size_t i = 0; i < option_count; ++i) {
317       if (value == options[i].name)
318         return options[i].value;
319     }
320     LogInvalidEnumValue(*feature, name, value, static_cast<int>(default_value));
321     return default_value;
322   }
323 
324   // Returns the param-string for the given enum value.
325   std::string GetName(Enum value) const {
326     for (size_t i = 0; i < option_count; ++i) {
327       if (value == options[i].value)
328         return options[i].name;
329     }
330     NOTREACHED();
331     return "";
332   }
333 
334   // This field is not a raw_ptr<> because it was filtered by the rewriter for:
335   // #global-scope, #constexpr-ctor-field-initializer
336   RAW_PTR_EXCLUSION const base::Feature* const feature;
337   const char* const name;
338   const Enum default_value;
339   // This field is not a raw_ptr<> because it was filtered by the rewriter for:
340   // #global-scope, #constexpr-ctor-field-initializer
341   RAW_PTR_EXCLUSION const Option* const options;
342   const size_t option_count;
343 };
344 
345 }  // namespace base
346 
347 #endif  // BASE_METRICS_FIELD_TRIAL_PARAMS_H_
348