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/converters/numpy_proxy.hpp>
10#include "./make_py_capsule.hpp"
11
12namespace nda::python {
13
14 using c2py::npy_type;
15
16 // Given an array or a view, it returns the numpy_proxy viewing its data
17 // NB : accepts ref, rvalue ref
18 // AUR is array<T,R> or array_view<T, R>, but NOT a the Array concept.
19 // It must be a container or a view.
20 template <MemoryArray AUR>
21 c2py::numpy_proxy make_numpy_proxy_from_array_or_view(AUR &&a)
23 {
24
25 using A = std::decay_t<AUR>;
26 using value_type = typename A::value_type; // NB May be const
27 using T = get_value_t<A>; // The canonical type without the possible const
28 static_assert(not std::is_reference_v<value_type>, "Logical Error");
29
30 // If T is a type which has a native Numpy equivalent, or it is PyObject * or pyref.
31 // we simply take a numpy of the data
32 if constexpr (c2py::has_npy_type<T>) {
33 std::vector<long> extents(A::rank), strides(A::rank);
34
35 for (int i = 0; i < A::rank; ++i) {
36 extents[i] = a.indexmap().lengths()[i];
37 strides[i] = a.indexmap().strides()[i] * sizeof(T);
38 }
39
40 return {A::rank, // dimension
41 npy_type<T>, // the npy type code
42 (void *)a.data(), // start of the data
43 std::is_const_v<value_type>, // if const, the numpy will be immutable in python
44 std::move(extents),
45 std::move(strides),
46 make_pycapsule(a.storage())}; // a PyCapsule with a SHARED view on the data
47 } else {
48 // If T is another type, which requires some conversion to python
49 // we make a new array of pyref and return a numpy view of it.
50 // each pyref handles the ownership of the object according to the T conversion rule,
51 // it is not the job of this function to handle this.
52 // We need to distinguish the special case where a is a RValue, in which case, the python will steal the ownership
53 // by moving the elements one by one.
54
55 nda::array<c2py::pyref, A::rank> aobj = map([](auto &&x) {
56 if constexpr (is_regular_v<AUR> and !std::is_reference_v<AUR>)
57 // nda::array rvalue (i.e. AUR is an array, and NOT a ref, so it matches array &&) Be sure to move
58 return c2py::py_converter<T>::c2py(std::move(x));
59 else
60 return c2py::py_converter<T>::c2py(x);
61 })(a);
62 return make_numpy_proxy_from_array_or_view(std::move(aobj));
63 }
64 }
65
66} // 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.