LLVM 23.0.0git
STLForwardCompat.h
Go to the documentation of this file.
1//===- STLForwardCompat.h - Library features from future STLs ------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/// \file
10/// This file contains library features backported from future STL versions.
11///
12/// These should be replaced with their STL counterparts as the C++ version LLVM
13/// is compiled with is updated.
14///
15//===----------------------------------------------------------------------===//
16
17#ifndef LLVM_ADT_STLFORWARDCOMPAT_H
18#define LLVM_ADT_STLFORWARDCOMPAT_H
19
21#include <optional>
22#include <tuple>
23#include <type_traits>
24#include <utility>
25
26namespace llvm {
27
28//===----------------------------------------------------------------------===//
29// Features from C++20
30//===----------------------------------------------------------------------===//
31
32namespace numbers {
33// clang-format off
34template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
35inline constexpr T e_v = T(0x1.5bf0a8b145769P+1); // (2.7182818284590452354) https://oeis.org/A001113
36template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
37inline constexpr T egamma_v = T(0x1.2788cfc6fb619P-1); // (.57721566490153286061) https://oeis.org/A001620
38template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
39inline constexpr T ln2_v = T(0x1.62e42fefa39efP-1); // (.69314718055994530942) https://oeis.org/A002162
40template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
41inline constexpr T ln10_v = T(0x1.26bb1bbb55516P+1); // (2.3025850929940456840) https://oeis.org/A002392
42template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
43inline constexpr T log2e_v = T(0x1.71547652b82feP+0); // (1.4426950408889634074)
44template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
45inline constexpr T log10e_v = T(0x1.bcb7b1526e50eP-2); // (.43429448190325182765)
46template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
47inline constexpr T pi_v = T(0x1.921fb54442d18P+1); // (3.1415926535897932385) https://oeis.org/A000796
48template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
49inline constexpr T inv_pi_v = T(0x1.45f306dc9c883P-2); // (.31830988618379067154) https://oeis.org/A049541
50template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
51inline constexpr T inv_sqrtpi_v = T(0x1.20dd750429b6dP-1); // (.56418958354775628695) https://oeis.org/A087197
52template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
53inline constexpr T sqrt2_v = T(0x1.6a09e667f3bcdP+0); // (1.4142135623730950488) https://oeis.org/A00219
54template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
55inline constexpr T inv_sqrt2_v = T(0x1.6a09e667f3bcdP-1); // (.70710678118654752440)
56template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
57inline constexpr T sqrt3_v = T(0x1.bb67ae8584caaP+0); // (1.7320508075688772935) https://oeis.org/A002194
58template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
59inline constexpr T inv_sqrt3_v = T(0x1.279a74590331cP-1); // (.57735026918962576451)
60template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
61inline constexpr T phi_v = T(0x1.9e3779b97f4a8P+0); // (1.6180339887498948482) https://oeis.org/A001622
62
63inline constexpr double e = e_v<double>;
64inline constexpr double egamma = egamma_v<double>;
65inline constexpr double ln2 = ln2_v<double>;
66inline constexpr double ln10 = ln10_v<double>;
67inline constexpr double log2e = log2e_v<double>;
68inline constexpr double log10e = log10e_v<double>;
69inline constexpr double pi = pi_v<double>;
70inline constexpr double inv_pi = inv_pi_v<double>;
71inline constexpr double inv_sqrtpi = inv_sqrtpi_v<double>;
72inline constexpr double sqrt2 = sqrt2_v<double>;
73inline constexpr double inv_sqrt2 = inv_sqrt2_v<double>;
74inline constexpr double sqrt3 = sqrt3_v<double>;
75inline constexpr double inv_sqrt3 = inv_sqrt3_v<double>;
76inline constexpr double phi = phi_v<double>;
77// clang-format on
78} // namespace numbers
79
80template <typename T>
81struct remove_cvref // NOLINT(readability-identifier-naming)
82{
83 using type = std::remove_cv_t<std::remove_reference_t<T>>;
84};
85
86template <typename T>
87using remove_cvref_t // NOLINT(readability-identifier-naming)
89
90// TODO: Remove this in favor of std::type_identity<T> once we switch to C++20.
91template <typename T>
92struct type_identity // NOLINT(readability-identifier-naming)
93{
94 using type = T;
95};
96
97// TODO: Remove this in favor of std::type_identity_t<T> once we switch to
98// C++20.
99template <typename T>
100using type_identity_t // NOLINT(readability-identifier-naming)
102
103namespace detail {
104template <class, template <class...> class Op, class... Args> struct detector {
105 using value_t = std::false_type;
106};
107template <template <class...> class Op, class... Args>
108struct detector<std::void_t<Op<Args...>>, Op, Args...> {
109 using value_t = std::true_type;
110};
111} // end namespace detail
112
113/// Detects if a given trait holds for some set of arguments 'Args'.
114/// For example, the given trait could be used to detect if a given type
115/// has a copy assignment operator:
116/// template<class T>
117/// using has_copy_assign_t = decltype(std::declval<T&>()
118/// = std::declval<const T&>());
119/// bool fooHasCopyAssign = is_detected<has_copy_assign_t, FooClass>::value;
120///
121/// NOTE: The C++20 standard has adopted concepts and requires clauses as a
122/// superior alternative to std::is_detected.
123///
124/// This utility is placed in STLForwardCompat.h as a reminder
125/// to migrate usages of llvm::is_detected to concepts and 'requires'
126/// clauses when the codebase adopts C++20.
127template <template <class...> class Op, class... Args>
128using is_detected = typename detail::detector<void, Op, Args...>::value_t;
129
130struct identity // NOLINT(readability-identifier-naming)
131{
132 using is_transparent = void;
133
134 template <typename T> constexpr T &&operator()(T &&self) const noexcept {
135 return std::forward<T>(self);
136 }
137};
138
139/// Returns a raw pointer that represents the same address as the argument.
140///
141/// This implementation can be removed once we move to C++20 where it's defined
142/// as std::to_address().
143///
144/// The std::pointer_traits<>::to_address(p) variations of these overloads has
145/// not been implemented.
146template <class Ptr> auto to_address(const Ptr &P) { return P.operator->(); }
147template <class T> constexpr T *to_address(T *P) {
148 static_assert(!std::is_function_v<T>);
149 return P;
150}
151
152/// C++20 constexpr invoke. This uses `std::apply` (constexpr in C++17) to
153/// achieve constexpr invocation.
154template <typename FnT, typename... ArgsT>
155constexpr std::invoke_result_t<FnT, ArgsT...>
156invoke(FnT &&Fn, ArgsT &&...Args) { // NOLINT(readability-identifier-naming)
157 return std::apply(std::forward<FnT>(Fn),
158 std::forward_as_tuple(std::forward<ArgsT>(Args)...));
159}
160
161//===----------------------------------------------------------------------===//
162// Features from C++23
163//===----------------------------------------------------------------------===//
164
165// TODO: Remove this in favor of std::optional<T>::transform once we switch to
166// C++23.
167template <typename Optional, typename Function,
168 typename Value = typename llvm::remove_cvref_t<Optional>::value_type>
169std::optional<std::invoke_result_t<Function, Value>>
170transformOptional(Optional &&O, Function &&F) {
171 if (O) {
172 return F(*std::forward<Optional>(O));
173 }
174 return std::nullopt;
175}
176
177/// Returns underlying integer value of an enum. Backport of C++23
178/// std::to_underlying.
179template <typename Enum>
180[[nodiscard]] constexpr std::underlying_type_t<Enum> to_underlying(Enum E) {
181 return static_cast<std::underlying_type_t<Enum>>(E);
182}
183
184// A tag for constructors accepting ranges.
186 explicit from_range_t() = default;
187};
188inline constexpr from_range_t from_range{};
189
190//===----------------------------------------------------------------------===//
191// Bind functions from C++20 / C++23 / C++26
192//===----------------------------------------------------------------------===//
193
194namespace detail {
195// Tag for constructing with a runtime callable.
196struct RuntimeFnTag {};
197// Tag for constructing with a compile-time constant callable.
199
200/// Stores a callable as a data member.
201template <typename FnT> struct FnHolder {
203
204 template <typename FnArgT>
205 constexpr explicit FnHolder(FnArgT &&F) : Fn(std::forward<FnArgT>(F)) {}
206
207 constexpr FnT &get() { return Fn; }
208 constexpr const FnT &get() const { return Fn; }
209};
210
211/// Holds a compile-time constant callable (empty storage).
212template <auto ConstFn> struct FnConstant {
213 constexpr decltype(auto) get() const { return ConstFn; }
214};
215
216// Storage class for bind_front/bind_back that properly handles const/non-const
217// qualification of the wrapper when invoking the stored callable.
218// If BindFront is true, bound args are prepended; otherwise appended.
219// FnStorageT is either FnHolder<FnT> (runtime) or FnConstant<ConstFn>.
220template <bool BindFront, typename BoundArgsTupleT, typename FnStorageT,
221 typename IndicesT>
223
224template <bool BindFront, typename BoundArgsTupleT, typename FnStorageT,
225 size_t... Indices>
226class BindStorage<BindFront, BoundArgsTupleT, FnStorageT,
227 std::index_sequence<Indices...>> {
228 BoundArgsTupleT BoundArgs;
229 // This may be empty for const functions, hence the `no_unique_address`.
230 LLVM_NO_UNIQUE_ADDRESS FnStorageT FnStorage;
231
232public:
233 // Constructor for FnHolder (runtime callable).
234 template <typename FnArgT, typename... BoundArgsArgT>
235 constexpr BindStorage(RuntimeFnTag, FnArgT &&F, BoundArgsArgT &&...Args)
236 : BoundArgs(std::forward<BoundArgsArgT>(Args)...),
237 FnStorage(std::forward<FnArgT>(F)) {}
238
239 // Constructor for FnConstant (compile-time callable).
240 template <typename... BoundArgsArgT>
241 constexpr BindStorage(ConstantFnTag, BoundArgsArgT &&...Args)
242 : BoundArgs(std::forward<BoundArgsArgT>(Args)...), FnStorage() {}
243
244 template <typename... CallArgsT>
245 constexpr auto operator()(CallArgsT &&...CallArgs) {
246 if constexpr (BindFront)
247 return llvm::invoke(FnStorage.get(), std::get<Indices>(BoundArgs)...,
248 std::forward<CallArgsT>(CallArgs)...);
249 else
250 return llvm::invoke(FnStorage.get(), std::forward<CallArgsT>(CallArgs)...,
251 std::get<Indices>(BoundArgs)...);
252 }
253
254 template <typename... CallArgsT>
255 constexpr auto operator()(CallArgsT &&...CallArgs) const {
256 if constexpr (BindFront)
257 return llvm::invoke(FnStorage.get(), std::get<Indices>(BoundArgs)...,
258 std::forward<CallArgsT>(CallArgs)...);
259 else
260 return llvm::invoke(FnStorage.get(), std::forward<CallArgsT>(CallArgs)...,
261 std::get<Indices>(BoundArgs)...);
262 }
263};
264} // end namespace detail
265
266/// C++20 bind_front. Prepends bound arguments to the callable. All bind
267/// arguments and the callable are forwarded and *stored* by value. If you would
268/// like to pass by reference, use `std::ref` or `std::cref`.
269template <typename FnT, typename... BindArgsT>
270constexpr auto bind_front(FnT &&Fn, // NOLINT(readability-identifier-naming)
271 BindArgsT &&...BindArgs) {
272 return detail::BindStorage</*BindFront=*/true,
273 std::tuple<std::decay_t<BindArgsT>...>,
275 std::index_sequence_for<BindArgsT...>>(
276 detail::RuntimeFnTag{}, std::forward<FnT>(Fn),
277 std::forward<BindArgsT>(BindArgs)...);
278}
279
280/// C++26 bind_front with compile-time callable. Prepends bound arguments.
281/// Bound arguments are forwarded and *stored* by value.
282template <auto ConstFn, typename... BindArgsT>
283constexpr auto
284bind_front(BindArgsT &&...BindArgs) { // NOLINT(readability-identifier-naming)
285 if constexpr (std::is_pointer_v<decltype(ConstFn)> ||
286 std::is_member_pointer_v<decltype(ConstFn)>)
287 static_assert(ConstFn != nullptr);
288
289 return detail::BindStorage<
290 /*BindFront=*/true, std::tuple<std::decay_t<BindArgsT>...>,
291 detail::FnConstant<ConstFn>, std::index_sequence_for<BindArgsT...>>(
292 detail::ConstantFnTag{}, std::forward<BindArgsT>(BindArgs)...);
293}
294
295/// C++23 bind_back. Appends bound arguments to the callable. All bind
296/// arguments and the callable are forwarded and *stored* by value. If you would
297/// like to pass by reference, use `std::ref` or `std::cref`.
298template <typename FnT, typename... BindArgsT>
299constexpr auto bind_back(FnT &&Fn, // NOLINT(readability-identifier-naming)
300 BindArgsT &&...BindArgs) {
301 return detail::BindStorage</*BindFront=*/false,
302 std::tuple<std::decay_t<BindArgsT>...>,
304 std::index_sequence_for<BindArgsT...>>(
305 detail::RuntimeFnTag{}, std::forward<FnT>(Fn),
306 std::forward<BindArgsT>(BindArgs)...);
307}
308
309/// C++26 bind_back with compile-time callable. Appends bound arguments.
310/// Bound arguments are forwarded and *stored* by value.
311template <auto ConstFn, typename... BindArgsT>
312constexpr auto
313bind_back(BindArgsT &&...BindArgs) { // NOLINT(readability-identifier-naming)
314 if constexpr (std::is_pointer_v<decltype(ConstFn)> ||
315 std::is_member_pointer_v<decltype(ConstFn)>)
316 static_assert(ConstFn != nullptr);
317
318 return detail::BindStorage<
319 /*BindFront=*/false, std::tuple<std::decay_t<BindArgsT>...>,
320 detail::FnConstant<ConstFn>, std::index_sequence_for<BindArgsT...>>(
321 detail::ConstantFnTag{}, std::forward<BindArgsT>(BindArgs)...);
322}
323} // namespace llvm
324
325#endif // LLVM_ADT_STLFORWARDCOMPAT_H
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define LLVM_NO_UNIQUE_ADDRESS
Definition Compiler.h:449
#define F(x, y, z)
Definition MD5.cpp:54
#define T
#define P(N)
Mathematical constants.
constexpr T log10e_v
constexpr double sqrt2
constexpr double inv_sqrt2
constexpr T e_v
constexpr double inv_pi
constexpr T log2e_v
constexpr T egamma_v
constexpr T sqrt3_v
constexpr double ln2
constexpr double inv_sqrt3
constexpr double egamma
constexpr T sqrt2_v
constexpr T inv_sqrt3_v
constexpr T inv_sqrtpi_v
constexpr double ln10
constexpr double inv_sqrtpi
constexpr T ln10_v
constexpr double e
constexpr double phi
constexpr T pi_v
constexpr double sqrt3
constexpr T phi_v
constexpr double log10e
constexpr double log2e
constexpr T ln2_v
constexpr T inv_pi_v
constexpr T inv_sqrt2_v
constexpr double pi
This is an optimization pass for GlobalISel generic memory operations.
Definition Types.h:26
constexpr from_range_t from_range
constexpr std::invoke_result_t< FnT, ArgsT... > invoke(FnT &&Fn, ArgsT &&...Args)
C++20 constexpr invoke.
constexpr auto bind_back(FnT &&Fn, BindArgsT &&...BindArgs)
C++23 bind_back.
constexpr auto bind_front(FnT &&Fn, BindArgsT &&...BindArgs)
C++20 bind_front.
constexpr std::underlying_type_t< Enum > to_underlying(Enum E)
Returns underlying integer value of an enum.
DWARFExpression::Operation Op
auto to_address(const Ptr &P)
Returns a raw pointer that represents the same address as the argument.
typename detail::detector< void, Op, Args... >::value_t is_detected
Detects if a given trait holds for some set of arguments 'Args'.
std::optional< std::invoke_result_t< Function, Value > > transformOptional(Optional &&O, Function &&F)
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:870
Holds a compile-time constant callable (empty storage).
constexpr decltype(auto) get() const
Stores a callable as a data member.
constexpr const FnT & get() const
constexpr FnHolder(FnArgT &&F)
from_range_t()=default
constexpr T && operator()(T &&self) const noexcept
std::remove_cv_t< std::remove_reference_t< T > > type