1//===-- allocator_config_wrapper.h ------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef SCUDO_ALLOCATOR_CONFIG_WRAPPER_H_
10#define SCUDO_ALLOCATOR_CONFIG_WRAPPER_H_
11
12#include "condition_variable.h"
13#include "internal_defs.h"
14#include "secondary.h"
15
16namespace {
17
18template <typename T> struct removeConst {
19 using type = T;
20};
21template <typename T> struct removeConst<const T> {
22 using type = T;
23};
24
25// This is only used for SFINAE when detecting if a type is defined.
26template <typename T> struct voidAdaptor {
27 using type = void;
28};
29
30// This is used for detecting the case that defines the flag with wrong type and
31// it'll be viewed as undefined optional flag.
32template <typename L, typename R> struct assertSameType {
33 template <typename, typename> struct isSame {
34 static constexpr bool value = false;
35 };
36 template <typename T> struct isSame<T, T> {
37 static constexpr bool value = true;
38 };
39 static_assert(isSame<L, R>::value, "Flag type mismatches");
40 using type = R;
41};
42
43} // namespace
44
45namespace scudo {
46
47#define OPTIONAL_TEMPLATE(TYPE, NAME, DEFAULT, MEMBER) \
48 template <typename Config, typename = TYPE> struct NAME##State { \
49 static constexpr removeConst<TYPE>::type getValue() { return DEFAULT; } \
50 }; \
51 template <typename Config> \
52 struct NAME##State< \
53 Config, typename assertSameType<decltype(Config::MEMBER), TYPE>::type> { \
54 static constexpr removeConst<TYPE>::type getValue() { \
55 return Config::MEMBER; \
56 } \
57 };
58
59#define OPTIONAL_TYPE_TEMPLATE(NAME, DEFAULT, MEMBER) \
60 template <typename Config, typename Void = void> struct NAME##Type { \
61 static constexpr bool enabled() { return false; } \
62 using NAME = DEFAULT; \
63 }; \
64 template <typename Config> \
65 struct NAME##Type<Config, \
66 typename voidAdaptor<typename Config::MEMBER>::type> { \
67 static constexpr bool enabled() { return true; } \
68 using NAME = typename Config::MEMBER; \
69 };
70
71template <typename AllocatorConfig> struct BaseConfig {
72#define BASE_REQUIRED_TEMPLATE_TYPE(NAME) \
73 template <typename T> using NAME = typename AllocatorConfig::template NAME<T>;
74
75#define BASE_OPTIONAL(TYPE, NAME, DEFAULT) \
76 OPTIONAL_TEMPLATE(TYPE, NAME, DEFAULT, NAME) \
77 static constexpr removeConst<TYPE>::type get##NAME() { \
78 return NAME##State<AllocatorConfig>::getValue(); \
79 }
80
81#include "allocator_config.def"
82}; // BaseConfig
83
84template <typename AllocatorConfig> struct PrimaryConfig {
85 // TODO: Pass this flag through template argument to remove this hard-coded
86 // function.
87 static constexpr bool getMaySupportMemoryTagging() {
88 return BaseConfig<AllocatorConfig>::getMaySupportMemoryTagging();
89 }
90
91#define PRIMARY_REQUIRED_TYPE(NAME) \
92 using NAME = typename AllocatorConfig::Primary::NAME;
93
94#define PRIMARY_REQUIRED(TYPE, NAME) \
95 static constexpr removeConst<TYPE>::type get##NAME() { \
96 return AllocatorConfig::Primary::NAME; \
97 }
98
99#define PRIMARY_OPTIONAL(TYPE, NAME, DEFAULT) \
100 OPTIONAL_TEMPLATE(TYPE, NAME, DEFAULT, NAME) \
101 static constexpr removeConst<TYPE>::type get##NAME() { \
102 return NAME##State<typename AllocatorConfig::Primary>::getValue(); \
103 }
104
105#define PRIMARY_OPTIONAL_TYPE(NAME, DEFAULT) \
106 OPTIONAL_TYPE_TEMPLATE(NAME, DEFAULT, NAME) \
107 static constexpr bool has##NAME() { \
108 return NAME##Type<typename AllocatorConfig::Primary>::enabled(); \
109 } \
110 using NAME = typename NAME##Type<typename AllocatorConfig::Primary>::NAME;
111
112#include "allocator_config.def"
113
114}; // PrimaryConfig
115
116template <typename AllocatorConfig> struct SecondaryConfig {
117 // TODO: Pass this flag through template argument to remove this hard-coded
118 // function.
119 static constexpr bool getMaySupportMemoryTagging() {
120 return BaseConfig<AllocatorConfig>::getMaySupportMemoryTagging();
121 }
122
123#define SECONDARY_REQUIRED_TEMPLATE_TYPE(NAME) \
124 template <typename T> \
125 using NAME = typename AllocatorConfig::Secondary::template NAME<T>;
126#include "allocator_config.def"
127
128 struct CacheConfig {
129 // TODO: Pass this flag through template argument to remove this hard-coded
130 // function.
131 static constexpr bool getMaySupportMemoryTagging() {
132 return BaseConfig<AllocatorConfig>::getMaySupportMemoryTagging();
133 }
134
135#define SECONDARY_CACHE_OPTIONAL(TYPE, NAME, DEFAULT) \
136 OPTIONAL_TEMPLATE(TYPE, NAME, DEFAULT, Cache::NAME) \
137 static constexpr removeConst<TYPE>::type get##NAME() { \
138 return NAME##State<typename AllocatorConfig::Secondary>::getValue(); \
139 }
140#include "allocator_config.def"
141 }; // CacheConfig
142}; // SecondaryConfig
143
144#undef OPTIONAL_TEMPLATE
145#undef OPTIONAL_TEMPLATE_TYPE
146
147} // namespace scudo
148
149#endif // SCUDO_ALLOCATOR_CONFIG_WRAPPER_H_
150