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