blob: d83ee1d4fdebd2176b89363a654c321fdcb30c8d [file]
// Copyright 2026 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_FEATURE_INTERNAL_H_
#define BASE_FEATURE_INTERNAL_H_
#include <array>
#include <cstddef>
#include "base/containers/span.h"
namespace base::internal {
// Secret handshake to (try to) ensure all places that construct a base::Feature
// go through the helper `BASE_FEATURE()` macro above.
enum class FeatureMacroHandshake { kSecret };
// Storage class for feature name. This is needed so we store the feature name
// "MyFeature" instead of the feature identifier name "kMyFeature" in .rodata.
template <size_t N>
struct StringStorage {
explicit constexpr StringStorage(base::span<const char, N + 1> feature) {
static_assert(N > 2, "Feature name cannot be too short.");
for (size_t i = 0; i < N; ++i) {
storage[i] = feature[i + 1];
}
}
std::array<char, N> storage;
};
// Deduce how much storage is needed for a given string literal. `feature`
// includes space for a NUL terminator; `StringStorage` also needs storage
// for the NUL terminator but drops the first character.
template <size_t N>
StringStorage(const char (&feature)[N]) -> StringStorage<N - 1>;
} // namespace base::internal
// Three-argument version of BASE_FEATURE macro.
#define BASE_FEATURE_INTERNAL_3_ARGS(feature, name, default_state) \
constinit const base::Feature feature( \
name, default_state, base::internal::FeatureMacroHandshake::kSecret)
// Two-argument version of BASE_FEATURE macro.
#define BASE_FEATURE_INTERNAL_2_ARGS(feature, default_state) \
constinit const base::Feature feature( \
[]() { \
static_assert(#feature[0] == 'k'); \
static constexpr base::internal::StringStorage storage(#feature); \
return storage.storage.data(); \
}(), \
default_state, base::internal::FeatureMacroHandshake::kSecret)
// Helper macro to deduce the whether to use the 2 or 3 argument version of
// the BASE_FEATURE macro.
#define BASE_FEATURE_INTERNAL_GET_FEATURE_MACRO(_1, _2, _3, NAME, ...) NAME
// Five-argument version of BASE_FEATURE_PARAM macro.
#define BASE_FEATURE_PARAM_INTERNAL_5_ARGS(T, feature_object_name, feature, \
name, default_value) \
namespace field_trial_params_internal { \
T GetFeatureParamWithCacheFor##feature_object_name( \
const base::FeatureParam<T>* feature_param) { \
static const typename base::internal::FeatureParamTraits< \
T>::CacheStorageType storage = \
base::internal::FeatureParamTraits<T>::ToCacheStorageType( \
feature_param->GetWithoutCache()); \
return base::internal::FeatureParamTraits<T>::FromCacheStorageType( \
storage); \
} \
} /* field_trial_params_internal */ \
constinit const base::FeatureParam<T> feature_object_name( \
feature, name, default_value, \
&field_trial_params_internal:: \
GetFeatureParamWithCacheFor##feature_object_name)
// Four-argument version of BASE_FEATURE_PARAM macro.
#define BASE_FEATURE_PARAM_INTERNAL_4_ARGS(T, feature_object_name, feature, \
default_value) \
BASE_FEATURE_PARAM_INTERNAL_5_ARGS( \
T, feature_object_name, feature, \
[]() { \
static_assert(#feature_object_name[0] == 'k'); \
static constexpr base::internal::StringStorage storage( \
#feature_object_name); \
return storage.storage.data(); \
}(), \
default_value)
// Helper macro to deduce the whether to use the 4 or 5 argument version of
// the BASE_FEATURE_PARAM macro.
#define BASE_FEATURE_INTERNAL_GET_FEATURE_PARAM_MACRO(_1, _2, _3, _4, _5, \
NAME, ...) \
NAME
// Six-argument version of BASE_FEATURE_ENUM_PARAM macro.
#define BASE_FEATURE_ENUM_PARAM_INTERNAL_6_ARGS( \
T, feature_object_name, feature, name, default_value, options) \
namespace field_trial_params_internal { \
T GetFeatureParamWithCacheFor##feature_object_name( \
const base::FeatureParam<T>* feature_param) { \
static const T param = feature_param->GetWithoutCache(); \
return param; \
} \
} /* field_trial_params_internal */ \
constinit const base::FeatureParam<T> feature_object_name( \
feature, name, default_value, options, \
&field_trial_params_internal:: \
GetFeatureParamWithCacheFor##feature_object_name)
// Five-argument version of BASE_FEATURE_ENUM_PARAM macro.
#define BASE_FEATURE_ENUM_PARAM_INTERNAL_5_ARGS( \
T, feature_object_name, feature, default_value, options) \
BASE_FEATURE_ENUM_PARAM_INTERNAL_6_ARGS( \
T, feature_object_name, feature, \
[]() { \
static_assert(#feature_object_name[0] == 'k'); \
static constexpr base::internal::StringStorage storage( \
#feature_object_name); \
return storage.storage.data(); \
}(), \
default_value, options)
// Helper macro to deduce the whether to use the 5 or 6 argument version of
// the BASE_FEATURE_ENUM_PARAM macro.
#define BASE_FEATURE_INTERNAL_GET_FEATURE_ENUM_PARAM_MACRO(_1, _2, _3, _4, _5, \
_6, NAME, ...) \
NAME
#endif // BASE_FEATURE_INTERNAL_H_