descr.h revision 12391
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 15NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 16NAMESPACE_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 22template <size_t Size1, size_t Size2> class descr { 23 template <size_t Size1_, size_t Size2_> friend class descr; 24public: 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 42protected: 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 63protected: 64 char m_text[Size1 + 1]; 65 const std::type_info * m_types[Size2 + 1]; 66}; 67 68template <size_t Size> constexpr descr<Size - 1, 0> _(char const(&text)[Size]) { 69 return descr<Size - 1, 0>(text, { nullptr }); 70} 71 72template <size_t Rem, size_t... Digits> struct int_to_str : int_to_str<Rem/10, Rem%10, Digits...> { }; 73template <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) 78template <bool B, size_t Size1, size_t Size2> 79constexpr enable_if_t<B, descr<Size1 - 1, 0>> _(char const(&text1)[Size1], char const(&)[Size2]) { 80 return _(text1); 81} 82template <bool B, size_t Size1, size_t Size2> 83constexpr enable_if_t<!B, descr<Size2 - 1, 0>> _(char const(&)[Size1], char const(&text2)[Size2]) { 84 return _(text2); 85} 86template <bool B, size_t SizeA1, size_t SizeA2, size_t SizeB1, size_t SizeB2> 87constexpr enable_if_t<B, descr<SizeA1, SizeA2>> _(descr<SizeA1, SizeA2> d, descr<SizeB1, SizeB2>) { return d; } 88template <bool B, size_t SizeA1, size_t SizeA2, size_t SizeB1, size_t SizeB2> 89constexpr enable_if_t<!B, descr<SizeB1, SizeB2>> _(descr<SizeA1, SizeA2>, descr<SizeB1, SizeB2> d) { return d; } 90 91template <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 95template <typename Type> constexpr descr<1, 1> _() { 96 return descr<1, 1>({ '%', '\0' }, { &typeid(Type), nullptr }); 97} 98 99inline constexpr descr<0, 0> concat() { return _(""); } 100template <size_t Size1, size_t Size2, typename... Args> auto constexpr concat(descr<Size1, Size2> descr) { return descr; } 101template <size_t Size1, size_t Size2, typename... Args> auto constexpr concat(descr<Size1, Size2> descr, Args&&... args) { return descr + _(", ") + concat(args...); } 102template <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 108class descr { 109public: 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 140protected: 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 156PYBIND11_NOINLINE inline descr _(const char *text) { 157 const std::type_info *types[1] = { nullptr }; 158 return descr(text, types); 159} 160 161template <bool B> PYBIND11_NOINLINE enable_if_t<B, descr> _(const char *text1, const char *) { return _(text1); } 162template <bool B> PYBIND11_NOINLINE enable_if_t<!B, descr> _(char const *, const char *text2) { return _(text2); } 163template <bool B> PYBIND11_NOINLINE enable_if_t<B, descr> _(descr d, descr) { return d; } 164template <bool B> PYBIND11_NOINLINE enable_if_t<!B, descr> _(descr, descr d) { return d; } 165 166template <typename Type> PYBIND11_NOINLINE descr _() { 167 const std::type_info *types[2] = { &typeid(Type), nullptr }; 168 return descr("%", types); 169} 170 171template <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 176PYBIND11_NOINLINE inline descr concat() { return _(""); } 177PYBIND11_NOINLINE inline descr concat(descr &&d) { return d; } 178template <typename... Args> PYBIND11_NOINLINE descr concat(descr &&d, Args&&... args) { return std::move(d) + _(", ") + concat(std::forward<Args>(args)...); } 179PYBIND11_NOINLINE inline descr type_descr(descr&& d) { return _("{") + std::move(d) + _("}"); } 180 181#define PYBIND11_DESCR ::pybind11::detail::descr 182#endif 183 184NAMESPACE_END(detail) 185NAMESPACE_END(PYBIND11_NAMESPACE) 186