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