blob: 5477236ac1f3976eb9c18d12934ba9f83bf23713 [file] [log] [blame]
//===-- allocator_config_wrapper.h ------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef SCUDO_ALLOCATOR_CONFIG_WRAPPER_H_
#define SCUDO_ALLOCATOR_CONFIG_WRAPPER_H_
#include "condition_variable.h"
#include "internal_defs.h"
#include "secondary.h"
namespace {
template <typename T> struct removeConst {
using type = T;
};
template <typename T> struct removeConst<const T> {
using type = T;
};
// This is only used for SFINAE when detecting if a type is defined.
template <typename T> struct voidAdaptor {
using type = void;
};
// This is used for detecting the case that defines the flag with wrong type and
// it'll be viewed as undefined optional flag.
template <typename L, typename R> struct assertSameType {
template <typename, typename> struct isSame {
static constexpr bool value = false;
};
template <typename T> struct isSame<T, T> {
static constexpr bool value = true;
};
static_assert(isSame<L, R>::value, "Flag type mismatches");
using type = R;
};
} // namespace
namespace scudo {
#define OPTIONAL_TEMPLATE(TYPE, NAME, DEFAULT, MEMBER) \
template <typename Config, typename = TYPE> struct NAME##State { \
static constexpr removeConst<TYPE>::type getValue() { return DEFAULT; } \
}; \
template <typename Config> \
struct NAME##State< \
Config, typename assertSameType<decltype(Config::MEMBER), TYPE>::type> { \
static constexpr removeConst<TYPE>::type getValue() { \
return Config::MEMBER; \
} \
};
#define OPTIONAL_TYPE_TEMPLATE(NAME, DEFAULT, MEMBER) \
template <typename Config, typename Void = void> struct NAME##Type { \
static constexpr bool enabled() { return false; } \
using NAME = DEFAULT; \
}; \
template <typename Config> \
struct NAME##Type<Config, \
typename voidAdaptor<typename Config::MEMBER>::type> { \
static constexpr bool enabled() { return true; } \
using NAME = typename Config::MEMBER; \
};
template <typename AllocatorConfig> struct BaseConfig {
#define BASE_REQUIRED_TEMPLATE_TYPE(NAME) \
template <typename T> using NAME = typename AllocatorConfig::template NAME<T>;
#define BASE_OPTIONAL(TYPE, NAME, DEFAULT) \
OPTIONAL_TEMPLATE(TYPE, NAME, DEFAULT, NAME) \
static constexpr removeConst<TYPE>::type get##NAME() { \
return NAME##State<AllocatorConfig>::getValue(); \
}
#include "allocator_config.def"
}; // BaseConfig
template <typename AllocatorConfig> struct PrimaryConfig {
// TODO: Pass this flag through template argument to remove this hard-coded
// function.
static constexpr bool getMaySupportMemoryTagging() {
return BaseConfig<AllocatorConfig>::getMaySupportMemoryTagging();
}
#define PRIMARY_REQUIRED_TYPE(NAME) \
using NAME = typename AllocatorConfig::Primary::NAME;
#define PRIMARY_REQUIRED(TYPE, NAME) \
static constexpr removeConst<TYPE>::type get##NAME() { \
return AllocatorConfig::Primary::NAME; \
}
#define PRIMARY_OPTIONAL(TYPE, NAME, DEFAULT) \
OPTIONAL_TEMPLATE(TYPE, NAME, DEFAULT, NAME) \
static constexpr removeConst<TYPE>::type get##NAME() { \
return NAME##State<typename AllocatorConfig::Primary>::getValue(); \
}
#define PRIMARY_OPTIONAL_TYPE(NAME, DEFAULT) \
OPTIONAL_TYPE_TEMPLATE(NAME, DEFAULT, NAME) \
static constexpr bool has##NAME() { \
return NAME##Type<typename AllocatorConfig::Primary>::enabled(); \
} \
using NAME = typename NAME##Type<typename AllocatorConfig::Primary>::NAME;
#include "allocator_config.def"
}; // PrimaryConfig
template <typename AllocatorConfig> struct SecondaryConfig {
// TODO: Pass this flag through template argument to remove this hard-coded
// function.
static constexpr bool getMaySupportMemoryTagging() {
return BaseConfig<AllocatorConfig>::getMaySupportMemoryTagging();
}
#define SECONDARY_REQUIRED_TEMPLATE_TYPE(NAME) \
template <typename T> \
using NAME = typename AllocatorConfig::Secondary::template NAME<T>;
#include "allocator_config.def"
struct CacheConfig {
// TODO: Pass this flag through template argument to remove this hard-coded
// function.
static constexpr bool getMaySupportMemoryTagging() {
return BaseConfig<AllocatorConfig>::getMaySupportMemoryTagging();
}
#define SECONDARY_CACHE_OPTIONAL(TYPE, NAME, DEFAULT) \
OPTIONAL_TEMPLATE(TYPE, NAME, DEFAULT, Cache::NAME) \
static constexpr removeConst<TYPE>::type get##NAME() { \
return NAME##State<typename AllocatorConfig::Secondary>::getValue(); \
}
#include "allocator_config.def"
}; // CacheConfig
}; // SecondaryConfig
#undef OPTIONAL_TEMPLATE
#undef OPTIONAL_TEMPLATE_TYPE
} // namespace scudo
#endif // SCUDO_ALLOCATOR_CONFIG_WRAPPER_H_