Warning: This file is not a C or C++ file. It does not have highlighting.
1 | //===-- include/flang/Common/visit.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 | // common::visit() is a drop-in replacement for std::visit() that reduces both |
10 | // compiler build time and compiler execution time modestly, and reduces |
11 | // compiler build memory requirements significantly (overall & maximum). |
12 | // It does not require redefinition of std::variant<>. |
13 | // |
14 | // The C++ standard mandates that std::visit be O(1), but most variants are |
15 | // small and O(logN) is faster in practice to compile and execute, avoiding |
16 | // the need to build a dispatch table. |
17 | // |
18 | // Define FLANG_USE_STD_VISIT to avoid this code and make common::visit() an |
19 | // alias for ::std::visit(). |
20 | |
21 | #ifndef FORTRAN_COMMON_VISIT_H_ |
22 | #define FORTRAN_COMMON_VISIT_H_ |
23 | |
24 | #include "variant.h" |
25 | #include "flang/Common/api-attrs.h" |
26 | #include <type_traits> |
27 | |
28 | namespace Fortran::common { |
29 | namespace log2visit { |
30 | |
31 | template <std::size_t LOW, std::size_t HIGH, typename RESULT, typename VISITOR, |
32 | typename... VARIANT> |
33 | inline RT_API_ATTRS RESULT Log2VisitHelper( |
34 | VISITOR &&visitor, std::size_t which, VARIANT &&...u) { |
35 | if constexpr (LOW + 7 >= HIGH) { |
36 | switch (which - LOW) { |
37 | #define VISIT_CASE_N(N) \ |
38 | case N: \ |
39 | if constexpr (LOW + N <= HIGH) { \ |
40 | return visitor(std::get<(LOW + N)>(std::forward<VARIANT>(u))...); \ |
41 | } |
42 | VISIT_CASE_N(1) |
43 | VISIT_CASE_N(2) |
44 | VISIT_CASE_N(3) |
45 | VISIT_CASE_N(4) |
46 | VISIT_CASE_N(5) |
47 | VISIT_CASE_N(6) |
48 | VISIT_CASE_N(7) |
49 | #undef VISIT_CASE_N |
50 | } |
51 | return visitor(std::get<LOW>(std::forward<VARIANT>(u))...); |
52 | } else { |
53 | static constexpr std::size_t mid{(HIGH + LOW) / 2}; |
54 | if (which <= mid) { |
55 | return Log2VisitHelper<LOW, mid, RESULT>( |
56 | std::forward<VISITOR>(visitor), which, std::forward<VARIANT>(u)...); |
57 | } else { |
58 | return Log2VisitHelper<(mid + 1), HIGH, RESULT>( |
59 | std::forward<VISITOR>(visitor), which, std::forward<VARIANT>(u)...); |
60 | } |
61 | } |
62 | } |
63 | |
64 | template <typename VISITOR, typename... VARIANT> |
65 | inline RT_API_ATTRS auto visit(VISITOR &&visitor, VARIANT &&...u) |
66 | -> decltype(visitor(std::get<0>(std::forward<VARIANT>(u))...)) { |
67 | using Result = decltype(visitor(std::get<0>(std::forward<VARIANT>(u))...)); |
68 | if constexpr (sizeof...(u) == 1) { |
69 | static constexpr std::size_t high{ |
70 | (std::variant_size_v<std::decay_t<decltype(u)>> * ...) - 1}; |
71 | return Log2VisitHelper<0, high, Result>(std::forward<VISITOR>(visitor), |
72 | u.index()..., std::forward<VARIANT>(u)...); |
73 | } else { |
74 | // TODO: figure out how to do multiple variant arguments |
75 | return ::std::visit( |
76 | std::forward<VISITOR>(visitor), std::forward<VARIANT>(u)...); |
77 | } |
78 | } |
79 | |
80 | } // namespace log2visit |
81 | |
82 | // Some versions of clang have bugs that cause compilation to hang |
83 | // on these templates. MSVC and older GCC versions may work but are |
84 | // not well tested. So enable only for GCC 9 and better. |
85 | #if __GNUC__ < 9 |
86 | #define FLANG_USE_STD_VISIT |
87 | #endif |
88 | |
89 | #ifdef FLANG_USE_STD_VISIT |
90 | using ::std::visit; |
91 | #else |
92 | using Fortran::common::log2visit::visit; |
93 | #endif |
94 | |
95 | } // namespace Fortran::common |
96 | #endif // FORTRAN_COMMON_VISIT_H_ |
97 |
Warning: This file is not a C or C++ file. It does not have highlighting.