descr.h revision 12391
112391Sjason@lowepower.com/*
212391Sjason@lowepower.com    pybind11/detail/descr.h: Helper type for concatenating type signatures
312391Sjason@lowepower.com    either at runtime (C++11) or compile time (C++14)
412391Sjason@lowepower.com
512391Sjason@lowepower.com    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
612391Sjason@lowepower.com
712391Sjason@lowepower.com    All rights reserved. Use of this source code is governed by a
812391Sjason@lowepower.com    BSD-style license that can be found in the LICENSE file.
912391Sjason@lowepower.com*/
1012391Sjason@lowepower.com
1112391Sjason@lowepower.com#pragma once
1212391Sjason@lowepower.com
1312391Sjason@lowepower.com#include "common.h"
1412391Sjason@lowepower.com
1512391Sjason@lowepower.comNAMESPACE_BEGIN(PYBIND11_NAMESPACE)
1612391Sjason@lowepower.comNAMESPACE_BEGIN(detail)
1712391Sjason@lowepower.com
1812391Sjason@lowepower.com/* Concatenate type signatures at compile time using C++14 */
1912391Sjason@lowepower.com#if defined(PYBIND11_CPP14) && !defined(_MSC_VER)
2012391Sjason@lowepower.com#define PYBIND11_CONSTEXPR_DESCR
2112391Sjason@lowepower.com
2212391Sjason@lowepower.comtemplate <size_t Size1, size_t Size2> class descr {
2312391Sjason@lowepower.com    template <size_t Size1_, size_t Size2_> friend class descr;
2412391Sjason@lowepower.compublic:
2512391Sjason@lowepower.com    constexpr descr(char const (&text) [Size1+1], const std::type_info * const (&types)[Size2+1])
2612391Sjason@lowepower.com        : descr(text, types,
2712391Sjason@lowepower.com                make_index_sequence<Size1>(),
2812391Sjason@lowepower.com                make_index_sequence<Size2>()) { }
2912391Sjason@lowepower.com
3012391Sjason@lowepower.com    constexpr const char *text() const { return m_text; }
3112391Sjason@lowepower.com    constexpr const std::type_info * const * types() const { return m_types; }
3212391Sjason@lowepower.com
3312391Sjason@lowepower.com    template <size_t OtherSize1, size_t OtherSize2>
3412391Sjason@lowepower.com    constexpr descr<Size1 + OtherSize1, Size2 + OtherSize2> operator+(const descr<OtherSize1, OtherSize2> &other) const {
3512391Sjason@lowepower.com        return concat(other,
3612391Sjason@lowepower.com                      make_index_sequence<Size1>(),
3712391Sjason@lowepower.com                      make_index_sequence<Size2>(),
3812391Sjason@lowepower.com                      make_index_sequence<OtherSize1>(),
3912391Sjason@lowepower.com                      make_index_sequence<OtherSize2>());
4012391Sjason@lowepower.com    }
4112391Sjason@lowepower.com
4212391Sjason@lowepower.comprotected:
4312391Sjason@lowepower.com    template <size_t... Indices1, size_t... Indices2>
4412391Sjason@lowepower.com    constexpr descr(
4512391Sjason@lowepower.com        char const (&text) [Size1+1],
4612391Sjason@lowepower.com        const std::type_info * const (&types) [Size2+1],
4712391Sjason@lowepower.com        index_sequence<Indices1...>, index_sequence<Indices2...>)
4812391Sjason@lowepower.com        : m_text{text[Indices1]..., '\0'},
4912391Sjason@lowepower.com          m_types{types[Indices2]...,  nullptr } {}
5012391Sjason@lowepower.com
5112391Sjason@lowepower.com    template <size_t OtherSize1, size_t OtherSize2, size_t... Indices1,
5212391Sjason@lowepower.com              size_t... Indices2, size_t... OtherIndices1, size_t... OtherIndices2>
5312391Sjason@lowepower.com    constexpr descr<Size1 + OtherSize1, Size2 + OtherSize2>
5412391Sjason@lowepower.com    concat(const descr<OtherSize1, OtherSize2> &other,
5512391Sjason@lowepower.com           index_sequence<Indices1...>, index_sequence<Indices2...>,
5612391Sjason@lowepower.com           index_sequence<OtherIndices1...>, index_sequence<OtherIndices2...>) const {
5712391Sjason@lowepower.com        return descr<Size1 + OtherSize1, Size2 + OtherSize2>(
5812391Sjason@lowepower.com            { m_text[Indices1]..., other.m_text[OtherIndices1]..., '\0' },
5912391Sjason@lowepower.com            { m_types[Indices2]..., other.m_types[OtherIndices2]..., nullptr }
6012391Sjason@lowepower.com        );
6112391Sjason@lowepower.com    }
6212391Sjason@lowepower.com
6312391Sjason@lowepower.comprotected:
6412391Sjason@lowepower.com    char m_text[Size1 + 1];
6512391Sjason@lowepower.com    const std::type_info * m_types[Size2 + 1];
6612391Sjason@lowepower.com};
6712391Sjason@lowepower.com
6812391Sjason@lowepower.comtemplate <size_t Size> constexpr descr<Size - 1, 0> _(char const(&text)[Size]) {
6912391Sjason@lowepower.com    return descr<Size - 1, 0>(text, { nullptr });
7012391Sjason@lowepower.com}
7112391Sjason@lowepower.com
7212391Sjason@lowepower.comtemplate <size_t Rem, size_t... Digits> struct int_to_str : int_to_str<Rem/10, Rem%10, Digits...> { };
7312391Sjason@lowepower.comtemplate <size_t...Digits> struct int_to_str<0, Digits...> {
7412391Sjason@lowepower.com    static constexpr auto digits = descr<sizeof...(Digits), 0>({ ('0' + Digits)..., '\0' }, { nullptr });
7512391Sjason@lowepower.com};
7612391Sjason@lowepower.com
7712391Sjason@lowepower.com// Ternary description (like std::conditional)
7812391Sjason@lowepower.comtemplate <bool B, size_t Size1, size_t Size2>
7912391Sjason@lowepower.comconstexpr enable_if_t<B, descr<Size1 - 1, 0>> _(char const(&text1)[Size1], char const(&)[Size2]) {
8012391Sjason@lowepower.com    return _(text1);
8112391Sjason@lowepower.com}
8212391Sjason@lowepower.comtemplate <bool B, size_t Size1, size_t Size2>
8312391Sjason@lowepower.comconstexpr enable_if_t<!B, descr<Size2 - 1, 0>> _(char const(&)[Size1], char const(&text2)[Size2]) {
8412391Sjason@lowepower.com    return _(text2);
8512391Sjason@lowepower.com}
8612391Sjason@lowepower.comtemplate <bool B, size_t SizeA1, size_t SizeA2, size_t SizeB1, size_t SizeB2>
8712391Sjason@lowepower.comconstexpr enable_if_t<B, descr<SizeA1, SizeA2>> _(descr<SizeA1, SizeA2> d, descr<SizeB1, SizeB2>) { return d; }
8812391Sjason@lowepower.comtemplate <bool B, size_t SizeA1, size_t SizeA2, size_t SizeB1, size_t SizeB2>
8912391Sjason@lowepower.comconstexpr enable_if_t<!B, descr<SizeB1, SizeB2>> _(descr<SizeA1, SizeA2>, descr<SizeB1, SizeB2> d) { return d; }
9012391Sjason@lowepower.com
9112391Sjason@lowepower.comtemplate <size_t Size> auto constexpr _() -> decltype(int_to_str<Size / 10, Size % 10>::digits) {
9212391Sjason@lowepower.com    return int_to_str<Size / 10, Size % 10>::digits;
9312391Sjason@lowepower.com}
9412391Sjason@lowepower.com
9512391Sjason@lowepower.comtemplate <typename Type> constexpr descr<1, 1> _() {
9612391Sjason@lowepower.com    return descr<1, 1>({ '%', '\0' }, { &typeid(Type), nullptr });
9712391Sjason@lowepower.com}
9812391Sjason@lowepower.com
9912391Sjason@lowepower.cominline constexpr descr<0, 0> concat() { return _(""); }
10012391Sjason@lowepower.comtemplate <size_t Size1, size_t Size2, typename... Args> auto constexpr concat(descr<Size1, Size2> descr) { return descr; }
10112391Sjason@lowepower.comtemplate <size_t Size1, size_t Size2, typename... Args> auto constexpr concat(descr<Size1, Size2> descr, Args&&... args) { return descr + _(", ") + concat(args...); }
10212391Sjason@lowepower.comtemplate <size_t Size1, size_t Size2> auto constexpr type_descr(descr<Size1, Size2> descr) { return _("{") + descr + _("}"); }
10312391Sjason@lowepower.com
10412391Sjason@lowepower.com#define PYBIND11_DESCR constexpr auto
10512391Sjason@lowepower.com
10612391Sjason@lowepower.com#else /* Simpler C++11 implementation based on run-time memory allocation and copying */
10712391Sjason@lowepower.com
10812391Sjason@lowepower.comclass descr {
10912391Sjason@lowepower.compublic:
11012391Sjason@lowepower.com    PYBIND11_NOINLINE descr(const char *text, const std::type_info * const * types) {
11112391Sjason@lowepower.com        size_t nChars = len(text), nTypes = len(types);
11212391Sjason@lowepower.com        m_text  = new char[nChars];
11312391Sjason@lowepower.com        m_types = new const std::type_info *[nTypes];
11412391Sjason@lowepower.com        memcpy(m_text, text, nChars * sizeof(char));
11512391Sjason@lowepower.com        memcpy(m_types, types, nTypes * sizeof(const std::type_info *));
11612391Sjason@lowepower.com    }
11712391Sjason@lowepower.com
11812391Sjason@lowepower.com    PYBIND11_NOINLINE descr operator+(descr &&d2) && {
11912391Sjason@lowepower.com        descr r;
12012391Sjason@lowepower.com
12112391Sjason@lowepower.com        size_t nChars1 = len(m_text),    nTypes1 = len(m_types);
12212391Sjason@lowepower.com        size_t nChars2 = len(d2.m_text), nTypes2 = len(d2.m_types);
12312391Sjason@lowepower.com
12412391Sjason@lowepower.com        r.m_text  = new char[nChars1 + nChars2 - 1];
12512391Sjason@lowepower.com        r.m_types = new const std::type_info *[nTypes1 + nTypes2 - 1];
12612391Sjason@lowepower.com        memcpy(r.m_text, m_text, (nChars1-1) * sizeof(char));
12712391Sjason@lowepower.com        memcpy(r.m_text + nChars1 - 1, d2.m_text, nChars2 * sizeof(char));
12812391Sjason@lowepower.com        memcpy(r.m_types, m_types, (nTypes1-1) * sizeof(std::type_info *));
12912391Sjason@lowepower.com        memcpy(r.m_types + nTypes1 - 1, d2.m_types, nTypes2 * sizeof(std::type_info *));
13012391Sjason@lowepower.com
13112391Sjason@lowepower.com        delete[] m_text;    delete[] m_types;
13212391Sjason@lowepower.com        delete[] d2.m_text; delete[] d2.m_types;
13312391Sjason@lowepower.com
13412391Sjason@lowepower.com        return r;
13512391Sjason@lowepower.com    }
13612391Sjason@lowepower.com
13712391Sjason@lowepower.com    char *text() { return m_text; }
13812391Sjason@lowepower.com    const std::type_info * * types() { return m_types; }
13912391Sjason@lowepower.com
14012391Sjason@lowepower.comprotected:
14112391Sjason@lowepower.com    PYBIND11_NOINLINE descr() { }
14212391Sjason@lowepower.com
14312391Sjason@lowepower.com    template <typename T> static size_t len(const T *ptr) { // return length including null termination
14412391Sjason@lowepower.com        const T *it = ptr;
14512391Sjason@lowepower.com        while (*it++ != (T) 0)
14612391Sjason@lowepower.com            ;
14712391Sjason@lowepower.com        return static_cast<size_t>(it - ptr);
14812391Sjason@lowepower.com    }
14912391Sjason@lowepower.com
15012391Sjason@lowepower.com    const std::type_info **m_types = nullptr;
15112391Sjason@lowepower.com    char *m_text = nullptr;
15212391Sjason@lowepower.com};
15312391Sjason@lowepower.com
15412391Sjason@lowepower.com/* The 'PYBIND11_NOINLINE inline' combinations below are intentional to get the desired linkage while producing as little object code as possible */
15512391Sjason@lowepower.com
15612391Sjason@lowepower.comPYBIND11_NOINLINE inline descr _(const char *text) {
15712391Sjason@lowepower.com    const std::type_info *types[1] = { nullptr };
15812391Sjason@lowepower.com    return descr(text, types);
15912391Sjason@lowepower.com}
16012391Sjason@lowepower.com
16112391Sjason@lowepower.comtemplate <bool B> PYBIND11_NOINLINE enable_if_t<B, descr> _(const char *text1, const char *) { return _(text1); }
16212391Sjason@lowepower.comtemplate <bool B> PYBIND11_NOINLINE enable_if_t<!B, descr> _(char const *, const char *text2) { return _(text2); }
16312391Sjason@lowepower.comtemplate <bool B> PYBIND11_NOINLINE enable_if_t<B, descr> _(descr d, descr) { return d; }
16412391Sjason@lowepower.comtemplate <bool B> PYBIND11_NOINLINE enable_if_t<!B, descr> _(descr, descr d) { return d; }
16512391Sjason@lowepower.com
16612391Sjason@lowepower.comtemplate <typename Type> PYBIND11_NOINLINE descr _() {
16712391Sjason@lowepower.com    const std::type_info *types[2] = { &typeid(Type), nullptr };
16812391Sjason@lowepower.com    return descr("%", types);
16912391Sjason@lowepower.com}
17012391Sjason@lowepower.com
17112391Sjason@lowepower.comtemplate <size_t Size> PYBIND11_NOINLINE descr _() {
17212391Sjason@lowepower.com    const std::type_info *types[1] = { nullptr };
17312391Sjason@lowepower.com    return descr(std::to_string(Size).c_str(), types);
17412391Sjason@lowepower.com}
17512391Sjason@lowepower.com
17612391Sjason@lowepower.comPYBIND11_NOINLINE inline descr concat() { return _(""); }
17712391Sjason@lowepower.comPYBIND11_NOINLINE inline descr concat(descr &&d) { return d; }
17812391Sjason@lowepower.comtemplate <typename... Args> PYBIND11_NOINLINE descr concat(descr &&d, Args&&... args) { return std::move(d) + _(", ") + concat(std::forward<Args>(args)...); }
17912391Sjason@lowepower.comPYBIND11_NOINLINE inline descr type_descr(descr&& d) { return _("{") + std::move(d) + _("}"); }
18012391Sjason@lowepower.com
18112391Sjason@lowepower.com#define PYBIND11_DESCR ::pybind11::detail::descr
18212391Sjason@lowepower.com#endif
18312391Sjason@lowepower.com
18412391Sjason@lowepower.comNAMESPACE_END(detail)
18512391Sjason@lowepower.comNAMESPACE_END(PYBIND11_NAMESPACE)
186