chromium/base/metrics/field_trial_params.h

// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
#pragma allow_unsafe_buffers
#endif

#ifndef BASE_METRICS_FIELD_TRIAL_PARAMS_H_
#define BASE_METRICS_FIELD_TRIAL_PARAMS_H_

#include <array>
#include <map>
#include <string>

#include "base/base_export.h"
#include "base/feature_list.h"
#include "base/logging.h"
#include "base/memory/raw_ptr_exclusion.h"
#include "base/notreached.h"
#include "base/time/time.h"

namespace base {

namespace field_trial_params_internal {
BASE_EXPORT bool IsFeatureParamWithCacheEnabled();
}

// Key-value mapping type for field trial parameters.
FieldTrialParams;

// Param string decoding function for AssociateFieldTrialParamsFromString().
FieldTrialParamsDecodeStringFunc;

// Unescapes special characters from the given string. Used in
// AssociateFieldTrialParamsFromString() as one of the feature params decoding
// functions.
BASE_EXPORT std::string UnescapeValue(const std::string& value);

// Associates the specified set of key-value |params| with the field trial
// specified by |trial_name| and |group_name|. Fails and returns false if the
// specified field trial already has params associated with it or the trial
// is already active (group() has been called on it). Thread safe.
BASE_EXPORT bool AssociateFieldTrialParams(const std::string& trial_name,
                                           const std::string& group_name,
                                           const FieldTrialParams& params);

// Provides a mechanism to associate multiple set of params to multiple groups
// with a formatted string as returned by FieldTrialList::AllParamsToString().
// |decode_data_func| allows specifying a custom decoding function.
BASE_EXPORT bool AssociateFieldTrialParamsFromString(
    const std::string& params_string,
    FieldTrialParamsDecodeStringFunc decode_data_func);

// Retrieves the set of key-value |params| for the specified field trial, based
// on its selected group. If the field trial does not exist or its selected
// group does not have any parameters associated with it, returns false and
// does not modify |params|. Calling this function will result in the field
// trial being marked as active if found (i.e. group() will be called on it),
// if it wasn't already. Thread safe.
BASE_EXPORT bool GetFieldTrialParams(const std::string& trial_name,
                                     FieldTrialParams* params);

// Retrieves the set of key-value |params| for the field trial associated with
// the specified |feature|. A feature is associated with at most one field
// trial and selected group. See  base/feature_list.h for more information on
// features. If the feature is not enabled, or if there's no associated params,
// returns false and does not modify |params|. Calling this function will
// result in the associated field trial being marked as active if found (i.e.
// group() will be called on it), if it wasn't already. Thread safe.
BASE_EXPORT bool GetFieldTrialParamsByFeature(const base::Feature& feature,
                                              FieldTrialParams* params);

// Retrieves a specific parameter value corresponding to |param_name| for the
// specified field trial, based on its selected group. If the field trial does
// not exist or the specified parameter does not exist, returns an empty
// string. Calling this function will result in the field trial being marked as
// active if found (i.e. group() will be called on it), if it wasn't already.
// Thread safe.
BASE_EXPORT std::string GetFieldTrialParamValue(const std::string& trial_name,
                                                const std::string& param_name);

// Retrieves a specific parameter value corresponding to |param_name| for the
// field trial associated with the specified |feature|. A feature is associated
// with at most one field trial and selected group. See base/feature_list.h for
// more information on features. If the feature is not enabled, or the
// specified parameter does not exist, returns an empty string. Calling this
// function will result in the associated field trial being marked as active if
// found (i.e. group() will be called on it), if it wasn't already. Thread safe.
BASE_EXPORT std::string GetFieldTrialParamValueByFeature(
    const base::Feature& feature,
    const std::string& param_name);

// Same as GetFieldTrialParamValueByFeature(). But internally relies on
// GetFieldTrialParamsByFeature to handle empty values in the map, and returns
// |default_value| only if |param_name| is not found in the map.
BASE_EXPORT std::string GetFieldTrialParamByFeatureAsString(
    const base::Feature& feature,
    const std::string& param_name,
    const std::string& default_value);

// Same as GetFieldTrialParamValueByFeature(). On top of that, it converts the
// string value into an int using base::StringToInt() and returns it, if
// successful. Otherwise, it returns |default_value|. If the string value is not
// empty and the conversion does not succeed, it produces a warning to LOG.
BASE_EXPORT int GetFieldTrialParamByFeatureAsInt(const base::Feature& feature,
                                                 const std::string& param_name,
                                                 int default_value);

// Same as GetFieldTrialParamValueByFeature(). On top of that, it converts the
// string value into a double using base::StringToDouble() and returns it, if
// successful. Otherwise, it returns |default_value|. If the string value is not
// empty and the conversion does not succeed, it produces a warning to LOG.
BASE_EXPORT double GetFieldTrialParamByFeatureAsDouble(
    const base::Feature& feature,
    const std::string& param_name,
    double default_value);

// Same as GetFieldTrialParamValueByFeature(). On top of that, it converts the
// string value into a boolean and returns it, if successful. Otherwise, it
// returns |default_value|. The only string representations accepted here are
// "true" and "false". If the string value is not empty and the conversion does
// not succeed, it produces a warning to LOG.
BASE_EXPORT bool GetFieldTrialParamByFeatureAsBool(
    const base::Feature& feature,
    const std::string& param_name,
    bool default_value);

// Same as GetFieldTrialParamValueByFeature(). On top of that, it converts the
// string value into a base::TimeDelta and returns it, if successful. Otherwise,
// it returns `default_value`. If the string value is not empty and the
// conversion does not succeed, it produces a warning to LOG.
BASE_EXPORT base::TimeDelta GetFieldTrialParamByFeatureAsTimeDelta(
    const Feature& feature,
    const std::string& param_name,
    base::TimeDelta default_value);

// Shared declaration for various FeatureParam<T> types.
//
// This template is defined for the following types T:
//   bool
//   int
//   size_t
//   double
//   std::string
//   enum types
//   base::TimeDelta
//
// See the individual definitions below for the appropriate interfaces.
// Attempting to use it with any other type is a compile error.
//
// Getting a param value from a FeatureParam<T> will have the same semantics as
// GetFieldTrialParamValueByFeature(), see that function's comments for details.
template <typename T, bool IsEnum = std::is_enum_v<T>>
struct FeatureParam {
  // Prevent use of FeatureParam<> with unsupported types (e.g. void*). Uses T
  // in its definition so that evaluation is deferred until the template is
  // instantiated.
  static_assert(!std::is_same_v<T, T>, "unsupported FeatureParam<> type");
};

// Declares a string-valued parameter. Example:
//
//     constexpr FeatureParam<string> kAssistantName = {
//         &kAssistantFeature, "assistant_name", "HAL"};
//
// If the feature is not enabled, the parameter is not set, or set to the empty
// string, then Get() will return the default value.
template <>
struct FeatureParam<std::string> {};

// Declares a double-valued parameter. Example:
//
//     constexpr FeatureParam<double> kAssistantTriggerThreshold = {
//         &kAssistantFeature, "trigger_threshold", 0.10};
//
// If the feature is not enabled, the parameter is not set, or set to an invalid
// double value, then Get() will return the default value.
template <>
struct FeatureParam<double> {};

// Declares an int-valued parameter. Example:
//
//     constexpr FeatureParam<int> kAssistantParallelism = {
//         &kAssistantFeature, "parallelism", 4};
//
// If the feature is not enabled, the parameter is not set, or set to an invalid
// int value, then Get() will return the default value.
template <>
struct FeatureParam<int> {};

// Declares a size_t-valued parameter. Example:
//
//     constexpr FeatureParam<size_t> kAssistantParallelism = {
//         &kAssistantFeature, "parallelism", 4u};
//
// If the feature is not enabled, the parameter is not set, or set to an invalid
// size_t value, then Get() will return the default value. Overflow and
// underflow will be checked via base::checked_cast<size_t>().
template <>
struct FeatureParam<size_t> {};

// Declares a bool-valued parameter. Example:
//
//     constexpr FeatureParam<int> kAssistantIsHelpful = {
//         &kAssistantFeature, "is_helpful", true};
//
// If the feature is not enabled, the parameter is not set, or set to value
// other than "true" or "false", then Get() will return the default value.
template <>
struct FeatureParam<bool> {};

// Declares an TimeDelta-valued parameter. Example:
//
//     constexpr base::FeatureParam<base::TimeDelta> kPerAgentDelay{
//         &kPerAgentSchedulingExperiments, "delay", base::TimeDelta()};
//
// If the feature is not enabled, the parameter is not set, or set to an
// invalid value (as defined by base::TimeDeltaFromString()), then Get() will
// return the default value.
template <>
struct FeatureParam<base::TimeDelta> {};

BASE_EXPORT void LogInvalidEnumValue(const Feature& feature,
                                     const std::string& param_name,
                                     const std::string& value_as_string,
                                     int default_value_as_int);

// Feature param declaration for an enum, with associated options. Example:
//
//     constexpr FeatureParam<ShapeEnum>::Option kShapeParamOptions[] = {
//         {SHAPE_CIRCLE, "circle"},
//         {SHAPE_CYLINDER, "cylinder"},
//         {SHAPE_PAPERCLIP, "paperclip"}};
//     constexpr FeatureParam<ShapeEnum> kAssistantShapeParam = {
//         &kAssistantFeature, "shape", SHAPE_CIRCLE, &kShapeParamOptions};
//
// With this declaration, the parameter may be set to "circle", "cylinder", or
// "paperclip", and that will be translated to one of the three enum values. By
// default, or if the param is set to an unknown value, the parameter will be
// assumed to be SHAPE_CIRCLE.
FeatureParam<Enum, true>;

}  // namespace base

#endif  // BASE_METRICS_FIELD_TRIAL_PARAMS_H_