NumCpp  2.12.1
A Templatized Header Only C++ Implementation of the Python NumPy Library
PybindInterface.hpp
Go to the documentation of this file.
1
28#pragma once
29
30#ifdef NUMCPP_INCLUDE_PYBIND_PYTHON_INTERFACE
31
32#include "pybind11/numpy.h"
33#include "pybind11/pybind11.h"
34
35#include <map>
36#include <utility>
37
38#include "NumCpp/Core/Enums.hpp"
40#include "NumCpp/Core/Shape.hpp"
41#include "NumCpp/NdArray.hpp"
42
43namespace nc::pybindInterface
44{
46 enum class ReturnPolicy
47 {
48 COPY,
49 REFERENCE,
50 TAKE_OWNERSHIP
51 };
52
53 static const std::map<ReturnPolicy, std::string> returnPolicyStringMap = { { ReturnPolicy::COPY, "COPY" },
54 { ReturnPolicy::REFERENCE, "REFERENCE" },
55 { ReturnPolicy::TAKE_OWNERSHIP,
56 "TAKE_OWNERSHIP" } };
57
58 template<typename dtype>
59 using pbArray = pybind11::array_t<dtype, pybind11::array::c_style>;
60 using pbArrayGeneric = pybind11::array;
61
62 //============================================================================
70 template<typename dtype>
71 NdArray<dtype> pybind2nc(pbArray<dtype>& numpyArray)
72 {
73 const auto dataPtr = numpyArray.mutable_data();
74 switch (numpyArray.ndim())
75 {
76 case 0:
77 {
78 return NdArray<dtype>(dataPtr, 0, 0, PointerPolicy::COPY);
79 }
80 case 1:
81 {
82 const auto size = static_cast<uint32>(numpyArray.size());
83 return NdArray<dtype>(dataPtr, 1, size, PointerPolicy::COPY);
84 }
85 case 2:
86 {
87 const auto numRows = static_cast<uint32>(numpyArray.shape(0));
88 const auto numCols = static_cast<uint32>(numpyArray.shape(1));
89 return NdArray<dtype>(dataPtr, numRows, numCols, PointerPolicy::COPY);
90 }
91 default:
92 {
93 THROW_INVALID_ARGUMENT_ERROR("input array must be no more than 2 dimensional.");
94 return {};
95 }
96 }
97 }
98
99 //============================================================================
107 template<typename dtype>
108 NdArray<dtype> pybind2nc_copy(const pbArray<dtype>& numpyArray)
109 {
110 const auto dataPtr = numpyArray.data();
111 switch (numpyArray.ndim())
112 {
113 case 0:
114 {
115 return NdArray<dtype>(dataPtr, 0, 0);
116 }
117 case 1:
118 {
119 const auto size = static_cast<uint32>(numpyArray.size());
120 return NdArray<dtype>(dataPtr, 1, size);
121 }
122 case 2:
123 {
124 const auto numRows = static_cast<uint32>(numpyArray.shape(0));
125 const auto numCols = static_cast<uint32>(numpyArray.shape(1));
126 return NdArray<dtype>(dataPtr, numRows, numCols);
127 }
128 default:
129 {
130 THROW_INVALID_ARGUMENT_ERROR("input array must be no more than 2 dimensional.");
131 return {};
132 }
133 }
134 }
135
136 //============================================================================
143 template<typename dtype>
144 pbArrayGeneric nc2pybind(const NdArray<dtype>& inArray)
145 {
146 const Shape inShape = inArray.shape();
147 const std::vector<pybind11::ssize_t> shape{ static_cast<pybind11::ssize_t>(inShape.rows),
148 static_cast<pybind11::ssize_t>(inShape.cols) };
149 const std::vector<pybind11::ssize_t> strides{ static_cast<pybind11::ssize_t>(inShape.cols * sizeof(dtype)),
150 static_cast<pybind11::ssize_t>(sizeof(dtype)) };
151 return pbArrayGeneric(shape, strides, inArray.data());
152 }
153
154 //============================================================================
162 template<typename dtype>
163 pbArrayGeneric nc2pybind(NdArray<dtype>& inArray, ReturnPolicy returnPolicy)
164 {
165 const Shape inShape = inArray.shape();
166 const std::vector<pybind11::ssize_t> shape{ static_cast<pybind11::ssize_t>(inShape.rows),
167 static_cast<pybind11::ssize_t>(inShape.cols) };
168 const std::vector<pybind11::ssize_t> strides{ static_cast<pybind11::ssize_t>(inShape.cols * sizeof(dtype)),
169 static_cast<pybind11::ssize_t>(sizeof(dtype)) };
170
171 switch (returnPolicy)
172 {
173 case ReturnPolicy::COPY:
174 {
175 return nc2pybind(inArray);
176 }
177 case ReturnPolicy::REFERENCE:
178 {
179 typename pybind11::capsule reference(inArray.data(), [](void* /*ptr*/) {});
180 return pbArrayGeneric(shape, strides, inArray.data(), reference);
181 }
182 case ReturnPolicy::TAKE_OWNERSHIP:
183 {
184 typename pybind11::capsule garbageCollect(inArray.dataRelease(),
185 [](void* ptr)
186 {
187 auto* dataPtr = reinterpret_cast<dtype*>(ptr);
188 delete[] dataPtr;
189 });
190 return pbArrayGeneric(shape, strides, inArray.data(), garbageCollect);
191 }
192 default:
193 {
194 std::stringstream sstream;
195 sstream << "ReturnPolicy " << returnPolicyStringMap.at(returnPolicy) << " has not been implemented yet"
196 << std::endl;
197 THROW_INVALID_ARGUMENT_ERROR(sstream.str());
198 }
199 }
200 }
201} // namespace nc::pybindInterface
202#endif
#define THROW_INVALID_ARGUMENT_ERROR(msg)
Definition: Error.hpp:37
uint32 size(const NdArray< dtype > &inArray) noexcept
Definition: size.hpp:43
Shape shape(const NdArray< dtype > &inArray) noexcept
Definition: Functions/Shape.hpp:42
std::uint32_t uint32
Definition: Types.hpp:40