1 | /* |
2 | pybind11/detail/descr.h: Helper type for concatenating type signatures at compile time |
3 | |
4 | Copyright (c) 2016 Wenzel Jakob <[email protected]> |
5 | |
6 | All rights reserved. Use of this source code is governed by a |
7 | BSD-style license that can be found in the LICENSE file. |
8 | */ |
9 | |
10 | #pragma once |
11 | |
12 | #include "common.h" |
13 | |
14 | PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) |
15 | PYBIND11_NAMESPACE_BEGIN(detail) |
16 | |
17 | #if !defined(_MSC_VER) |
18 | # define PYBIND11_DESCR_CONSTEXPR static constexpr |
19 | #else |
20 | # define PYBIND11_DESCR_CONSTEXPR const |
21 | #endif |
22 | |
23 | /* Concatenate type signatures at compile time */ |
24 | template <size_t N, typename... Ts> |
25 | struct descr { |
26 | char text[N + 1]{'\0'}; |
27 | |
28 | constexpr descr() = default; |
29 | // NOLINTNEXTLINE(google-explicit-constructor) |
30 | constexpr descr(char const (&s)[N + 1]) : descr(s, make_index_sequence<N>()) {} |
31 | |
32 | template <size_t... Is> |
33 | constexpr descr(char const (&s)[N + 1], index_sequence<Is...>) : text{s[Is]..., '\0'} {} |
34 | |
35 | template <typename... Chars> |
36 | // NOLINTNEXTLINE(google-explicit-constructor) |
37 | constexpr descr(char c, Chars... cs) : text{c, static_cast<char>(cs)..., '\0'} {} |
38 | |
39 | static constexpr std::array<const std::type_info *, sizeof...(Ts) + 1> types() { |
40 | return {{&typeid(Ts)..., nullptr}}; |
41 | } |
42 | }; |
43 | |
44 | template <size_t N1, size_t N2, typename... Ts1, typename... Ts2, size_t... Is1, size_t... Is2> |
45 | constexpr descr<N1 + N2, Ts1..., Ts2...> plus_impl(const descr<N1, Ts1...> &a, |
46 | const descr<N2, Ts2...> &b, |
47 | index_sequence<Is1...>, |
48 | index_sequence<Is2...>) { |
49 | PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(b); |
50 | return {a.text[Is1]..., b.text[Is2]...}; |
51 | } |
52 | |
53 | template <size_t N1, size_t N2, typename... Ts1, typename... Ts2> |
54 | constexpr descr<N1 + N2, Ts1..., Ts2...> operator+(const descr<N1, Ts1...> &a, |
55 | const descr<N2, Ts2...> &b) { |
56 | return plus_impl(a, b, make_index_sequence<N1>(), make_index_sequence<N2>()); |
57 | } |
58 | |
59 | template <size_t N> |
60 | constexpr descr<N - 1> const_name(char const (&text)[N]) { |
61 | return descr<N - 1>(text); |
62 | } |
63 | constexpr descr<0> const_name(char const (&)[1]) { return {}; } |
64 | |
65 | template <size_t Rem, size_t... Digits> |
66 | struct int_to_str : int_to_str<Rem / 10, Rem % 10, Digits...> {}; |
67 | template <size_t... Digits> |
68 | struct int_to_str<0, Digits...> { |
69 | // WARNING: This only works with C++17 or higher. |
70 | static constexpr auto digits = descr<sizeof...(Digits)>(('0' + Digits)...); |
71 | }; |
72 | |
73 | // Ternary description (like std::conditional) |
74 | template <bool B, size_t N1, size_t N2> |
75 | constexpr enable_if_t<B, descr<N1 - 1>> const_name(char const (&text1)[N1], char const (&)[N2]) { |
76 | return const_name(text1); |
77 | } |
78 | template <bool B, size_t N1, size_t N2> |
79 | constexpr enable_if_t<!B, descr<N2 - 1>> const_name(char const (&)[N1], char const (&text2)[N2]) { |
80 | return const_name(text2); |
81 | } |
82 | |
83 | template <bool B, typename T1, typename T2> |
84 | constexpr enable_if_t<B, T1> const_name(const T1 &d, const T2 &) { |
85 | return d; |
86 | } |
87 | template <bool B, typename T1, typename T2> |
88 | constexpr enable_if_t<!B, T2> const_name(const T1 &, const T2 &d) { |
89 | return d; |
90 | } |
91 | |
92 | template <size_t Size> |
93 | auto constexpr const_name() -> remove_cv_t<decltype(int_to_str<Size / 10, Size % 10>::digits)> { |
94 | return int_to_str<Size / 10, Size % 10>::digits; |
95 | } |
96 | |
97 | template <typename Type> |
98 | constexpr descr<1, Type> const_name() { |
99 | return {'%'}; |
100 | } |
101 | |
102 | // If "_" is defined as a macro, py::detail::_ cannot be provided. |
103 | // It is therefore best to use py::detail::const_name universally. |
104 | // This block is for backward compatibility only. |
105 | // (The const_name code is repeated to avoid introducing a "_" #define ourselves.) |
106 | #ifndef _ |
107 | # define PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY |
108 | template <size_t N> |
109 | constexpr descr<N - 1> _(char const (&text)[N]) { |
110 | return const_name<N>(text); |
111 | } |
112 | template <bool B, size_t N1, size_t N2> |
113 | constexpr enable_if_t<B, descr<N1 - 1>> _(char const (&text1)[N1], char const (&text2)[N2]) { |
114 | return const_name<B, N1, N2>(text1, text2); |
115 | } |
116 | template <bool B, size_t N1, size_t N2> |
117 | constexpr enable_if_t<!B, descr<N2 - 1>> _(char const (&text1)[N1], char const (&text2)[N2]) { |
118 | return const_name<B, N1, N2>(text1, text2); |
119 | } |
120 | template <bool B, typename T1, typename T2> |
121 | constexpr enable_if_t<B, T1> _(const T1 &d1, const T2 &d2) { |
122 | return const_name<B, T1, T2>(d1, d2); |
123 | } |
124 | template <bool B, typename T1, typename T2> |
125 | constexpr enable_if_t<!B, T2> _(const T1 &d1, const T2 &d2) { |
126 | return const_name<B, T1, T2>(d1, d2); |
127 | } |
128 | |
129 | template <size_t Size> |
130 | auto constexpr _() -> remove_cv_t<decltype(int_to_str<Size / 10, Size % 10>::digits)> { |
131 | return const_name<Size>(); |
132 | } |
133 | template <typename Type> |
134 | constexpr descr<1, Type> _() { |
135 | return const_name<Type>(); |
136 | } |
137 | #endif // #ifndef _ |
138 | |
139 | constexpr descr<0> concat() { return {}; } |
140 | |
141 | template <size_t N, typename... Ts> |
142 | constexpr descr<N, Ts...> concat(const descr<N, Ts...> &descr) { |
143 | return descr; |
144 | } |
145 | |
146 | template <size_t N, typename... Ts, typename... Args> |
147 | constexpr auto concat(const descr<N, Ts...> &d, const Args &...args) |
148 | -> decltype(std::declval<descr<N + 2, Ts...>>() + concat(args...)) { |
149 | return d + const_name(", " ) + concat(args...); |
150 | } |
151 | |
152 | template <size_t N, typename... Ts> |
153 | constexpr descr<N + 2, Ts...> type_descr(const descr<N, Ts...> &descr) { |
154 | return const_name("{" ) + descr + const_name("}" ); |
155 | } |
156 | |
157 | PYBIND11_NAMESPACE_END(detail) |
158 | PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) |
159 | |