blob: 260a70c6ae8e2dcf43e891dd4e5f62d3d48d8800 [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2017 The Chromium Authors
asvitkine79ab08c2017-01-30 23:27:052// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
danakj51d26a42024-04-25 14:23:565#ifdef UNSAFE_BUFFERS_BUILD
6// TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7#pragma allow_unsafe_buffers
8#endif
9
asvitkine79ab08c2017-01-30 23:27:0510#ifndef BASE_METRICS_FIELD_TRIAL_PARAMS_H_
11#define BASE_METRICS_FIELD_TRIAL_PARAMS_H_
12
danakje75c6c812024-07-26 20:37:4713#include <array>
asvitkine79ab08c2017-01-30 23:27:0514#include <map>
15#include <string>
16
17#include "base/base_export.h"
Anthony Vallee-Dubois9dbbbda32022-08-26 01:25:3118#include "base/feature_list.h"
Keishi Hattori8a7e15d2023-01-19 07:16:2919#include "base/memory/raw_ptr_exclusion.h"
Hans Wennborgafeb3902020-06-17 14:42:2920#include "base/notreached.h"
Tal Pressman3e91d6fd2020-07-02 04:38:0121#include "base/time/time.h"
asvitkine79ab08c2017-01-30 23:27:0522
23namespace base {
24
Takashi Toyoshima03c3a4d2024-09-06 06:32:0225namespace internal {
26
Takashi Toyoshima5e7b25152024-08-23 04:48:0327BASE_EXPORT bool IsFeatureParamWithCacheEnabled();
Takashi Toyoshima03c3a4d2024-09-06 06:32:0228
29// A traits struct to manage the type for the default value in the following
30// FeatureParam<> template. `std::string` needs to use a string literal instead
31// of `std::string` to realize compile time construction.
32template <typename T>
33struct FeatureParamTraits {
34 using DefaultValueType = T;
35};
36
37template <>
38struct FeatureParamTraits<std::string> {
39 using DefaultValueType = const char*;
40};
41
42} // namespace internal
Takashi Toyoshima5e7b25152024-08-23 04:48:0343
Miyoung Shinb5ad87f2019-05-13 20:12:4544// Key-value mapping type for field trial parameters.
45typedef std::map<std::string, std::string> FieldTrialParams;
46
Alexei Svitkine8724ea502019-06-14 21:51:4647// Param string decoding function for AssociateFieldTrialParamsFromString().
48typedef std::string (*FieldTrialParamsDecodeStringFunc)(const std::string& str);
49
Weilun Shi1cd8fb92020-07-17 23:31:0050// Unescapes special characters from the given string. Used in
51// AssociateFieldTrialParamsFromString() as one of the feature params decoding
52// functions.
53BASE_EXPORT std::string UnescapeValue(const std::string& value);
54
asvitkine79ab08c2017-01-30 23:27:0555// Associates the specified set of key-value |params| with the field trial
56// specified by |trial_name| and |group_name|. Fails and returns false if the
57// specified field trial already has params associated with it or the trial
58// is already active (group() has been called on it). Thread safe.
Miyoung Shinb5ad87f2019-05-13 20:12:4559BASE_EXPORT bool AssociateFieldTrialParams(const std::string& trial_name,
60 const std::string& group_name,
61 const FieldTrialParams& params);
asvitkine79ab08c2017-01-30 23:27:0562
Alexei Svitkine8724ea502019-06-14 21:51:4663// Provides a mechanism to associate multiple set of params to multiple groups
64// with a formatted string as returned by FieldTrialList::AllParamsToString().
65// |decode_data_func| allows specifying a custom decoding function.
66BASE_EXPORT bool AssociateFieldTrialParamsFromString(
67 const std::string& params_string,
68 FieldTrialParamsDecodeStringFunc decode_data_func);
69
asvitkine79ab08c2017-01-30 23:27:0570// Retrieves the set of key-value |params| for the specified field trial, based
71// on its selected group. If the field trial does not exist or its selected
72// group does not have any parameters associated with it, returns false and
73// does not modify |params|. Calling this function will result in the field
74// trial being marked as active if found (i.e. group() will be called on it),
75// if it wasn't already. Thread safe.
Miyoung Shinb5ad87f2019-05-13 20:12:4576BASE_EXPORT bool GetFieldTrialParams(const std::string& trial_name,
77 FieldTrialParams* params);
asvitkine79ab08c2017-01-30 23:27:0578
79// Retrieves the set of key-value |params| for the field trial associated with
80// the specified |feature|. A feature is associated with at most one field
81// trial and selected group. See base/feature_list.h for more information on
82// features. If the feature is not enabled, or if there's no associated params,
83// returns false and does not modify |params|. Calling this function will
84// result in the associated field trial being marked as active if found (i.e.
85// group() will be called on it), if it wasn't already. Thread safe.
Miyoung Shinb5ad87f2019-05-13 20:12:4586BASE_EXPORT bool GetFieldTrialParamsByFeature(const base::Feature& feature,
87 FieldTrialParams* params);
asvitkine79ab08c2017-01-30 23:27:0588
89// Retrieves a specific parameter value corresponding to |param_name| for the
90// specified field trial, based on its selected group. If the field trial does
91// not exist or the specified parameter does not exist, returns an empty
92// string. Calling this function will result in the field trial being marked as
93// active if found (i.e. group() will be called on it), if it wasn't already.
94// Thread safe.
95BASE_EXPORT std::string GetFieldTrialParamValue(const std::string& trial_name,
96 const std::string& param_name);
97
98// Retrieves a specific parameter value corresponding to |param_name| for the
99// field trial associated with the specified |feature|. A feature is associated
100// with at most one field trial and selected group. See base/feature_list.h for
101// more information on features. If the feature is not enabled, or the
102// specified parameter does not exist, returns an empty string. Calling this
103// function will result in the associated field trial being marked as active if
104// found (i.e. group() will be called on it), if it wasn't already. Thread safe.
105BASE_EXPORT std::string GetFieldTrialParamValueByFeature(
106 const base::Feature& feature,
107 const std::string& param_name);
108
Takashi Toyoshima2671988952024-08-26 05:58:34109// Same as GetFieldTrialParamValueByFeature(). But internally relies on
110// GetFieldTrialParamsByFeature to handle empty values in the map, and returns
111// |default_value| only if |param_name| is not found in the map.
112BASE_EXPORT std::string GetFieldTrialParamByFeatureAsString(
113 const base::Feature& feature,
114 const std::string& param_name,
115 const std::string& default_value);
116
asvitkine79ab08c2017-01-30 23:27:05117// Same as GetFieldTrialParamValueByFeature(). On top of that, it converts the
118// string value into an int using base::StringToInt() and returns it, if
119// successful. Otherwise, it returns |default_value|. If the string value is not
120// empty and the conversion does not succeed, it produces a warning to LOG.
121BASE_EXPORT int GetFieldTrialParamByFeatureAsInt(const base::Feature& feature,
122 const std::string& param_name,
123 int default_value);
124
125// Same as GetFieldTrialParamValueByFeature(). On top of that, it converts the
126// string value into a double using base::StringToDouble() and returns it, if
127// successful. Otherwise, it returns |default_value|. If the string value is not
128// empty and the conversion does not succeed, it produces a warning to LOG.
129BASE_EXPORT double GetFieldTrialParamByFeatureAsDouble(
130 const base::Feature& feature,
131 const std::string& param_name,
132 double default_value);
133
134// Same as GetFieldTrialParamValueByFeature(). On top of that, it converts the
135// string value into a boolean and returns it, if successful. Otherwise, it
136// returns |default_value|. The only string representations accepted here are
137// "true" and "false". If the string value is not empty and the conversion does
138// not succeed, it produces a warning to LOG.
139BASE_EXPORT bool GetFieldTrialParamByFeatureAsBool(
140 const base::Feature& feature,
141 const std::string& param_name,
142 bool default_value);
143
Minoru Chikamunefedb8272023-09-27 02:08:24144// Same as GetFieldTrialParamValueByFeature(). On top of that, it converts the
145// string value into a base::TimeDelta and returns it, if successful. Otherwise,
146// it returns `default_value`. If the string value is not empty and the
147// conversion does not succeed, it produces a warning to LOG.
148BASE_EXPORT base::TimeDelta GetFieldTrialParamByFeatureAsTimeDelta(
149 const Feature& feature,
150 const std::string& param_name,
151 base::TimeDelta default_value);
152
sfiera01757be62017-09-20 16:36:13153// Shared declaration for various FeatureParam<T> types.
154//
155// This template is defined for the following types T:
156// bool
157// int
Takashi Toyoshima89bc55b2024-08-26 06:02:41158// size_t
sfiera01757be62017-09-20 16:36:13159// double
160// std::string
161// enum types
Tal Pressman3e91d6fd2020-07-02 04:38:01162// base::TimeDelta
sfiera01757be62017-09-20 16:36:13163//
sfiera01757be62017-09-20 16:36:13164// Attempting to use it with any other type is a compile error.
Jesse Doherty031e56932020-10-21 23:23:47165//
166// Getting a param value from a FeatureParam<T> will have the same semantics as
167// GetFieldTrialParamValueByFeature(), see that function's comments for details.
Takashi Toyoshima03c3a4d2024-09-06 06:32:02168// `cache_getter` is used to provide a dedicated getter tbat is used to give a
169// local cache to the FeatureParam. Usually, this is automatically generated and
170// provided via BASE_FEATURE_PARAM() or BASE_FEATURE_ENUM_PARAM() macro.
sfiera01757be62017-09-20 16:36:13171//
Takashi Toyoshima03c3a4d2024-09-06 06:32:02172// Example to declares a double-valued parameter.
sfiera01757be62017-09-20 16:36:13173//
mlcuif190ddea2024-04-25 15:26:59174// constexpr FeatureParam<double> kAssistantTriggerThreshold = {
sfiera01757be62017-09-20 16:36:13175// &kAssistantFeature, "trigger_threshold", 0.10};
176//
Xiaohan Wang0c04ab32023-04-26 16:01:44177// If the feature is not enabled, the parameter is not set, or set to an invalid
Takashi Toyoshima03c3a4d2024-09-06 06:32:02178// value, then Get() will return the default value.
179template <typename T, bool IsEnum = std::is_enum_v<T>>
180struct FeatureParam {
181 using DefaultValueType =
182 typename internal::FeatureParamTraits<T>::DefaultValueType;
sfiera01757be62017-09-20 16:36:13183
Takashi Toyoshima03c3a4d2024-09-06 06:32:02184 // Prevent use of FeatureParam<> with unsupported types (e.g. void*). Uses T
185 // in its definition so that evaluation is deferred until the template is
186 // instantiated.
187 static_assert(std::is_same_v<bool, T> || std::is_same_v<int, T> ||
188 std::is_same_v<size_t, T> || std::is_same_v<double, T> ||
189 std::is_same_v<std::string, T> ||
190 std::is_same_v<base::TimeDelta, T>,
191 "Unsupported FeatureParam<> type");
sfiera01757be62017-09-20 16:36:13192
Tal Pressman3e91d6fd2020-07-02 04:38:01193 constexpr FeatureParam(const Feature* feature,
194 const char* name,
Takashi Toyoshima03c3a4d2024-09-06 06:32:02195 DefaultValueType default_value,
196 T (*cache_getter)(const FeatureParam<T>*) = nullptr)
Takashi Toyoshimaf031fbef2024-08-19 06:48:15197 : feature(feature),
198 name(name),
199 default_value(default_value),
200 cache_getter(cache_getter) {}
Tal Pressman3e91d6fd2020-07-02 04:38:01201
Takashi Toyoshimaf031fbef2024-08-19 06:48:15202 // Calling Get() or GetWithoutCache() will activate the field trial associated
203 // with |feature|. See GetFieldTrialParamValueByFeature() for more details.
Takashi Toyoshima03c3a4d2024-09-06 06:32:02204 BASE_EXPORT T Get() const {
205 if (internal::IsFeatureParamWithCacheEnabled() && cache_getter) {
206 return cache_getter(this);
207 }
208 return GetWithoutCache();
209 }
210 BASE_EXPORT T GetWithoutCache() const;
Tal Pressman3e91d6fd2020-07-02 04:38:01211
Bartek Nowierski26a2cce2024-06-23 21:34:06212 // RAW_PTR_EXCLUSION: #global-scope
Keishi Hattori8a7e15d2023-01-19 07:16:29213 RAW_PTR_EXCLUSION const Feature* const feature;
Tal Pressman3e91d6fd2020-07-02 04:38:01214 const char* const name;
Takashi Toyoshima03c3a4d2024-09-06 06:32:02215 const DefaultValueType default_value;
216 T (*const cache_getter)(const FeatureParam<T>*);
Tal Pressman3e91d6fd2020-07-02 04:38:01217};
218
Takashi Toyoshima03c3a4d2024-09-06 06:32:02219// Declarations for GetWithoutCache() specializations and explicit
220// instantiations for the FeatureParam<> to ensure instantiating them
221// in the base components to export them.
222template <>
223bool FeatureParam<bool>::GetWithoutCache() const;
224template struct FeatureParam<bool>;
225
226template <>
227int FeatureParam<int>::GetWithoutCache() const;
228template struct FeatureParam<int>;
229
230template <>
231size_t FeatureParam<size_t>::GetWithoutCache() const;
232template struct FeatureParam<size_t>;
233
234template <>
235double FeatureParam<double>::GetWithoutCache() const;
236template struct FeatureParam<double>;
237
238template <>
239std::string FeatureParam<std::string>::GetWithoutCache() const;
240template struct FeatureParam<std::string>;
241
242template <>
243TimeDelta FeatureParam<TimeDelta>::GetWithoutCache() const;
244template struct FeatureParam<TimeDelta>;
245
sfiera01757be62017-09-20 16:36:13246BASE_EXPORT void LogInvalidEnumValue(const Feature& feature,
247 const std::string& param_name,
248 const std::string& value_as_string,
249 int default_value_as_int);
250
251// Feature param declaration for an enum, with associated options. Example:
252//
Kenichi Ishibashi0a84cb5f32018-12-13 04:02:10253// constexpr FeatureParam<ShapeEnum>::Option kShapeParamOptions[] = {
sfiera01757be62017-09-20 16:36:13254// {SHAPE_CIRCLE, "circle"},
255// {SHAPE_CYLINDER, "cylinder"},
256// {SHAPE_PAPERCLIP, "paperclip"}};
mlcuif190ddea2024-04-25 15:26:59257// constexpr FeatureParam<ShapeEnum> kAssistantShapeParam = {
sfiera01757be62017-09-20 16:36:13258// &kAssistantFeature, "shape", SHAPE_CIRCLE, &kShapeParamOptions};
259//
260// With this declaration, the parameter may be set to "circle", "cylinder", or
261// "paperclip", and that will be translated to one of the three enum values. By
262// default, or if the param is set to an unknown value, the parameter will be
263// assumed to be SHAPE_CIRCLE.
264template <typename Enum>
265struct FeatureParam<Enum, true> {
266 struct Option {
267 constexpr Option(Enum value, const char* name) : value(value), name(name) {}
268
269 const Enum value;
270 const char* const name;
271 };
272
273 template <size_t option_count>
Takashi Toyoshima5e7b25152024-08-23 04:48:03274 constexpr FeatureParam(
275 const Feature* feature,
276 const char* name,
277 const Enum default_value,
278 const std::array<Option, option_count>& options,
279 Enum (*cache_getter)(const FeatureParam<Enum>*) = nullptr)
danakje75c6c812024-07-26 20:37:47280 : feature(feature),
281 name(name),
282 default_value(default_value),
283 options(options.data()),
Takashi Toyoshima5e7b25152024-08-23 04:48:03284 option_count(option_count),
285 cache_getter(cache_getter) {
danakje75c6c812024-07-26 20:37:47286 static_assert(option_count >= 1, "FeatureParam<enum> has no options");
287 }
288
289 template <size_t option_count>
Takashi Toyoshima5e7b25152024-08-23 04:48:03290 constexpr FeatureParam(
291 const Feature* feature,
292 const char* name,
293 const Enum default_value,
294 const Option (*options)[option_count],
295 Enum (*cache_getter)(const FeatureParam<Enum>*) = nullptr)
sfiera01757be62017-09-20 16:36:13296 : feature(feature),
297 name(name),
298 default_value(default_value),
299 options(*options),
Takashi Toyoshima5e7b25152024-08-23 04:48:03300 option_count(option_count),
301 cache_getter(cache_getter) {
sfiera01757be62017-09-20 16:36:13302 static_assert(option_count >= 1, "FeatureParam<enum> has no options");
303 }
304
Takashi Toyoshima5e7b25152024-08-23 04:48:03305 // Calling Get() or GetWithoutCache() will activate the field trial associated
306 // with |feature|. See GetFieldTrialParamValueByFeature() for more details.
sfiera01757be62017-09-20 16:36:13307 Enum Get() const {
Takashi Toyoshima03c3a4d2024-09-06 06:32:02308 if (internal::IsFeatureParamWithCacheEnabled() && cache_getter) {
Takashi Toyoshima5e7b25152024-08-23 04:48:03309 return cache_getter(this);
310 }
311 return GetWithoutCache();
312 }
313 Enum GetWithoutCache() const {
sfiera01757be62017-09-20 16:36:13314 std::string value = GetFieldTrialParamValueByFeature(*feature, name);
Takashi Toyoshima03c3a4d2024-09-06 06:32:02315 if (value.empty()) {
sfiera01757be62017-09-20 16:36:13316 return default_value;
Takashi Toyoshima03c3a4d2024-09-06 06:32:02317 }
sfiera01757be62017-09-20 16:36:13318 for (size_t i = 0; i < option_count; ++i) {
Takashi Toyoshima03c3a4d2024-09-06 06:32:02319 if (value == options[i].name) {
sfiera01757be62017-09-20 16:36:13320 return options[i].value;
Takashi Toyoshima03c3a4d2024-09-06 06:32:02321 }
sfiera01757be62017-09-20 16:36:13322 }
323 LogInvalidEnumValue(*feature, name, value, static_cast<int>(default_value));
324 return default_value;
325 }
326
Fergal Dalybcac47a2020-03-27 01:54:21327 // Returns the param-string for the given enum value.
328 std::string GetName(Enum value) const {
329 for (size_t i = 0; i < option_count; ++i) {
Takashi Toyoshima03c3a4d2024-09-06 06:32:02330 if (value == options[i].value) {
Fergal Dalybcac47a2020-03-27 01:54:21331 return options[i].name;
Takashi Toyoshima03c3a4d2024-09-06 06:32:02332 }
Fergal Dalybcac47a2020-03-27 01:54:21333 }
Peter Boströmde573332024-08-26 20:42:45334 NOTREACHED();
Fergal Dalybcac47a2020-03-27 01:54:21335 }
336
Bartek Nowierski26a2cce2024-06-23 21:34:06337 // RAW_PTR_EXCLUSION: #global-scope
Keishi Hattori8a7e15d2023-01-19 07:16:29338 RAW_PTR_EXCLUSION const base::Feature* const feature;
sfiera01757be62017-09-20 16:36:13339 const char* const name;
340 const Enum default_value;
Bartek Nowierski26a2cce2024-06-23 21:34:06341 // RAW_PTR_EXCLUSION: #global-scope
Keishi Hattori8a7e15d2023-01-19 07:16:29342 RAW_PTR_EXCLUSION const Option* const options;
sfiera01757be62017-09-20 16:36:13343 const size_t option_count;
Takashi Toyoshima5e7b25152024-08-23 04:48:03344 Enum (*const cache_getter)(const FeatureParam<Enum>*);
sfiera01757be62017-09-20 16:36:13345};
346
asvitkine79ab08c2017-01-30 23:27:05347} // namespace base
348
349#endif // BASE_METRICS_FIELD_TRIAL_PARAMS_H_