MatlabParamParser.h
Go to the documentation of this file.
1 #pragma once
2 #include "mex.h"
3 #include "matrix.h"
4 #include <string>
5 #include <memory>
6 #include <vector>
7 #include <array>
8 #include <type_traits>
9 
10 namespace std
11 {
12 template <bool B> using bool_constant = integral_constant<bool, B>;
13 }
14 
16 template <typename T> struct is_array_type : std::false_type {};
17 template <typename T> struct is_array_type<std::vector<T>> : std::true_type { using inner_t = T; };
18 
19 // TODO: consider using nested impl/detail namespace
21 {
22  // in charge of which overloads to use
23 
24  // helper information for overloaded functions
25  template <typename T, typename voider = void> struct mx_wrapper_fns
26  {
27  static T parse(const mxArray* cell);
28  static mxArray* wrap(T&& var);
29  static void destroy(const mxArray* cell);
30  };
31  template <typename T, typename = void> struct mx_wrapper;
32  // enums are exposed as 64bit integers, using the underlying type to determine signedness
33  template <typename T> struct mx_wrapper<T, typename std::enable_if<std::is_enum<T>::value>::type>
34  {
35  private:
36  using signed_t = std::integral_constant<mxClassID, mxINT64_CLASS>;
37  using unsigned_t = std::integral_constant<mxClassID, mxUINT64_CLASS>;
39  public:
40 // static const mxClassID value = /*value_t::value*/ signed_t::value;
41  using value = signed_t;
43  };
44  // pointers are cast to uint64_t because matlab doesn't have a concept of pointers
45  template <typename T> struct mx_wrapper<T, typename std::enable_if<std::is_pointer<T>::value>::type>
46  {
47  // static const mxClassID value = mxUINT64_CLASS;
48  using value = std::integral_constant<mxClassID, mxUINT64_CLASS>;
49  using type = uint64_t;
50  };
51  // bools are exposed as matlab's native logical type
52  template <> struct mx_wrapper<bool, void>
53  {
54 // static const mxClassID value = mxLOGICAL_CLASS;
55  using value = std::integral_constant<mxClassID, mxLOGICAL_CLASS>;
56  using type = mxLogical;
57  };
58  // floating points are exposed as matlab's native double type
59  template <typename T> struct mx_wrapper<T, typename std::enable_if<std::is_floating_point<T>::value>::type>
60  {
61 // static const mxClassID value = mxDOUBLE_CLASS;
62  using value = std::integral_constant<mxClassID, mxDOUBLE_CLASS>;
63  using type = double;
64  };
65  // integral types are exposed like enums
66  template <typename T> struct mx_wrapper<T, typename std::enable_if<std::is_integral<T>::value>::type>
67  {
68  private:
69  using signed_t = std::integral_constant<mxClassID, mxINT64_CLASS>;
70  using unsigned_t = std::integral_constant<mxClassID, mxUINT64_CLASS>;
72  public:
73 // static const mxClassID value = value_t::value;
74  using value = value_t;
76  };
77  // uint8_t, uint16_t, uint32_t, uint64_t, int8_t, int16_t, int32_t, and int64_t
78  // are exposed as the relevant native Matlab type
79  template <> struct mx_wrapper<uint8_t> {
80  using value = std::integral_constant<mxClassID, mxUINT8_CLASS>;
81  using type = uint8_t;
82  };
83  template <> struct mx_wrapper<uint16_t> {
84  using value = std::integral_constant<mxClassID, mxUINT16_CLASS>;
85  using type = uint16_t;
86  };
87  template <> struct mx_wrapper<uint32_t> {
88  using value = std::integral_constant<mxClassID, mxUINT32_CLASS>;
89  using type = uint32_t;
90  };
91  template <> struct mx_wrapper<uint64_t> {
92  using value = std::integral_constant<mxClassID, mxUINT64_CLASS>;
93  using type = uint64_t;
94  };
95  template <> struct mx_wrapper<int8_t> {
96  using value = std::integral_constant<mxClassID, mxINT8_CLASS>;
97  using type = int8_t;
98  };
99  template <> struct mx_wrapper<int16_t> {
100  using value = std::integral_constant<mxClassID, mxINT16_CLASS>;
101  using type = int16_t;
102  };
103  template <> struct mx_wrapper<int32_t> {
104  using value = std::integral_constant<mxClassID, mxINT32_CLASS>;
105  using type = int32_t;
106  };
107  template <> struct mx_wrapper<int64_t> {
108  using value = std::integral_constant<mxClassID, mxINT64_CLASS>;
109  using type = int64_t;
110  };
111  // by default non-basic types are wrapped as pointers
112  template <typename T> struct mx_wrapper<T, typename std::enable_if<!is_basic_type<T>::value>::type> : mx_wrapper<void*> {};
113  template <typename T, typename = void> struct type_traits {
114  // KEEP THESE COMMENTED. They are only here to show the signature
115  // should you choose to declare these functions
116  // static rs2_internal_t* to_internal(T&& val);
117  // static T from_internal(rs2_internal_t* ptr);
118  };
120  private:
121  template <typename T> struct detector {
122  struct fallback { int to_internal, from_internal, use_cells; };
123  struct derived : type_traits<T>, fallback {};
124  template <typename U, U> struct checker;
125  typedef char ao1[1];
126  typedef char ao2[2];
127  template <typename U> static ao1& check_to(checker<int fallback::*, &U::to_internal> *);
128  template <typename U> static ao2& check_to(...);
129  template <typename U> static ao1& check_from(checker<int fallback::*, &U::from_internal> *);
130  template <typename U> static ao2& check_from(...);
131  template <typename U> static ao1& check_cells(checker<int fallback::*, &U::use_cells> *);
132  template <typename U> static ao2& check_cells(...);
133 // template <typename, typename = void> struct use_cells_t : false_type {};
134 // template <typename U> struct use_cells_t<U, typename std::enable_if<sizeof(check_cells<U>(0)) == 2>::type>
135 // : T::use_cells {};
136 
137  enum { has_to = sizeof(check_to<derived>(0)) == 2 };
138  enum { has_from = sizeof(check_from<derived>(0)) == 2 };
139 // enum { use_cells = use_cells_t<derived>::value };
140  enum { use_cells = sizeof(check_cells<derived>(0)) == 2 };
141  };
142  template <typename T> using internal_t = typename type_traits<T>::rs2_internal_t;
143  public:
144  // selected if type_traits<T>::to_internal exists
145  template <typename T> static typename std::enable_if<detector<T>::has_to, internal_t<T>*>::type
147  // selected if it doesnt
148  template <typename T> static typename std::enable_if<!detector<T>::has_to, internal_t<T>*>::type
149  to_internal(T&& val) { mexLock(); return new internal_t<T>(val); }
150 
151  // selected if type_traits<T>::from_internal exists
152  template <typename T> static typename std::enable_if<detector<T>::has_from, T>::type
154  // selected if it doesnt
155  template <typename T> static typename std::enable_if<!detector<T>::has_from, T>::type
156  from_internal(internal_t<T>* ptr) { return T(*ptr); }
157  template <typename T> using use_cells = std::integral_constant<bool, detector<T>::use_cells>;
158  };
159 
160  // TODO: try/catch->err msg?
161  template <typename T> static T parse(const mxArray* cell) { return mx_wrapper_fns<T>::parse(cell); }
162  template <typename T> static mxArray* wrap(T&& var) { return mx_wrapper_fns<T>::wrap(std::move(var)); };
163  template <typename T> static void destroy(const mxArray* cell) { return mx_wrapper_fns<T>::destroy(cell); }
164 
165  template <typename T> static typename std::enable_if<!is_basic_type<T>::value, std::vector<T>>::type parse_array(const mxArray* cells);
166  template <typename T> static typename std::enable_if<is_basic_type<T>::value, std::vector<T>>::type parse_array(const mxArray* cells);
167 
168  template <typename T> static typename std::enable_if<!is_basic_type<T>::value && !traits_trampoline::use_cells<T>::value, mxArray*>::type wrap_array(const T* var, size_t length);
169  template <typename T> static typename std::enable_if<!is_basic_type<T>::value && traits_trampoline::use_cells<T>::value, mxArray*>::type wrap_array(const T* var, size_t length);
170  template <typename T> static typename std::enable_if<is_basic_type<T>::value, mxArray*>::type wrap_array(const T* var, size_t length);
171 };
172 
173 #include "rs2_type_traits.h"
174 
175 // for basic types (aka arithmetic, pointer, and enum types)
176 template <typename T> struct MatlabParamParser::mx_wrapper_fns<T, typename std::enable_if<is_basic_type<T>::value && !extra_checks<T>::value && !is_array_type<T>::value>::type>
177 {
178  // Use full width types when converting integers.
179  // Always using full width makes some things easier, and doing it this way
180  // still allows us to use the mx_wrapper<T> class to send more exact types
181  // for frame data arrays
184  static T parse(const mxArray* cell)
185  {
186  // obtain pointer to data, cast to proper matlab type
187  auto *p = static_cast<typename wrapper::type*>(mxGetData(cell));
188  // dereference pointer and cast to correct C++ type
189  return T(*p);
190  }
191  static mxArray* wrap(T&& var)
192  {
193  // request 1x1 matlab matrix of correct type
194  mxArray* cell = mxCreateNumericMatrix(1, 1, wrapper::value::value, mxREAL);
195  // access matrix's data as pointer to correct C++ type
196  auto *outp = static_cast<typename wrapper::type*>(mxGetData(cell));
197  // cast object to correct C++ type and then store it in the matrix
198  *outp = typename wrapper::type(var);
199  return cell;
200  }
201  static void destroy(const mxArray* cell)
202  {
203  static_assert(!is_basic_type<T>::value, "Trying to destroy basic type. This shouldn't happen.");
204  static_assert(is_basic_type<T>::value, "Non-basic type ended up in basic type's destroy function. How?");
205  }
206 };
207 
208 // default for non-basic types (eg classes)
209 template<typename T> struct MatlabParamParser::mx_wrapper_fns<T, typename std::enable_if<!is_basic_type<T>::value && !extra_checks<T>::value && !is_array_type<T>::value>::type>
210 {
211  // librealsense types are sent to matlab using a pointer to the internal type.
212  // to get it back from matlab we first parse that pointer and then reconstruct the C++ wrapper
213  static T parse(const mxArray* cell)
214  {
215  using internal_t = typename type_traits<T>::rs2_internal_t;
216  return traits_trampoline::from_internal<T>(mx_wrapper_fns<internal_t*>::parse(cell));
217  }
218 
219  static mxArray* wrap(T&& var)
220  {
221  using internal_t = typename type_traits<T>::rs2_internal_t;
222  return mx_wrapper_fns<internal_t*>::wrap(traits_trampoline::to_internal<T>(std::move(var)));
223  }
224 
225  static void destroy(const mxArray* cell)
226  {
227  using internal_t = typename type_traits<T>::rs2_internal_t;
228  // get pointer to the internal type we put on the heap
229  auto ptr = mx_wrapper_fns<internal_t*>::parse(cell);
230  delete ptr;
231  // signal to matlab that the wrapper owns one fewer objects
232  mexUnlock();
233  }
234 };
235 
236 // simple helper overload to refer std::array and std::vector to wrap_array
237 template<typename T> struct MatlabParamParser::mx_wrapper_fns<T, typename std::enable_if<is_array_type<T>::value>::type>
238 {
239  static T parse(const mxArray* cell)
240  {
241  return MatlabParamParser::parse_array<typename is_array_type<T>::inner_t>(cell);
242  }
243  static mxArray* wrap(T&& var)
244  {
245  return MatlabParamParser::wrap_array(var.data(), var.size());
246  }
247 };
248 
249 // overload for wrapping C-strings. TODO: do we need special parsing too?
251 {
252  return mxCreateString(str);
253 }
254 
256 {
257  auto str = mxArrayToString(cell);
258  auto ret = std::string(str);
259  mxFree(str);
260  return ret;
261 }
263 {
264  return mx_wrapper_fns<const char*>::wrap(str.c_str());
265 }
266 
268 {
269  static std::chrono::nanoseconds parse(const mxArray* cell)
270  {
271  auto ptr = static_cast<double*>(mxGetData(cell));
272  return std::chrono::nanoseconds{ static_cast<long long>(*ptr * 1e6) }; // convert from milliseconds, smallest time unit that's easy to work with in matlab
273  }
274  static mxArray* wrap(std::chrono::nanoseconds&& dur)
275  {
276  auto cell = mxCreateNumericMatrix(1, 1, mxDOUBLE_CLASS, mxREAL);
277  auto ptr = static_cast<double*>(mxGetData(cell));
278  *ptr = dur.count() / 1.e6; // convert to milliseconds, smallest time unit that's easy to work with in matlab
279  return cell;
280  }
281 };
282 
283 template <typename T> static typename std::enable_if<!is_basic_type<T>::value, std::vector<T>>::type MatlabParamParser::parse_array(const mxArray* cells)
284 {
285  using wrapper_t = mx_wrapper<T>;
286  using internal_t = typename type_traits<T>::rs2_internal_t;
287 
288  std::vector<T> ret;
289  auto length = mxGetNumberOfElements(cells);
290  ret.reserve(length);
291  auto ptr = static_cast<typename wrapper_t::type*>(mxGetData(cells)); // array of uint64_t's
292  for (int i = 0; i < length; ++i) {
293  ret.push_back(traits_trampoline::from_internal<T>(reinterpret_cast<internal_t*>(ptr[i])));
294  }
295  return ret;
296 }
297 template <typename T> static typename std::enable_if<is_basic_type<T>::value, std::vector<T>>::type MatlabParamParser::parse_array(const mxArray* cells)
298 {
299  using wrapper_t = mx_wrapper<T>;
300 
301  std::vector<T> ret;
302  auto length = mxGetNumberOfElements(cells);
303  ret.reserve(length);
304  auto ptr = static_cast<typename wrapper_t::type*>(mxGetData(cells)); // array of uint64_t's
305  for (int i = 0; i < length; ++i) {
306  ret.push_back(ptr[i]);
307  }
308  return ret;
309 }
311 MatlabParamParser::wrap_array(const T* var, size_t length)
312 {
313  auto cells = mxCreateNumericMatrix(1, length, MatlabParamParser::mx_wrapper<T>::value::value, mxREAL);
314  auto ptr = static_cast<typename mx_wrapper<T>::type*>(mxGetData(cells));
315  for (int x = 0; x < length; ++x)
316  ptr[x] = reinterpret_cast<typename mx_wrapper<T>::type>(traits_trampoline::to_internal<T>(T(var[x])));
317 
318  return cells;
319 }
320 
322 MatlabParamParser::wrap_array(const T* var, size_t length)
323 {
324  auto cells = mxCreateCellMatrix(1, length);
325  for (int x = 0; x < length; ++x)
326  mxSetCell(cells, x, wrap(T(var[x])));
327 
328  return cells;
329 }
330 
331 template <typename T> static typename std::enable_if<is_basic_type<T>::value, mxArray*>::type MatlabParamParser::wrap_array(const T* var, size_t length)
332 {
333  auto cells = mxCreateNumericMatrix(1, length, MatlabParamParser::mx_wrapper<T>::value::value, mxREAL);
334  auto ptr = static_cast<typename mx_wrapper<T>::type*>(mxGetData(cells));
335  for (int x = 0; x < length; ++x)
336  ptr[x] = typename mx_wrapper<T>::type(var[x]);
337 
338  return cells;
339 }
340 #include "types.h"
typename type_traits< T >::rs2_internal_t internal_t
typename std::conditional< bool(std::is_signed< typename std::underlying_type< T >::type >::value), signed_t, unsigned_t >::type value_t
typedef void(APIENTRY *GLDEBUGPROC)(GLenum source
std::integral_constant< mxClassID, mxUINT16_CLASS > value
GLfloat GLfloat p
Definition: glext.h:12687
integral_constant< bool, false > false_type
std::integral_constant< mxClassID, mxUINT8_CLASS > value
GLfloat value
static std::enable_if< is_basic_type< T >::value, std::vector< T > >::type parse_array(const mxArray *cells)
std::integral_constant< bool, detector< T >::use_cells > use_cells
std::integral_constant< mxClassID, mxINT8_CLASS > value
unsigned short uint16_t
Definition: stdint.h:79
GLsizei const GLchar *const * string
std::integral_constant< mxClassID, mxINT16_CLASS > value
typename std::conditional< std::is_same< value_t, signed_t >::value, int64_t, uint64_t >::type type
unsigned char uint8_t
Definition: stdint.h:78
static mxArray * wrap(T &&var)
static std::enable_if< detector< T >::has_to, internal_t< T > * >::type to_internal(T &&val)
static std::enable_if< is_basic_type< T >::value, mxArray * >::type wrap_array(const T *var, size_t length)
GLuint GLfloat * val
static void destroy(const mxArray *cell)
static T parse(const mxArray *cell)
integral_constant< bool, B > bool_constant
std::bool_constant< std::is_arithmetic< T >::value||std::is_pointer< T >::value||std::is_enum< T >::value > is_basic_type
GLdouble x
unsigned int uint32_t
Definition: stdint.h:80
signed short int16_t
Definition: stdint.h:76
static std::chrono::nanoseconds parse(const mxArray *cell)
unsigned __int64 uint64_t
Definition: stdint.h:90
typename std::conditional< std::is_same< value_t, signed_t >::value, int64_t, uint64_t >::type type
signed char int8_t
Definition: stdint.h:75
typename std::conditional< std::is_integral< T >::value, typename std::conditional< std::is_signed< T >::value, int64_t, uint64_t >::type, T >::type type
std::integral_constant< mxClassID, mxUINT64_CLASS > value
std::chrono::duration< uint64_t, std::nano > nanoseconds
static std::enable_if<!detector< T >::has_to, internal_t< T > * >::type to_internal(T &&val)
std::integral_constant< mxClassID, mxINT64_CLASS > value
static mxArray * wrap(std::chrono::nanoseconds &&dur)
static std::enable_if<!is_basic_type< T >::value, std::vector< T > >::type parse_array(const mxArray *cells)
std::integral_constant< mxClassID, mxINT32_CLASS > value
GLenum type
signed __int64 int64_t
Definition: stdint.h:89
typename::boost::move_detail::remove_reference< T >::type && move(T &&t) BOOST_NOEXCEPT
std::integral_constant< mxClassID, mxUINT32_CLASS > value
typename std::conditional< std::is_signed< T >::value, signed_t, unsigned_t >::type value_t
int i
GLenum GLuint GLenum GLsizei length
static std::enable_if< detector< T >::has_from, T >::type from_internal(internal_t< T > *ptr)
signed int int32_t
Definition: stdint.h:77
static std::enable_if<!detector< T >::has_from, T >::type from_internal(internal_t< T > *ptr)
static mxArray * wrap(T &&var)
static T parse(const mxArray *cell)
integral_constant< bool, true > true_type
static std::enable_if<!is_basic_type< T >::value &&!traits_trampoline::use_cells< T >::value, mxArray * >::type wrap_array(const T *var, size_t length)
std::integral_constant< mxClassID, mxLOGICAL_CLASS > value


librealsense2
Author(s): Sergey Dorodnicov , Doron Hirshberg , Mark Horn , Reagan Lopez , Itay Carpis
autogenerated on Mon May 3 2021 02:47:21