Nektar++
Python/BasicUtils/SharedArray.hpp
Go to the documentation of this file.
1///////////////////////////////////////////////////////////////////////////////
2//
3// File: SharedArray.cpp
4//
5// For more information, please see: http://www.nektar.info
6//
7// The MIT License
8//
9// Copyright (c) 2006 Scientific Computing and Imaging Institute,
10// University of Utah (USA) and Department of Aeronautics, Imperial
11// College London (UK).
12//
13// Permission is hereby granted, free of charge, to any person obtaining a
14// copy of this software and associated documentation files (the "Software"),
15// to deal in the Software without restriction, including without limitation
16// the rights to use, copy, modify, merge, publish, distribute, sublicense,
17// and/or sell copies of the Software, and to permit persons to whom the
18// Software is furnished to do so, subject to the following conditions:
19//
20// The above copyright notice and this permission notice shall be included
21// in all copies or substantial portions of the Software.
22//
23// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29// DEALINGS IN THE SOFTWARE.
30//
31// Description: Python wrapper for ShareArray.
32//
33///////////////////////////////////////////////////////////////////////////////
34
35#ifndef NEKTAR_LIBUTILITIES_PYTHON_BASICUTILS_SHAREDARRAY_HPP
36#define NEKTAR_LIBUTILITIES_PYTHON_BASICUTILS_SHAREDARRAY_HPP
37
39
41
42#include <type_traits>
43
45{
46
47/// Template utility to determine whether @tparam T is a Nektar::Array<OneD, .>.
48template <typename T> struct is_nekarray_oned : std::false_type
49{
50};
51
52template <typename T>
53struct is_nekarray_oned<Nektar::Array<Nektar::OneD, T>> : std::true_type
54{
55};
56
57template <typename T>
58struct is_nekarray_oned<const Nektar::Array<Nektar::OneD, T>> : std::true_type
59{
60};
61
62/**
63 * @brief Convert for Array<OneD, T> to Python list of objects for numeric
64 * types, self-array types and shared_ptr types.
65 *
66 * @tparam Type The overall type Array<OneD, T>
67 * @tparam T The data type T
68 */
69template <typename Type, typename T> struct nekarray_caster
70{
71public:
72 PYBIND11_TYPE_CASTER(Type, const_name("Array<OneD, ") +
73 handle_type_name<T>::name + const_name(">"));
74
75 bool load(handle src, bool enable)
76 {
77 return load_impl(src, enable);
78 }
79
80 static handle cast(Nektar::Array<Nektar::OneD, T> const &arr,
81 return_value_policy policy, handle parent)
82 {
83 return cast_impl(arr, policy, parent);
84 }
85
86 template <typename U = T,
87 std::enable_if_t<std::is_arithmetic_v<U>, bool> = true>
88 bool load_impl(handle src, bool)
89 {
90 if (!array_t<U>::check_(src))
91 {
92 return false;
93 }
94
95 auto arr = array_t<U, array::c_style | array::forcecast>::ensure(src);
96 if (!arr)
97 {
98 return false;
99 }
100
101 if (arr.ndim() != 1)
102 {
103 return false;
104 }
105
106 using nonconst_t = typename std::remove_const<U>::type;
107 value = Nektar::Array<Nektar::OneD, T>(arr.shape(0),
108 (nonconst_t *)arr.data(),
109 (void *)src.ptr(), &decrement);
110
111 // We increase the refcount on src so that even if on the Python side we
112 // go out of scope, the data will still exist in at least one reference
113 // until it is no longer used on the C++ side.
114 src.inc_ref();
115
116 return true;
117 }
118
119 static void decrement(void *objPtr)
120 {
121 if (!Py_IsInitialized())
122 {
123 // In deinitialisation phase, reference counters appear to not be
124 // terribly robust; decremementing counters here can lead to
125 // segfaults during program exit in some cases.
126 return;
127 }
128
129 // Otherwise decrement reference counter.
130 handle obj((PyObject *)objPtr);
131 obj.dec_ref();
132 }
133
134 template <typename U = T,
135 std::enable_if_t<std::is_arithmetic_v<U>, bool> = true>
137 return_value_policy, handle)
138 {
139 // Create a Python capsule to hold a pointer that contains a lightweight
140 // copy of arr. Uhat way we guarantee Python will still have access to
141 // the memory allocated inside arr even if arr is deallocated in C++.
142 capsule c(new Nektar::Array<Nektar::OneD, U>(arr), [](void *ptr) {
145 delete tmp;
146 });
147
148 // Create the NumPy array, passing the capsule. When we go out of scope,
149 // c's reference count will have been reduced by 1, but array increases
150 // the reference count when it assigns the base to the array.
151 array_t<U> array({arr.size()}, {}, arr.data(), c);
152
153 // This causes the array to be released without decreasing its reference
154 // count, otherwise the array would be deallocated immediately when this
155 // function returns.
156 return array.release();
157 }
158
159 template <typename U = T,
160 std::enable_if_t<
161 is_shared_ptr<typename std::remove_const<U>::type>::value ||
163 bool> = true>
164 bool load_impl(handle src, bool)
165 {
166 if (!py::isinstance<py::list>(src))
167 {
168 return false;
169 }
170
171 py::list l = py::cast<py::list>(src);
172 const std::size_t nItems = l.size();
173
174 using nonconst_t = typename std::remove_const<U>::type;
175 auto tmparr = Nektar::Array<Nektar::OneD, nonconst_t>(nItems);
176
177 // We'll need to construct a temporary vector to hold each item in the
178 // list.
179 try
180 {
181 for (std::size_t i = 0; i < nItems; ++i)
182 {
183 tmparr[i] = py::cast<nonconst_t>(l[i]);
184 }
185 }
186 catch (...)
187 {
188 return false;
189 }
190
191 value = tmparr;
192
193 return true;
194 }
195
196 template <typename U = T,
197 std::enable_if_t<
198 is_shared_ptr<typename std::remove_const<U>::type>::value ||
200 bool> = true>
202 return_value_policy, handle)
203 {
204 py::list tmp;
205
206 for (std::size_t i = 0; i < arr.size(); ++i)
207 {
208 tmp.append(arr[i]);
209 }
210
211 return tmp.release();
212 }
213};
214
215template <typename Type>
216struct type_caster<Nektar::Array<Nektar::OneD, Type>>
217 : nekarray_caster<Nektar::Array<Nektar::OneD, Type>, Type>
218{
219};
220
221} // namespace pybind11::detail
222
223#endif
Template utility to determine whether.
Convert for Array<OneD, T> to Python list of objects for numeric types, self-array types and shared_p...
static handle cast_impl(Nektar::Array< Nektar::OneD, U > const &arr, return_value_policy, handle)
static handle cast(Nektar::Array< Nektar::OneD, T > const &arr, return_value_policy policy, handle parent)
PYBIND11_TYPE_CASTER(Type, const_name("Array<OneD, ")+handle_type_name< T >::name+const_name(">"))
static handle cast_impl(Nektar::Array< Nektar::OneD, T > const &arr, return_value_policy, handle)