You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

185 lines
7.5 KiB

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