File indexing completed on 2025-02-23 05:15:01

0001 /*
0002     pybind11/detail/descr.h: Helper type for concatenating type signatures at compile time
0003 
0004     Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
0005 
0006     All rights reserved. Use of this source code is governed by a
0007     BSD-style license that can be found in the LICENSE file.
0008 */
0009 
0010 #pragma once
0011 
0012 #include "common.h"
0013 
0014 PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
0015 PYBIND11_NAMESPACE_BEGIN(detail)
0016 
0017 #if !defined(_MSC_VER)
0018 #  define PYBIND11_DESCR_CONSTEXPR static constexpr
0019 #else
0020 #  define PYBIND11_DESCR_CONSTEXPR const
0021 #endif
0022 
0023 /* Concatenate type signatures at compile time */
0024 template <size_t N, typename... Ts>
0025 struct descr {
0026     char text[N + 1]{'\0'};
0027 
0028     constexpr descr() = default;
0029     // NOLINTNEXTLINE(google-explicit-constructor)
0030     constexpr descr(char const (&s)[N+1]) : descr(s, make_index_sequence<N>()) { }
0031 
0032     template <size_t... Is>
0033     constexpr descr(char const (&s)[N+1], index_sequence<Is...>) : text{s[Is]..., '\0'} { }
0034 
0035     template <typename... Chars>
0036     // NOLINTNEXTLINE(google-explicit-constructor)
0037     constexpr descr(char c, Chars... cs) : text{c, static_cast<char>(cs)..., '\0'} { }
0038 
0039     static constexpr std::array<const std::type_info *, sizeof...(Ts) + 1> types() {
0040         return {{&typeid(Ts)..., nullptr}};
0041     }
0042 };
0043 
0044 template <size_t N1, size_t N2, typename... Ts1, typename... Ts2, size_t... Is1, size_t... Is2>
0045 constexpr descr<N1 + N2, Ts1..., Ts2...> plus_impl(const descr<N1, Ts1...> &a, const descr<N2, Ts2...> &b,
0046                                                    index_sequence<Is1...>, index_sequence<Is2...>) {
0047     PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(b);
0048     return {a.text[Is1]..., b.text[Is2]...};
0049 }
0050 
0051 template <size_t N1, size_t N2, typename... Ts1, typename... Ts2>
0052 constexpr descr<N1 + N2, Ts1..., Ts2...> operator+(const descr<N1, Ts1...> &a, const descr<N2, Ts2...> &b) {
0053     return plus_impl(a, b, make_index_sequence<N1>(), make_index_sequence<N2>());
0054 }
0055 
0056 template <size_t N>
0057 constexpr descr<N - 1> const_name(char const(&text)[N]) { return descr<N - 1>(text); }
0058 constexpr descr<0> const_name(char const(&)[1]) { return {}; }
0059 
0060 template <size_t Rem, size_t... Digits> struct int_to_str : int_to_str<Rem/10, Rem%10, Digits...> { };
0061 template <size_t...Digits> struct int_to_str<0, Digits...> {
0062     // WARNING: This only works with C++17 or higher.
0063     static constexpr auto digits = descr<sizeof...(Digits)>(('0' + Digits)...);
0064 };
0065 
0066 // Ternary description (like std::conditional)
0067 template <bool B, size_t N1, size_t N2>
0068 constexpr enable_if_t<B, descr<N1 - 1>> const_name(char const(&text1)[N1], char const(&)[N2]) {
0069     return const_name(text1);
0070 }
0071 template <bool B, size_t N1, size_t N2>
0072 constexpr enable_if_t<!B, descr<N2 - 1>> const_name(char const(&)[N1], char const(&text2)[N2]) {
0073     return const_name(text2);
0074 }
0075 
0076 template <bool B, typename T1, typename T2>
0077 constexpr enable_if_t<B, T1> const_name(const T1 &d, const T2 &) { return d; }
0078 template <bool B, typename T1, typename T2>
0079 constexpr enable_if_t<!B, T2> const_name(const T1 &, const T2 &d) { return d; }
0080 
0081 template <size_t Size>
0082 auto constexpr const_name() -> remove_cv_t<decltype(int_to_str<Size / 10, Size % 10>::digits)> {
0083     return int_to_str<Size / 10, Size % 10>::digits;
0084 }
0085 
0086 template <typename Type> constexpr descr<1, Type> const_name() { return {'%'}; }
0087 
0088 // If "_" is defined as a macro, py::detail::_ cannot be provided.
0089 // It is therefore best to use py::detail::const_name universally.
0090 // This block is for backward compatibility only.
0091 // (The const_name code is repeated to avoid introducing a "_" #define ourselves.)
0092 #ifndef _
0093 #define PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY
0094 template <size_t N>
0095 constexpr descr<N-1> _(char const(&text)[N]) { return const_name<N>(text); }
0096 template <bool B, size_t N1, size_t N2>
0097 constexpr enable_if_t<B, descr<N1 - 1>> _(char const(&text1)[N1], char const(&text2)[N2]) {
0098     return const_name<B,N1,N2>(text1, text2);
0099 }
0100 template <bool B, size_t N1, size_t N2>
0101 constexpr enable_if_t<!B, descr<N2 - 1>> _(char const(&text1)[N1], char const(&text2)[N2]) {
0102     return const_name<B,N1,N2>(text1, text2);
0103 }
0104 template <bool B, typename T1, typename T2>
0105 constexpr enable_if_t<B, T1> _(const T1 &d1, const T2 &d2) { return const_name<B,T1,T2>(d1, d2); }
0106 template <bool B, typename T1, typename T2>
0107 constexpr enable_if_t<!B, T2> _(const T1 &d1, const T2 &d2) { return const_name<B,T1,T2>(d1, d2); }
0108 
0109 template <size_t Size>
0110 auto constexpr _() -> remove_cv_t<decltype(int_to_str<Size / 10, Size % 10>::digits)> {
0111     return const_name<Size>();
0112 }
0113 template <typename Type> constexpr descr<1, Type> _() { return const_name<Type>(); }
0114 #endif  // #ifndef _
0115 
0116 constexpr descr<0> concat() { return {}; }
0117 
0118 template <size_t N, typename... Ts>
0119 constexpr descr<N, Ts...> concat(const descr<N, Ts...> &descr) { return descr; }
0120 
0121 template <size_t N, typename... Ts, typename... Args>
0122 constexpr auto concat(const descr<N, Ts...> &d, const Args &...args)
0123     -> decltype(std::declval<descr<N + 2, Ts...>>() + concat(args...)) {
0124     return d + const_name(", ") + concat(args...);
0125 }
0126 
0127 template <size_t N, typename... Ts>
0128 constexpr descr<N + 2, Ts...> type_descr(const descr<N, Ts...> &descr) {
0129     return const_name("{") + descr + const_name("}");
0130 }
0131 
0132 PYBIND11_NAMESPACE_END(detail)
0133 PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)