TRIQS/nda 1.3.0
Multi-dimensional array library for C++
Loading...
Searching...
No Matches
make_numpy_proxy_from_array.hpp
1// Copyright (c) 2019--present, The Simons Foundation
2// This file is part of TRIQS/nda and is licensed under the Apache License, Version 2.0.
3// SPDX-License-Identifier: Apache-2.0
4// See LICENSE in the root of this distribution for details.
5
6#pragma once
7#include <vector>
8#include <nda/nda.hpp>
9#include <c2py/py_converter.hpp>
10#include <c2py/converters/numpy_proxy.hpp>
11#include "./make_py_capsule.hpp"
12
13namespace nda::python {
14
15 using c2py::npy_type;
16
17 // Given an array or a view, it returns the numpy_proxy viewing its data
18 // NB : accepts ref, rvalue ref
19 // AUR is array<T,R> or array_view<T, R>, but NOT a the Array concept.
20 // It must be a container or a view.
21 template <MemoryArray AUR>
22 c2py::numpy_proxy make_numpy_proxy_from_array_or_view(AUR &&a)
24 {
25
26 using A = std::decay_t<AUR>;
27 using value_type = typename A::value_type; // NB May be const
28 using T = get_value_t<A>; // The canonical type without the possible const
29 static_assert(not std::is_reference_v<value_type>, "Logical Error");
30
31 // If T is a type which has a native Numpy equivalent, or it is PyObject * or pyref.
32 // we simply take a numpy of the data
33 if constexpr (c2py::has_npy_type<T>) {
34 std::vector<long> extents(A::rank), strides(A::rank);
35
36 for (int i = 0; i < A::rank; ++i) {
37 extents[i] = a.indexmap().lengths()[i];
38 strides[i] = a.indexmap().strides()[i] * sizeof(T);
39 }
40
41 return {A::rank, // dimension
42 npy_type<T>, // the npy type code
43 (void *)a.data(), // start of the data
44 std::is_const_v<value_type>, // if const, the numpy will be immutable in python
45 std::move(extents),
46 std::move(strides),
47 make_pycapsule(a.storage())}; // a PyCapsule with a SHARED view on the data
48 } else {
49 // If T is another type, which requires some conversion to python
50 // we make a new array of pyref and return a numpy view of it.
51 // each pyref handles the ownership of the object according to the T conversion rule,
52 // it is not the job of this function to handle this.
53 // We need to distinguish the special case where a is a RValue, in which case, the python will steal the ownership
54 // by moving the elements one by one.
55
56 nda::array<c2py::pyref, A::rank> aobj = map([](auto &&x) {
57 if constexpr (is_regular_v<AUR> and !std::is_reference_v<AUR>)
58 // nda::array rvalue (i.e. AUR is an array, and NOT a ref, so it matches array &&) Be sure to move
59 return c2py::py_converter<T>::c2py(std::move(x));
60 else
61 return c2py::py_converter<T>::c2py(x);
62 })(a);
63 return make_numpy_proxy_from_array_or_view(std::move(aobj));
64 }
65 }
66
67} // namespace nda::python
mapped< F > map(F f)
Create a lazy function call expression on arrays/views.
Definition map.hpp:206
basic_array< ValueType, Rank, Layout, 'A', ContainerPolicy > array
Alias template of an nda::basic_array with an 'A' algebra.
constexpr bool is_regular_v
Constexpr variable that is true if type A is a regular array, i.e. an nda::basic_array.
Definition traits.hpp:144
std::decay_t< decltype(get_first_element(std::declval< A const >()))> get_value_t
Get the value type of an array/view or a scalar type.
Definition traits.hpp:191
constexpr bool is_regular_or_view_v
Constexpr variable that is true if type A is either a regular array or a view.
Definition traits.hpp:162
Includes all relevant headers for the core nda library.