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
14PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
15PYBIND11_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 */
24template <size_t N, typename... Ts>
25struct 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
44template <size_t N1, size_t N2, typename... Ts1, typename... Ts2, size_t... Is1, size_t... Is2>
45constexpr 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
53template <size_t N1, size_t N2, typename... Ts1, typename... Ts2>
54constexpr 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
59template <size_t N>
60constexpr descr<N - 1> const_name(char const (&text)[N]) {
61 return descr<N - 1>(text);
62}
63constexpr descr<0> const_name(char const (&)[1]) { return {}; }
64
65template <size_t Rem, size_t... Digits>
66struct int_to_str : int_to_str<Rem / 10, Rem % 10, Digits...> {};
67template <size_t... Digits>
68struct 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)
74template <bool B, size_t N1, size_t N2>
75constexpr enable_if_t<B, descr<N1 - 1>> const_name(char const (&text1)[N1], char const (&)[N2]) {
76 return const_name(text1);
77}
78template <bool B, size_t N1, size_t N2>
79constexpr enable_if_t<!B, descr<N2 - 1>> const_name(char const (&)[N1], char const (&text2)[N2]) {
80 return const_name(text2);
81}
82
83template <bool B, typename T1, typename T2>
84constexpr enable_if_t<B, T1> const_name(const T1 &d, const T2 &) {
85 return d;
86}
87template <bool B, typename T1, typename T2>
88constexpr enable_if_t<!B, T2> const_name(const T1 &, const T2 &d) {
89 return d;
90}
91
92template <size_t Size>
93auto 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
97template <typename Type>
98constexpr 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
108template <size_t N>
109constexpr descr<N - 1> _(char const (&text)[N]) {
110 return const_name<N>(text);
111}
112template <bool B, size_t N1, size_t N2>
113constexpr 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}
116template <bool B, size_t N1, size_t N2>
117constexpr 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}
120template <bool B, typename T1, typename T2>
121constexpr enable_if_t<B, T1> _(const T1 &d1, const T2 &d2) {
122 return const_name<B, T1, T2>(d1, d2);
123}
124template <bool B, typename T1, typename T2>
125constexpr enable_if_t<!B, T2> _(const T1 &d1, const T2 &d2) {
126 return const_name<B, T1, T2>(d1, d2);
127}
128
129template <size_t Size>
130auto constexpr _() -> remove_cv_t<decltype(int_to_str<Size / 10, Size % 10>::digits)> {
131 return const_name<Size>();
132}
133template <typename Type>
134constexpr descr<1, Type> _() {
135 return const_name<Type>();
136}
137#endif // #ifndef _
138
139constexpr descr<0> concat() { return {}; }
140
141template <size_t N, typename... Ts>
142constexpr descr<N, Ts...> concat(const descr<N, Ts...> &descr) {
143 return descr;
144}
145
146template <size_t N, typename... Ts, typename... Args>
147constexpr 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
152template <size_t N, typename... Ts>
153constexpr descr<N + 2, Ts...> type_descr(const descr<N, Ts...> &descr) {
154 return const_name("{") + descr + const_name("}");
155}
156
157PYBIND11_NAMESPACE_END(detail)
158PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
159