Merge branch release-2019 into master
[alexxy/gromacs.git] / python_packaging / src / external / pybind / include / pybind11 / detail / descr.h
1 /*
2     pybind11/detail/descr.h: Helper type for concatenating type signatures
3     either at runtime (C++11) or compile time (C++14)
4
5     Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
6
7     All rights reserved. Use of this source code is governed by a
8     BSD-style license that can be found in the LICENSE file.
9 */
10
11 #pragma once
12
13 #include "common.h"
14
15 NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
16 NAMESPACE_BEGIN(detail)
17
18 /* Concatenate type signatures at compile time using C++14 */
19 #if defined(PYBIND11_CPP14) && !defined(_MSC_VER)
20 #define PYBIND11_CONSTEXPR_DESCR
21
22 template <size_t Size1, size_t Size2> class descr {
23     template <size_t Size1_, size_t Size2_> friend class descr;
24 public:
25     constexpr descr(char const (&text) [Size1+1], const std::type_info * const (&types)[Size2+1])
26         : descr(text, types,
27                 make_index_sequence<Size1>(),
28                 make_index_sequence<Size2>()) { }
29
30     constexpr const char *text() const { return m_text; }
31     constexpr const std::type_info * const * types() const { return m_types; }
32
33     template <size_t OtherSize1, size_t OtherSize2>
34     constexpr descr<Size1 + OtherSize1, Size2 + OtherSize2> operator+(const descr<OtherSize1, OtherSize2> &other) const {
35         return concat(other,
36                       make_index_sequence<Size1>(),
37                       make_index_sequence<Size2>(),
38                       make_index_sequence<OtherSize1>(),
39                       make_index_sequence<OtherSize2>());
40     }
41
42 protected:
43     template <size_t... Indices1, size_t... Indices2>
44     constexpr descr(
45         char const (&text) [Size1+1],
46         const std::type_info * const (&types) [Size2+1],
47         index_sequence<Indices1...>, index_sequence<Indices2...>)
48         : m_text{text[Indices1]..., '\0'},
49           m_types{types[Indices2]...,  nullptr } {}
50
51     template <size_t OtherSize1, size_t OtherSize2, size_t... Indices1,
52               size_t... Indices2, size_t... OtherIndices1, size_t... OtherIndices2>
53     constexpr descr<Size1 + OtherSize1, Size2 + OtherSize2>
54     concat(const descr<OtherSize1, OtherSize2> &other,
55            index_sequence<Indices1...>, index_sequence<Indices2...>,
56            index_sequence<OtherIndices1...>, index_sequence<OtherIndices2...>) const {
57         return descr<Size1 + OtherSize1, Size2 + OtherSize2>(
58             { m_text[Indices1]..., other.m_text[OtherIndices1]..., '\0' },
59             { m_types[Indices2]..., other.m_types[OtherIndices2]..., nullptr }
60         );
61     }
62
63 protected:
64     char m_text[Size1 + 1];
65     const std::type_info * m_types[Size2 + 1];
66 };
67
68 template <size_t Size> constexpr descr<Size - 1, 0> _(char const(&text)[Size]) {
69     return descr<Size - 1, 0>(text, { nullptr });
70 }
71
72 template <size_t Rem, size_t... Digits> struct int_to_str : int_to_str<Rem/10, Rem%10, Digits...> { };
73 template <size_t...Digits> struct int_to_str<0, Digits...> {
74     static constexpr auto digits = descr<sizeof...(Digits), 0>({ ('0' + Digits)..., '\0' }, { nullptr });
75 };
76
77 // Ternary description (like std::conditional)
78 template <bool B, size_t Size1, size_t Size2>
79 constexpr enable_if_t<B, descr<Size1 - 1, 0>> _(char const(&text1)[Size1], char const(&)[Size2]) {
80     return _(text1);
81 }
82 template <bool B, size_t Size1, size_t Size2>
83 constexpr enable_if_t<!B, descr<Size2 - 1, 0>> _(char const(&)[Size1], char const(&text2)[Size2]) {
84     return _(text2);
85 }
86 template <bool B, size_t SizeA1, size_t SizeA2, size_t SizeB1, size_t SizeB2>
87 constexpr enable_if_t<B, descr<SizeA1, SizeA2>> _(descr<SizeA1, SizeA2> d, descr<SizeB1, SizeB2>) { return d; }
88 template <bool B, size_t SizeA1, size_t SizeA2, size_t SizeB1, size_t SizeB2>
89 constexpr enable_if_t<!B, descr<SizeB1, SizeB2>> _(descr<SizeA1, SizeA2>, descr<SizeB1, SizeB2> d) { return d; }
90
91 template <size_t Size> auto constexpr _() -> decltype(int_to_str<Size / 10, Size % 10>::digits) {
92     return int_to_str<Size / 10, Size % 10>::digits;
93 }
94
95 template <typename Type> constexpr descr<1, 1> _() {
96     return descr<1, 1>({ '%', '\0' }, { &typeid(Type), nullptr });
97 }
98
99 inline constexpr descr<0, 0> concat() { return _(""); }
100 template <size_t Size1, size_t Size2, typename... Args> auto constexpr concat(descr<Size1, Size2> descr) { return descr; }
101 template <size_t Size1, size_t Size2, typename... Args> auto constexpr concat(descr<Size1, Size2> descr, Args&&... args) { return descr + _(", ") + concat(args...); }
102 template <size_t Size1, size_t Size2> auto constexpr type_descr(descr<Size1, Size2> descr) { return _("{") + descr + _("}"); }
103
104 #define PYBIND11_DESCR constexpr auto
105
106 #else /* Simpler C++11 implementation based on run-time memory allocation and copying */
107
108 class descr {
109 public:
110     PYBIND11_NOINLINE descr(const char *text, const std::type_info * const * types) {
111         size_t nChars = len(text), nTypes = len(types);
112         m_text  = new char[nChars];
113         m_types = new const std::type_info *[nTypes];
114         memcpy(m_text, text, nChars * sizeof(char));
115         memcpy(m_types, types, nTypes * sizeof(const std::type_info *));
116     }
117
118     PYBIND11_NOINLINE descr operator+(descr &&d2) && {
119         descr r;
120
121         size_t nChars1 = len(m_text),    nTypes1 = len(m_types);
122         size_t nChars2 = len(d2.m_text), nTypes2 = len(d2.m_types);
123
124         r.m_text  = new char[nChars1 + nChars2 - 1];
125         r.m_types = new const std::type_info *[nTypes1 + nTypes2 - 1];
126         memcpy(r.m_text, m_text, (nChars1-1) * sizeof(char));
127         memcpy(r.m_text + nChars1 - 1, d2.m_text, nChars2 * sizeof(char));
128         memcpy(r.m_types, m_types, (nTypes1-1) * sizeof(std::type_info *));
129         memcpy(r.m_types + nTypes1 - 1, d2.m_types, nTypes2 * sizeof(std::type_info *));
130
131         delete[] m_text;    delete[] m_types;
132         delete[] d2.m_text; delete[] d2.m_types;
133
134         return r;
135     }
136
137     char *text() { return m_text; }
138     const std::type_info * * types() { return m_types; }
139
140 protected:
141     PYBIND11_NOINLINE descr() { }
142
143     template <typename T> static size_t len(const T *ptr) { // return length including null termination
144         const T *it = ptr;
145         while (*it++ != (T) 0)
146             ;
147         return static_cast<size_t>(it - ptr);
148     }
149
150     const std::type_info **m_types = nullptr;
151     char *m_text = nullptr;
152 };
153
154 /* The 'PYBIND11_NOINLINE inline' combinations below are intentional to get the desired linkage while producing as little object code as possible */
155
156 PYBIND11_NOINLINE inline descr _(const char *text) {
157     const std::type_info *types[1] = { nullptr };
158     return descr(text, types);
159 }
160
161 template <bool B> PYBIND11_NOINLINE enable_if_t<B, descr> _(const char *text1, const char *) { return _(text1); }
162 template <bool B> PYBIND11_NOINLINE enable_if_t<!B, descr> _(char const *, const char *text2) { return _(text2); }
163 template <bool B> PYBIND11_NOINLINE enable_if_t<B, descr> _(descr d, descr) { return d; }
164 template <bool B> PYBIND11_NOINLINE enable_if_t<!B, descr> _(descr, descr d) { return d; }
165
166 template <typename Type> PYBIND11_NOINLINE descr _() {
167     const std::type_info *types[2] = { &typeid(Type), nullptr };
168     return descr("%", types);
169 }
170
171 template <size_t Size> PYBIND11_NOINLINE descr _() {
172     const std::type_info *types[1] = { nullptr };
173     return descr(std::to_string(Size).c_str(), types);
174 }
175
176 PYBIND11_NOINLINE inline descr concat() { return _(""); }
177 PYBIND11_NOINLINE inline descr concat(descr &&d) { return d; }
178 template <typename... Args> PYBIND11_NOINLINE descr concat(descr &&d, Args&&... args) { return std::move(d) + _(", ") + concat(std::forward<Args>(args)...); }
179 PYBIND11_NOINLINE inline descr type_descr(descr&& d) { return _("{") + std::move(d) + _("}"); }
180
181 #define PYBIND11_DESCR ::pybind11::detail::descr
182 #endif
183
184 NAMESPACE_END(detail)
185 NAMESPACE_END(PYBIND11_NAMESPACE)