[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/ghisvail/xtensor-python/master/include/xtensor-python/pyarray.hpp [Back]  [Original]

/***************************************************************************
* Copyright (c) 2016, Johan Mabille and Sylvain Corlay                     *
*                                                                          *
* Distributed under the terms of the BSD 3-Clause License.                 *
*                                                                          *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/

#ifndef PY_ARRAY_HPP
#define PY_ARRAY_HPP

#include 
#include 
#include 
#include "xtensor/xsemantic.hpp"
#include "xtensor/xiterator.hpp"

#include "pycontainer.hpp"
#include "pybuffer_adaptor.hpp"

namespace xt
{
    template 
    class pyarray;
}

namespace pybind11
{
    namespace detail
    {
        template 
        struct handle_type_name
        {
            static PYBIND11_DESCR name()
            {
                return _("numpy.ndarray[") + make_caster::name() + _("]");
            }
        };

        template 
        struct pyobject_caster
        {
            using type = xt::pyarray;

            bool load(handle src, bool)
            {
                value = type::ensure(src);
                return static_cast(value);
            }

            static handle cast(const handle &src, return_value_policy, handle)
            {
                return src.inc_ref();
            }

            PYBIND11_TYPE_CASTER(type, handle_type_name::name());
        };
    }
}

namespace xt
{

    template 
    class pyarray_backstrides
    {

    public:

        using array_type = A;
        using value_type = typename array_type::size_type;
        using size_type = typename array_type::size_type;

        pyarray_backstrides() = default;
        pyarray_backstrides(const array_type& a);

        value_type operator[](size_type i) const;

        size_type size() const;

    private:

        const array_type* p_a;
    };

    template 
    struct xiterable_inner_types
        : xcontainer_iterable_types
    {
    };

    template 
    struct xcontainer_inner_types
    {
        using container_type = pybuffer_adaptor;
        using shape_type = std::vector;
        using strides_type = shape_type;
        using backstrides_type = pyarray_backstrides;
        using inner_shape_type = pybuffer_adaptor;
        using inner_strides_type = pystrides_adaptor;
        using inner_backstrides_type = backstrides_type;
        using temporary_type = pyarray;
    };

    /**
     * @class pyarray
     * @brief Wrapper on the Python buffer protocol.
     */
    template 
    class pyarray : public pycontainer,
                    public xcontainer_semantic
    {
    public:

        using self_type = pyarray;
        using semantic_base = xcontainer_semantic;
        using base_type = pycontainer;
        using container_type = typename base_type::container_type;
        using value_type = typename base_type::value_type; 
        using reference = typename base_type::reference; 
        using const_reference = typename base_type::const_reference; 
        using pointer = typename base_type::pointer;
        using size_type = typename base_type::size_type;
        using shape_type = typename base_type::shape_type;
        using strides_type = typename base_type::strides_type;
        using backstrides_type = typename base_type::backstrides_type;
        using inner_shape_type = typename base_type::inner_shape_type;
        using inner_strides_type = typename base_type::inner_strides_type;
        using inner_backstrides_type = typename base_type::inner_backstrides_type;

        pyarray();
        pyarray(const self_type&) = default;
        pyarray(self_type&&) = default;
        pyarray(const value_type& t);
        pyarray(nested_initializer_list_t t);
        pyarray(nested_initializer_list_t t);
        pyarray(nested_initializer_list_t t);
        pyarray(nested_initializer_list_t t);
        pyarray(nested_initializer_list_t t);

        pyarray(pybind11::handle h, pybind11::object::borrowed_t);
        pyarray(pybind11::handle h, pybind11::object::stolen_t);
        pyarray(const pybind11::object &o);
        
        explicit pyarray(const shape_type& shape, layout l = layout::row_major);
        explicit pyarray(const shape_type& shape, const_reference value, layout l = layout::row_major);
        explicit pyarray(const shape_type& shape, const strides_type& strides, const_reference value);
        explicit pyarray(const shape_type& shape, const strides_type& strides);

        template 
        pyarray(const xexpression& e);

        self_type& operator=(const self_type& e) = default;
        self_type& operator=(self_type&& e) = default;

        template 
        self_type& operator=(const xexpression& e);

        using base_type::begin;
        using base_type::end;

        static self_type ensure(pybind11::handle h);
        static bool check_(pybind11::handle h);

    private:

        inner_shape_type m_shape;
        inner_strides_type m_strides;
        mutable inner_backstrides_type m_backstrides;
        container_type m_data;

        void init_array(const shape_type& shape, const strides_type& strides);
        void init_from_python();

        const inner_shape_type& shape_impl() const;
        const inner_strides_type& strides_impl() const;
        const inner_backstrides_type& backstrides_impl() const;

        container_type& data_impl();
        const container_type& data_impl() const;

        friend class xcontainer;
    };
    
    /**************************************
     * pyarray_backstrides implementation *
     **************************************/

    template 
    inline pyarray_backstrides::pyarray_backstrides(const array_type& a)
        : p_a(&a)
    {
    }

    template 
    inline auto pyarray_backstrides::size() const -> size_type
    {
        return p_a->dimension();
    }

    template 
    inline auto pyarray_backstrides::operator[](size_type i) const -> value_type
    {
        value_type sh = p_a->shape()[i];
        value_type res = sh == 1 ? 0 : (sh - 1) * p_a->strides()[i];
        return  res;
    }

    /**************************
     * pyarray implementation *
     **************************/

    template 
    inline pyarray::pyarray()
    {
        // TODO: avoid allocation
        shape_type shape = make_sequence(0, size_type(1));
        strides_type strides = make_sequence(0, size_type(0));
        init_array(shape, strides);
        m_data[0] = T();
    }

    template 
    inline pyarray::pyarray(const value_type& t)
    {
        base_type::reshape(xt::shape(t), layout::row_major);
        nested_copy(m_data.begin(), t);
    }

    template 
    inline pyarray::pyarray(nested_initializer_list_t t)
    {
        base_type::reshape(xt::shape(t), layout::row_major);
        nested_copy(m_data.begin(), t);
    }

    template 
    inline pyarray::pyarray(nested_initializer_list_t t)
    {
        base_type::reshape(xt::shape(t), layout::row_major);
        nested_copy(m_data.begin(), t);
    }

    template 
    inline pyarray::pyarray(nested_initializer_list_t t)
    {
        base_type::reshape(xt::shape(t), layout::row_major);
        nested_copy(m_data.begin(), t);
    }

    template 
    inline pyarray::pyarray(nested_initializer_list_t t)
    {
        base_type::reshape(xt::shape(t), layout::row_major);
        nested_copy(m_data.begin(), t);
    }

    template 
    inline pyarray::pyarray(nested_initializer_list_t t)
    {
        base_type::reshape(xt::shape(t), layout::row_major);
        nested_copy(m_data.begin(), t);
    }

    template 
    inline pyarray::pyarray(pybind11::handle h, pybind11::object::borrowed_t)
        : base_type(h, pybind11::object::borrowed)
    {
        init_from_python();
    }

    template 
    inline pyarray::pyarray(pybind11::handle h, pybind11::object::stolen_t)
        : base_type(h, pybind11::object::stolen)
    {
        init_from_python();
    }

    template 
    inline pyarray::pyarray(const pybind11::object &o)
        : base_type(o)
    {
        init_from_python();
    }

    template 
    inline pyarray::pyarray(const shape_type& shape, layout l)
    {
        strides_type strides(shape.size());
        compute_strides(shape, l, strides);
        init_array(shape, strides);
    }

    template 
    inline pyarray::pyarray(const shape_type& shape, const_reference value, layout l)
    {
        strides_type strides(shape.size());
        compute_strides(shape, l, strides);
        init_array(shape, strides);
        std::fill(m_data.begin(), m_data.end(), value);
    }
    
    template 
    inline pyarray::pyarray(const shape_type& shape, const strides_type& strides, const_reference value)
    {
        init_array(shape, strides);
        std::fill(m_data.begin(), m_data.end(), value);
    }

    template 
    inline pyarray::pyarray(const shape_type& shape, const strides_type& strides)
    {
        init_array(shape, strides);
    }

    template 
    template 
    inline pyarray::pyarray(const xexpression& e)
    {
        semantic_base::assign(e);
    }

    template 
    template 
    inline auto pyarray::operator=(const xexpression& e) -> self_type&
    {
        return semantic_base::operator=(e);
    }

    template 
    inline auto pyarray::ensure(pybind11::handle h) -> self_type
    {
        return base_type::ensure(h);
    }

    template 
    inline bool pyarray::check_(pybind11::handle h)
    {
        return base_type::check_(h);
    }

    template 
    inline void pyarray::init_array(const shape_type& shape, const strides_type& strides)
    {
        strides_type adapted_strides(strides);

        std::transform(strides.begin(), strides.end(), adapted_strides.begin(),
                [](auto v) { return sizeof(T) * v; });

        int flags = NPY_ARRAY_ALIGNED;
        if (!std::is_const::value)
        {
            flags |= NPY_ARRAY_WRITEABLE;
        }
        int type_num = detail::numpy_traits::type_num;
        
        npy_intp* shape_data = reinterpret_cast(const_cast(shape.data()));
        npy_intp* strides_data = reinterpret_cast(adapted_strides.data());
        auto tmp = pybind11::reinterpret_steal(
                PyArray_New(&PyArray_Type, static_cast(shape.size()), shape_data, type_num, strides_data,
                            nullptr, static_cast(sizeof(T)), flags, nullptr)
                );
        
        if (!tmp)
        {
            throw std::runtime_error("NumPy: unable to create ndarray");
        }

        this->m_ptr = tmp.release().ptr();
        init_from_python();
    }

    template 
    inline void pyarray::init_from_python()
    {
        m_shape = inner_shape_type(reinterpret_cast(PyArray_SHAPE(this->python_array())),
                                   static_cast(PyArray_NDIM(this->python_array())));
        m_strides = inner_strides_type(reinterpret_cast(PyArray_STRIDES(this->python_array())),
                                       static_cast(PyArray_NDIM(this->python_array())));
        m_backstrides = backstrides_type(*this);
        m_data = container_type(reinterpret_cast(PyArray_DATA(this->python_array())),
                                static_cast(PyArray_SIZE(this->python_array())));
    }

    template 
    inline auto pyarray::shape_impl() const -> const inner_shape_type&
    {
        return m_shape;
    }

    template 
    inline auto pyarray::strides_impl() const -> const inner_strides_type&
    {
        return m_strides;
    }

    template 
    inline auto pyarray::backstrides_impl() const -> const inner_backstrides_type&
    {
        // The pyarray object may be copied, invalidating m_backstrides. Building
        // it each time it is needed avoids tricky bugs.
        m_backstrides = backstrides_type(*this);
        return m_backstrides;
    }

    template 
    inline auto pyarray::data_impl() -> container_type&
    {
        return m_data;
    }

    template 
    inline auto pyarray::data_impl() const -> const container_type&
    {
        return m_data;
    }
}

#endif



Web Proxy Viewer  |  New URL  |  Original Page