Learn more  » Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Bower components Debian packages RPM packages NuGet packages

edgify / torch   python

Repository URL to install this package:

/ include / pybind11 / cast.h

/*
    pybind11/cast.h: Partial template specializations to cast between
    C++ and Python types

    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>

    All rights reserved. Use of this source code is governed by a
    BSD-style license that can be found in the LICENSE file.
*/

#pragma once

#include "detail/common.h"
#include "detail/descr.h"
#include "detail/type_caster_base.h"
#include "detail/typeid.h"
#include "pytypes.h"

#include <array>
#include <cstring>
#include <functional>
#include <iosfwd>
#include <iterator>
#include <memory>
#include <string>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>

PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)

template <typename type, typename SFINAE = void>
class type_caster : public type_caster_base<type> {};
template <typename type>
using make_caster = type_caster<intrinsic_t<type>>;

// Shortcut for calling a caster's `cast_op_type` cast operator for casting a type_caster to a T
template <typename T>
typename make_caster<T>::template cast_op_type<T> cast_op(make_caster<T> &caster) {
    return caster.operator typename make_caster<T>::template cast_op_type<T>();
}
template <typename T>
typename make_caster<T>::template cast_op_type<typename std::add_rvalue_reference<T>::type>
cast_op(make_caster<T> &&caster) {
    return std::move(caster).operator typename make_caster<T>::
        template cast_op_type<typename std::add_rvalue_reference<T>::type>();
}

template <typename type>
class type_caster<std::reference_wrapper<type>> {
private:
    using caster_t = make_caster<type>;
    caster_t subcaster;
    using reference_t = type &;
    using subcaster_cast_op_type = typename caster_t::template cast_op_type<reference_t>;

    static_assert(
        std::is_same<typename std::remove_const<type>::type &, subcaster_cast_op_type>::value
            || std::is_same<reference_t, subcaster_cast_op_type>::value,
        "std::reference_wrapper<T> caster requires T to have a caster with an "
        "`operator T &()` or `operator const T &()`");

public:
    bool load(handle src, bool convert) { return subcaster.load(src, convert); }
    static constexpr auto name = caster_t::name;
    static handle
    cast(const std::reference_wrapper<type> &src, return_value_policy policy, handle parent) {
        // It is definitely wrong to take ownership of this pointer, so mask that rvp
        if (policy == return_value_policy::take_ownership
            || policy == return_value_policy::automatic) {
            policy = return_value_policy::automatic_reference;
        }
        return caster_t::cast(&src.get(), policy, parent);
    }
    template <typename T>
    using cast_op_type = std::reference_wrapper<type>;
    explicit operator std::reference_wrapper<type>() { return cast_op<type &>(subcaster); }
};

#define PYBIND11_TYPE_CASTER(type, py_name)                                                       \
protected:                                                                                        \
    type value;                                                                                   \
                                                                                                  \
public:                                                                                           \
    static constexpr auto name = py_name;                                                         \
    template <typename T_,                                                                        \
              ::pybind11::detail::enable_if_t<                                                    \
                  std::is_same<type, ::pybind11::detail::remove_cv_t<T_>>::value,                 \
                  int> = 0>                                                                       \
    static ::pybind11::handle cast(                                                               \
        T_ *src, ::pybind11::return_value_policy policy, ::pybind11::handle parent) {             \
        if (!src)                                                                                 \
            return ::pybind11::none().release();                                                  \
        if (policy == ::pybind11::return_value_policy::take_ownership) {                          \
            auto h = cast(std::move(*src), policy, parent);                                       \
            delete src;                                                                           \
            return h;                                                                             \
        }                                                                                         \
        return cast(*src, policy, parent);                                                        \
    }                                                                                             \
    operator type *() { return &value; }               /* NOLINT(bugprone-macro-parentheses) */   \
    operator type &() { return value; }                /* NOLINT(bugprone-macro-parentheses) */   \
    operator type &&() && { return std::move(value); } /* NOLINT(bugprone-macro-parentheses) */   \
    template <typename T_>                                                                        \
    using cast_op_type = ::pybind11::detail::movable_cast_op_type<T_>

template <typename CharT>
using is_std_char_type = any_of<std::is_same<CharT, char>, /* std::string */
#if defined(PYBIND11_HAS_U8STRING)
                                std::is_same<CharT, char8_t>, /* std::u8string */
#endif
                                std::is_same<CharT, char16_t>, /* std::u16string */
                                std::is_same<CharT, char32_t>, /* std::u32string */
                                std::is_same<CharT, wchar_t>   /* std::wstring */
                                >;

template <typename T>
struct type_caster<T, enable_if_t<std::is_arithmetic<T>::value && !is_std_char_type<T>::value>> {
    using _py_type_0 = conditional_t<sizeof(T) <= sizeof(long), long, long long>;
    using _py_type_1 = conditional_t<std::is_signed<T>::value,
                                     _py_type_0,
                                     typename std::make_unsigned<_py_type_0>::type>;
    using py_type = conditional_t<std::is_floating_point<T>::value, double, _py_type_1>;

public:
    bool load(handle src, bool convert) {
        py_type py_value;

        if (!src) {
            return false;
        }

#if !defined(PYPY_VERSION)
        auto index_check = [](PyObject *o) { return PyIndex_Check(o); };
#else
        // In PyPy 7.3.3, `PyIndex_Check` is implemented by calling `__index__`,
        // while CPython only considers the existence of `nb_index`/`__index__`.
        auto index_check = [](PyObject *o) { return hasattr(o, "__index__"); };
#endif

        if (std::is_floating_point<T>::value) {
            if (convert || PyFloat_Check(src.ptr())) {
                py_value = (py_type) PyFloat_AsDouble(src.ptr());
            } else {
                return false;
            }
        } else if (PyFloat_Check(src.ptr())
                   || (!convert && !PYBIND11_LONG_CHECK(src.ptr()) && !index_check(src.ptr()))) {
            return false;
        } else {
            handle src_or_index = src;
            // PyPy: 7.3.7's 3.8 does not implement PyLong_*'s __index__ calls.
#if PY_VERSION_HEX < 0x03080000 || defined(PYPY_VERSION)
            object index;
            if (!PYBIND11_LONG_CHECK(src.ptr())) { // So: index_check(src.ptr())
                index = reinterpret_steal<object>(PyNumber_Index(src.ptr()));
                if (!index) {
                    PyErr_Clear();
                    if (!convert)
                        return false;
                } else {
                    src_or_index = index;
                }
            }
#endif
            if (std::is_unsigned<py_type>::value) {
                py_value = as_unsigned<py_type>(src_or_index.ptr());
            } else { // signed integer:
                py_value = sizeof(T) <= sizeof(long)
                               ? (py_type) PyLong_AsLong(src_or_index.ptr())
                               : (py_type) PYBIND11_LONG_AS_LONGLONG(src_or_index.ptr());
            }
        }

        // Python API reported an error
        bool py_err = py_value == (py_type) -1 && PyErr_Occurred();

        // Check to see if the conversion is valid (integers should match exactly)
        // Signed/unsigned checks happen elsewhere
        if (py_err
            || (std::is_integral<T>::value && sizeof(py_type) != sizeof(T)
                && py_value != (py_type) (T) py_value)) {
            PyErr_Clear();
            if (py_err && convert && (PyNumber_Check(src.ptr()) != 0)) {
                auto tmp = reinterpret_steal<object>(std::is_floating_point<T>::value
                                                         ? PyNumber_Float(src.ptr())
                                                         : PyNumber_Long(src.ptr()));
                PyErr_Clear();
                return load(tmp, false);
            }
            return false;
        }

        value = (T) py_value;
        return true;
    }

    template <typename U = T>
    static typename std::enable_if<std::is_floating_point<U>::value, handle>::type
    cast(U src, return_value_policy /* policy */, handle /* parent */) {
        return PyFloat_FromDouble((double) src);
    }

    template <typename U = T>
    static typename std::enable_if<!std::is_floating_point<U>::value && std::is_signed<U>::value
                                       && (sizeof(U) <= sizeof(long)),
                                   handle>::type
    cast(U src, return_value_policy /* policy */, handle /* parent */) {
        return PYBIND11_LONG_FROM_SIGNED((long) src);
    }

    template <typename U = T>
    static typename std::enable_if<!std::is_floating_point<U>::value && std::is_unsigned<U>::value
                                       && (sizeof(U) <= sizeof(unsigned long)),
                                   handle>::type
    cast(U src, return_value_policy /* policy */, handle /* parent */) {
        return PYBIND11_LONG_FROM_UNSIGNED((unsigned long) src);
    }

    template <typename U = T>
    static typename std::enable_if<!std::is_floating_point<U>::value && std::is_signed<U>::value
                                       && (sizeof(U) > sizeof(long)),
                                   handle>::type
    cast(U src, return_value_policy /* policy */, handle /* parent */) {
        return PyLong_FromLongLong((long long) src);
    }

    template <typename U = T>
    static typename std::enable_if<!std::is_floating_point<U>::value && std::is_unsigned<U>::value
                                       && (sizeof(U) > sizeof(unsigned long)),
                                   handle>::type
    cast(U src, return_value_policy /* policy */, handle /* parent */) {
        return PyLong_FromUnsignedLongLong((unsigned long long) src);
    }

    PYBIND11_TYPE_CASTER(T, const_name<std::is_integral<T>::value>("int", "float"));
};

template <typename T>
struct void_caster {
public:
    bool load(handle src, bool) {
        if (src && src.is_none()) {
            return true;
        }
        return false;
    }
    static handle cast(T, return_value_policy /* policy */, handle /* parent */) {
        return none().release();
    }
    PYBIND11_TYPE_CASTER(T, const_name("None"));
};

template <>
class type_caster<void_type> : public void_caster<void_type> {};

template <>
class type_caster<void> : public type_caster<void_type> {
public:
    using type_caster<void_type>::cast;

    bool load(handle h, bool) {
        if (!h) {
            return false;
        }
        if (h.is_none()) {
            value = nullptr;
            return true;
        }

        /* Check if this is a capsule */
        if (isinstance<capsule>(h)) {
            value = reinterpret_borrow<capsule>(h);
            return true;
        }

        /* Check if this is a C++ type */
        const auto &bases = all_type_info((PyTypeObject *) type::handle_of(h).ptr());
        if (bases.size() == 1) { // Only allowing loading from a single-value type
            value = values_and_holders(reinterpret_cast<instance *>(h.ptr())).begin()->value_ptr();
            return true;
        }

        /* Fail */
        return false;
    }

    static handle cast(const void *ptr, return_value_policy /* policy */, handle /* parent */) {
        if (ptr) {
            return capsule(ptr).release();
        }
        return none().release();
    }

    template <typename T>
    using cast_op_type = void *&;
    explicit operator void *&() { return value; }
    static constexpr auto name = const_name("capsule");

private:
    void *value = nullptr;
};

template <>
class type_caster<std::nullptr_t> : public void_caster<std::nullptr_t> {};

template <>
class type_caster<bool> {
public:
    bool load(handle src, bool convert) {
        if (!src) {
            return false;
        }
        if (src.ptr() == Py_True) {
            value = true;
            return true;
        }
        if (src.ptr() == Py_False) {
            value = false;
            return true;
        }
        if (convert || (std::strcmp("numpy.bool_", Py_TYPE(src.ptr())->tp_name) == 0)) {
            // (allow non-implicit conversion for numpy booleans)

            Py_ssize_t res = -1;
            if (src.is_none()) {
                res = 0; // None is implicitly converted to False
            }
#if defined(PYPY_VERSION)
            // On PyPy, check that "__bool__" attr exists
            else if (hasattr(src, PYBIND11_BOOL_ATTR)) {
                res = PyObject_IsTrue(src.ptr());
            }
#else
            // Alternate approach for CPython: this does the same as the above, but optimized
            // using the CPython API so as to avoid an unneeded attribute lookup.
            else if (auto *tp_as_number = src.ptr()->ob_type->tp_as_number) {
                if (PYBIND11_NB_BOOL(tp_as_number)) {
                    res = (*PYBIND11_NB_BOOL(tp_as_number))(src.ptr());
                }
            }
#endif
            if (res == 0 || res == 1) {
Loading ...