-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathPyArray.hpp
292 lines (254 loc) · 10.3 KB
/
PyArray.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
/*
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Copyright (c) 2019, Lawrence Livermore National Security, LLC.
*
* Produced at the Lawrence Livermore National Laboratory
*
* LLNL-CODE-746361
*
* All rights reserved. See COPYRIGHT for details.
*
* This file is part of the GEOSX Simulation Framework.
*
* GEOSX is a free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License (as published by the
* Free Software Foundation) version 2.1 dated February 1999.
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
/**
* @file
*/
#pragma once
// Source includes
#include "pythonForwardDeclarations.hpp"
#include "numpyHelpers.hpp"
#include "../Array.hpp"
#include "../Macros.hpp"
#include "../limits.hpp"
#include "../output.hpp"
#include "pythonHelpers.hpp"
// System includes
#include <string>
#include <memory>
#include <typeindex>
namespace LvArray
{
namespace python
{
namespace internal
{
/**
* @class PyArrayWrapperBase
* @brief Provides A virtual Python wrapper around an Array.
*/
class PyArrayWrapperBase
{
public:
/**
* @brief Default destructor.
*/
virtual ~PyArrayWrapperBase() = default;
/**
* @brief Return the access level for the Array.
* @return The access level for the array.
*/
virtual int getAccessLevel() const
{ return m_accessLevel; }
/**
* @brief Set the access level for the Array.
* @param accessLevel The access level.
* @param memorySpace The space to access the array.
*/
virtual void setAccessLevel( int const accessLevel, int const memorySpace ) = 0;
/**
* @brief Return a string representing to the underlying Array type.
* @return A string representing the underlying Array type.
*/
virtual std::string repr() const = 0;
/**
* @brief Return the number of dimensions in the Array.
* @return The number of dimensions in the array.
* @note This wraps Array::ndim.
*/
virtual int ndim() const = 0;
/**
* @brief Resize the default dimension of the Array.
* @param newSize The new size of the default dimension.
* @note This wraps Array::resize( INDEX_TYPE ).
*/
virtual void resize( long long const newSize ) = 0;
/**
* @brief Resize all the dimensions of the Array.
* @param newSizes The new sizes of each dimension, must be of length @c ndim().
* @note Ths wraps Array::resize( int, INDEX_TYPE const * )
*/
virtual void resize( long long const * const newSizes ) = 0;
/**
* @brief Return a NumPy ndarray wrapping the Array.
* @details This is a shallow copy and is modifiable if @c modifiable() is @c true.
* @return A NumPy ndarray wrapping the Array.
* @note Iff this wraps a 1D Array of @c std::string then then a copy of the values is returned
* in a Python list.
*/
virtual PyObject * toNumPy() const = 0;
/**
* @brief Return the type of the values stored in the Array.
* @return The type of the values stored in the Array.
*/
virtual std::type_index valueType() const = 0;
protected:
/// If the array can be modified.
int m_accessLevel = static_cast< int >( LvArray::python::PyModify::READ_ONLY );
};
/**
* @class PyArrayWrapper
* @brief An implements the PyArrayWrapperBase interface for a particular Array type.
* @tparam T The type of values in the array.
* @tparam NDIM The dimensionality of the array.
* @tparam PERM The permutation of the array.
* @tparam INDEX_TYPE The index type of the array.
* @tparam BUFFER_TYPE The buffer type of the array.
* @note This holds a reference to the wrapped Array, you must ensure that the reference remains valid
* for the lifetime of this object.
*/
template< typename T,
int NDIM,
typename PERM,
typename INDEX_TYPE,
template< typename > class BUFFER_TYPE >
class PyArrayWrapper final : public PyArrayWrapperBase
{
public:
/**
* @brief Constructor.
* @param array The array to wrap.
* @param accessLevel The access level (see PyModify).
*/
PyArrayWrapper( Array< T, NDIM, PERM, INDEX_TYPE, BUFFER_TYPE > & array,
int accessLevel = static_cast< int >( LvArray::python::PyModify::READ_ONLY )):
PyArrayWrapperBase(),
m_array( array )
{
setAccessLevel( accessLevel, static_cast< int >(LvArray::MemorySpace::host));
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual ~PyArrayWrapper() = default;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual std::string repr() const final override
{ return system::demangleType< Array< T, NDIM, PERM, INDEX_TYPE, BUFFER_TYPE > >(); }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual int ndim() const final override
{ return NDIM; }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual void resize( long long const newSize ) final override
{ m_array.resize( integerConversion< INDEX_TYPE >( newSize ) ); }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual void resize( long long const * const newSizes ) final override
{
INDEX_TYPE dims[ NDIM ];
for( int i = 0; i < NDIM; ++i )
{ dims[ i ] = integerConversion< INDEX_TYPE >( newSizes[ i ] ); }
m_array.resize( NDIM, dims );
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual void setAccessLevel( int accessLevel, int memorySpace ) final override
{
LVARRAY_UNUSED_VARIABLE( memorySpace );
if( accessLevel >= static_cast< int >( LvArray::python::PyModify::RESIZEABLE ) )
{
// touch
}
m_accessLevel = accessLevel;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual PyObject * toNumPy() const final override
{
m_array.move( MemorySpace::host, m_accessLevel != static_cast< int >(PyModify::READ_ONLY) );
return toNumPyImpl();
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual std::type_index valueType() const final override
{
if( std::is_same< T, std::string >::value && NDIM == 1 )
{ return std::type_index( typeid( PyObject * ) ); }
return std::type_index( typeid( T ) );
}
private:
/**
* @brief Create a NumPy ndarray for an Array that doesn't contain std::strings.
* @return A NumPy ndarray, it is not modifiable if @c getAccessLevel() is @c READ_ONLY
*/
template< typename _T=T >
std::enable_if_t< !std::is_same< _T, std::string >::value, PyObject * >
toNumPyImpl() const
{
return createNumPyArray( m_array.data(),
m_accessLevel >= static_cast< int >( LvArray::python::PyModify::MODIFIABLE ),
NDIM,
m_array.dims(),
m_array.strides() );
}
/**
* @brief Create Python list of strings from a 1D Array of strings.
* @return A Python list of strings from a 1D Array of strings.
* @note The list is a copy.
*/
template< typename _T=T >
std::enable_if_t< std::is_same< _T, std::string >::value && NDIM == 1, PyObject * >
toNumPyImpl() const
{ return createPyListOfStrings( m_array.data(), integerConversion< long long >( m_array.size() ) ); }
/// The wrapped Array.
Array< T, NDIM, PERM, INDEX_TYPE, BUFFER_TYPE > & m_array;
};
/**
* @brief Create a Python object corresponding to @c array.
* @param array The Array to export to Python.
* @return A Python object corresponding to @c array.
*/
PyObject * create( std::unique_ptr< internal::PyArrayWrapperBase > && array );
} // namespace internal
/**
* @brief Create a MODIFIABLE Python object corresponding to @c array.
* @tparam T The type of values in the array.
* @tparam NDIM The dimensionality of the array.
* @tparam PERM The permutation of the array.
* @tparam INDEX_TYPE The index type of the array.
* @tparam BUFFER_TYPE The buffer type of the array.
* @param array The Array to export to Python.
* @return A Python object corresponding to @c array.
* @note The returned Python object holds a reference to @c array, you must ensure
* the reference remains valid throughout the lifetime of the object.
*/
template< typename T, int NDIM, typename PERM, typename INDEX_TYPE, template< typename > class BUFFER_TYPE >
std::enable_if_t< internal::canExportToNumpy< T > || (std::is_same< T, std::string >::value && NDIM == 1 ), PyObject * >
create( Array< T, NDIM, PERM, INDEX_TYPE, BUFFER_TYPE > & array )
{
using WrapperType = internal::PyArrayWrapper< T, NDIM, PERM, INDEX_TYPE, BUFFER_TYPE >;
return internal::create( std::make_unique< WrapperType >( array, static_cast< int >(LvArray::python::PyModify::MODIFIABLE) ) );
}
/**
* @brief Create a READ_ONLY Python object corresponding to @c array.
* @tparam T The type of values in the array.
* @tparam NDIM The dimensionality of the array.
* @tparam PERM The permutation of the array.
* @tparam INDEX_TYPE The index type of the array.
* @tparam BUFFER_TYPE The buffer type of the array.
* @param array The Array to export to Python.
* @return A Python object corresponding to @c array.
* @note The returned Python object holds a reference to @c array, you must ensure
* the reference remains valid throughout the lifetime of the object.
*/
template< typename T, int NDIM, typename PERM, typename INDEX_TYPE, template< typename > class BUFFER_TYPE >
std::enable_if_t< internal::canExportToNumpy< T > || (std::is_same< T, std::string >::value && NDIM == 1 ), PyObject * >
create( Array< T, NDIM, PERM, INDEX_TYPE, BUFFER_TYPE > const & array )
{
using WrapperType = internal::PyArrayWrapper< T, NDIM, PERM, INDEX_TYPE, BUFFER_TYPE >;
return internal::create( std::make_unique< WrapperType >( const_cast< Array< T, NDIM, PERM, INDEX_TYPE, BUFFER_TYPE > & >( array ), static_cast< int >(LvArray::python::PyModify::READ_ONLY) ) );
}
/**
* @brief Return the Python type for the Array.
* @return The Python type object for the Array.
*/
PyTypeObject * getPyArrayType();
} // namespace python
} // namespace LvArray