blob: 9bd7a0ad5d581a58bd10955dd6b63a42c23a71d9 [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"
Takashi Toyoshima8a54cdf2024-11-21 02:38:4020#include "base/no_destructor.h"
Hans Wennborgafeb3902020-06-17 14:42:2921#include "base/notreached.h"
Tal Pressman3e91d6fd2020-07-02 04:38:0122#include "base/time/time.h"
asvitkine79ab08c2017-01-30 23:27:0523
24namespace base {
25
Takashi Toyoshima03c3a4d2024-09-06 06:32:0226namespace internal {
27
Takashi Toyoshima5e7b25152024-08-23 04:48:0328BASE_EXPORT bool IsFeatureParamWithCacheEnabled();
Takashi Toyoshima03c3a4d2024-09-06 06:32:0229
30// A traits struct to manage the type for the default value in the following
31// FeatureParam<> template. `std::string` needs to use a string literal instead
32// of `std::string` to realize compile time construction.
33template <typename T>
34struct FeatureParamTraits {
35 using DefaultValueType = T;
Takashi Toyoshima8a54cdf2024-11-21 02:38:4036 using CacheStorageType = T;
37 static CacheStorageType ToCacheStorageType(const T& value) {
38 return value;
39 }
40 static constexpr T FromCacheStorageType(const CacheStorageType& storage) {
41 return storage;
42 }
Takashi Toyoshima03c3a4d2024-09-06 06:32:0243};
44
45template <>
46struct FeatureParamTraits<std::string> {
47 using DefaultValueType = const char*;
Takashi Toyoshima8a54cdf2024-11-21 02:38:4048 using CacheStorageType = NoDestructor<std::string>;
49 static CacheStorageType ToCacheStorageType(
50 const std::string& value) {
51 return CacheStorageType(value);
52 }
53 static constexpr std::string FromCacheStorageType(
54 const CacheStorageType& storage) {
55 return *storage;
56 }
Takashi Toyoshima03c3a4d2024-09-06 06:32:0257};
58
59} // namespace internal
Takashi Toyoshima5e7b25152024-08-23 04:48:0360
Miyoung Shinb5ad87f2019-05-13 20:12:4561// Key-value mapping type for field trial parameters.
62typedef std::map<std::string, std::string> FieldTrialParams;
63
Alexei Svitkine8724ea502019-06-14 21:51:4664// Param string decoding function for AssociateFieldTrialParamsFromString().
65typedef std::string (*FieldTrialParamsDecodeStringFunc)(const std::string& str);
66
Weilun Shi1cd8fb92020-07-17 23:31:0067// Unescapes special characters from the given string. Used in
68// AssociateFieldTrialParamsFromString() as one of the feature params decoding
69// functions.
70BASE_EXPORT std::string UnescapeValue(const std::string& value);
71
asvitkine79ab08c2017-01-30 23:27:0572// Associates the specified set of key-value |params| with the field trial
73// specified by |trial_name| and |group_name|. Fails and returns false if the
74// specified field trial already has params associated with it or the trial
75// is already active (group() has been called on it). Thread safe.
Miyoung Shinb5ad87f2019-05-13 20:12:4576BASE_EXPORT bool AssociateFieldTrialParams(const std::string& trial_name,
77 const std::string& group_name,
78 const FieldTrialParams& params);
asvitkine79ab08c2017-01-30 23:27:0579
Alexei Svitkine8724ea502019-06-14 21:51:4680// Provides a mechanism to associate multiple set of params to multiple groups
81// with a formatted string as returned by FieldTrialList::AllParamsToString().
82// |decode_data_func| allows specifying a custom decoding function.
83BASE_EXPORT bool AssociateFieldTrialParamsFromString(
84 const std::string& params_string,
85 FieldTrialParamsDecodeStringFunc decode_data_func);
86
asvitkine79ab08c2017-01-30 23:27:0587// Retrieves the set of key-value |params| for the specified field trial, based
88// on its selected group. If the field trial does not exist or its selected
89// group does not have any parameters associated with it, returns false and
90// does not modify |params|. Calling this function will result in the field
91// trial being marked as active if found (i.e. group() will be called on it),
92// if it wasn't already. Thread safe.
Miyoung Shinb5ad87f2019-05-13 20:12:4593BASE_EXPORT bool GetFieldTrialParams(const std::string& trial_name,
94 FieldTrialParams* params);
asvitkine79ab08c2017-01-30 23:27:0595
96// Retrieves the set of key-value |params| for the field trial associated with
97// the specified |feature|. A feature is associated with at most one field
98// trial and selected group. See base/feature_list.h for more information on
99// features. If the feature is not enabled, or if there's no associated params,
100// returns false and does not modify |params|. Calling this function will
101// result in the associated field trial being marked as active if found (i.e.
102// group() will be called on it), if it wasn't already. Thread safe.
Miyoung Shinb5ad87f2019-05-13 20:12:45103BASE_EXPORT bool GetFieldTrialParamsByFeature(const base::Feature& feature,
104 FieldTrialParams* params);
asvitkine79ab08c2017-01-30 23:27:05105
106// Retrieves a specific parameter value corresponding to |param_name| for the
107// specified field trial, based on its selected group. If the field trial does
108// not exist or the specified parameter does not exist, returns an empty
109// string. Calling this function will result in the field trial being marked as
110// active if found (i.e. group() will be called on it), if it wasn't already.
111// Thread safe.
112BASE_EXPORT std::string GetFieldTrialParamValue(const std::string& trial_name,
113 const std::string& param_name);
114
115// Retrieves a specific parameter value corresponding to |param_name| for the
116// field trial associated with the specified |feature|. A feature is associated
117// with at most one field trial and selected group. See base/feature_list.h for
118// more information on features. If the feature is not enabled, or the
119// specified parameter does not exist, returns an empty string. Calling this
120// function will result in the associated field trial being marked as active if
121// found (i.e. group() will be called on it), if it wasn't already. Thread safe.
122BASE_EXPORT std::string GetFieldTrialParamValueByFeature(
123 const base::Feature& feature,
124 const std::string& param_name);
125
Takashi Toyoshima2671988952024-08-26 05:58:34126// Same as GetFieldTrialParamValueByFeature(). But internally relies on
127// GetFieldTrialParamsByFeature to handle empty values in the map, and returns
128// |default_value| only if |param_name| is not found in the map.
129BASE_EXPORT std::string GetFieldTrialParamByFeatureAsString(
130 const base::Feature& feature,
131 const std::string& param_name,
132 const std::string& default_value);
133
asvitkine79ab08c2017-01-30 23:27:05134// Same as GetFieldTrialParamValueByFeature(). On top of that, it converts the
135// string value into an int using base::StringToInt() and returns it, if
136// successful. Otherwise, it returns |default_value|. If the string value is not
137// empty and the conversion does not succeed, it produces a warning to LOG.
138BASE_EXPORT int GetFieldTrialParamByFeatureAsInt(const base::Feature& feature,
139 const std::string& param_name,
140 int default_value);
141
142// Same as GetFieldTrialParamValueByFeature(). On top of that, it converts the
143// string value into a double using base::StringToDouble() and returns it, if
144// successful. Otherwise, it returns |default_value|. If the string value is not
145// empty and the conversion does not succeed, it produces a warning to LOG.
146BASE_EXPORT double GetFieldTrialParamByFeatureAsDouble(
147 const base::Feature& feature,
148 const std::string& param_name,
149 double default_value);
150
151// Same as GetFieldTrialParamValueByFeature(). On top of that, it converts the
152// string value into a boolean and returns it, if successful. Otherwise, it
153// returns |default_value|. The only string representations accepted here are
154// "true" and "false". If the string value is not empty and the conversion does
155// not succeed, it produces a warning to LOG.
156BASE_EXPORT bool GetFieldTrialParamByFeatureAsBool(
157 const base::Feature& feature,
158 const std::string& param_name,
159 bool default_value);
160
Minoru Chikamunefedb8272023-09-27 02:08:24161// Same as GetFieldTrialParamValueByFeature(). On top of that, it converts the
162// string value into a base::TimeDelta and returns it, if successful. Otherwise,
163// it returns `default_value`. If the string value is not empty and the
164// conversion does not succeed, it produces a warning to LOG.
165BASE_EXPORT base::TimeDelta GetFieldTrialParamByFeatureAsTimeDelta(
166 const Feature& feature,
167 const std::string& param_name,
168 base::TimeDelta default_value);
169
sfiera01757be62017-09-20 16:36:13170// Shared declaration for various FeatureParam<T> types.
171//
172// This template is defined for the following types T:
173// bool
174// int
Takashi Toyoshima89bc55b2024-08-26 06:02:41175// size_t
sfiera01757be62017-09-20 16:36:13176// double
177// std::string
178// enum types
Tal Pressman3e91d6fd2020-07-02 04:38:01179// base::TimeDelta
sfiera01757be62017-09-20 16:36:13180//
sfiera01757be62017-09-20 16:36:13181// Attempting to use it with any other type is a compile error.
Jesse Doherty031e56932020-10-21 23:23:47182//
183// Getting a param value from a FeatureParam<T> will have the same semantics as
184// GetFieldTrialParamValueByFeature(), see that function's comments for details.
Takashi Toyoshima03c3a4d2024-09-06 06:32:02185// `cache_getter` is used to provide a dedicated getter tbat is used to give a
186// local cache to the FeatureParam. Usually, this is automatically generated and
187// provided via BASE_FEATURE_PARAM() or BASE_FEATURE_ENUM_PARAM() macro.
sfiera01757be62017-09-20 16:36:13188//
Takashi Toyoshima03c3a4d2024-09-06 06:32:02189// Example to declares a double-valued parameter.
sfiera01757be62017-09-20 16:36:13190//
mlcuif190ddea2024-04-25 15:26:59191// constexpr FeatureParam<double> kAssistantTriggerThreshold = {
sfiera01757be62017-09-20 16:36:13192// &kAssistantFeature, "trigger_threshold", 0.10};
193//
Xiaohan Wang0c04ab32023-04-26 16:01:44194// If the feature is not enabled, the parameter is not set, or set to an invalid
Takashi Toyoshima03c3a4d2024-09-06 06:32:02195// value, then Get() will return the default value.
196template <typename T, bool IsEnum = std::is_enum_v<T>>
197struct FeatureParam {
198 using DefaultValueType =
199 typename internal::FeatureParamTraits<T>::DefaultValueType;
sfiera01757be62017-09-20 16:36:13200
Takashi Toyoshima03c3a4d2024-09-06 06:32:02201 // Prevent use of FeatureParam<> with unsupported types (e.g. void*). Uses T
202 // in its definition so that evaluation is deferred until the template is
203 // instantiated.
204 static_assert(std::is_same_v<bool, T> || std::is_same_v<int, T> ||
205 std::is_same_v<size_t, T> || std::is_same_v<double, T> ||
206 std::is_same_v<std::string, T> ||
207 std::is_same_v<base::TimeDelta, T>,
208 "Unsupported FeatureParam<> type");
sfiera01757be62017-09-20 16:36:13209
Tal Pressman3e91d6fd2020-07-02 04:38:01210 constexpr FeatureParam(const Feature* feature,
211 const char* name,
Takashi Toyoshima03c3a4d2024-09-06 06:32:02212 DefaultValueType default_value,
213 T (*cache_getter)(const FeatureParam<T>*) = nullptr)
Takashi Toyoshimaf031fbef2024-08-19 06:48:15214 : feature(feature),
215 name(name),
216 default_value(default_value),
217 cache_getter(cache_getter) {}
Tal Pressman3e91d6fd2020-07-02 04:38:01218
Takashi Toyoshimaf031fbef2024-08-19 06:48:15219 // Calling Get() or GetWithoutCache() will activate the field trial associated
220 // with |feature|. See GetFieldTrialParamValueByFeature() for more details.
Takashi Toyoshima03c3a4d2024-09-06 06:32:02221 BASE_EXPORT T Get() const {
222 if (internal::IsFeatureParamWithCacheEnabled() && cache_getter) {
223 return cache_getter(this);
224 }
225 return GetWithoutCache();
226 }
227 BASE_EXPORT T GetWithoutCache() const;
Tal Pressman3e91d6fd2020-07-02 04:38:01228
Bartek Nowierski26a2cce2024-06-23 21:34:06229 // RAW_PTR_EXCLUSION: #global-scope
Keishi Hattori8a7e15d2023-01-19 07:16:29230 RAW_PTR_EXCLUSION const Feature* const feature;
Tal Pressman3e91d6fd2020-07-02 04:38:01231 const char* const name;
Takashi Toyoshima03c3a4d2024-09-06 06:32:02232 const DefaultValueType default_value;
233 T (*const cache_getter)(const FeatureParam<T>*);
Tal Pressman3e91d6fd2020-07-02 04:38:01234};
235
Takashi Toyoshima03c3a4d2024-09-06 06:32:02236// Declarations for GetWithoutCache() specializations and explicit
237// instantiations for the FeatureParam<> to ensure instantiating them
238// in the base components to export them.
239template <>
240bool FeatureParam<bool>::GetWithoutCache() const;
241template struct FeatureParam<bool>;
Takashi Toyoshima8a54cdf2024-11-21 02:38:40242template struct internal::FeatureParamTraits<bool>;
Takashi Toyoshima03c3a4d2024-09-06 06:32:02243
244template <>
245int FeatureParam<int>::GetWithoutCache() const;
246template struct FeatureParam<int>;
Takashi Toyoshima8a54cdf2024-11-21 02:38:40247template struct internal::FeatureParamTraits<int>;
Takashi Toyoshima03c3a4d2024-09-06 06:32:02248
249template <>
250size_t FeatureParam<size_t>::GetWithoutCache() const;
251template struct FeatureParam<size_t>;
Takashi Toyoshima8a54cdf2024-11-21 02:38:40252template struct internal::FeatureParamTraits<size_t>;
Takashi Toyoshima03c3a4d2024-09-06 06:32:02253
254template <>
255double FeatureParam<double>::GetWithoutCache() const;
256template struct FeatureParam<double>;
Takashi Toyoshima8a54cdf2024-11-21 02:38:40257template struct internal::FeatureParamTraits<double>;
Takashi Toyoshima03c3a4d2024-09-06 06:32:02258
259template <>
260std::string FeatureParam<std::string>::GetWithoutCache() const;
261template struct FeatureParam<std::string>;
262
263template <>
264TimeDelta FeatureParam<TimeDelta>::GetWithoutCache() const;
265template struct FeatureParam<TimeDelta>;
Takashi Toyoshima8a54cdf2024-11-21 02:38:40266template struct internal::FeatureParamTraits<TimeDelta>;
Takashi Toyoshima03c3a4d2024-09-06 06:32:02267
sfiera01757be62017-09-20 16:36:13268BASE_EXPORT void LogInvalidEnumValue(const Feature& feature,
269 const std::string& param_name,
270 const std::string& value_as_string,
271 int default_value_as_int);
272
273// Feature param declaration for an enum, with associated options. Example:
274//
Kenichi Ishibashi0a84cb5f32018-12-13 04:02:10275// constexpr FeatureParam<ShapeEnum>::Option kShapeParamOptions[] = {
sfiera01757be62017-09-20 16:36:13276// {SHAPE_CIRCLE, "circle"},
277// {SHAPE_CYLINDER, "cylinder"},
278// {SHAPE_PAPERCLIP, "paperclip"}};
mlcuif190ddea2024-04-25 15:26:59279// constexpr FeatureParam<ShapeEnum> kAssistantShapeParam = {
sfiera01757be62017-09-20 16:36:13280// &kAssistantFeature, "shape", SHAPE_CIRCLE, &kShapeParamOptions};
281//
282// With this declaration, the parameter may be set to "circle", "cylinder", or
283// "paperclip", and that will be translated to one of the three enum values. By
284// default, or if the param is set to an unknown value, the parameter will be
285// assumed to be SHAPE_CIRCLE.
286template <typename Enum>
287struct FeatureParam<Enum, true> {
288 struct Option {
289 constexpr Option(Enum value, const char* name) : value(value), name(name) {}
290
291 const Enum value;
292 const char* const name;
293 };
294
295 template <size_t option_count>
Takashi Toyoshima5e7b25152024-08-23 04:48:03296 constexpr FeatureParam(
297 const Feature* feature,
298 const char* name,
299 const Enum default_value,
300 const std::array<Option, option_count>& options,
301 Enum (*cache_getter)(const FeatureParam<Enum>*) = nullptr)
danakje75c6c812024-07-26 20:37:47302 : feature(feature),
303 name(name),
304 default_value(default_value),
305 options(options.data()),
Takashi Toyoshima5e7b25152024-08-23 04:48:03306 option_count(option_count),
307 cache_getter(cache_getter) {
danakje75c6c812024-07-26 20:37:47308 static_assert(option_count >= 1, "FeatureParam<enum> has no options");
309 }
310
311 template <size_t option_count>
Takashi Toyoshima5e7b25152024-08-23 04:48:03312 constexpr FeatureParam(
313 const Feature* feature,
314 const char* name,
315 const Enum default_value,
316 const Option (*options)[option_count],
317 Enum (*cache_getter)(const FeatureParam<Enum>*) = nullptr)
sfiera01757be62017-09-20 16:36:13318 : feature(feature),
319 name(name),
320 default_value(default_value),
321 options(*options),
Takashi Toyoshima5e7b25152024-08-23 04:48:03322 option_count(option_count),
323 cache_getter(cache_getter) {
sfiera01757be62017-09-20 16:36:13324 static_assert(option_count >= 1, "FeatureParam<enum> has no options");
325 }
326
Takashi Toyoshima5e7b25152024-08-23 04:48:03327 // Calling Get() or GetWithoutCache() will activate the field trial associated
328 // with |feature|. See GetFieldTrialParamValueByFeature() for more details.
sfiera01757be62017-09-20 16:36:13329 Enum Get() const {
Takashi Toyoshima03c3a4d2024-09-06 06:32:02330 if (internal::IsFeatureParamWithCacheEnabled() && cache_getter) {
Takashi Toyoshima5e7b25152024-08-23 04:48:03331 return cache_getter(this);
332 }
333 return GetWithoutCache();
334 }
335 Enum GetWithoutCache() const {
sfiera01757be62017-09-20 16:36:13336 std::string value = GetFieldTrialParamValueByFeature(*feature, name);
Takashi Toyoshima03c3a4d2024-09-06 06:32:02337 if (value.empty()) {
sfiera01757be62017-09-20 16:36:13338 return default_value;
Takashi Toyoshima03c3a4d2024-09-06 06:32:02339 }
sfiera01757be62017-09-20 16:36:13340 for (size_t i = 0; i < option_count; ++i) {
Takashi Toyoshima03c3a4d2024-09-06 06:32:02341 if (value == options[i].name) {
sfiera01757be62017-09-20 16:36:13342 return options[i].value;
Takashi Toyoshima03c3a4d2024-09-06 06:32:02343 }
sfiera01757be62017-09-20 16:36:13344 }
345 LogInvalidEnumValue(*feature, name, value, static_cast<int>(default_value));
346 return default_value;
347 }
348
Fergal Dalybcac47a2020-03-27 01:54:21349 // Returns the param-string for the given enum value.
350 std::string GetName(Enum value) const {
351 for (size_t i = 0; i < option_count; ++i) {
Takashi Toyoshima03c3a4d2024-09-06 06:32:02352 if (value == options[i].value) {
Fergal Dalybcac47a2020-03-27 01:54:21353 return options[i].name;
Takashi Toyoshima03c3a4d2024-09-06 06:32:02354 }
Fergal Dalybcac47a2020-03-27 01:54:21355 }
Peter Boströmde573332024-08-26 20:42:45356 NOTREACHED();
Fergal Dalybcac47a2020-03-27 01:54:21357 }
358
Bartek Nowierski26a2cce2024-06-23 21:34:06359 // RAW_PTR_EXCLUSION: #global-scope
Keishi Hattori8a7e15d2023-01-19 07:16:29360 RAW_PTR_EXCLUSION const base::Feature* const feature;
sfiera01757be62017-09-20 16:36:13361 const char* const name;
362 const Enum default_value;
Bartek Nowierski26a2cce2024-06-23 21:34:06363 // RAW_PTR_EXCLUSION: #global-scope
Keishi Hattori8a7e15d2023-01-19 07:16:29364 RAW_PTR_EXCLUSION const Option* const options;
sfiera01757be62017-09-20 16:36:13365 const size_t option_count;
Takashi Toyoshima5e7b25152024-08-23 04:48:03366 Enum (*const cache_getter)(const FeatureParam<Enum>*);
sfiera01757be62017-09-20 16:36:13367};
368
asvitkine79ab08c2017-01-30 23:27:05369} // namespace base
370
371#endif // BASE_METRICS_FIELD_TRIAL_PARAMS_H_