GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
mex.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2006-2024 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 // #define DEBUG 1
31 
32 #if defined (DEBUG)
33 # include <iostream>
34 #endif
35 
36 #include <cstdarg>
37 #include <cstdlib>
38 #include <cstring>
39 #include <cctype>
40 
41 #include <limits>
42 #include <map>
43 #if defined (OCTAVE_HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR)
44 # include <memory_resource>
45 #endif
46 #include <set>
47 #include <string>
48 
49 #include "f77-fcn.h"
50 #include "lo-ieee.h"
51 #include "oct-locbuf.h"
52 #include "quit.h"
53 
54 #include "Cell.h"
55 #include "error.h"
56 #include "interpreter-private.h"
57 #include "interpreter.h"
58 // mxArray must be declared as a class before including mexproto.h.
59 #include "mxarray.h"
60 #include "mexproto.h"
61 #include "oct-map.h"
62 #include "ovl.h"
63 #include "ov.h"
64 #include "ov-classdef.h"
65 #include "ov-mex-fcn.h"
66 #include "ov-usr-fcn.h"
67 #include "pager.h"
68 #include "unwind-prot.h"
69 #include "utils.h"
70 #include "variables.h"
71 #include "graphics.h"
72 
73 // These must be declared extern "C" but may be omitted from the set of
74 // symbols declared in mexproto.h, so we declare them here as well.
75 
76 extern "C"
77 {
78  extern OCTINTERP_API const mxArray *
79  mexGet_interleaved (double handle, const char *property);
80 
81  extern OCTINTERP_API mxArray *
82  mxCreateCellArray (mwSize ndims, const mwSize *dims);
83 
84  extern OCTINTERP_API mxArray *
86 
87  extern OCTINTERP_API mxArray *
88  mxCreateCharArray (mwSize ndims, const mwSize *dims);
89 
90  extern OCTINTERP_API mxArray *
91  mxCreateCharMatrixFromStrings (mwSize m, const char **str);
92 
93  extern OCTINTERP_API mxArray *
95 
96  extern OCTINTERP_API mxArray *
97  mxCreateDoubleScalar (double val);
98 
99  extern OCTINTERP_API mxArray *
100  mxCreateLogicalArray (mwSize ndims, const mwSize *dims);
101 
102  extern OCTINTERP_API mxArray *
104 
105  extern OCTINTERP_API mxArray *
107 
108  extern OCTINTERP_API mxArray *
109  mxCreateNumericArray (mwSize ndims, const mwSize *dims, mxClassID class_id,
110  mxComplexity flag);
111 
112  extern OCTINTERP_API mxArray *
114  mxComplexity flag);
115 
116  extern OCTINTERP_API mxArray *
117  mxCreateUninitNumericArray (mwSize ndims, const mwSize *dims,
118  mxClassID class_id, mxComplexity flag);
119 
120  extern OCTINTERP_API mxArray *
122  mxComplexity flag);
123 
124  extern OCTINTERP_API mxArray *
126 
127  extern OCTINTERP_API mxArray *
129 
130  extern OCTINTERP_API mxArray *
131  mxCreateString (const char *str);
132 
133  extern OCTINTERP_API mxArray *
134  mxCreateStructArray (mwSize ndims, const mwSize *dims, int num_keys,
135  const char **keys);
136 
137  extern OCTINTERP_API mxArray *
138  mxCreateStructMatrix (mwSize rows, mwSize cols, int num_keys,
139  const char **keys);
140 
141  extern OCTINTERP_API mxArray *
142  mxCreateCellArray_interleaved (mwSize ndims, const mwSize *dims);
143 
144  extern OCTINTERP_API mxArray *
146 
147  extern OCTINTERP_API mxArray *
148  mxCreateCharArray_interleaved (mwSize ndims, const mwSize *dims);
149 
150  extern OCTINTERP_API mxArray *
152 
153  extern OCTINTERP_API mxArray *
155 
156  extern OCTINTERP_API mxArray *
158 
159  extern OCTINTERP_API mxArray *
160  mxCreateLogicalArray_interleaved (mwSize ndims, const mwSize *dims);
161 
162  extern OCTINTERP_API mxArray *
164 
165  extern OCTINTERP_API mxArray *
167 
168  extern OCTINTERP_API mxArray *
169  mxCreateNumericArray_interleaved (mwSize ndims, const mwSize *dims,
170  mxClassID class_id, mxComplexity flag);
171 
172  extern OCTINTERP_API mxArray *
174  mxComplexity flag);
175 
176  extern OCTINTERP_API mxArray *
178  mxClassID class_id,
179  mxComplexity flag);
180 
181  extern OCTINTERP_API mxArray *
183  mxClassID class_id,
184  mxComplexity flag);
185 
186  extern OCTINTERP_API mxArray *
188  mxComplexity flag);
189 
190  extern OCTINTERP_API mxArray *
192 
193  extern OCTINTERP_API mxArray *
194  mxCreateString_interleaved (const char *str);
195 
196  extern OCTINTERP_API mxArray *
197  mxCreateStructArray_interleaved (mwSize ndims, const mwSize *dims,
198  int num_keys, const char **keys);
199 
200  extern OCTINTERP_API mxArray *
201  mxCreateStructMatrix_interleaved (mwSize rows, mwSize cols, int num_keys,
202  const char **keys);
203 
204  extern OCTINTERP_API int mxMakeArrayReal (mxArray *ptr);
205  extern OCTINTERP_API int mxMakeArrayComplex (mxArray *ptr);
206 
207  extern OCTINTERP_API mxDouble * mxGetDoubles (const mxArray *p);
208  extern OCTINTERP_API mxSingle * mxGetSingles (const mxArray *p);
209  extern OCTINTERP_API mxInt8 * mxGetInt8s (const mxArray *p);
210  extern OCTINTERP_API mxInt16 * mxGetInt16s (const mxArray *p);
211  extern OCTINTERP_API mxInt32 * mxGetInt32s (const mxArray *p);
212  extern OCTINTERP_API mxInt64 * mxGetInt64s (const mxArray *p);
213  extern OCTINTERP_API mxUint8 * mxGetUint8s (const mxArray *p);
214  extern OCTINTERP_API mxUint16 * mxGetUint16s (const mxArray *p);
215  extern OCTINTERP_API mxUint32 * mxGetUint32s (const mxArray *p);
216  extern OCTINTERP_API mxUint64 * mxGetUint64s (const mxArray *p);
217 
218  extern OCTINTERP_API mxComplexDouble * mxGetComplexDoubles (const mxArray *p);
219  extern OCTINTERP_API mxComplexSingle * mxGetComplexSingles (const mxArray *p);
220 
221  extern OCTINTERP_API double * mxGetPi (const mxArray *ptr);
222  extern OCTINTERP_API void * mxGetImagData (const mxArray *ptr);
223 
224  extern OCTINTERP_API int mxSetDoubles (mxArray *p, mxDouble *d);
225  extern OCTINTERP_API int mxSetSingles (mxArray *p, mxSingle *d);
226  extern OCTINTERP_API int mxSetInt8s (mxArray *p, mxInt8 *d);
227  extern OCTINTERP_API int mxSetInt16s (mxArray *p, mxInt16 *d);
228  extern OCTINTERP_API int mxSetInt32s (mxArray *p, mxInt32 *d);
229  extern OCTINTERP_API int mxSetInt64s (mxArray *p, mxInt64 *d);
230  extern OCTINTERP_API int mxSetUint8s (mxArray *p, mxUint8 *d);
231  extern OCTINTERP_API int mxSetUint16s (mxArray *p, mxUint16 *d);
232  extern OCTINTERP_API int mxSetUint32s (mxArray *p, mxUint32 *d);
233  extern OCTINTERP_API int mxSetUint64s (mxArray *p, mxUint64 *d);
234 
235  extern OCTINTERP_API int mxSetComplexDoubles (mxArray *p, mxComplexDouble *d);
236  extern OCTINTERP_API int mxSetComplexSingles (mxArray *p, mxComplexSingle *d);
237 
238  extern OCTINTERP_API void mxSetPi (mxArray *ptr, double *pi);
239  extern OCTINTERP_API void mxSetImagData (mxArray *ptr, void *pi);
240 }
241 
242 static void *
243 xmalloc (size_t n)
244 {
245  void *ptr = std::malloc (n);
246 
247 #if defined (DEBUG)
248  std::cerr << "xmalloc (" << n << ") = " << ptr << std::endl;
249 #endif
250 
251  return ptr;
252 }
253 
254 static void *
255 xrealloc (void *ptr, size_t n)
256 {
257  void *newptr = std::realloc (ptr, n);
258 
259 #if defined (DEBUG)
260  std::cerr << "xrealloc (" << ptr << ", " << n << ") = " << newptr
261  << std::endl;
262 #endif
263 
264  return newptr;
265 }
266 
267 static void
268 xfree (void *ptr)
269 {
270 #if defined (DEBUG)
271  std::cerr << "xfree (" << ptr << ")" << std::endl;
272 #endif
273 
274  std::free (ptr);
275 }
276 
277 static mwSize
278 max_str_len (mwSize m, const char **str)
279 {
280  int max_len = 0;
281 
282  for (mwSize i = 0; i < m; i++)
283  {
284  mwSize tmp = strlen (str[i]);
285 
286  if (tmp > max_len)
287  max_len = tmp;
288  }
289 
290  return max_len;
291 }
292 
293 // FIXME: Is there a better/standard way to do this job?
294 
295 template <typename T>
296 class fp_type_traits
297 {
298 public:
299  static const bool is_complex = false;
300 };
301 
302 template <>
303 class fp_type_traits<Complex>
304 {
305 public:
306  static const bool is_complex = true;
307 };
308 
309 template <>
310 class fp_type_traits <FloatComplex>
311 {
312 public:
313  static const bool is_complex = true;
314 };
315 
316 #if defined (OCTAVE_HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR)
317 
318 class mx_deleting_memory_resource : public std::pmr::memory_resource
319 {
320 private:
321 
322  void * do_allocate (std::size_t bytes, size_t /*alignment*/)
323  {
324  void *ptr = xmalloc (bytes);
325 
326  if (! ptr)
327  throw std::bad_alloc ();
328 
329  return ptr;
330  }
331 
332  void do_deallocate (void *ptr, std::size_t /*bytes*/,
333  std::size_t /*alignment*/)
334  {
335  xfree (ptr);
336  }
337 
338  bool do_is_equal (const std::pmr::memory_resource& other) const noexcept
339  {
340  return this == dynamic_cast<const mx_deleting_memory_resource *> (&other);
341  }
342 };
343 
344 class mx_preserving_memory_resource : public std::pmr::memory_resource
345 {
346 private:
347 
348  void * do_allocate (std::size_t bytes, size_t /*alignment*/)
349  {
350  void *ptr = xmalloc (bytes);
351 
352  if (! ptr)
353  throw std::bad_alloc ();
354 
355  return ptr;
356  }
357 
358  void do_deallocate (void * /*ptr*/, std::size_t /*bytes*/,
359  std::size_t /*alignment*/)
360  { }
361 
362  bool do_is_equal (const std::pmr::memory_resource& other) const noexcept
363  {
364  return this == dynamic_cast<const mx_preserving_memory_resource *> (&other);
365  }
366 };
367 
368 // FIXME: Is it OK for the memory resource object to be defined this
369 // way?
370 static mx_deleting_memory_resource the_mx_deleting_memory_resource;
371 static mx_preserving_memory_resource the_mx_preserving_memory_resource;
372 
373 static std::pmr::memory_resource *current_mx_memory_resource = &the_mx_deleting_memory_resource;
374 
375 #endif
376 
377 // ------------------------------------------------------------------
378 
379 mxArray_base::mxArray_base (bool interleaved)
380  : m_interleaved (interleaved)
381 { }
382 
383 static mwIndex
384 calc_single_subscript_internal (mwSize ndims, const mwSize *dims,
385  mwSize nsubs, const mwIndex *subs)
386 {
387  mwIndex retval = 0;
388 
389  switch (nsubs)
390  {
391  case 0:
392  break;
393 
394  case 1:
395  retval = subs[0];
396  break;
397 
398  default:
399  {
400  // Both nsubs and ndims should be at least 2 here.
401 
402  mwSize n = (nsubs <= ndims ? nsubs : ndims);
403 
404  retval = subs[--n];
405 
406  while (--n >= 0)
407  retval = dims[n] * retval + subs[n];
408  }
409  break;
410  }
411 
412  return retval;
413 }
414 
415 // The object that handles values pass to MEX files from Octave. Some
416 // methods in this class may set mutate_flag to TRUE to tell the
417 // mxArray class to convert to the Matlab-style representation and
418 // then invoke the method on that object instead (for example, getting
419 // a pointer to real or imaginary data from a complex object requires
420 // a mutation but getting a pointer to real data from a real object
421 // does not). Changing the representation causes a copy so we try to
422 // avoid it unless it is really necessary. Once the conversion
423 // happens, we delete this representation, so the conversion can only
424 // happen once per call to a MEX file.
425 
426 static inline void * maybe_mark_foreign (void *ptr);
427 
428 #if defined (OCTAVE_HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR)
429 static inline void maybe_disown_ptr (void *ptr);
430 #endif
431 
432 #define VOID_MUTATION_METHOD(FCN_NAME, ARG_LIST) \
433  void FCN_NAME ARG_LIST { request_mutation (); }
434 
435 #define CONST_VOID_MUTATION_METHOD(FCN_NAME, ARG_LIST) \
436  void FCN_NAME ARG_LIST const { request_mutation (); }
437 
438 #define MUTATION_METHOD(RET_TYPE, FCN_NAME, ARG_LIST, RET_VAL) \
439  RET_TYPE FCN_NAME ARG_LIST { request_mutation (); return RET_VAL; }
440 
441 #define CONST_MUTATION_METHOD(RET_TYPE, FCN_NAME, ARG_LIST, RET_VAL) \
442  RET_TYPE FCN_NAME ARG_LIST const { request_mutation (); return RET_VAL; }
443 
444 #define GET_DATA_METHOD(RT, FCN_NAME, ID, COMPLEXITY) \
445  RT * FCN_NAME (void) const { return get_data<RT> (ID, COMPLEXITY); }
446 
447 class mxArray_octave_value : public mxArray_base
448 {
449 public:
450 
451  mxArray_octave_value () = delete;
452 
453  mxArray_octave_value (bool interleaved, const octave_value& ov)
454  : mxArray_base (interleaved), m_val (ov), m_mutate_flag (false),
455  m_id (mxUNKNOWN_CLASS), m_class_name (nullptr), m_ndims (-1),
456  m_dims (nullptr)
457  { }
458 
459  // No assignment! FIXME: should this be implemented? Note that we
460  // do have a copy constructor.
461 
462  mxArray_octave_value& operator = (const mxArray_octave_value&) = delete;
463 
464  mxArray_base * dup (void) const { return new mxArray_octave_value (*this); }
465 
466  mxArray * as_mxArray (void) const
467  {
468  mxArray *retval = m_val.as_mxArray (m_interleaved);
469 
470  // RETVAL is assumed to be an mxArray_matlab object. Should we
471  // error_unless that condition here?
472 
473  if (retval)
474  {
475  // Preserve cached values of class name and dimensions in case
476  // they will be used after we mutate.
477 
478  // set_class_name will handle deleting class name that comes
479  // from as_mxArray conversion function.
480 
481  if (m_class_name)
482  {
483  retval->set_class_name (m_class_name);
484 
485  m_class_name = nullptr;
486  }
487 
488  if (m_dims)
489  {
490  mwSize *xdims = retval->get_dimensions ();
491 
492  mxFree (xdims);
493 
494  retval->set_dimensions (m_dims, m_ndims);
495 
496  m_dims = nullptr;
497  }
498  }
499 
500  return retval;
501  }
502 
503  ~mxArray_octave_value (void)
504  {
505  mxFree (m_class_name);
506  mxFree (m_dims);
507  }
508 
509  bool is_octave_value (void) const { return true; }
510 
511  int iscell (void) const { return m_val.iscell (); }
512 
513  int is_char (void) const { return m_val.is_string (); }
514 
515  int is_complex (void) const { return m_val.iscomplex (); }
516 
517  int is_double (void) const { return m_val.is_double_type (); }
518 
519  int is_function_handle (void) const { return m_val.is_function_handle (); }
520 
521  int is_int16 (void) const { return m_val.is_int16_type (); }
522 
523  int is_int32 (void) const { return m_val.is_int32_type (); }
524 
525  int is_int64 (void) const { return m_val.is_int64_type (); }
526 
527  int is_int8 (void) const { return m_val.is_int8_type (); }
528 
529  int is_logical (void) const { return m_val.islogical (); }
530 
531  int is_numeric (void) const { return m_val.isnumeric (); }
532 
533  int is_single (void) const { return m_val.is_single_type (); }
534 
535  int is_sparse (void) const { return m_val.issparse (); }
536 
537  int is_struct (void) const { return m_val.isstruct (); }
538 
539  int is_uint16 (void) const { return m_val.is_uint16_type (); }
540 
541  int is_uint32 (void) const { return m_val.is_uint32_type (); }
542 
543  int is_uint64 (void) const { return m_val.is_uint64_type (); }
544 
545  int is_uint8 (void) const { return m_val.is_uint8_type (); }
546 
547  int is_range (void) const { return m_val.is_range (); }
548 
549  int isreal (void) const { return m_val.isreal (); }
550 
551  int is_logical_scalar_true (void) const
552  {
553  return (is_logical_scalar () && m_val.is_true ());
554  }
555 
556  mwSize get_m (void) const { return m_val.rows (); }
557 
558  mwSize get_n (void) const
559  {
560  mwSize n = 1;
561 
562  // Force m_dims and m_ndims to be cached.
563  get_dimensions ();
564 
565  for (mwIndex i = m_ndims - 1; i > 0; i--)
566  n *= m_dims[i];
567 
568  return n;
569  }
570 
571  mwSize * get_dimensions (void) const
572  {
573  if (! m_dims)
574  {
575  m_ndims = m_val.ndims ();
576 
577  m_dims = static_cast<mwSize *> (mxArray::malloc (m_ndims
578  * sizeof (mwSize)));
579 
580  dim_vector dv = m_val.dims ();
581 
582  for (mwIndex i = 0; i < m_ndims; i++)
583  m_dims[i] = dv(i);
584  }
585 
586  return m_dims;
587  }
588 
589  mwSize get_number_of_dimensions (void) const
590  {
591  // Force m_dims and m_ndims to be cached.
592  get_dimensions ();
593 
594  return m_ndims;
595  }
596 
597  VOID_MUTATION_METHOD (set_m, (mwSize))
598  VOID_MUTATION_METHOD (set_n, (mwSize))
599 
600  MUTATION_METHOD (int, set_dimensions, (mwSize *, mwSize), 0)
601 
602  mwSize get_number_of_elements (void) const { return m_val.numel (); }
603 
604  int isempty (void) const { return m_val.isempty (); }
605 
606  bool is_scalar (void) const
607  {
608  // Force m_dims and m_ndims to be cached.
609  get_dimensions ();
610 
611  return m_ndims == 2 && m_dims[0] == 1 && m_dims[1] == 1;
612  }
613 
614  mxClassID get_class_id (void) const
615  {
616  m_id = mxUNKNOWN_CLASS;
617 
618  std::string cn = m_val.class_name ();
619 
620  if (cn == "double")
621  m_id = mxDOUBLE_CLASS;
622  else if (cn == "single")
623  m_id = mxSINGLE_CLASS;
624  else if (cn == "char")
625  m_id = mxCHAR_CLASS;
626  else if (cn == "logical")
627  m_id = mxLOGICAL_CLASS;
628  else if (cn == "cell")
629  m_id = mxCELL_CLASS;
630  else if (cn == "struct")
631  m_id = mxSTRUCT_CLASS;
632  else if (cn == "function_handle")
633  m_id = mxFUNCTION_CLASS;
634  else if (cn == "int8")
635  m_id = mxINT8_CLASS;
636  else if (cn == "uint8")
637  m_id = mxUINT8_CLASS;
638  else if (cn == "int16")
639  m_id = mxINT16_CLASS;
640  else if (cn == "uint16")
641  m_id = mxUINT16_CLASS;
642  else if (cn == "int32")
643  m_id = mxINT32_CLASS;
644  else if (cn == "uint32")
645  m_id = mxUINT32_CLASS;
646  else if (cn == "int64")
647  m_id = mxINT64_CLASS;
648  else if (cn == "uint64")
649  m_id = mxUINT64_CLASS;
650 
651  return m_id;
652  }
653 
654  const char * get_class_name (void) const
655  {
656  if (! m_class_name)
657  {
658  std::string s = m_val.class_name ();
659  m_class_name = mxArray::strsave (s.c_str ());
660  }
661 
662  return m_class_name;
663  }
664 
665  // Not allowed.
666  VOID_MUTATION_METHOD (set_class_name, (const char *))
667 
668  mxArray * get_property (mwIndex idx, const char *pname) const
669  {
670  mxArray *retval = nullptr;
671 
672  if (m_val.is_classdef_object ())
673  {
674  octave_classdef *ov_cdef = m_val.classdef_object_value ();
675 
676  if (ov_cdef)
677  {
678  octave_value pval = ov_cdef->get_property (idx, pname);
679 
680  if (pval.is_defined())
681  retval = new mxArray (m_interleaved, pval);
682  }
683  }
684 
685  return retval;
686  }
687 
688  void set_property (mwIndex idx, const char *pname, const mxArray *pval)
689  {
690  if (m_val.is_classdef_object ())
691  {
692  octave_classdef *ov_cdef = m_val.classdef_object_value ();
693 
694  if (ov_cdef)
695  ov_cdef->set_property (idx, pname, pval->as_octave_value ());
696  }
697  else
698  err_invalid_type ("set_property");
699  }
700 
701  CONST_MUTATION_METHOD (mxArray *, get_cell, (mwIndex), nullptr)
702 
703  // Not allowed.
704  VOID_MUTATION_METHOD (set_cell, (mwIndex, mxArray *))
705 
706  double get_scalar (void) const
707  {
708  if (m_val.issparse ())
709  {
710  // For sparse arrays, return the first nonzero value.
711  const void *m_data = m_val.mex_get_data ();
712  if (m_data == nullptr)
713  return 0.0;
714 
715  if (m_val.islogical ())
716  return *static_cast<const bool *> (m_data);
717  else if (m_val.isreal ())
718  return *static_cast<const double *> (m_data);
719  else // Complex type, only return real part
720  return *static_cast<const double *> (m_data);
721  }
722  else
723  return m_val.scalar_value (true);
724  }
725 
726  void * get_data (void) const
727  {
728  // Casting away const required for MEX interface.
729 
730  void *retval = const_cast<void *> (m_val.mex_get_data ());
731 
732  if (retval && (m_val.isreal () || m_interleaved))
733  {
734  maybe_mark_foreign (retval);
735  return retval;
736  }
737 
738  request_mutation ();
739  return nullptr;
740  }
741 
742  template <typename T>
743  T * get_data (mxClassID class_id, mxComplexity complexity) const
744  {
745  // Casting away const required for MEX interface.
746 
747  void *ptr = const_cast<void *> (m_val.mex_get_data (class_id, complexity));
748 
749  T *retval = static_cast<T *> (ptr);
750 
751  if (retval && (complexity == mxREAL || m_interleaved))
752  {
753  maybe_mark_foreign (retval);
754  return retval;
755  }
756 
757  request_mutation ();
758  return nullptr;
759  }
760 
762 
764 
765  GET_DATA_METHOD (mxInt8, get_int8s, mxINT8_CLASS, mxREAL);
766 
768 
770 
772 
774 
776 
778 
780 
781  GET_DATA_METHOD (mxComplexDouble, get_complex_doubles,
783 
784  GET_DATA_METHOD (mxComplexSingle, get_complex_singles,
786 
787  void * get_imag_data (void) const
788  {
789  void *retval = nullptr;
790 
791  if (is_numeric () && isreal ())
792  retval = nullptr;
793  else
794  request_mutation ();
795 
796  return retval;
797  }
798 
799  // Not allowed.
800  VOID_MUTATION_METHOD (set_data, (void *))
801 
802  MUTATION_METHOD (int, set_doubles, (mxDouble *), 0)
803  MUTATION_METHOD (int, set_singles, (mxSingle *), 0)
804  MUTATION_METHOD (int, set_int8s, (mxInt8 *), 0)
805  MUTATION_METHOD (int, set_int16s, (mxInt16 *), 0)
806  MUTATION_METHOD (int, set_int32s, (mxInt32 *), 0)
807  MUTATION_METHOD (int, set_int64s, (mxInt64 *), 0)
808  MUTATION_METHOD (int, set_uint8s, (mxUint8 *), 0)
809  MUTATION_METHOD (int, set_uint16s, (mxUint16 *), 0)
810  MUTATION_METHOD (int, set_uint32s, (mxUint32 *), 0)
811  MUTATION_METHOD (int, set_uint64s, (mxUint64 *), 0)
812 
813  MUTATION_METHOD (int, set_complex_doubles, (mxComplexDouble *), 0)
814  MUTATION_METHOD (int, set_complex_singles, (mxComplexSingle *), 0)
815 
816  // Not allowed.
817  VOID_MUTATION_METHOD (set_imag_data, (void *))
818 
819  mwIndex * get_ir (void) const
820  {
821  // Casting away const required for MEX interface.
822 
823  octave_idx_type *ptr = const_cast<octave_idx_type *> (m_val.mex_get_ir ());
824  return static_cast<mwIndex *> (maybe_mark_foreign (ptr));
825  }
826 
827  mwIndex * get_jc (void) const
828  {
829  // Casting away const required for MEX interface.
830 
831  octave_idx_type *ptr = const_cast<octave_idx_type *> (m_val.mex_get_jc ());
832  return static_cast<mwIndex *> (maybe_mark_foreign (ptr));
833  }
834 
835  mwSize get_nzmax (void) const { return m_val.nzmax (); }
836 
837  // Not allowed.
838  VOID_MUTATION_METHOD (set_ir, (mwIndex *))
839 
840  // Not allowed.
841  VOID_MUTATION_METHOD (set_jc, (mwIndex *))
842 
843  // Not allowed.
844  VOID_MUTATION_METHOD (set_nzmax, (mwSize))
845 
846  // Not allowed.
847  MUTATION_METHOD (int, add_field, (const char *), 0)
848 
849  // Not allowed.
850  VOID_MUTATION_METHOD (remove_field, (int))
851 
852  CONST_MUTATION_METHOD (mxArray *, get_field_by_number, (mwIndex, int), nullptr)
853 
854  // Not allowed.
855  VOID_MUTATION_METHOD (set_field_by_number, (mwIndex, int, mxArray *))
856 
857  int get_number_of_fields (void) const { return m_val.nfields (); }
858 
859  CONST_MUTATION_METHOD (const char *, get_field_name_by_number, (int), nullptr)
860 
861  CONST_MUTATION_METHOD (int, get_field_number, (const char *), 0)
862 
863  int get_string (char *buf, mwSize buflen) const
864  {
865  int retval = 1;
866 
868 
869  if (m_val.is_string () && nel < buflen)
870  {
871  charNDArray tmp = m_val.char_array_value ();
872 
873  const char *p = tmp.data ();
874 
875  for (mwIndex i = 0; i < nel; i++)
876  buf[i] = p[i];
877 
878  buf[nel] = 0;
879 
880  retval = 0;
881  }
882 
883  return retval;
884  }
885 
886  char * array_to_string (void) const
887  {
888  // FIXME: this is supposed to handle multi-byte character strings.
889 
890  char *buf = nullptr;
891 
892  if (m_val.is_string ())
893  {
895 
896  buf = static_cast<char *> (mxArray::malloc (nel + 1));
897 
898  if (buf)
899  {
900  charNDArray tmp = m_val.char_array_value ();
901 
902  const char *p = tmp.data ();
903 
904  for (mwIndex i = 0; i < nel; i++)
905  buf[i] = p[i];
906 
907  buf[nel] = '\0';
908  }
909  }
910 
911  return buf;
912  }
913 
914  mwIndex calc_single_subscript (mwSize nsubs, mwIndex *subs) const
915  {
916  // Force m_ndims, n_dims to be cached.
917  get_dimensions ();
918 
919  return calc_single_subscript_internal (m_ndims, m_dims, nsubs, subs);
920  }
921 
922  std::size_t get_element_size (void) const
923  {
924  // Force m_id to be cached.
925  get_class_id ();
926 
927  switch (m_id)
928  {
929  case mxCELL_CLASS: return sizeof (mxArray *);
930  case mxSTRUCT_CLASS: return sizeof (mxArray *);
931  case mxLOGICAL_CLASS: return sizeof (mxLogical);
932  case mxCHAR_CLASS: return sizeof (mxChar);
933  case mxDOUBLE_CLASS: return get_numeric_element_size (sizeof (mxDouble));
934  case mxSINGLE_CLASS: return get_numeric_element_size (sizeof (mxSingle));
935  case mxINT8_CLASS: return get_numeric_element_size (sizeof (mxInt8));
936  case mxUINT8_CLASS: return get_numeric_element_size (sizeof (mxUint8));
937  case mxINT16_CLASS: return get_numeric_element_size (sizeof (mxInt16));
938  case mxUINT16_CLASS: return get_numeric_element_size (sizeof (mxUint16));
939  case mxINT32_CLASS: return get_numeric_element_size (sizeof (mxInt32));
940  case mxUINT32_CLASS: return get_numeric_element_size (sizeof (mxUint32));
941  case mxINT64_CLASS: return get_numeric_element_size (sizeof (mxInt64));
942  case mxUINT64_CLASS: return get_numeric_element_size (sizeof (mxUint64));
943  case mxFUNCTION_CLASS: return 0;
944  // FIXME: user-defined objects need their own class ID.
945  // What should they return, size of pointer?
946  default: return 0;
947  }
948  }
949 
950  bool mutation_needed (void) const { return m_mutate_flag; }
951 
952  void request_mutation (void) const
953  {
954  if (m_mutate_flag)
955  panic_impossible ();
956 
957  m_mutate_flag = true;
958  }
959 
960  mxArray * mutate (void) const { return as_mxArray (); }
961 
962  octave_value as_octave_value (void) const { return m_val; }
963 
964 protected:
965 
966  mxArray_octave_value (const mxArray_octave_value& arg)
967  : mxArray_base (arg), m_val (arg.m_val), m_mutate_flag (arg.m_mutate_flag),
968  m_id (arg.m_id), m_class_name (mxArray::strsave (arg.m_class_name)),
969  m_ndims (arg.m_ndims),
970  m_dims (m_ndims > 0
971  ? static_cast<mwSize *> (mxArray::malloc (m_ndims * sizeof (mwSize)))
972  : nullptr)
973  {
974  if (m_dims)
975  {
976  for (mwIndex i = 0; i < m_ndims; i++)
977  m_dims[i] = arg.m_dims[i];
978  }
979  }
980 
981 private:
982 
983  octave_value m_val;
984 
985  mutable bool m_mutate_flag;
986 
987  // Caching these does not cost much or lead to much duplicated
988  // code. For other things, we just request mutation to a
989  // Matlab-style mxArray object.
990 
991  mutable mxClassID m_id;
992  mutable char *m_class_name;
993  mutable mwSize m_ndims;
994  mutable mwSize *m_dims;
995 };
996 
997 // The base class for the Matlab-style representation, used to handle
998 // things that are common to all Matlab-style objects.
999 
1000 class mxArray_matlab : public mxArray_base
1001 {
1002 public:
1003 
1004  mxArray_matlab () = delete;
1005 
1006  // No assignment!
1007  // FIXME: should this be implemented?
1008  // Note that we *do* have a copy constructor.
1009 
1010  mxArray_matlab& operator = (const mxArray_matlab&) = delete;
1011 
1012  ~mxArray_matlab (void)
1013  {
1014  mxFree (m_class_name);
1015  mxFree (m_dims);
1016  }
1017 
1018  int iscell (void) const { return m_id == mxCELL_CLASS; }
1019 
1020  int is_char (void) const { return m_id == mxCHAR_CLASS; }
1021 
1022  int is_complex (void) const { return m_is_complex; }
1023 
1024  int is_double (void) const { return m_id == mxDOUBLE_CLASS; }
1025 
1026  int is_function_handle (void) const { return m_id == mxFUNCTION_CLASS; }
1027 
1028  int is_int16 (void) const { return m_id == mxINT16_CLASS; }
1029 
1030  int is_int32 (void) const { return m_id == mxINT32_CLASS; }
1031 
1032  int is_int64 (void) const { return m_id == mxINT64_CLASS; }
1033 
1034  int is_int8 (void) const { return m_id == mxINT8_CLASS; }
1035 
1036  int is_logical (void) const { return m_id == mxLOGICAL_CLASS; }
1037 
1038  int is_numeric (void) const
1039  {
1040  return (m_id == mxDOUBLE_CLASS || m_id == mxSINGLE_CLASS
1041  || m_id == mxINT8_CLASS || m_id == mxUINT8_CLASS
1042  || m_id == mxINT16_CLASS || m_id == mxUINT16_CLASS
1043  || m_id == mxINT32_CLASS || m_id == mxUINT32_CLASS
1044  || m_id == mxINT64_CLASS || m_id == mxUINT64_CLASS);
1045  }
1046 
1047  int is_single (void) const { return m_id == mxSINGLE_CLASS; }
1048 
1049  int is_sparse (void) const { return 0; }
1050 
1051  int is_struct (void) const { return m_id == mxSTRUCT_CLASS; }
1052 
1053  int is_uint16 (void) const { return m_id == mxUINT16_CLASS; }
1054 
1055  int is_uint32 (void) const { return m_id == mxUINT32_CLASS; }
1056 
1057  int is_uint64 (void) const { return m_id == mxUINT64_CLASS; }
1058 
1059  int is_uint8 (void) const { return m_id == mxUINT8_CLASS; }
1060 
1061  int is_logical_scalar_true (void) const
1062  {
1063  return (is_logical_scalar ()
1064  && static_cast<mxLogical *> (get_data ())[0] != 0);
1065  }
1066 
1067  mwSize get_m (void) const { return m_dims[0]; }
1068 
1069  mwSize get_n (void) const
1070  {
1071  mwSize n = 1;
1072 
1073  for (mwSize i = m_ndims - 1 ; i > 0 ; i--)
1074  n *= m_dims[i];
1075 
1076  return n;
1077  }
1078 
1079  mwSize * get_dimensions (void) const { return m_dims; }
1080 
1081  mwSize get_number_of_dimensions (void) const { return m_ndims; }
1082 
1083  void set_m (mwSize m) { m_dims[0] = m; }
1084 
1085  void set_n (mwSize n) { m_dims[1] = n; }
1086 
1087  int set_dimensions (mwSize *dims, mwSize ndims)
1088  {
1089  m_ndims = ndims;
1090 
1091  mxFree (m_dims);
1092 
1093  if (m_ndims > 0)
1094  {
1095  m_dims
1096  = static_cast<mwSize *> (mxArray::malloc (m_ndims * sizeof (mwSize)));
1097 
1098  if (m_dims == nullptr)
1099  return 1;
1100 
1101  for (int i = 0; i < m_ndims; i++)
1102  m_dims[i] = dims[i];
1103 
1104  return 0;
1105  }
1106  else
1107  {
1108  m_dims = nullptr;
1109  return 0;
1110  }
1111  }
1112 
1113  mwSize get_number_of_elements (void) const
1114  {
1115  mwSize retval = m_dims[0];
1116 
1117  for (mwIndex i = 1; i < m_ndims; i++)
1118  retval *= m_dims[i];
1119 
1120  return retval;
1121  }
1122 
1123  int isempty (void) const { return get_number_of_elements () == 0; }
1124 
1125  bool is_scalar (void) const
1126  {
1127  return m_ndims == 2 && m_dims[0] == 1 && m_dims[1] == 1;
1128  }
1129 
1130  mxClassID get_class_id (void) const { return m_id; }
1131 
1132  const char * get_class_name (void) const
1133  {
1134  switch (m_id)
1135  {
1136  case mxDOUBLE_CLASS: return "double";
1137  case mxSINGLE_CLASS: return "single";
1138  case mxCHAR_CLASS: return "char";
1139  case mxLOGICAL_CLASS: return "logical";
1140  case mxCELL_CLASS: return "cell";
1141  case mxSTRUCT_CLASS: return "struct";
1142  case mxFUNCTION_CLASS: return "function_handle";
1143  case mxINT8_CLASS: return "int8";
1144  case mxUINT8_CLASS: return "uint8";
1145  case mxINT16_CLASS: return "int16";
1146  case mxUINT16_CLASS: return "uint16";
1147  case mxINT32_CLASS: return "int32";
1148  case mxUINT32_CLASS: return "uint32";
1149  case mxINT64_CLASS: return "int64";
1150  case mxUINT64_CLASS: return "uint64";
1151  case mxUNKNOWN_CLASS: return "unknown";
1152  // FIXME: should return the classname of user-defined objects
1153  default: return "unknown";
1154  }
1155  }
1156 
1157  void set_class_name (const char *name)
1158  {
1159  mxFree (m_class_name);
1160  m_class_name = static_cast<char *> (mxArray::malloc (strlen (name) + 1));
1161  strcpy (m_class_name, name);
1162  }
1163 
1164  mxArray * get_cell (mwIndex /*idx*/) const
1165  {
1166  err_invalid_type ("get_cell");
1167  }
1168 
1169  void set_cell (mwIndex /*idx*/, mxArray * /*val*/)
1170  {
1171  err_invalid_type ("set_cell");
1172  }
1173 
1174  double get_scalar (void) const
1175  {
1176  err_invalid_type ("get_scalar");
1177  }
1178 
1179  void * get_data (void) const
1180  {
1181  err_invalid_type ("get_data");
1182  }
1183 
1184  mxDouble * get_doubles (void) const
1185  {
1186  err_invalid_type ("get_doubles");
1187  }
1188 
1189  mxSingle * get_singles (void) const
1190  {
1191  err_invalid_type ("get_singles");
1192  }
1193 
1194  mxInt8 * get_int8s (void) const
1195  {
1196  err_invalid_type ("get_int8s");
1197  }
1198 
1199  mxInt16 * get_int16s (void) const
1200  {
1201  err_invalid_type ("get_int16s");
1202  }
1203 
1204  mxInt32 * get_int32s (void) const
1205  {
1206  err_invalid_type ("get_int32s");
1207  }
1208 
1209  mxInt64 * get_int64s (void) const
1210  {
1211  err_invalid_type ("get_int64s");
1212  }
1213 
1214  mxUint8 * get_uint8s (void) const
1215  {
1216  err_invalid_type ("get_uint8s");
1217  }
1218 
1219  mxUint16 * get_uint16s (void) const
1220  {
1221  err_invalid_type ("get_uint16s");
1222  }
1223 
1224  mxUint32 * get_uint32s (void) const
1225  {
1226  err_invalid_type ("get_uint32s");
1227  }
1228 
1229  mxUint64 * get_uint64s (void) const
1230  {
1231  err_invalid_type ("get_uint64s");
1232  }
1233 
1234  mxComplexDouble * get_complex_doubles (void) const
1235  {
1236  err_invalid_type ("get_complex_doubles");
1237  }
1238 
1239  mxComplexSingle * get_complex_singles (void) const
1240  {
1241  err_invalid_type ("get_complex_singles");
1242  }
1243 
1244  void * get_imag_data (void) const
1245  {
1246  err_invalid_type ("get_imag_data");
1247  }
1248 
1249  void set_data (void * /*pr*/)
1250  {
1251  err_invalid_type ("set_data");
1252  }
1253 
1254  int set_doubles (mxDouble *)
1255  {
1256  err_invalid_type ("set_doubles");
1257  }
1258 
1259  int set_singles (mxSingle *)
1260  {
1261  err_invalid_type ("set_singles");
1262  }
1263 
1264  int set_int8s (mxInt8 *)
1265  {
1266  err_invalid_type ("set_int8s");
1267  }
1268 
1269  int set_int16s (mxInt16 *)
1270  {
1271  err_invalid_type ("set_int16s");
1272  }
1273 
1274  int set_int32s (mxInt32 *)
1275  {
1276  err_invalid_type ("set_int32s");
1277  }
1278 
1279  int set_int64s (mxInt64 *)
1280  {
1281  err_invalid_type ("set_int64s");
1282  }
1283 
1284  int set_uint8s (mxUint8 *)
1285  {
1286  err_invalid_type ("set_uint8s");
1287  }
1288 
1289  int set_uint16s (mxUint16 *)
1290  {
1291  err_invalid_type ("set_uint16s");
1292  }
1293 
1294  int set_uint32s (mxUint32 *)
1295  {
1296  err_invalid_type ("set_uint32s");
1297  }
1298 
1299  int set_uint64s (mxUint64 *)
1300  {
1301  err_invalid_type ("set_uint64s");
1302  }
1303 
1305  {
1306  err_invalid_type ("set_complex_doubles");
1307  }
1308 
1310  {
1311  err_invalid_type ("set_complex_singles");
1312  }
1313 
1314  void set_imag_data (void * /*pi*/)
1315  {
1316  err_invalid_type ("set_imag_data");
1317  }
1318 
1319  mwIndex * get_ir (void) const
1320  {
1321  err_invalid_type ("get_ir");
1322  }
1323 
1324  mwIndex * get_jc (void) const
1325  {
1326  err_invalid_type ("get_jc");
1327  }
1328 
1329  mwSize get_nzmax (void) const
1330  {
1331  err_invalid_type ("get_nzmax");
1332  }
1333 
1334  void set_ir (mwIndex * /*ir*/)
1335  {
1336  err_invalid_type ("set_ir");
1337  }
1338 
1339  void set_jc (mwIndex * /*jc*/)
1340  {
1341  err_invalid_type ("set_jc");
1342  }
1343 
1344  void set_nzmax (mwSize /*nzmax*/)
1345  {
1346  err_invalid_type ("set_nzmax");
1347  }
1348 
1349  int add_field (const char * /*key*/)
1350  {
1351  err_invalid_type ("add_field");
1352  }
1353 
1354  void remove_field (int /*key_num*/)
1355  {
1356  err_invalid_type ("remove_field");
1357  }
1358 
1359  mxArray * get_field_by_number (mwIndex /*index*/, int /*key_num*/) const
1360  {
1361  err_invalid_type ("get_field_by_number");
1362  }
1363 
1364  void set_field_by_number (mwIndex /*index*/, int /*key_num*/,
1365  mxArray * /*val*/)
1366  {
1367  err_invalid_type ("set_field_by_number");
1368  }
1369 
1370  int get_number_of_fields (void) const
1371  {
1372  err_invalid_type ("get_number_of_fields");
1373  }
1374 
1375  const char * get_field_name_by_number (int /*key_num*/) const
1376  {
1377  err_invalid_type ("get_field_name_by_number");
1378  }
1379 
1380  int get_field_number (const char * /*key*/) const
1381  {
1382  return -1;
1383  }
1384 
1385  int get_string (char * /*buf*/, mwSize /*buflen*/) const
1386  {
1387  err_invalid_type ("get_string");
1388  }
1389 
1390  char * array_to_string (void) const
1391  {
1392  err_invalid_type ("array_to_string");
1393  }
1394 
1395  mwIndex calc_single_subscript (mwSize nsubs, mwIndex *subs) const
1396  {
1397  return calc_single_subscript_internal (m_ndims, m_dims, nsubs, subs);
1398  }
1399 
1400  std::size_t get_element_size (void) const
1401  {
1402  switch (m_id)
1403  {
1404  case mxCELL_CLASS: return sizeof (mxArray *);
1405  case mxSTRUCT_CLASS: return sizeof (mxArray *);
1406  case mxLOGICAL_CLASS: return sizeof (mxLogical);
1407  case mxCHAR_CLASS: return sizeof (mxChar);
1408  case mxDOUBLE_CLASS: return get_numeric_element_size (sizeof (mxDouble));
1409  case mxSINGLE_CLASS: return get_numeric_element_size (sizeof (mxSingle));
1410  case mxINT8_CLASS: return get_numeric_element_size (sizeof (mxInt8));
1411  case mxUINT8_CLASS: return get_numeric_element_size (sizeof (mxUint8));
1412  case mxINT16_CLASS: return get_numeric_element_size (sizeof (mxInt16));
1413  case mxUINT16_CLASS: return get_numeric_element_size (sizeof (mxUint16));
1414  case mxINT32_CLASS: return get_numeric_element_size (sizeof (mxInt32));
1415  case mxUINT32_CLASS: return get_numeric_element_size (sizeof (mxUint32));
1416  case mxINT64_CLASS: return get_numeric_element_size (sizeof (mxInt64));
1417  case mxUINT64_CLASS: return get_numeric_element_size (sizeof (mxUint64));
1418  case mxFUNCTION_CLASS: return 0;
1419  // FIXME: user-defined objects need their own class ID.
1420  // What should they return, size of pointer?
1421  default: return 0;
1422  }
1423  }
1424 
1425 protected:
1426 
1427  mxArray_matlab (bool interleaved, bool is_complex, mxClassID id,
1428  mwSize ndims, const mwSize *dims)
1429  : mxArray_base (interleaved), m_class_name (nullptr), m_id (id),
1430  m_is_complex (is_complex), m_ndims (ndims < 2 ? 2 : ndims),
1431  m_dims (static_cast<mwSize *> (mxArray::malloc (m_ndims * sizeof (mwSize))))
1432  {
1433  if (ndims == 0)
1434  {
1435  m_dims[0] = 0;
1436  m_dims[1] = 0;
1437  }
1438  else if (ndims < 2)
1439  {
1440  m_dims[0] = 1;
1441  m_dims[1] = 1;
1442  }
1443 
1444  for (mwIndex i = 0; i < ndims; i++)
1445  m_dims[i] = dims[i];
1446 
1447  for (mwIndex i = m_ndims - 1; i > 1; i--)
1448  {
1449  if (m_dims[i] == 1)
1450  m_ndims--;
1451  else
1452  break;
1453  }
1454  }
1455 
1456  mxArray_matlab (bool interleaved, bool is_complex, mxClassID id,
1457  const dim_vector& dv)
1458  : mxArray_base (interleaved), m_class_name (nullptr), m_id (id),
1459  m_is_complex (is_complex), m_ndims (dv.ndims ()),
1460  m_dims (static_cast<mwSize *> (mxArray::malloc (m_ndims * sizeof (mwSize))))
1461  {
1462  for (mwIndex i = 0; i < m_ndims; i++)
1463  m_dims[i] = dv(i);
1464 
1465  for (mwIndex i = m_ndims - 1; i > 1; i--)
1466  {
1467  if (m_dims[i] == 1)
1468  m_ndims--;
1469  else
1470  break;
1471  }
1472  }
1473 
1474  mxArray_matlab (bool interleaved, bool is_complex, mxClassID id,
1475  mwSize m, mwSize n)
1476  : mxArray_base (interleaved), m_class_name (nullptr), m_id (id),
1477  m_is_complex (is_complex), m_ndims (2),
1478  m_dims (static_cast<mwSize *> (mxArray::malloc (m_ndims * sizeof (mwSize))))
1479  {
1480  m_dims[0] = m;
1481  m_dims[1] = n;
1482  }
1483 
1484  mxArray_matlab (const mxArray_matlab& val)
1485  : mxArray_base (val), m_class_name (mxArray::strsave (val.m_class_name)),
1486  m_id (val.m_id), m_is_complex (val.m_is_complex), m_ndims (val.m_ndims),
1487  m_dims (static_cast<mwSize *> (mxArray::malloc (m_ndims * sizeof (mwSize))))
1488  {
1489  for (mwIndex i = 0; i < m_ndims; i++)
1490  m_dims[i] = val.m_dims[i];
1491  }
1492 
1493  void set_complexity (bool is_complex) { m_is_complex = is_complex; }
1494 
1495  dim_vector
1496  dims_to_dim_vector (void) const
1497  {
1498  mwSize nd = get_number_of_dimensions ();
1499 
1500  mwSize *d = get_dimensions ();
1501 
1502  dim_vector dv;
1503  dv.resize (nd);
1504 
1505  for (mwIndex i = 0; i < nd; i++)
1506  dv(i) = d[i];
1507 
1508  return dv;
1509  }
1510 
1511 private:
1512 
1513  char *m_class_name;
1514 
1515  mxClassID m_id;
1516 
1517  bool m_is_complex;
1518 
1519  mwSize m_ndims;
1520  mwSize *m_dims;
1521 };
1522 
1523 
1524 // Matlab-style numeric, character, and logical data.
1525 
1526 class mxArray_base_full : public mxArray_matlab
1527 {
1528 public:
1529 
1530  mxArray_base_full () = delete;
1531 
1532  mxArray_base_full (bool interleaved, bool is_complex, mxClassID id,
1533  mwSize ndims, const mwSize *dims, bool init = true)
1534  : mxArray_matlab (interleaved, is_complex, id, ndims, dims),
1535  m_pr (mxArray::alloc (init, get_number_of_elements (), get_element_size ()))
1536  { }
1537 
1538  mxArray_base_full (bool interleaved, bool is_complex, mxClassID id,
1539  const dim_vector& dv)
1540  : mxArray_matlab (interleaved, is_complex, id, dv),
1541  m_pr (mxArray::calloc (get_number_of_elements (), get_element_size ()))
1542  { }
1543 
1544  mxArray_base_full (bool interleaved, bool is_complex, mxClassID id,
1545  mwSize m, mwSize n, bool init = true)
1546  : mxArray_matlab (interleaved, is_complex, id, m, n),
1547  m_pr (mxArray::alloc (init, get_number_of_elements (), get_element_size ()))
1548  { }
1549 
1550  mxArray_base_full (bool interleaved, mxClassID id, double val)
1551  : mxArray_matlab (interleaved, false, id, 1, 1),
1552  m_pr (mxArray::calloc (get_number_of_elements (), get_element_size ()))
1553  {
1554  double *dpr = static_cast<double *> (m_pr);
1555  dpr[0] = val;
1556  }
1557 
1558  mxArray_base_full (bool interleaved, mxClassID id, mxLogical val)
1559  : mxArray_matlab (interleaved, false, id, 1, 1),
1560  m_pr (mxArray::calloc (get_number_of_elements (), get_element_size ()))
1561  {
1562  mxLogical *lpr = static_cast<mxLogical *> (m_pr);
1563  lpr[0] = val;
1564  }
1565 
1566  mxArray_base_full (bool interleaved, const char *str)
1567  : mxArray_matlab (interleaved, false, mxCHAR_CLASS,
1568  str ? (strlen (str) ? 1 : 0) : 0,
1569  str ? strlen (str) : 0),
1570  m_pr (mxArray::calloc (get_number_of_elements (), get_element_size ()))
1571  {
1572  mxChar *cpr = static_cast<mxChar *> (m_pr);
1573  mwSize nel = get_number_of_elements ();
1574  for (mwIndex i = 0; i < nel; i++)
1575  cpr[i] = str[i];
1576  }
1577 
1578  // FIXME: ???
1579  mxArray_base_full (bool interleaved, mwSize m, const char **str)
1580  : mxArray_matlab (interleaved, false, mxCHAR_CLASS, m, max_str_len (m, str)),
1581  m_pr (mxArray::calloc (get_number_of_elements (), get_element_size ()))
1582  {
1583  mxChar *cpr = static_cast<mxChar *> (m_pr);
1584 
1585  mwSize *dv = get_dimensions ();
1586 
1587  mwSize nc = dv[1];
1588 
1589  for (mwIndex j = 0; j < m; j++)
1590  {
1591  const char *ptr = str[j];
1592 
1593  std::size_t tmp_len = strlen (ptr);
1594 
1595  for (std::size_t i = 0; i < tmp_len; i++)
1596  cpr[m*i+j] = static_cast<mxChar> (ptr[i]);
1597 
1598  for (std::size_t i = tmp_len; i < static_cast<std::size_t> (nc); i++)
1599  cpr[m*i+j] = static_cast<mxChar> (' ');
1600  }
1601  }
1602 
1603  // No assignment! FIXME: should this be implemented? Note that we
1604  // do have a copy constructor.
1605 
1606  mxArray_base_full& operator = (const mxArray_base_full&) = delete;
1607 
1608  mxArray_base * dup (void) const
1609  {
1610  return new mxArray_base_full (*this);
1611  }
1612 
1613  ~mxArray_base_full (void)
1614  {
1615  mxFree (m_pr);
1616  }
1617 
1618  double get_scalar (void) const
1619  {
1620  // FIXME: how does this work for interleaved complex arrays?
1621 
1622  double retval = 0;
1623 
1624  switch (get_class_id ())
1625  {
1626  case mxDOUBLE_CLASS:
1627  retval = *(static_cast<double *> (m_pr));
1628  break;
1629 
1630  case mxSINGLE_CLASS:
1631  retval = *(static_cast<float *> (m_pr));
1632  break;
1633 
1634  case mxCHAR_CLASS:
1635  retval = *(static_cast<mxChar *> (m_pr));
1636  break;
1637 
1638  case mxLOGICAL_CLASS:
1639  retval = *(static_cast<bool *> (m_pr));
1640  break;
1641 
1642  case mxINT8_CLASS:
1643  retval = *(static_cast<int8_t *> (m_pr));
1644  break;
1645 
1646  case mxUINT8_CLASS:
1647  retval = *(static_cast<uint8_t *> (m_pr));
1648  break;
1649 
1650  case mxINT16_CLASS:
1651  retval = *(static_cast<int16_t *> (m_pr));
1652  break;
1653 
1654  case mxUINT16_CLASS:
1655  retval = *(static_cast<uint16_t *> (m_pr));
1656  break;
1657 
1658  case mxINT32_CLASS:
1659  retval = *(static_cast<int32_t *> (m_pr));
1660  break;
1661 
1662  case mxUINT32_CLASS:
1663  retval = *(static_cast<uint32_t *> (m_pr));
1664  break;
1665 
1666  case mxINT64_CLASS:
1667  retval = *(static_cast<int64_t *> (m_pr));
1668  break;
1669 
1670  case mxUINT64_CLASS:
1671  retval = *(static_cast<uint64_t *> (m_pr));
1672  break;
1673 
1674  default:
1675  panic_impossible ();
1676  }
1677 
1678  return retval;
1679  }
1680 
1681  void * get_data (void) const { return m_pr; }
1682 
1683  void set_data (void *pr) { m_pr = pr; }
1684 
1685  // The typed get and set functions only work for interleaved data but
1686  // they are defined here because this class owns PR. There are
1687  // definitions in the mxArray_separate_full class that override these
1688  // functions.
1689 
1690  mxDouble * get_doubles (void) const
1691  {
1692  return static_cast<mxDouble *> (m_pr);
1693  }
1694 
1695  mxSingle * get_singles (void) const
1696  {
1697  return static_cast<mxSingle *> (m_pr);
1698  }
1699 
1700  mxInt8 * get_int8s (void) const
1701  {
1702  return static_cast<mxInt8 *> (m_pr);
1703  }
1704 
1705  mxInt16 * get_int16s (void) const
1706  {
1707  return static_cast<mxInt16 *> (m_pr);
1708  }
1709 
1710  mxInt32 * get_int32s (void) const
1711  {
1712  return static_cast<mxInt32 *> (m_pr);
1713  }
1714 
1715  mxInt64 * get_int64s (void) const
1716  {
1717  return static_cast<mxInt64 *> (m_pr);
1718  }
1719 
1720  mxUint8 * get_uint8s (void) const
1721  {
1722  return static_cast<mxUint8 *> (m_pr);
1723  }
1724 
1725  mxUint16 * get_uint16s (void) const
1726  {
1727  return static_cast<mxUint16 *> (m_pr);
1728  }
1729 
1730  mxUint32 * get_uint32s (void) const
1731  {
1732  return static_cast<mxUint32 *> (m_pr);
1733  }
1734 
1735  mxUint64 * get_uint64s (void) const
1736  {
1737  return static_cast<mxUint64 *> (m_pr);
1738  }
1739 
1740  mxComplexDouble * get_complex_doubles (void) const
1741  {
1742  return static_cast<mxComplexDouble *> (m_pr);
1743  }
1744 
1745  mxComplexSingle * get_complex_singles (void) const
1746  {
1747  return static_cast<mxComplexSingle *> (m_pr);
1748  }
1749 
1750  int set_doubles (mxDouble *d)
1751  {
1752  m_pr = d;
1753  return 0;
1754  }
1755 
1756  int set_singles (mxSingle *d)
1757  {
1758  m_pr = d;
1759  return 0;
1760  }
1761 
1762  int set_int8s (mxInt8 *d)
1763  {
1764  m_pr = d;
1765  return 0;
1766  }
1767 
1768  int set_int16s (mxInt16 *d)
1769  {
1770  m_pr = d;
1771  return 0;
1772  }
1773 
1774  int set_int32s (mxInt32 *d)
1775  {
1776  m_pr = d;
1777  return 0;
1778  }
1779 
1780  int set_int64s (mxInt64 *d)
1781  {
1782  m_pr = d;
1783  return 0;
1784  }
1785 
1786  int set_uint8s (mxUint8 *d)
1787  {
1788  m_pr = d;
1789  return 0;
1790  }
1791 
1792  int set_uint16s (mxUint16 *d)
1793  {
1794  m_pr = d;
1795  return 0;
1796  }
1797 
1798  int set_uint32s (mxUint32 *d)
1799  {
1800  m_pr = d;
1801  return 0;
1802  }
1803 
1804  int set_uint64s (mxUint64 *d)
1805  {
1806  m_pr = d;
1807  return 0;
1808  }
1809 
1810  int set_complex_doubles (mxComplexDouble *d)
1811  {
1812  m_pr = d;
1813  return 0;
1814  }
1815 
1816  int set_complex_singles (mxComplexSingle *d)
1817  {
1818  m_pr = d;
1819  return 0;
1820  }
1821 
1822  int get_string (char *buf, mwSize buflen) const
1823  {
1824  int retval = 0;
1825 
1826  mwSize nel = get_number_of_elements ();
1827 
1828  if (! (nel < buflen))
1829  {
1830  retval = 1;
1831  if (buflen > 0)
1832  nel = buflen-1;
1833  }
1834 
1835  if (nel < buflen)
1836  {
1837  mxChar *ptr = static_cast<mxChar *> (m_pr);
1838 
1839  for (mwIndex i = 0; i < nel; i++)
1840  buf[i] = static_cast<char> (ptr[i]);
1841 
1842  buf[nel] = 0;
1843  }
1844 
1845  return retval;
1846  }
1847 
1848  char * array_to_string (void) const
1849  {
1850  // FIXME: this is supposed to handle multi-byte character strings.
1851 
1852  mwSize nel = get_number_of_elements ();
1853 
1854  char *buf = static_cast<char *> (mxArray::malloc (nel + 1));
1855 
1856  if (buf)
1857  {
1858  mxChar *ptr = static_cast<mxChar *> (m_pr);
1859 
1860  for (mwIndex i = 0; i < nel; i++)
1861  buf[i] = static_cast<char> (ptr[i]);
1862 
1863  buf[nel] = '\0';
1864  }
1865 
1866  return buf;
1867  }
1868 
1869  octave_value as_octave_value (void) const
1870  {
1871  octave_value retval;
1872 
1873  dim_vector dv = dims_to_dim_vector ();
1874 
1875  switch (get_class_id ())
1876  {
1877  case mxDOUBLE_CLASS:
1878  return (is_complex ()
1879  ? fp_to_ov<Complex> (dv) : fp_to_ov<double> (dv));
1880 
1881  case mxSINGLE_CLASS:
1882  return (is_complex ()
1883  ? fp_to_ov<FloatComplex> (dv) : fp_to_ov<float> (dv));
1884 
1885  case mxCHAR_CLASS:
1886  return int_to_ov<mxChar, charNDArray, char> (dv);
1887 
1888  case mxLOGICAL_CLASS:
1889  return int_to_ov<mxLogical, boolNDArray, bool> (dv);
1890 
1891  case mxINT8_CLASS:
1892  return int_to_ov<int8_t, int8NDArray, octave_int8> (dv);
1893 
1894  case mxUINT8_CLASS:
1895  return int_to_ov<uint8_t, uint8NDArray, octave_uint8> (dv);
1896 
1897  case mxINT16_CLASS:
1898  return int_to_ov<int16_t, int16NDArray, octave_int16> (dv);
1899 
1900  case mxUINT16_CLASS:
1901  return int_to_ov<uint16_t, uint16NDArray, octave_uint16> (dv);
1902 
1903  case mxINT32_CLASS:
1904  return int_to_ov<int32_t, int32NDArray, octave_int32> (dv);
1905 
1906  case mxUINT32_CLASS:
1907  return int_to_ov<uint32_t, uint32NDArray, octave_uint32> (dv);
1908 
1909  case mxINT64_CLASS:
1910  return int_to_ov<int64_t, int64NDArray, octave_int64> (dv);
1911 
1912  case mxUINT64_CLASS:
1913  return int_to_ov<uint64_t, uint64NDArray, octave_uint64> (dv);
1914 
1915  default:
1916  panic_impossible ();
1917  }
1918 
1919  return retval;
1920  }
1921 
1922 protected:
1923 
1924  mxArray_base_full (const mxArray_base_full& val)
1925  : mxArray_matlab (val),
1926  m_pr (mxArray::malloc (get_number_of_elements () * get_element_size ()))
1927  {
1928  if (m_pr)
1929  memcpy (m_pr, val.m_pr, get_number_of_elements () * get_element_size ());
1930  }
1931 
1932  template <typename ELT_T>
1933  octave_value
1934  fp_to_ov (const dim_vector& dv) const
1935  {
1936  octave_value retval;
1937 
1938  ELT_T *ppr = static_cast<ELT_T *> (m_pr);
1939 
1940 #if defined (OCTAVE_HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR)
1941 
1942  if (current_mx_memory_resource == &the_mx_deleting_memory_resource)
1943  {
1944  octave::unwind_action act ([=] () { maybe_disown_ptr (m_pr); });
1945 
1946  return octave_value (Array<ELT_T> (ppr, dv, current_mx_memory_resource));
1947  }
1948  else
1949  return octave_value (Array<ELT_T> (ppr, dv, current_mx_memory_resource));
1950 
1951 #else
1952 
1953  // Copy data instead of allowing the octave_value object to borrow
1954  // the mxArray object data.
1955 
1956  Array<ELT_T> val (dv);
1957 
1958  ELT_T *ptr = val.fortran_vec ();
1959 
1960  mwSize nel = get_number_of_elements ();
1961 
1962  for (mwIndex i = 0; i < nel; i++)
1963  ptr[i] = ppr[i];
1964 
1965  return octave_value (val);
1966 
1967 #endif
1968  }
1969 
1970  template <typename ELT_T, typename ARRAY_T, typename ARRAY_ELT_T>
1971  octave_value
1972  int_to_ov (const dim_vector& dv) const
1973  {
1974  if (is_complex ())
1975  error ("complex integer types are not supported");
1976 
1977  ELT_T *ppr = static_cast<ELT_T *> (m_pr);
1978 
1979  // Copy data instead of allowing the octave_value object to borrow
1980  // the mxArray object data.
1981 
1982  ARRAY_T val (dv);
1983 
1984  ARRAY_ELT_T *ptr = val.fortran_vec ();
1985 
1986  mwSize nel = get_number_of_elements ();
1987 
1988  for (mwIndex i = 0; i < nel; i++)
1989  ptr[i] = ppr[i];
1990 
1991  return octave_value (val);
1992 
1993  }
1994 
1995 protected:
1996 
1997  // If using interleaved complex storage, this is the pointer to data
1998  // (real, complex, or logical). Otherwise, it is the pointer to the
1999  // real part of the data.
2000  void *m_pr;
2001 };
2002 
2003 class mxArray_interleaved_full : public mxArray_base_full
2004 {
2005 public:
2006 
2007  mxArray_interleaved_full () = delete;
2008 
2009  mxArray_interleaved_full (mxClassID id, mwSize ndims, const mwSize *dims,
2010  mxComplexity flag = mxREAL, bool init = true)
2011  : mxArray_base_full (true, flag == mxCOMPLEX, id, ndims, dims, init)
2012  { }
2013 
2014  mxArray_interleaved_full (mxClassID id, const dim_vector& dv,
2015  mxComplexity flag = mxREAL)
2016  : mxArray_base_full (true, flag == mxCOMPLEX, id, dv)
2017  { }
2018 
2019  mxArray_interleaved_full (mxClassID id, mwSize m, mwSize n,
2020  mxComplexity flag = mxREAL, bool init = true)
2021  : mxArray_base_full (true, flag == mxCOMPLEX, id, m, n, init)
2022  { }
2023 
2024  mxArray_interleaved_full (mxClassID id, double val)
2025  : mxArray_base_full (true, id, val)
2026  { }
2027 
2028  mxArray_interleaved_full (mxClassID id, mxLogical val)
2029  : mxArray_base_full (true, id, val)
2030  { }
2031 
2032  mxArray_interleaved_full (const char *str)
2033  : mxArray_base_full (true, str)
2034  { }
2035 
2036  // FIXME: ???
2037  mxArray_interleaved_full (mwSize m, const char **str)
2038  : mxArray_base_full (true, m, str)
2039  { }
2040 
2041  // No assignment! FIXME: should this be implemented? Note that we
2042  // do have a copy constructor.
2043 
2044  mxArray_interleaved_full& operator = (const mxArray_interleaved_full&) = delete;
2045 
2046  mxArray_base * dup (void) const
2047  {
2048  return new mxArray_interleaved_full (*this);
2049  }
2050 
2051  ~mxArray_interleaved_full (void) = default;
2052 
2053  void * get_imag_data (void) const { panic_impossible (); }
2054 
2055  void set_imag_data (void */*pi*/) { panic_impossible (); }
2056 
2057 protected:
2058 
2059  mxArray_interleaved_full (const mxArray_interleaved_full& val)
2060  : mxArray_base_full (val)
2061  { }
2062 };
2063 
2064 class mxArray_separate_full : public mxArray_base_full
2065 {
2066 public:
2067 
2068  mxArray_separate_full () = delete;
2069 
2070  mxArray_separate_full (mxClassID id, mwSize ndims, const mwSize *dims,
2071  mxComplexity flag = mxREAL, bool init = true)
2072  : mxArray_base_full (false, flag == mxCOMPLEX, id, ndims, dims, init),
2073  m_pi (flag == mxCOMPLEX
2074  ? mxArray::alloc (init, get_number_of_elements (), get_element_size ())
2075  : nullptr)
2076  { }
2077 
2078  mxArray_separate_full (mxClassID id, const dim_vector& dv,
2079  mxComplexity flag = mxREAL)
2080  : mxArray_base_full (false, flag == mxCOMPLEX, id, dv),
2081  m_pi (is_complex ()
2082  ? mxArray::calloc (get_number_of_elements (), get_element_size ())
2083  : nullptr)
2084  { }
2085 
2086  mxArray_separate_full (mxClassID id, mwSize m, mwSize n,
2087  mxComplexity flag = mxREAL, bool init = true)
2088  : mxArray_base_full (false, flag == mxCOMPLEX, id, m, n, init),
2089  m_pi (is_complex ()
2090  ? (mxArray::alloc (init, get_number_of_elements (), get_element_size ()))
2091  : nullptr)
2092  { }
2093 
2094  mxArray_separate_full (mxClassID id, double val)
2095  : mxArray_base_full (false, id, val), m_pi (nullptr)
2096  { }
2097 
2098  mxArray_separate_full (mxClassID id, mxLogical val)
2099  : mxArray_base_full (false, id, val), m_pi (nullptr)
2100  { }
2101 
2102  mxArray_separate_full (const char *str)
2103  : mxArray_base_full (false, str), m_pi (nullptr)
2104  { }
2105 
2106  // FIXME: ???
2107  mxArray_separate_full (mwSize m, const char **str)
2108  : mxArray_base_full (false, m, str), m_pi (nullptr)
2109  { }
2110 
2111  // No assignment! FIXME: should this be implemented? Note that we
2112  // do have a copy constructor.
2113 
2114  mxArray_separate_full& operator = (const mxArray_separate_full&) = delete;
2115 
2116  mxArray_base * dup (void) const
2117  {
2118  return new mxArray_separate_full (*this);
2119  }
2120 
2121  ~mxArray_separate_full (void)
2122  {
2123  mxFree (m_pi);
2124  }
2125 
2126  void * get_imag_data (void) const { return m_pi; }
2127 
2128  void set_imag_data (void *pi)
2129  {
2130  m_pi = pi;
2131 
2132  set_complexity (m_pi != nullptr);
2133  }
2134 
2135  mxDouble * get_doubles (void) const { panic_impossible (); }
2136  mxSingle * get_singles (void) const { panic_impossible (); }
2137  mxInt8 * get_int8s (void) const { panic_impossible (); }
2138  mxInt16 * get_int16s (void) const { panic_impossible (); }
2139  mxInt32 * get_int32s (void) const { panic_impossible (); }
2140  mxInt64 * get_int64s (void) const { panic_impossible (); }
2141  mxUint8 * get_uint8s (void) const { panic_impossible (); }
2142  mxUint16 * get_uint16s (void) const { panic_impossible (); }
2143  mxUint32 * get_uint32s (void) const { panic_impossible (); }
2144  mxUint64 * get_uint64s (void) const { panic_impossible (); }
2145 
2146  mxComplexDouble * get_complex_doubles (void) const { panic_impossible (); }
2147  mxComplexSingle * get_complex_singles (void) const { panic_impossible (); }
2148 
2149  // We don't have complex integer types, but for separate storage they
2150  // still would not work.
2151  mxComplexInt8 * get_complex_int8s (void) const { panic_impossible (); }
2152  mxComplexInt16 * get_complex_int16s (void) const { panic_impossible (); }
2153  mxComplexInt32 * get_complex_int32s (void) const { panic_impossible (); }
2154  mxComplexInt64 * get_complex_int64s (void) const { panic_impossible (); }
2155  mxComplexUint8 * get_complex_uint8s (void) const { panic_impossible (); }
2156  mxComplexUint16 * get_complex_uint16s (void) const { panic_impossible (); }
2157  mxComplexUint32 * get_complex_uint32s (void) const { panic_impossible (); }
2158  mxComplexUint64 * get_complex_uint64s (void) const { panic_impossible (); }
2159 
2160  int set_doubles (mxDouble *) { panic_impossible (); }
2161  int set_singles (mxSingle *) { panic_impossible (); }
2162  int set_int8s (mxInt8 *) { panic_impossible (); }
2163  int set_int16s (mxInt16 *) { panic_impossible (); }
2164  int set_int32s (mxInt32 *) { panic_impossible (); }
2165  int set_int64s (mxInt64 *) { panic_impossible (); }
2166  int set_uint8s (mxUint8 *) { panic_impossible (); }
2167  int set_uint16s (mxUint16 *) { panic_impossible (); }
2168  int set_uint32s (mxUint32 *) { panic_impossible (); }
2169  int set_uint64s (mxUint64 *) { panic_impossible (); }
2170 
2171  int set_complex_doubles (mxComplexDouble *) { panic_impossible (); }
2172  int set_complex_singles (mxComplexSingle *) { panic_impossible (); }
2173 
2174  // We don't have complex integer types, but for separate storage they
2175  // still would not work.
2176  int set_complex_int8s (mxComplexInt8 *) { panic_impossible (); }
2177  int set_complex_int16s (mxComplexInt16 *) { panic_impossible (); }
2178  int set_complex_int32s (mxComplexInt32 *) { panic_impossible (); }
2179  int set_complex_int64s (mxComplexInt64 *) { panic_impossible (); }
2180  int set_complex_uint8s (mxComplexUint8 *) { panic_impossible (); }
2181  int set_complex_uint16s (mxComplexUint16 *) { panic_impossible (); }
2182  int set_complex_uint32s (mxComplexUint32 *) { panic_impossible (); }
2183  int set_complex_uint64s (mxComplexUint64 *) { panic_impossible (); }
2184 
2185  octave_value as_octave_value (void) const
2186  {
2187  if (! is_complex ())
2188  return mxArray_base_full::as_octave_value ();
2189 
2190  octave_value retval;
2191 
2192  dim_vector dv = dims_to_dim_vector ();
2193 
2194  switch (get_class_id ())
2195  {
2196  case mxDOUBLE_CLASS:
2197  return to_ov<double> (dv);
2198 
2199  case mxSINGLE_CLASS:
2200  return to_ov<float> (dv);
2201 
2202  case mxLOGICAL_CLASS:
2203  case mxINT8_CLASS:
2204  case mxUINT8_CLASS:
2205  case mxINT16_CLASS:
2206  case mxUINT16_CLASS:
2207  case mxINT32_CLASS:
2208  case mxUINT32_CLASS:
2209  case mxINT64_CLASS:
2210  case mxUINT64_CLASS:
2211  error ("complex integer types are not supported");
2212 
2213  default:
2214  panic_impossible ();
2215  }
2216 
2217  return retval;
2218  }
2219 
2220 protected:
2221 
2222  mxArray_separate_full (const mxArray_separate_full& val)
2223  : mxArray_base_full (val),
2224  m_pi (val.m_pi
2225  ? mxArray::malloc (get_number_of_elements () * get_element_size ())
2226  : nullptr)
2227  {
2228  if (m_pi)
2229  memcpy (m_pi, val.m_pi, get_number_of_elements () * get_element_size ());
2230  }
2231 
2232 private:
2233 
2234  template <typename T>
2235  octave_value
2236  to_ov (const dim_vector& dv) const
2237  {
2238  mwSize nel = get_number_of_elements ();
2239 
2240  T *ppr = static_cast<T *> (m_pr);
2241 
2242  // We allocate in the Array<T> constructor and copy here, so we
2243  // don't need the custom allocator for this object.
2244 
2245  Array<std::complex<T>> val (dv);
2246 
2247  std::complex<T> *ptr = val.fortran_vec ();
2248 
2249  T *ppi = static_cast<T *> (m_pi);
2250 
2251  for (mwIndex i = 0; i < nel; i++)
2252  ptr[i] = std::complex<T> (ppr[i], ppi[i]);
2253 
2254  return octave_value (val);
2255  }
2256 
2257  // Pointer to the imaginary part of the data.
2258  void *m_pi;
2259 };
2260 
2261 // Matlab-style sparse arrays.
2262 
2263 class mxArray_base_sparse : public mxArray_matlab
2264 {
2265 public:
2266 
2267  mxArray_base_sparse () = delete;
2268 
2269  mxArray_base_sparse (bool interleaved, bool is_complex,
2270  mxClassID id, mwSize m, mwSize n, mwSize nzmax)
2271  : mxArray_matlab (interleaved, is_complex, id, m, n),
2272 
2273  m_nzmax (nzmax > 0 ? nzmax : 1),
2274  m_ir (static_cast<mwIndex *> (mxArray::calloc (m_nzmax, sizeof (mwIndex)))),
2275  m_jc (static_cast<mwIndex *> (mxArray::calloc (n + 1, sizeof (mwIndex)))),
2276  m_pr (mxArray::calloc (m_nzmax, get_element_size ()))
2277  { }
2278 
2279 protected:
2280 
2281  mxArray_base_sparse (const mxArray_base_sparse& val)
2282  : mxArray_matlab (val), m_nzmax (val.m_nzmax),
2283  m_ir (static_cast<mwIndex *> (mxArray::malloc (m_nzmax * sizeof (mwIndex)))),
2284  m_jc (static_cast<mwIndex *> (mxArray::malloc (m_nzmax * sizeof (mwIndex)))),
2285  m_pr (mxArray::malloc (m_nzmax * get_element_size ()))
2286  {
2287  if (m_ir)
2288  memcpy (m_ir, val.m_ir, m_nzmax * sizeof (mwIndex));
2289 
2290  if (m_jc)
2291  memcpy (m_jc, val.m_jc, (val.get_n () + 1) * sizeof (mwIndex));
2292 
2293  if (m_pr)
2294  memcpy (m_pr, val.m_pr, m_nzmax * get_element_size ());
2295  }
2296 
2297 public:
2298 
2299  // No assignment! FIXME: should this be implemented? Note that we
2300  // do have a copy constructor.
2301 
2302  mxArray_base_sparse& operator = (const mxArray_base_sparse&) = delete;
2303 
2304  mxArray_base * dup (void) const
2305  {
2306  return new mxArray_base_sparse (*this);
2307  }
2308 
2309  ~mxArray_base_sparse (void)
2310  {
2311  mxFree (m_ir);
2312  mxFree (m_jc);
2313  mxFree (m_pr);
2314  }
2315 
2316  int is_sparse (void) const { return 1; }
2317 
2318  void * get_data (void) const { return m_pr; }
2319 
2320  void set_data (void *pr) { m_pr = pr; }
2321 
2322  mxDouble * get_doubles (void) const
2323  {
2324  return static_cast<mxDouble *> (m_pr);
2325  }
2326 
2327  mxComplexDouble * get_complex_doubles (void) const
2328  {
2329  return static_cast<mxComplexDouble *> (m_pr);
2330  }
2331 
2332  int set_doubles (mxDouble *d)
2333  {
2334  m_pr = d;
2335  return 0;
2336  }
2337 
2338  int set_complex_doubles (mxComplexDouble *d)
2339  {
2340  m_pr = d;
2341  return 0;
2342  }
2343 
2344  mwIndex * get_ir (void) const { return m_ir; }
2345 
2346  mwIndex * get_jc (void) const { return m_jc; }
2347 
2348  mwSize get_nzmax (void) const { return m_nzmax; }
2349 
2350  void set_ir (mwIndex *ir) { m_ir = ir; }
2351 
2352  void set_jc (mwIndex *jc) { m_jc = jc; }
2353 
2354  void set_nzmax (mwSize nzmax)
2355  {
2356  /* Require storage for at least 1 element */
2357  m_nzmax = (nzmax > 0 ? nzmax : 1);
2358  }
2359 
2360  octave_value as_octave_value (void) const
2361  {
2362  octave_value retval;
2363 
2364  dim_vector dv = dims_to_dim_vector ();
2365 
2366  switch (get_class_id ())
2367  {
2368  case mxDOUBLE_CLASS:
2369  return is_complex () ? to_ov<Complex> (dv): to_ov<double> (dv);
2370 
2371  case mxSINGLE_CLASS:
2372  error ("single precision sparse data type not supported");
2373 
2374  case mxLOGICAL_CLASS:
2375  return to_ov<bool> (dv);
2376 
2377  default:
2378  panic_impossible ();
2379  }
2380 
2381  return retval;
2382  }
2383 
2384 protected:
2385 
2386  template <typename ELT_T>
2387  octave_value
2388  to_ov (const dim_vector& dv) const
2389  {
2390  ELT_T *ppr = static_cast<ELT_T *> (m_pr);
2391 
2392 #if defined (OCTAVE_HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR)
2393 
2394  if (current_mx_memory_resource == &the_mx_deleting_memory_resource)
2395  {
2396  octave::unwind_action act ([=] ()
2397  {
2398  maybe_disown_ptr (m_pr);
2399  maybe_disown_ptr (m_ir);
2400  maybe_disown_ptr (m_jc);
2401  });
2402 
2403  return octave_value
2404  (Sparse<ELT_T> (dv, static_cast<octave_idx_type> (m_nzmax),
2405  ppr, m_ir, m_jc, current_mx_memory_resource));
2406  }
2407  else
2408  return octave_value
2409  (Sparse<ELT_T> (dv, static_cast<octave_idx_type> (m_nzmax),
2410  ppr, m_ir, m_jc, current_mx_memory_resource));
2411 #else
2412 
2413  // Copy data instead of allowing the octave_value object to borrow
2414  // the mxArray object data.
2415 
2416  octave_idx_type m = dv(0);
2417  octave_idx_type n = dv(1);
2418 
2419  Sparse<ELT_T> val (m, n, static_cast<octave_idx_type> (m_nzmax));
2420 
2421  for (mwIndex i = 0; i < m_nzmax; i++)
2422  {
2423  val.xdata (i) = ppr[i];
2424  val.xridx (i) = m_ir[i];
2425  }
2426 
2427  for (mwIndex i = 0; i < n + 1; i++)
2428  val.xcidx (i) = m_jc[i];
2429 
2430  return octave_value (val);
2431 
2432 #endif
2433  }
2434 
2435  // Maximun number of nonzero elements.
2436  mwSize m_nzmax;
2437 
2438  // Sparse storage indexing arrays.
2439  mwIndex *m_ir;
2440  mwIndex *m_jc;
2441 
2442  // If using interleaved complex storage, this is the pointer to data
2443  // (real, complex, or logical). Otherwise, it is the pointer to the
2444  // real part of the data.
2445  void *m_pr;
2446 };
2447 
2448 class mxArray_interleaved_sparse : public mxArray_base_sparse
2449 {
2450 public:
2451 
2452  mxArray_interleaved_sparse () = delete;
2453 
2454  mxArray_interleaved_sparse (mxClassID id, mwSize m, mwSize n, mwSize nzmax,
2455  mxComplexity flag = mxREAL)
2456  : mxArray_base_sparse (true, flag == mxCOMPLEX, id, m, n, nzmax)
2457  { }
2458 
2459 private:
2460 
2461  mxArray_interleaved_sparse (const mxArray_interleaved_sparse& val)
2462  : mxArray_base_sparse (val)
2463  { }
2464 
2465 public:
2466 
2467  // No assignment! FIXME: should this be implemented? Note that we
2468  // do have a copy constructor.
2469 
2470  mxArray_interleaved_sparse& operator = (const mxArray_interleaved_sparse&) = delete;
2471 
2472  mxArray_base * dup (void) const
2473  {
2474  return new mxArray_interleaved_sparse (*this);
2475  }
2476 
2477  ~mxArray_interleaved_sparse (void) = default;
2478 
2479  void * get_imag_data (void) const { panic_impossible (); }
2480 
2481  void set_imag_data (void */*pi*/) { panic_impossible (); }
2482 };
2483 
2484 class mxArray_separate_sparse : public mxArray_base_sparse
2485 {
2486 public:
2487 
2488  mxArray_separate_sparse () = delete;
2489 
2490  mxArray_separate_sparse (mxClassID id, mwSize m, mwSize n, mwSize nzmax,
2491  mxComplexity flag = mxREAL)
2492  : mxArray_base_sparse (false, flag == mxCOMPLEX, id, m, n, nzmax),
2493  m_pi (is_complex ()
2494  ? mxArray::calloc (m_nzmax, get_element_size ())
2495  : nullptr)
2496  { }
2497 
2498 private:
2499 
2500  mxArray_separate_sparse (const mxArray_separate_sparse& val)
2501  : mxArray_base_sparse (val),
2502  m_pi (val.m_pi
2503  ? mxArray::malloc (m_nzmax * get_element_size ())
2504  : nullptr)
2505  {
2506  if (m_pi)
2507  memcpy (m_pi, val.m_pi, m_nzmax * get_element_size ());
2508  }
2509 
2510 public:
2511 
2512  // No assignment! FIXME: should this be implemented? Note that we
2513  // do have a copy constructor.
2514 
2515  mxArray_separate_sparse& operator = (const mxArray_separate_sparse&) = delete;
2516 
2517  mxArray_base * dup (void) const
2518  {
2519  return new mxArray_separate_sparse (*this);
2520  }
2521 
2522  ~mxArray_separate_sparse (void)
2523  {
2524  mxFree (m_pi);
2525  }
2526 
2527  void * get_imag_data (void) const { return m_pi; }
2528 
2529  void set_imag_data (void *pi)
2530  {
2531  m_pi = pi;
2532  set_complexity (m_pi != nullptr);
2533  }
2534 
2535  mxDouble * get_doubles (void) const { panic_impossible (); }
2536  mxComplexDouble * get_complex_doubles (void) const { panic_impossible (); }
2537 
2538  int set_doubles (mxDouble *) { panic_impossible (); }
2539  int set_complex_doubles (mxComplexDouble *) { panic_impossible (); }
2540 
2541  octave_value as_octave_value (void) const
2542  {
2543  if (! is_complex ())
2544  return mxArray_base_sparse::as_octave_value ();
2545 
2546  octave_value retval;
2547 
2548  dim_vector dv = dims_to_dim_vector ();
2549 
2550  switch (get_class_id ())
2551  {
2552  case mxDOUBLE_CLASS:
2553  {
2554  double *ppr = static_cast<double *> (m_pr);
2555  double *ppi = static_cast<double *> (m_pi);
2556 
2557  SparseComplexMatrix val (get_m (), get_n (),
2558  static_cast<octave_idx_type> (m_nzmax));
2559 
2560  for (mwIndex i = 0; i < m_nzmax; i++)
2561  {
2562  val.xdata (i) = Complex (ppr[i], ppi[i]);
2563  val.xridx (i) = m_ir[i];
2564  }
2565 
2566  for (mwIndex i = 0; i < get_n () + 1; i++)
2567  val.xcidx (i) = m_jc[i];
2568 
2569  retval = val;
2570  }
2571  break;
2572 
2573  case mxSINGLE_CLASS:
2574  error ("single precision sparse data type not supported");
2575 
2576  default:
2577  panic_impossible ();
2578  }
2579 
2580  return retval;
2581  }
2582 
2583 private:
2584 
2585  // Pointer to the imaginary part of the data.
2586  void *m_pi;
2587 };
2588 
2589 // Matlab-style struct arrays.
2590 
2591 class mxArray_struct : public mxArray_matlab
2592 {
2593 public:
2594 
2595  mxArray_struct () = delete;
2596 
2597  mxArray_struct (bool interleaved, mwSize ndims, const mwSize *dims,
2598  int num_keys, const char **keys)
2599  : mxArray_matlab (interleaved, false, mxSTRUCT_CLASS, ndims, dims),
2600  m_nfields (num_keys),
2601  m_fields (static_cast<char **> (mxArray::calloc (m_nfields,
2602  sizeof (char *)))),
2603  m_data (static_cast<mxArray * *> (mxArray::calloc (m_nfields *
2604  get_number_of_elements (),
2605  sizeof (mxArray *))))
2606  {
2607  init (keys);
2608  }
2609 
2610  mxArray_struct (bool interleaved, const dim_vector& dv, int num_keys,
2611  const char **keys)
2612  : mxArray_matlab (interleaved, false, mxSTRUCT_CLASS, dv),
2613  m_nfields (num_keys),
2614  m_fields (static_cast<char **> (mxArray::calloc (m_nfields,
2615  sizeof (char *)))),
2616  m_data (static_cast<mxArray * *> (mxArray::calloc (m_nfields *
2617  get_number_of_elements (),
2618  sizeof (mxArray *))))
2619  {
2620  init (keys);
2621  }
2622 
2623  mxArray_struct (bool interleaved, mwSize m, mwSize n, int num_keys,
2624  const char **keys)
2625  : mxArray_matlab (interleaved, false, mxSTRUCT_CLASS, m, n),
2626  m_nfields (num_keys),
2627  m_fields (static_cast<char **> (mxArray::calloc (m_nfields,
2628  sizeof (char *)))),
2629  m_data (static_cast<mxArray * *> (mxArray::calloc (m_nfields *
2630  get_number_of_elements (),
2631  sizeof (mxArray *))))
2632  {
2633  init (keys);
2634  }
2635 
2636 private:
2637 
2638  mxArray_struct (const mxArray_struct& val)
2639  : mxArray_matlab (val), m_nfields (val.m_nfields),
2640  m_fields (static_cast<char **> (mxArray::malloc (m_nfields
2641  * sizeof (char *)))),
2642  m_data (static_cast<mxArray * *> (mxArray::malloc (m_nfields *
2643  get_number_of_elements ()
2644  * sizeof (mxArray *))))
2645  {
2646  for (int i = 0; i < m_nfields; i++)
2647  m_fields[i] = mxArray::strsave (val.m_fields[i]);
2648 
2649  mwSize nel = get_number_of_elements ();
2650 
2651  for (mwIndex i = 0; i < nel * m_nfields; i++)
2652  {
2653  mxArray *ptr = val.m_data[i];
2654  m_data[i] = (ptr ? ptr->dup () : nullptr);
2655  }
2656  }
2657 
2658 public:
2659 
2660  // No assignment! FIXME: should this be implemented? Note that we
2661  // do have a copy constructor.
2662 
2663  mxArray_struct& operator = (const mxArray_struct& val) = delete;
2664 
2665  void init (const char **keys)
2666  {
2667  for (int i = 0; i < m_nfields; i++)
2668  m_fields[i] = mxArray::strsave (keys[i]);
2669  }
2670 
2671  mxArray_base * dup (void) const { return new mxArray_struct (*this); }
2672 
2673  ~mxArray_struct (void)
2674  {
2675  for (int i = 0; i < m_nfields; i++)
2676  mxFree (m_fields[i]);
2677 
2678  mxFree (m_fields);
2679 
2680  mwSize ntot = m_nfields * get_number_of_elements ();
2681 
2682  for (mwIndex i = 0; i < ntot; i++)
2683  delete m_data[i];
2684 
2685  mxFree (m_data);
2686  }
2687 
2688  int add_field (const char *key)
2689  {
2690  int retval = -1;
2691 
2692  m_nfields++;
2693 
2694  m_fields = static_cast<char **>
2695  (mxRealloc (m_fields, m_nfields * sizeof (char *)));
2696 
2697  if (m_fields)
2698  {
2699  m_fields[m_nfields-1] = mxArray::strsave (key);
2700 
2701  mwSize nel = get_number_of_elements ();
2702 
2703  mwSize ntot = m_nfields * nel;
2704 
2705  mxArray **new_data;
2706  new_data = static_cast<mxArray **>
2707  (mxArray::malloc (ntot * sizeof (mxArray *)));
2708 
2709  if (new_data)
2710  {
2711  mwIndex j = 0;
2712  mwIndex k = 0;
2713  mwIndex n = 0;
2714 
2715  for (mwIndex i = 0; i < ntot; i++)
2716  {
2717  if (++n == m_nfields)
2718  {
2719  new_data[j++] = nullptr;
2720  n = 0;
2721  }
2722  else
2723  new_data[j++] = m_data[k++];
2724  }
2725 
2726  mxFree (m_data);
2727 
2728  m_data = new_data;
2729 
2730  retval = m_nfields - 1;
2731  }
2732  }
2733 
2734  return retval;
2735  }
2736 
2737  void remove_field (int key_num)
2738  {
2739  if (key_num >= 0 && key_num < m_nfields)
2740  {
2741  mwSize nel = get_number_of_elements ();
2742 
2743  mwSize ntot = m_nfields * nel;
2744 
2745  int new_nfields = m_nfields - 1;
2746 
2747  char **new_fields = static_cast<char **>
2748  (mxArray::malloc (new_nfields * sizeof (char *)));
2749 
2750  mxArray **new_data = static_cast<mxArray **>
2751  (mxArray::malloc (new_nfields * nel
2752  * sizeof (mxArray *)));
2753 
2754  for (int i = 0; i < key_num; i++)
2755  new_fields[i] = m_fields[i];
2756 
2757  for (int i = key_num + 1; i < m_nfields; i++)
2758  new_fields[i-1] = m_fields[i];
2759 
2760  if (new_nfields > 0)
2761  {
2762  mwIndex j = 0;
2763  mwIndex k = 0;
2764  mwIndex n = 0;
2765 
2766  for (mwIndex i = 0; i < ntot; i++)
2767  {
2768  if (n == key_num)
2769  k++;
2770  else
2771  new_data[j++] = m_data[k++];
2772 
2773  if (++n == m_nfields)
2774  n = 0;
2775  }
2776  }
2777 
2778  m_nfields = new_nfields;
2779 
2780  mxFree (m_fields);
2781  mxFree (m_data);
2782 
2783  m_fields = new_fields;
2784  m_data = new_data;
2785  }
2786  }
2787 
2788  mxArray * get_field_by_number (mwIndex index, int key_num) const
2789  {
2790  return key_num >= 0 && key_num < m_nfields
2791  ? m_data[m_nfields * index + key_num] : nullptr;
2792  }
2793 
2794  void set_field_by_number (mwIndex index, int key_num, mxArray *val);
2795 
2796  int get_number_of_fields (void) const { return m_nfields; }
2797 
2798  const char * get_field_name_by_number (int key_num) const
2799  {
2800  return key_num >= 0 && key_num < m_nfields ? m_fields[key_num] : nullptr;
2801  }
2802 
2803  int get_field_number (const char *key) const
2804  {
2805  int retval = -1;
2806 
2807  for (int i = 0; i < m_nfields; i++)
2808  {
2809  if (! strcmp (key, m_fields[i]))
2810  {
2811  retval = i;
2812  break;
2813  }
2814  }
2815 
2816  return retval;
2817  }
2818 
2819  void * get_data (void) const { return m_data; }
2820 
2821  void set_data (void *data) { m_data = static_cast<mxArray **> (data); }
2822 
2823  octave_value as_octave_value (void) const
2824  {
2825  dim_vector dv = dims_to_dim_vector ();
2826 
2827  string_vector keys (m_fields, m_nfields);
2828 
2829  octave_map m (dv);
2830 
2831  mwSize ntot = m_nfields * get_number_of_elements ();
2832 
2833  for (int i = 0; i < m_nfields; i++)
2834  {
2835  Cell c (dv);
2836 
2837  octave_value *p = c.fortran_vec ();
2838 
2839  mwIndex k = 0;
2840  for (mwIndex j = i; j < ntot; j += m_nfields)
2841  p[k++] = mxArray::as_octave_value (m_data[j]);
2842 
2843  m.assign (keys[i], c);
2844  }
2845 
2846  return m;
2847  }
2848 
2849 private:
2850 
2851  int m_nfields;
2852 
2853  char **m_fields;
2854 
2855  mxArray **m_data;
2856 };
2857 
2858 // Matlab-style cell arrays.
2859 
2860 class mxArray_cell : public mxArray_matlab
2861 {
2862 public:
2863 
2864  mxArray_cell () = delete;
2865 
2866  mxArray_cell (bool interleaved, mwSize ndims, const mwSize *dims)
2867  : mxArray_matlab (interleaved, false, mxCELL_CLASS, ndims, dims),
2868  m_data (static_cast<mxArray **> (mxArray::calloc (get_number_of_elements (), sizeof (mxArray *))))
2869  { }
2870 
2871  mxArray_cell (bool interleaved, const dim_vector& dv)
2872  : mxArray_matlab (interleaved, false, mxCELL_CLASS, dv),
2873  m_data (static_cast<mxArray **> (mxArray::calloc (get_number_of_elements (), sizeof (mxArray *))))
2874  { }
2875 
2876  mxArray_cell (bool interleaved, mwSize m, mwSize n)
2877  : mxArray_matlab (interleaved, false, mxCELL_CLASS, m, n),
2878  m_data (static_cast<mxArray **> (mxArray::calloc (get_number_of_elements (), sizeof (mxArray *))))
2879  { }
2880 
2881 private:
2882 
2883  mxArray_cell (const mxArray_cell& val)
2884  : mxArray_matlab (val),
2885  m_data (static_cast<mxArray **> (mxArray::malloc (get_number_of_elements () * sizeof (mxArray *))))
2886  {
2887  mwSize nel = get_number_of_elements ();
2888 
2889  for (mwIndex i = 0; i < nel; i++)
2890  {
2891  mxArray *ptr = val.m_data[i];
2892  m_data[i] = (ptr ? ptr->dup () : nullptr);
2893  }
2894  }
2895 
2896 public:
2897 
2898  // No assignment! FIXME: should this be implemented? Note that we
2899  // do have a copy constructor.
2900 
2901  mxArray_cell& operator = (const mxArray_cell&) = delete;
2902 
2903  mxArray_base * dup (void) const { return new mxArray_cell (*this); }
2904 
2905  ~mxArray_cell (void)
2906  {
2907  mwSize nel = get_number_of_elements ();
2908 
2909  for (mwIndex i = 0; i < nel; i++)
2910  delete m_data[i];
2911 
2912  mxFree (m_data);
2913  }
2914 
2915  mxArray * get_cell (mwIndex idx) const
2916  {
2917  return idx >= 0 && idx < get_number_of_elements () ? m_data[idx] : nullptr;
2918  }
2919 
2920  void set_cell (mwIndex idx, mxArray *val);
2921 
2922  void * get_data (void) const { return m_data; }
2923 
2924  void set_data (void *data) { m_data = static_cast<mxArray **> (data); }
2925 
2926  octave_value as_octave_value (void) const
2927  {
2928  dim_vector dv = dims_to_dim_vector ();
2929 
2930  Cell c (dv);
2931 
2932  mwSize nel = get_number_of_elements ();
2933 
2934  octave_value *p = c.fortran_vec ();
2935 
2936  for (mwIndex i = 0; i < nel; i++)
2937  p[i] = mxArray::as_octave_value (m_data[i]);
2938 
2939  return c;
2940  }
2941 
2942 private:
2943 
2944  mxArray **m_data;
2945 };
2946 
2947 // ------------------------------------------------------------------
2948 
2949 mxArray::mxArray (bool interleaved, const octave_value& ov)
2950  : m_rep (create_rep (interleaved, ov)), m_name (nullptr)
2951 { }
2952 
2953 mxArray::mxArray (bool interleaved, mxClassID id, mwSize ndims,
2954  const mwSize *dims, mxComplexity flag, bool init)
2955  : m_rep (create_rep (interleaved, id, ndims, dims, flag, init)),
2956  m_name (nullptr)
2957 { }
2958 
2959 mxArray::mxArray (bool interleaved, mxClassID id, const dim_vector& dv,
2960  mxComplexity flag)
2961  : m_rep (create_rep (interleaved, id, dv, flag)), m_name (nullptr)
2962 { }
2963 
2964 mxArray::mxArray (bool interleaved, mxClassID id, mwSize m, mwSize n,
2965  mxComplexity flag, bool init)
2966  : m_rep (create_rep (interleaved, id, m, n, flag, init)), m_name (nullptr)
2967 { }
2968 
2969 mxArray::mxArray (bool interleaved, mxClassID id, double val)
2970  : m_rep (create_rep (interleaved, id, val)), m_name (nullptr)
2971 { }
2972 
2973 mxArray::mxArray (bool interleaved, mxClassID id, mxLogical val)
2974  : m_rep (create_rep (interleaved, id, val)), m_name (nullptr)
2975 { }
2976 
2977 mxArray::mxArray (bool interleaved, const char *str)
2978  : m_rep (create_rep (interleaved, str)), m_name (nullptr)
2979 { }
2980 
2981 mxArray::mxArray (bool interleaved, mwSize m, const char **str)
2982  : m_rep (create_rep (interleaved, m, str)), m_name (nullptr)
2983 { }
2984 
2985 mxArray::mxArray (bool interleaved, mxClassID id, mwSize m, mwSize n,
2986  mwSize nzmax, mxComplexity flag)
2987  : m_rep (create_rep (interleaved, id, m, n, nzmax, flag)), m_name (nullptr)
2988 { }
2989 
2990 mxArray::mxArray (bool interleaved, mwSize ndims, const mwSize *dims,
2991  int num_keys,
2992  const char **keys)
2993  : m_rep (new mxArray_struct (interleaved, ndims, dims, num_keys, keys)),
2994  m_name (nullptr)
2995 { }
2996 
2997 mxArray::mxArray (bool interleaved, const dim_vector& dv, int num_keys,
2998  const char **keys)
2999  : m_rep (new mxArray_struct (interleaved, dv, num_keys, keys)),
3000  m_name (nullptr)
3001 { }
3002 
3003 mxArray::mxArray (bool interleaved, mwSize m, mwSize n, int num_keys,
3004  const char **keys)
3005  : m_rep (new mxArray_struct (interleaved, m, n, num_keys, keys)),
3006  m_name (nullptr)
3007 { }
3008 
3009 mxArray::mxArray (bool interleaved, mwSize ndims, const mwSize *dims)
3010  : m_rep (new mxArray_cell (interleaved, ndims, dims)), m_name (nullptr)
3011 { }
3012 
3013 mxArray::mxArray (bool interleaved, const dim_vector& dv)
3014  : m_rep (new mxArray_cell (interleaved, dv)), m_name (nullptr)
3015 { }
3016 
3017 mxArray::mxArray (bool interleaved, mwSize m, mwSize n)
3018  : m_rep (new mxArray_cell (interleaved, m, n)), m_name (nullptr)
3019 { }
3020 
3022 {
3023  mxFree (m_name);
3024 
3025  delete m_rep;
3026 }
3027 
3028 void
3029 mxArray::set_name (const char *name)
3030 {
3031  mxFree (m_name);
3032  m_name = mxArray::strsave (name);
3033 }
3034 
3036 mxArray::as_octave_value (const mxArray *ptr, bool null_is_empty)
3037 {
3038  static const octave_value empty_matrix = Matrix ();
3039 
3040  return (ptr
3041  ? ptr->as_octave_value ()
3042  : (null_is_empty ? empty_matrix : octave_value ()));
3043 }
3044 
3047 {
3048  return m_rep->as_octave_value ();
3049 }
3050 
3051 mxArray_base *
3052 mxArray::create_rep (bool interleaved, const octave_value& ov)
3053 {
3054  return new mxArray_octave_value (interleaved, ov);
3055 }
3056 
3057 mxArray_base *
3058 mxArray::create_rep (bool interleaved, mxClassID id, mwSize ndims,
3059  const mwSize *dims, mxComplexity flag, bool init)
3060 {
3061  if (interleaved)
3062  return new mxArray_interleaved_full (id, ndims, dims, flag, init);
3063  else
3064  return new mxArray_separate_full (id, ndims, dims, flag, init);
3065 }
3066 
3067 mxArray_base *
3068 mxArray::create_rep (bool interleaved, mxClassID id, const dim_vector& dv,
3069  mxComplexity flag)
3070 {
3071  if (interleaved)
3072  return new mxArray_interleaved_full (id, dv, flag);
3073  else
3074  return new mxArray_separate_full (id, dv, flag);
3075 }
3076 
3077 mxArray_base *
3078 mxArray::create_rep (bool interleaved, mxClassID id, mwSize m, mwSize n,
3079  mxComplexity flag, bool init)
3080 {
3081  if (interleaved)
3082  return new mxArray_interleaved_full (id, m, n, flag, init);
3083  else
3084  return new mxArray_separate_full (id, m, n, flag, init);
3085 }
3086 
3087 mxArray_base *
3088 mxArray::create_rep (bool interleaved, mxClassID id, double val)
3089 {
3090  if (interleaved)
3091  return new mxArray_interleaved_full (id, val);
3092  else
3093  return new mxArray_separate_full (id, val);
3094 }
3095 
3096 mxArray_base *
3097 mxArray::create_rep (bool interleaved, mxClassID id, mxLogical val)
3098 {
3099  if (interleaved)
3100  return new mxArray_interleaved_full (id, val);
3101  else
3102  return new mxArray_separate_full (id, val);
3103 }
3104 
3105 mxArray_base *
3106 mxArray::create_rep (bool interleaved, const char *str)
3107 {
3108  if (interleaved)
3109  return new mxArray_interleaved_full (str);
3110  else
3111  return new mxArray_separate_full (str);
3112 }
3113 
3114 mxArray_base *
3115 mxArray::create_rep (bool interleaved, mwSize m, const char **str)
3116 {
3117  if (interleaved)
3118  return new mxArray_interleaved_full (m, str);
3119  else
3120  return new mxArray_separate_full (m, str);
3121 }
3122 
3123 mxArray_base *
3124 mxArray::create_rep (bool interleaved, mxClassID id, mwSize m, mwSize n,
3125  mwSize nzmax, mxComplexity flag)
3126 {
3127  if (interleaved)
3128  return new mxArray_interleaved_sparse (id, m, n, nzmax, flag);
3129  else
3130  return new mxArray_separate_sparse (id, m, n, nzmax, flag);
3131 }
3132 
3133 void
3134 mxArray::maybe_mutate (void) const
3135 {
3136  if (m_rep->is_octave_value ())
3137  {
3138  // The mutate function returns a pointer to a complete new
3139  // mxArray object (or 0, if no mutation happened). We just want
3140  // to replace the existing rep with the rep from the new object.
3141 
3142  mxArray *new_val = m_rep->mutate ();
3143 
3144  if (new_val)
3145  {
3146  delete m_rep;
3147  m_rep = new_val->m_rep;
3148  new_val->m_rep = nullptr;
3149  delete new_val;
3150  }
3151  }
3152 }
3153 
3154 // ------------------------------------------------------------------
3155 
3156 // A class to manage calls to MEX functions. Mostly deals with memory
3157 // management.
3158 
3159 class mex
3160 {
3161 public:
3162 
3163  mex (octave_mex_function& f)
3164  : m_curr_mex_fcn (f), m_memlist (), m_arraylist (), m_fname (nullptr) { }
3165 
3166  OCTAVE_DISABLE_CONSTRUCT_COPY_MOVE (mex)
3167 
3168  ~mex (void)
3169  {
3170  // We can't use mex::free here because it modifies memlist.
3171  while (! m_memlist.empty ())
3172  {
3173  auto p = m_memlist.begin ();
3174  xfree (*p);
3175  m_memlist.erase (p);
3176  }
3177 
3178  // We can't use mex::free_value here because it modifies arraylist.
3179  while (! m_arraylist.empty ())
3180  {
3181  auto p = m_arraylist.begin ();
3182  delete *p;
3183  m_arraylist.erase (p);
3184  }
3185 
3186  if (! (m_memlist.empty () && m_arraylist.empty ()))
3187  error ("mex: %s: cleanup failed", function_name ());
3188 
3189  mxFree (m_fname);
3190  }
3191 
3192  const char * function_name (void) const
3193  {
3194  if (! m_fname)
3195  {
3196  octave::tree_evaluator& tw = octave::__get_evaluator__ ();
3197 
3198  octave_function *fcn = tw.current_function ();
3199 
3200  if (fcn)
3201  {
3202  std::string nm = fcn->name ();
3203  m_fname = mxArray::strsave (nm.c_str ());
3204  }
3205  else
3206  m_fname = mxArray::strsave ("unknown");
3207  }
3208 
3209  return m_fname;
3210  }
3211 
3212  // Allocate memory.
3213  void * malloc_unmarked (std::size_t n)
3214  {
3215  void *ptr = xmalloc (n);
3216 
3217  if (! ptr)
3218  {
3219  // FIXME: could use "octave_new_handler();" instead
3220  error ("%s: failed to allocate %zd bytes of memory",
3221  function_name (), n);
3222  }
3223 
3224  global_mark (ptr);
3225 
3226  return ptr;
3227  }
3228 
3229  // Allocate memory to be freed on exit.
3230  void * malloc (std::size_t n)
3231  {
3232  void *ptr = malloc_unmarked (n);
3233 
3234  mark (ptr);
3235 
3236  return ptr;
3237  }
3238 
3239  // Allocate memory and initialize to 0.
3240  void * calloc_unmarked (std::size_t n, std::size_t t)
3241  {
3242  void *ptr = malloc_unmarked (n*t);
3243 
3244  memset (ptr, 0, n*t);
3245 
3246  return ptr;
3247  }
3248 
3249  // Allocate memory to be freed on exit and initialize to 0.
3250  void * calloc (std::size_t n, std::size_t t)
3251  {
3252  void *ptr = calloc_unmarked (n, t);
3253 
3254  mark (ptr);
3255 
3256  return ptr;
3257  }
3258 
3259  // Reallocate a pointer obtained from malloc or calloc.
3260  // If the pointer is NULL, allocate using malloc.
3261  // We don't need an "unmarked" version of this.
3262  void * realloc (void *ptr, std::size_t n)
3263  {
3264  void *v;
3265 
3266  if (ptr)
3267  {
3268  auto p_local = m_memlist.find (ptr);
3269  auto p_global = s_global_memlist.find (ptr);
3270 
3271  v = xrealloc (ptr, n);
3272 
3273  if (v)
3274  {
3275  if (p_local != m_memlist.end ())
3276  {
3277  m_memlist.erase (p_local);
3278  m_memlist.insert (v);
3279  }
3280 
3281  if (p_global != s_global_memlist.end ())
3282  {
3283  s_global_memlist.erase (p_global);
3284  s_global_memlist.insert (v);
3285  }
3286  }
3287  }
3288  else
3289  v = malloc (n);
3290 
3291  return v;
3292  }
3293 
3294  // Free a pointer obtained from malloc or calloc.
3295  void free (void *ptr)
3296  {
3297  if (ptr)
3298  {
3299  unmark (ptr);
3300 
3301  auto p = s_global_memlist.find (ptr);
3302 
3303  if (p != s_global_memlist.end ())
3304  {
3305  s_global_memlist.erase (p);
3306 
3307  xfree (ptr);
3308  }
3309  else
3310  {
3311  p = m_foreign_memlist.find (ptr);
3312 
3313  if (p != m_foreign_memlist.end ())
3314  m_foreign_memlist.erase (p);
3315 #if defined (DEBUG)
3316  else
3317  warning ("mxFree: skipping memory not allocated by mxMalloc, mxCalloc, or mxRealloc");
3318 #endif
3319  }
3320  }
3321  }
3322 
3323  // Mark a pointer to be freed on exit.
3324  void mark (void *ptr)
3325  {
3326 #if defined (DEBUG)
3327  if (m_memlist.find (ptr) != m_memlist.end ())
3328  warning ("%s: double registration ignored", function_name ());
3329 #endif
3330 
3331  m_memlist.insert (ptr);
3332  }
3333 
3334  // Unmark a pointer to be freed on exit, either because it was
3335  // made persistent, or because it was already freed.
3336  void unmark (void *ptr)
3337  {
3338  auto p = m_memlist.find (ptr);
3339 
3340  if (p != m_memlist.end ())
3341  m_memlist.erase (p);
3342 #if defined (DEBUG)
3343  else
3344  warning ("%s: value not marked", function_name ());
3345 #endif
3346  }
3347 
3348  mxArray * mark_array (mxArray *ptr)
3349  {
3350  m_arraylist.insert (ptr);
3351  return ptr;
3352  }
3353 
3354  void unmark_array (mxArray *ptr)
3355  {
3356  auto p = m_arraylist.find (ptr);
3357 
3358  if (p != m_arraylist.end ())
3359  m_arraylist.erase (p);
3360  }
3361 
3362  // Mark a pointer as one we allocated.
3363  void mark_foreign (void *ptr)
3364  {
3365 #if defined (DEBUG)
3366  if (m_foreign_memlist.find (ptr) != m_foreign_memlist.end ())
3367  warning ("%s: double registration ignored", function_name ());
3368 #endif
3369 
3370  m_foreign_memlist.insert (ptr);
3371  }
3372 
3373  // Unmark a pointer as one we allocated.
3374  void unmark_foreign (void *ptr)
3375  {
3376  auto p = m_foreign_memlist.find (ptr);
3377 
3378  if (p != m_foreign_memlist.end ())
3379  m_foreign_memlist.erase (p);
3380 #if defined (DEBUG)
3381  else
3382  warning ("%s: value not marked", function_name ());
3383 #endif
3384 
3385  }
3386 
3387  // Make a new array value and initialize from an octave value; it will be
3388  // freed on exit unless marked as persistent.
3389  mxArray * make_value (const octave_value& ov)
3390  {
3391  bool interleaved = m_curr_mex_fcn.use_interleaved_complex ();
3392 
3393  return mark_array (new mxArray (interleaved, ov));
3394  }
3395 
3396  // Free an array and its contents.
3397  bool free_value (mxArray *ptr)
3398  {
3399  bool inlist = false;
3400 
3401  auto p = m_arraylist.find (ptr);
3402 
3403  if (p != m_arraylist.end ())
3404  {
3405  inlist = true;
3406  m_arraylist.erase (p);
3407  delete ptr;
3408  }
3409 #if defined (DEBUG)
3410  else
3411  warning ("mex::free_value: skipping memory not allocated by mex::make_value");
3412 #endif
3413 
3414  return inlist;
3415  }
3416 
3417  octave_mex_function& current_mex_function (void) const
3418  {
3419  return m_curr_mex_fcn;
3420  }
3421 
3422  // 1 if error should be returned to MEX file, 0 if abort.
3423  int trap_feval_error = 0;
3424 
3425  // Mark a pointer as one we allocated.
3426  void global_mark (void *ptr)
3427  {
3428 #if defined (DEBUG)
3429  if (s_global_memlist.find (ptr) != s_global_memlist.end ())
3430  warning ("%s: double registration ignored", function_name ());
3431 #endif
3432 
3433  s_global_memlist.insert (ptr);
3434  }
3435 
3436  // Unmark a pointer as one we allocated.
3437  void global_unmark (void *ptr)
3438  {
3439  auto p = s_global_memlist.find (ptr);
3440 
3441  if (p != s_global_memlist.end ())
3442  s_global_memlist.erase (p);
3443 #if defined (DEBUG)
3444  else
3445  warning ("%s: value not marked", function_name ());
3446 #endif
3447  }
3448 
3449 private:
3450 
3451  // Pointer to the mex function that corresponds to this mex context.
3452  octave_mex_function& m_curr_mex_fcn;
3453 
3454  // List of memory resources that need to be freed upon exit.
3455  std::set<void *> m_memlist;
3456 
3457  // List of mxArray objects that need to be freed upon exit.
3458  std::set<mxArray *> m_arraylist;
3459 
3460  // List of memory resources we know about, but that were allocated
3461  // elsewhere.
3462  std::set<void *> m_foreign_memlist;
3463 
3464  // The name of the currently executing function.
3465  mutable char *m_fname;
3466 
3467  // List of memory resources we allocated.
3468  static std::set<void *> s_global_memlist;
3469 
3470 };
3471 
3472 // List of memory resources we allocated.
3473 std::set<void *> mex::s_global_memlist;
3474 
3475 // Current context.
3476 mex *mex_context = nullptr;
3477 
3478 void *
3479 mxArray::malloc (std::size_t n)
3480 {
3481  return mex_context ? mex_context->malloc_unmarked (n) : xmalloc (n);
3482 }
3483 
3484 void *
3485 mxArray::calloc (std::size_t n, std::size_t t)
3486 {
3487  return mex_context ? mex_context->calloc_unmarked (n, t) : ::calloc (n, t);
3488 }
3489 
3490 void *
3491 mxArray::alloc (bool init, std::size_t n, std::size_t t)
3492 {
3493  return init ? mxArray::calloc (n, t) : mxArray::malloc (n * t);
3494 }
3495 
3496 static inline void *
3497 maybe_mark_foreign (void *ptr)
3498 {
3499  if (mex_context)
3500  mex_context->mark_foreign (ptr);
3501 
3502  return ptr;
3503 }
3504 
3505 #if defined (OCTAVE_HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR)
3506 
3507 static inline void
3508 maybe_disown_ptr (void *ptr)
3509 {
3510  if (mex_context)
3511  {
3512  mex_context->unmark (ptr);
3513  mex_context->global_unmark (ptr);
3514  mex_context->mark_foreign (ptr);
3515  }
3516 }
3517 
3518 #endif
3519 
3520 static inline mxArray *
3521 maybe_unmark_array (mxArray *ptr)
3522 {
3523  if (mex_context)
3524  mex_context->unmark_array (ptr);
3525 
3526  return ptr;
3527 }
3528 
3529 template <typename T>
3530 static inline T *
3531 maybe_unmark (T *ptr)
3532 {
3533  if (mex_context)
3534  mex_context->unmark (ptr);
3535 
3536  return ptr;
3537 }
3538 
3539 void
3540 mxArray_struct::set_field_by_number (mwIndex index, int key_num, mxArray *val)
3541 {
3542  if (key_num >= 0 && key_num < m_nfields)
3543  m_data[m_nfields * index + key_num] = maybe_unmark_array (val);
3544 }
3545 
3546 void
3547 mxArray_cell::set_cell (mwIndex idx, mxArray *val)
3548 {
3549  if (idx >= 0 && idx < get_number_of_elements ())
3550  m_data[idx] = maybe_unmark_array (val);
3551 }
3552 
3553 // ------------------------------------------------------------------
3554 
3555 // C interface to mxArray objects:
3556 
3557 // Floating point predicates.
3558 
3559 bool
3560 mxIsFinite (const double v)
3561 {
3562  return lo_ieee_isfinite (v) != 0;
3563 }
3564 
3565 bool
3566 mxIsInf (const double v)
3567 {
3568  return lo_ieee_isinf (v) != 0;
3569 }
3570 
3571 bool
3572 mxIsNaN (const double v)
3573 {
3574  return lo_ieee_isnan (v) != 0;
3575 }
3576 
3577 double
3578 mxGetEps (void)
3579 {
3580  return std::numeric_limits<double>::epsilon ();
3581 }
3582 
3583 double
3584 mxGetInf (void)
3585 {
3586  return lo_ieee_inf_value ();
3587 }
3588 
3589 double
3590 mxGetNaN (void)
3591 {
3592  return lo_ieee_nan_value ();
3593 }
3594 
3595 // Memory management.
3596 void *
3597 mxCalloc (std::size_t n, std::size_t size)
3598 {
3599  return mex_context ? mex_context->calloc (n, size) : ::calloc (n, size);
3600 }
3601 
3602 void *
3603 mxMalloc (std::size_t n)
3604 {
3605  return mex_context ? mex_context->malloc (n) : xmalloc (n);
3606 }
3607 
3608 void *
3609 mxRealloc (void *ptr, std::size_t size)
3610 {
3611  return (mex_context
3612  ? mex_context->realloc (ptr, size) : xrealloc (ptr, size));
3613 }
3614 
3615 void
3616 mxFree (void *ptr)
3617 {
3618  if (mex_context)
3619  mex_context->free (ptr);
3620  else
3621  xfree (ptr);
3622 }
3623 
3624 static inline mxArray *
3625 maybe_mark_array (mxArray *ptr)
3626 {
3627  return mex_context ? mex_context->mark_array (ptr) : ptr;
3628 }
3629 
3630 // Constructors.
3631 mxArray *
3633 {
3634  return maybe_mark_array (new mxArray (true, ndims, dims));
3635 }
3636 
3637 mxArray *
3638 mxCreateCellArray (mwSize ndims, const mwSize *dims)
3639 {
3640  return maybe_mark_array (new mxArray (false, ndims, dims));
3641 }
3642 
3643 mxArray *
3645 {
3646  return maybe_mark_array (new mxArray (true, m, n));
3647 }
3648 
3649 mxArray *
3651 {
3652  return maybe_mark_array (new mxArray (false, m, n));
3653 }
3654 
3655 mxArray *
3657 {
3658  return maybe_mark_array (new mxArray (true, mxCHAR_CLASS, ndims, dims));
3659 }
3660 
3661 mxArray *
3662 mxCreateCharArray (mwSize ndims, const mwSize *dims)
3663 {
3664  return maybe_mark_array (new mxArray (false, mxCHAR_CLASS, ndims, dims));
3665 }
3666 
3667 mxArray *
3669 {
3670  return maybe_mark_array (new mxArray (true, m, str));
3671 }
3672 
3673 mxArray *
3675 {
3676  return maybe_mark_array (new mxArray (false, m, str));
3677 }
3678 
3679 mxArray *
3681 {
3682  return maybe_mark_array (new mxArray (true, mxDOUBLE_CLASS, m, n, flag));
3683 }
3684 
3685 mxArray *
3687 {
3688  return maybe_mark_array (new mxArray (false, mxDOUBLE_CLASS, m, n, flag));
3689 }
3690 
3691 mxArray *
3693 {
3694  return maybe_mark_array (new mxArray (true, mxDOUBLE_CLASS, val));
3695 }
3696 
3697 mxArray *
3699 {
3700  return maybe_mark_array (new mxArray (false, mxDOUBLE_CLASS, val));
3701 }
3702 
3703 mxArray *
3705 {
3706  return maybe_mark_array (new mxArray (true, mxLOGICAL_CLASS, ndims, dims));
3707 }
3708 
3709 mxArray *
3710 mxCreateLogicalArray (mwSize ndims, const mwSize *dims)
3711 {
3712  return maybe_mark_array (new mxArray (false, mxLOGICAL_CLASS, ndims, dims));
3713 }
3714 
3715 mxArray *
3717 {
3718  return maybe_mark_array (new mxArray (true, mxLOGICAL_CLASS, m, n));
3719 }
3720 
3721 mxArray *
3723 {
3724  return maybe_mark_array (new mxArray (false, mxLOGICAL_CLASS, m, n));
3725 }
3726 
3727 mxArray *
3729 {
3730  return maybe_mark_array (new mxArray (true, mxLOGICAL_CLASS, val));
3731 }
3732 
3733 mxArray *
3735 {
3736  return maybe_mark_array (new mxArray (false, mxLOGICAL_CLASS, val));
3737 }
3738 
3739 mxArray *
3741  mxClassID class_id, mxComplexity flag)
3742 {
3743  return maybe_mark_array (new mxArray (true, class_id, ndims, dims, flag));
3744 }
3745 
3746 mxArray *
3747 mxCreateNumericArray (mwSize ndims, const mwSize *dims,
3748  mxClassID class_id, mxComplexity flag)
3749 {
3750  return maybe_mark_array (new mxArray (false, class_id, ndims, dims, flag));
3751 }
3752 
3753 mxArray *
3755  mxComplexity flag)
3756 {
3757  return maybe_mark_array (new mxArray (true, class_id, m, n, flag));
3758 }
3759 
3760 mxArray *
3762  mxComplexity flag)
3763 {
3764  return maybe_mark_array (new mxArray (false, class_id, m, n, flag));
3765 }
3766 
3767 mxArray *
3769  mxClassID class_id, mxComplexity flag)
3770 {
3771  return maybe_mark_array (new mxArray (true, class_id, ndims, dims, flag,
3772  false));
3773 }
3774 
3775 mxArray *
3777  mxClassID class_id, mxComplexity flag)
3778 {
3779  return maybe_mark_array (new mxArray (false, class_id, ndims, dims, flag,
3780  false));
3781 }
3782 
3783 mxArray *
3785  mxClassID class_id, mxComplexity flag)
3786 {
3787  return maybe_mark_array (new mxArray (true, class_id, m, n, flag, false));
3788 }
3789 
3790 mxArray *
3792  mxComplexity flag)
3793 {
3794  return maybe_mark_array (new mxArray (false, class_id, m, n, flag, false));
3795 }
3796 
3797 mxArray *
3799 {
3800  return maybe_mark_array (new mxArray (true, mxDOUBLE_CLASS, m, n, nzmax,
3801  flag));
3802 }
3803 
3804 mxArray *
3806 {
3807  return maybe_mark_array (new mxArray (false, mxDOUBLE_CLASS, m, n, nzmax,
3808  flag));
3809 }
3810 
3811 mxArray *
3813 {
3814  return maybe_mark_array (new mxArray (true, mxLOGICAL_CLASS, m, n, nzmax));
3815 }
3816 
3817 mxArray *
3819 {
3820  return maybe_mark_array (new mxArray (false, mxLOGICAL_CLASS, m, n, nzmax));
3821 }
3822 
3823 mxArray *
3825 {
3826  return maybe_mark_array (new mxArray (true, str));
3827 }
3828 
3829 mxArray *
3830 mxCreateString (const char *str)
3831 {
3832  return maybe_mark_array (new mxArray (false, str));
3833 }
3834 
3835 mxArray *
3837  int num_keys, const char **keys)
3838 {
3839  return maybe_mark_array (new mxArray (true, ndims, dims, num_keys, keys));
3840 }
3841 
3842 mxArray *
3843 mxCreateStructArray (mwSize ndims, const mwSize *dims, int num_keys,
3844  const char **keys)
3845 {
3846  return maybe_mark_array (new mxArray (false, ndims, dims, num_keys, keys));
3847 }
3848 
3849 mxArray *
3851  const char **keys)
3852 {
3853  return maybe_mark_array (new mxArray (true, m, n, num_keys, keys));
3854 }
3855 
3856 mxArray *
3858  const char **keys)
3859 {
3860  return maybe_mark_array (new mxArray (false, m, n, num_keys, keys));
3861 }
3862 
3863 // Copy constructor.
3864 mxArray *
3866 {
3867  return maybe_mark_array (ptr->dup ());
3868 }
3869 
3870 // Destructor.
3871 void
3873 {
3874  if (! (mex_context && mex_context->free_value (ptr)))
3875  delete ptr;
3876 }
3877 
3878 // Type Predicates.
3879 bool
3880 mxIsCell (const mxArray *ptr)
3881 {
3882  return ptr->iscell ();
3883 }
3884 
3885 bool
3886 mxIsChar (const mxArray *ptr)
3887 {
3888  return ptr->is_char ();
3889 }
3890 
3891 bool
3892 mxIsClass (const mxArray *ptr, const char *name)
3893 {
3894  return ptr->is_class (name);
3895 }
3896 
3897 bool
3898 mxIsComplex (const mxArray *ptr)
3899 {
3900  return ptr->is_complex ();
3901 }
3902 
3903 bool
3904 mxIsDouble (const mxArray *ptr)
3905 {
3906  return ptr->is_double ();
3907 }
3908 
3909 bool
3911 {
3912  return ptr->is_function_handle ();
3913 }
3914 
3915 bool
3916 mxIsInt16 (const mxArray *ptr)
3917 {
3918  return ptr->is_int16 ();
3919 }
3920 
3921 bool
3922 mxIsInt32 (const mxArray *ptr)
3923 {
3924  return ptr->is_int32 ();
3925 }
3926 
3927 bool
3928 mxIsInt64 (const mxArray *ptr)
3929 {
3930  return ptr->is_int64 ();
3931 }
3932 
3933 bool
3934 mxIsInt8 (const mxArray *ptr)
3935 {
3936  return ptr->is_int8 ();
3937 }
3938 
3939 bool
3940 mxIsLogical (const mxArray *ptr)
3941 {
3942  return ptr->is_logical ();
3943 }
3944 
3945 bool
3946 mxIsNumeric (const mxArray *ptr)
3947 {
3948  return ptr->is_numeric ();
3949 }
3950 
3951 bool
3952 mxIsSingle (const mxArray *ptr)
3953 {
3954  return ptr->is_single ();
3955 }
3956 
3957 bool
3958 mxIsSparse (const mxArray *ptr)
3959 {
3960  return ptr->is_sparse ();
3961 }
3962 
3963 bool
3964 mxIsStruct (const mxArray *ptr)
3965 {
3966  return ptr->is_struct ();
3967 }
3968 
3969 bool
3970 mxIsUint16 (const mxArray *ptr)
3971 {
3972  return ptr->is_uint16 ();
3973 }
3974 
3975 bool
3976 mxIsUint32 (const mxArray *ptr)
3977 {
3978  return ptr->is_uint32 ();
3979 }
3980 
3981 bool
3982 mxIsUint64 (const mxArray *ptr)
3983 {
3984  return ptr->is_uint64 ();
3985 }
3986 
3987 bool
3988 mxIsUint8 (const mxArray *ptr)
3989 {
3990  return ptr->is_uint8 ();
3991 }
3992 
3993 // Odd type+size predicate.
3994 bool
3996 {
3997  return ptr->is_logical_scalar ();
3998 }
3999 
4000 // Odd type+size+value predicate.
4001 bool
4003 {
4004  return ptr->is_logical_scalar_true ();
4005 }
4006 
4007 // Size predicate.
4008 bool
4009 mxIsEmpty (const mxArray *ptr)
4010 {
4011  return ptr->isempty ();
4012 }
4013 
4014 bool
4015 mxIsScalar (const mxArray *ptr)
4016 {
4017  return ptr->is_scalar ();
4018 }
4019 
4020 // FIXME: Just plain odd thing to ask of a value.
4021 // Still, Octave is incompatible because it does not implement this.
4022 bool
4023 mxIsFromGlobalWS (const mxArray * /*ptr*/)
4024 {
4025  mexErrMsgTxt ("mxIsFromGlobalWS() is unimplemented");
4026 
4027  return 0;
4028 }
4029 
4030 // Dimension extractors.
4031 std::size_t
4032 mxGetM (const mxArray *ptr)
4033 {
4034  return ptr->get_m ();
4035 }
4036 
4037 std::size_t
4038 mxGetN (const mxArray *ptr)
4039 {
4040  return ptr->get_n ();
4041 }
4042 
4043 const mwSize *
4045 {
4046  return ptr->get_dimensions ();
4047 }
4048 
4049 mwSize
4051 {
4052  return ptr->get_number_of_dimensions ();
4053 }
4054 
4055 std::size_t
4057 {
4058  return ptr->get_number_of_elements ();
4059 }
4060 
4061 // Dimension setters.
4062 void
4064 {
4065  ptr->set_m (m);
4066 }
4067 
4068 void
4070 {
4071  ptr->set_n (n);
4072 }
4073 
4074 int
4075 mxSetDimensions (mxArray *ptr, const mwSize *dims, mwSize ndims)
4076 {
4077  return (ptr->set_dimensions (static_cast<mwSize *>
4078  (maybe_unmark (const_cast<mwSize *> (dims))),
4079  ndims));
4080 }
4081 
4082 // Data extractors.
4083 double *
4084 mxGetPr (const mxArray *ptr)
4085 {
4086  return static_cast<double *> (ptr->get_data ());
4087 }
4088 
4089 double
4090 mxGetScalar (const mxArray *ptr)
4091 {
4092  return ptr->get_scalar ();
4093 }
4094 
4095 mxChar *
4096 mxGetChars (const mxArray *ptr)
4097 {
4098  if (mxIsChar (ptr))
4099  return static_cast<mxChar *> (ptr->get_data ());
4100  else
4101  return nullptr;
4102 }
4103 
4104 mxLogical *
4106 {
4107  return static_cast<mxLogical *> (ptr->get_data ());
4108 }
4109 
4110 void *
4111 mxGetData (const mxArray *ptr)
4112 {
4113  return ptr->get_data ();
4114 }
4115 
4116 double *
4117 mxGetPi (const mxArray *ptr)
4118 {
4119  return static_cast<double *> (ptr->get_imag_data ());
4120 }
4121 
4122 void *
4124 {
4125  return ptr->get_imag_data ();
4126 }
4127 
4128 mxDouble *
4129 mxGetDoubles (const mxArray *ptr)
4130 {
4131  return ptr->get_doubles ();
4132 }
4133 
4134 mxSingle *
4135 mxGetSingles (const mxArray *ptr)
4136 {
4137  return ptr->get_singles ();
4138 }
4139 
4140 mxInt8 *
4141 mxGetInt8s (const mxArray *ptr)
4142 {
4143  return ptr->get_int8s ();
4144 }
4145 
4146 mxInt16 *
4147 mxGetInt16s (const mxArray *ptr)
4148 {
4149  return ptr->get_int16s ();
4150 }
4151 
4152 mxInt32 *
4153 mxGetInt32s (const mxArray *ptr)
4154 {
4155  return ptr->get_int32s ();
4156 }
4157 
4158 mxInt64 *
4159 mxGetInt64s (const mxArray *ptr)
4160 {
4161  return ptr->get_int64s ();
4162 }
4163 
4164 mxUint8 *
4165 mxGetUint8s (const mxArray *ptr)
4166 {
4167  return ptr->get_uint8s ();
4168 }
4169 
4170 mxUint16 *
4171 mxGetUint16s (const mxArray *ptr)
4172 {
4173  return ptr->get_uint16s ();
4174 }
4175 
4176 mxUint32 *
4177 mxGetUint32s (const mxArray *ptr)
4178 {
4179  return ptr->get_uint32s ();
4180 }
4181 
4182 mxUint64 *
4183 mxGetUint64s (const mxArray *ptr)
4184 {
4185  return ptr->get_uint64s ();
4186 }
4187 
4190 {
4191  return ptr->get_complex_doubles ();
4192 }
4193 
4196 {
4197  return ptr->get_complex_singles ();
4198 }
4199 
4200 // Data setters.
4201 void
4202 mxSetPr (mxArray *ptr, double *pr)
4203 {
4204  ptr->set_data (maybe_unmark (pr));
4205 }
4206 
4207 void
4208 mxSetData (mxArray *ptr, void *pr)
4209 {
4210  ptr->set_data (maybe_unmark (pr));
4211 }
4212 
4213 int
4215 {
4216  return ptr->set_doubles (maybe_unmark (data));
4217 }
4218 
4219 int
4221 {
4222  return ptr->set_singles (maybe_unmark (data));
4223 }
4224 
4225 int
4227 {
4228  return ptr->set_int8s (maybe_unmark (data));
4229 }
4230 
4231 int
4233 {
4234  return ptr->set_int16s (maybe_unmark (data));
4235 }
4236 
4237 int
4239 {
4240  return ptr->set_int32s (maybe_unmark (data));
4241 }
4242 
4243 int
4245 {
4246  return ptr->set_int64s (maybe_unmark (data));
4247 }
4248 
4249 int
4251 {
4252  return ptr->set_uint8s (maybe_unmark (data));
4253 }
4254 
4255 int
4257 {
4258  return ptr->set_uint16s (maybe_unmark (data));
4259 }
4260 
4261 int
4263 {
4264  return ptr->set_uint32s (maybe_unmark (data));
4265 }
4266 
4267 int
4269 {
4270  return ptr->set_uint64s (maybe_unmark (data));
4271 }
4272 
4273 int
4275 {
4276  return ptr->set_complex_doubles (maybe_unmark (data));
4277 }
4278 
4279 int
4281 {
4282  return ptr->set_complex_singles (maybe_unmark (data));
4283 }
4284 
4285 void
4286 mxSetPi (mxArray *ptr, double *pi)
4287 {
4288  ptr->set_imag_data (maybe_unmark (pi));
4289 }
4290 
4291 void
4292 mxSetImagData (mxArray *ptr, void *pi)
4293 {
4294  ptr->set_imag_data (maybe_unmark (pi));
4295 }
4296 
4297 // Classes.
4298 mxClassID
4299 mxGetClassID (const mxArray *ptr)
4300 {
4301  return ptr->get_class_id ();
4302 }
4303 
4304 const char *
4306 {
4307  return ptr->get_class_name ();
4308 }
4309 
4310 void
4311 mxSetClassName (mxArray *ptr, const char *name)
4312 {
4313  ptr->set_class_name (name);
4314 }
4315 
4316 void
4317 mxSetProperty (mxArray *ptr, mwIndex idx, const char *property_name,
4318  const mxArray *property_value)
4319 {
4320  ptr->set_property (idx, property_name, property_value);
4321 }
4322 
4323 mxArray *
4324 mxGetProperty (const mxArray *ptr, mwIndex idx, const char *property_name)
4325 {
4326  return ptr->get_property (idx, property_name);
4327 }
4328 
4329 // Cell support.
4330 mxArray *
4331 mxGetCell (const mxArray *ptr, mwIndex idx)
4332 {
4333  return ptr->get_cell (idx);
4334 }
4335 
4336 void
4338 {
4339  ptr->set_cell (idx, val);
4340 }
4341 
4342 // Sparse support.
4343 mwIndex *
4344 mxGetIr (const mxArray *ptr)
4345 {
4346  return ptr->get_ir ();
4347 }
4348 
4349 mwIndex *
4350 mxGetJc (const mxArray *ptr)
4351 {
4352  return ptr->get_jc ();
4353 }
4354 
4355 mwSize
4356 mxGetNzmax (const mxArray *ptr)
4357 {
4358  return ptr->get_nzmax ();
4359 }
4360 
4361 void
4363 {
4364  ptr->set_ir (static_cast<mwIndex *> (maybe_unmark (ir)));
4365 }
4366 
4367 void
4369 {
4370  ptr->set_jc (static_cast<mwIndex *> (maybe_unmark (jc)));
4371 }
4372 
4373 void
4375 {
4376  ptr->set_nzmax (nzmax);
4377 }
4378 
4379 // Structure support.
4380 int
4381 mxAddField (mxArray *ptr, const char *key)
4382 {
4383  return ptr->add_field (key);
4384 }
4385 
4386 void
4387 mxRemoveField (mxArray *ptr, int key_num)
4388 {
4389  ptr->remove_field (key_num);
4390 }
4391 
4392 mxArray *
4393 mxGetField (const mxArray *ptr, mwIndex index, const char *key)
4394 {
4395  int key_num = mxGetFieldNumber (ptr, key);
4396  return mxGetFieldByNumber (ptr, index, key_num);
4397 }
4398 
4399 mxArray *
4400 mxGetFieldByNumber (const mxArray *ptr, mwIndex index, int key_num)
4401 {
4402  return ptr->get_field_by_number (index, key_num);
4403 }
4404 
4405 void
4406 mxSetField (mxArray *ptr, mwIndex index, const char *key, mxArray *val)
4407 {
4408  int key_num = mxGetFieldNumber (ptr, key);
4409  mxSetFieldByNumber (ptr, index, key_num, val);
4410 }
4411 
4412 void
4413 mxSetFieldByNumber (mxArray *ptr, mwIndex index, int key_num, mxArray *val)
4414 {
4415  ptr->set_field_by_number (index, key_num, val);
4416 }
4417 
4418 int
4420 {
4421  return ptr->get_number_of_fields ();
4422 }
4423 
4424 const char *
4425 mxGetFieldNameByNumber (const mxArray *ptr, int key_num)
4426 {
4427  return ptr->get_field_name_by_number (key_num);
4428 }
4429 
4430 int
4431 mxGetFieldNumber (const mxArray *ptr, const char *key)
4432 {
4433  return ptr->get_field_number (key);
4434 }
4435 
4436 int
4437 mxGetString (const mxArray *ptr, char *buf, mwSize buflen)
4438 {
4439  return ptr->get_string (buf, buflen);
4440 }
4441 
4442 char *
4444 {
4445  return ptr->array_to_string ();
4446 }
4447 
4448 mwIndex
4449 mxCalcSingleSubscript (const mxArray *ptr, mwSize nsubs, mwIndex *subs)
4450 {
4451  return ptr->calc_single_subscript (nsubs, subs);
4452 }
4453 
4454 std::size_t
4456 {
4457  return ptr->get_element_size ();
4458 }
4459 
4460 // ------------------------------------------------------------------
4461 
4462 typedef void (*cmex_fptr) (int nlhs, mxArray **plhs, int nrhs, mxArray **prhs);
4463 typedef F77_RET_T (*fmex_fptr) (F77_INT& nlhs, mxArray **plhs,
4464  F77_INT& nrhs, mxArray **prhs);
4465 
4467 
4470  int nargout_arg)
4471 {
4472  octave_quit ();
4473 
4474  // Use at least 1 for nargout since even for zero specified args,
4475  // still want to be able to return an ans.
4476 
4477  volatile int nargout = nargout_arg;
4478 
4479  int nargin = args.length ();
4480  OCTAVE_LOCAL_BUFFER (mxArray *, argin, nargin);
4481  for (int i = 0; i < nargin; i++)
4482  argin[i] = nullptr;
4483 
4484  int nout = (nargout == 0 ? 1 : nargout);
4485  OCTAVE_LOCAL_BUFFER (mxArray *, argout, nout);
4486  for (int i = 0; i < nout; i++)
4487  argout[i] = nullptr;
4488 
4489  // Save old mex pointer.
4490  octave::unwind_protect_var<mex *> restore_var (mex_context);
4491 
4492  mex context (mex_fcn);
4493 
4494  for (int i = 0; i < nargin; i++)
4495  argin[i] = context.make_value (args(i));
4496 
4497  mex_context = &context;
4498 
4499  void *mex_fcn_ptr = mex_fcn.mex_fcn_ptr ();
4500 
4501  if (mex_fcn.is_fmex ())
4502  {
4503  fmex_fptr fcn = reinterpret_cast<fmex_fptr> (mex_fcn_ptr);
4504 
4505  F77_INT tmp_nargout = nargout;
4506  F77_INT tmp_nargin = nargin;
4507 
4508  fcn (tmp_nargout, argout, tmp_nargin, argin);
4509  }
4510  else
4511  {
4512  cmex_fptr fcn = reinterpret_cast<cmex_fptr> (mex_fcn_ptr);
4513 
4514  fcn (nargout, argout, nargin, argin);
4515  }
4516 
4517  // Convert returned array entries back into octave values.
4518 
4519  octave_value_list retval;
4520 
4521  if (nargout == 0 && argout[0])
4522  {
4523  // We have something for ans.
4524  nargout = 1;
4525  }
4526 
4527  retval.resize (nargout);
4528 
4529  // If using std::pmr::memory_resource object to manage memory, pass
4530  // default allocator here because we are done with these mxArray
4531  // values and want Octave to delete them.
4532 
4533  for (int i = 0; i < nargout; i++)
4534  retval(i) = mxArray::as_octave_value (argout[i], false);
4535 
4536  return retval;
4537 }
4538 
4539 OCTAVE_END_NAMESPACE(octave)
4540 
4541 // C interface to mex functions:
4542 
4543 const char *
4545 {
4546  return mex_context ? mex_context->function_name () : "unknown";
4547 }
4548 
4549 static inline octave_value_list
4550 mx_to_ov_args (int nargin, mxArray *argin[])
4551 {
4552  // Use a separate function for this job so that the
4553  // current_mx_memory_resource will be restored immediately after the
4554  // octave_value objects borrow the mxArray data. We could also use a
4555  // dummy scope in mexCallMATLAB, but this function seems less likely
4556  // to be accidentally deleted.
4557 
4558  octave_value_list args (nargin);
4559 
4560 #if defined (OCTAVE_HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR)
4561 
4562  // Use allocator that doesn't free memory because Octave may mutate
4563  // the value (single element mxArray -> scalar octave_value object,
4564  // for example) and we need these objects to continue to exist after
4565  // mexCallMATLAB returns.
4566 
4567  octave::unwind_protect_var<std::pmr::memory_resource *>
4568  upv (current_mx_memory_resource, &the_mx_preserving_memory_resource);
4569 
4570 #endif
4571 
4572  for (int i = 0; i < nargin; i++)
4573  args(i) = mxArray::as_octave_value (argin[i]);
4574 
4575  return args;
4576 }
4577 
4578 int
4579 mexCallMATLAB (int nargout, mxArray *argout[], int nargin,
4580  mxArray *argin[], const char *fname)
4581 {
4582  octave_value_list args = mx_to_ov_args (nargin, argin);
4583 
4584  octave::interpreter& interp = octave::__get_interpreter__ ();
4585 
4586  bool execution_error = false;
4587 
4588  octave_value_list retval;
4589 
4590  try
4591  {
4592  octave::tree_evaluator& tw = interp.get_evaluator ();
4593 
4594  octave::unwind_action act
4595  ([&tw] (const std::list<octave::octave_lvalue> *lvl)
4596  {
4597  tw.set_lvalue_list (lvl);
4598  }, tw.lvalue_list ());
4599 
4600  tw.set_lvalue_list (nullptr);
4601 
4602  retval = interp.feval (fname, args, nargout);
4603  }
4604  catch (const octave::execution_exception&)
4605  {
4606  if (mex_context->trap_feval_error)
4607  {
4608  // FIXME: is there a way to indicate what error occurred?
4609  // Should the error message be displayed here? Do we need to
4610  // save the exception info for lasterror?
4611 
4612  interp.recover_from_exception ();
4613 
4614  execution_error = true;
4615  }
4616  else
4617  {
4618  args.resize (0);
4619  retval.resize (0);
4620 
4621  throw;
4622  }
4623  }
4624 
4625  int num_to_copy = retval.length ();
4626 
4627  if (nargout < retval.length ())
4628  num_to_copy = nargout;
4629 
4630  for (int i = 0; i < num_to_copy; i++)
4631  {
4632  // FIXME: it would be nice to avoid copying the value here,
4633  // but there is no way to steal memory from a matrix, never mind
4634  // that matrix memory is allocated by new[] and mxArray memory
4635  // is allocated by malloc().
4636  argout[i] = mex_context->make_value (retval(i));
4637  }
4638 
4639  while (num_to_copy < nargout)
4640  argout[num_to_copy++] = nullptr;
4641 
4642  return execution_error ? 1 : 0;
4643 }
4644 
4645 mxArray *
4646 mexCallMATLABWithTrap (int nargout, mxArray *argout[], int nargin,
4647  mxArray *argin[], const char *fname)
4648 {
4649  mxArray *mx = nullptr;
4650 
4651  int old_flag = (mex_context ? mex_context->trap_feval_error : 0);
4652  mexSetTrapFlag (1);
4653  if (mexCallMATLAB (nargout, argout, nargin, argin, fname))
4654  {
4655  const char *field_names[] = {"identifier", "message", "case", "stack"};
4656  mx = mxCreateStructMatrix (1, 1, 4, field_names);
4657  mxSetFieldByNumber (mx, 0, 0, mxCreateString ("Octave:MEX"));
4658  std::string msg = "mexCallMATLABWithTrap: function call <"
4659  + std::string (fname) + "> failed";
4660  mxSetFieldByNumber (mx, 0, 1, mxCreateString (msg.c_str ()));
4661  mxSetFieldByNumber (mx, 0, 2, mxCreateCellMatrix (0, 0));
4662  mxSetFieldByNumber (mx, 0, 3, mxCreateStructMatrix (0, 1, 0, nullptr));
4663  }
4664  mexSetTrapFlag (old_flag);
4665 
4666  return mx;
4667 }
4668 
4669 void
4670 mexSetTrapFlag (int flag)
4671 {
4672  if (mex_context)
4673  mex_context->trap_feval_error = flag;
4674 }
4675 
4676 int
4677 mexEvalString (const char *s)
4678 {
4679  int retval = 0;
4680 
4681  octave::interpreter& interp = octave::__get_interpreter__ ();
4682 
4683  int parse_status;
4684  bool execution_error = false;
4685 
4686  octave_value_list ret;
4687 
4688  try
4689  {
4690  ret = interp.eval_string (std::string (s), false, parse_status, 0);
4691  }
4692  catch (const octave::execution_exception&)
4693  {
4694  interp.recover_from_exception ();
4695 
4696  execution_error = true;
4697  }
4698 
4699  if (parse_status || execution_error)
4700  retval = 1;
4701 
4702  return retval;
4703 }
4704 
4705 mxArray *
4706 mexEvalStringWithTrap (const char *s)
4707 {
4708  mxArray *mx = nullptr;
4709 
4710  octave::interpreter& interp = octave::__get_interpreter__ ();
4711 
4712  int parse_status;
4713  bool execution_error = false;
4714 
4715  octave_value_list ret;
4716 
4717  try
4718  {
4719  ret = interp.eval_string (std::string (s), false, parse_status, 0);
4720  }
4721  catch (const octave::execution_exception&)
4722  {
4723  interp.recover_from_exception ();
4724 
4725  execution_error = true;
4726  }
4727 
4728  if (parse_status || execution_error)
4729  {
4730  const char *field_names[] = {"identifier", "message", "case", "stack"};
4731  mx = mxCreateStructMatrix (1, 1, 4, field_names);
4732  mxSetFieldByNumber (mx, 0, 0, mxCreateString ("Octave:MEX"));
4733  std::string msg = "mexEvalStringWithTrap: eval of <"
4734  + std::string (s) + "> failed";
4735  mxSetFieldByNumber (mx, 0, 1, mxCreateString (msg.c_str ()));
4736  mxSetFieldByNumber (mx, 0, 2, mxCreateCellMatrix (0, 0));
4737  mxSetFieldByNumber (mx, 0, 3, mxCreateStructMatrix (0, 1, 0, nullptr));
4738  }
4739 
4740  return mx;
4741 }
4742 
4743 void
4744 mexErrMsgTxt (const char *s)
4745 {
4746  std::size_t len;
4747 
4748  if (s && (len = strlen (s)) > 0)
4749  {
4750  if (s[len - 1] == '\n')
4751  {
4752  std::string s_tmp (s, len - 1);
4753  error ("%s: %s\n", mexFunctionName (), s_tmp.c_str ());
4754  }
4755  else
4756  error ("%s: %s", mexFunctionName (), s);
4757  }
4758  else
4759  {
4760  // For compatibility with Matlab, print an empty message.
4761  // Octave's error routine requires a non-null input so use a SPACE.
4762  error (" ");
4763  }
4764 }
4765 
4766 void
4767 mexErrMsgIdAndTxt (const char *id, const char *fmt, ...)
4768 {
4769  if (fmt && strlen (fmt) > 0)
4770  {
4771  const char *fname = mexFunctionName ();
4772  std::size_t len = strlen (fname) + 2 + strlen (fmt) + 1;
4773  OCTAVE_LOCAL_BUFFER (char, tmpfmt, len);
4774  sprintf (tmpfmt, "%s: %s", fname, fmt);
4775  va_list args;
4776  va_start (args, fmt);
4777  verror_with_id (id, tmpfmt, args);
4778  va_end (args);
4779  }
4780  else
4781  {
4782  // For compatibility with Matlab, print an empty message.
4783  // Octave's error routine requires a non-null input so use a SPACE.
4784  error (" ");
4785  }
4786 }
4787 
4788 void
4789 mexWarnMsgTxt (const char *s)
4790 {
4791  std::size_t len;
4792 
4793  if (s && (len = strlen (s)) > 0)
4794  {
4795  if (s[len - 1] == '\n')
4796  {
4797  std::string s_tmp (s, len - 1);
4798  warning ("%s\n", s_tmp.c_str ());
4799  }
4800  else
4801  warning ("%s", s);
4802  }
4803  else
4804  {
4805  // For compatibility with Matlab, print an empty message.
4806  // Octave's warning routine requires a non-null input so use a SPACE.
4807  warning (" ");
4808  }
4809 }
4810 
4811 void
4812 mexWarnMsgIdAndTxt (const char *id, const char *fmt, ...)
4813 {
4814  // FIXME: is this right? What does Matlab do if fmt is NULL or
4815  // an empty string?
4816 
4817  if (fmt && strlen (fmt) > 0)
4818  {
4819  const char *fname = mexFunctionName ();
4820  std::size_t len = strlen (fname) + 2 + strlen (fmt) + 1;
4821  OCTAVE_LOCAL_BUFFER (char, tmpfmt, len);
4822  sprintf (tmpfmt, "%s: %s", fname, fmt);
4823  va_list args;
4824  va_start (args, fmt);
4825  vwarning_with_id (id, tmpfmt, args);
4826  va_end (args);
4827  }
4828 }
4829 
4830 int
4831 mexPrintf (const char *fmt, ...)
4832 {
4833  int retval;
4834  va_list args;
4835  va_start (args, fmt);
4836  retval = octave::vformat (octave_stdout, fmt, args);
4837  va_end (args);
4838  return retval;
4839 }
4840 
4841 mxArray *
4842 mexGetVariable (const char *space, const char *name)
4843 {
4844  mxArray *retval = nullptr;
4845 
4846  octave_value val;
4847 
4848  octave::interpreter& interp = octave::__get_interpreter__ ();
4849 
4850  if (! strcmp (space, "global"))
4851  val = interp.global_varval (name);
4852  else
4853  {
4854  // FIXME: should this be in variables.cc?
4855 
4856  octave::unwind_protect frame;
4857 
4858  bool caller = ! strcmp (space, "caller");
4859  bool base = ! strcmp (space, "base");
4860 
4861  if (caller || base)
4862  {
4863  // MEX files don't create a separate frame in the call stack,
4864  // so we are already in the "caller" frame.
4865 
4866  if (base)
4867  {
4868  octave::tree_evaluator& tw = interp.get_evaluator ();
4869 
4870  frame.add (&octave::tree_evaluator::restore_frame, &tw,
4871  tw.current_call_stack_frame_number ());
4872 
4873  tw.goto_base_frame ();
4874  }
4875 
4876  val = interp.varval (name);
4877  }
4878  else
4879  mexErrMsgTxt ("mexGetVariable: symbol table does not exist");
4880  }
4881 
4882  if (val.is_defined ())
4883  {
4884  retval = mex_context->make_value (val);
4885 
4886  retval->set_name (name);
4887  }
4888 
4889  return retval;
4890 }
4891 
4892 const mxArray *
4893 mexGetVariablePtr (const char *space, const char *name)
4894 {
4895  return mexGetVariable (space, name);
4896 }
4897 
4898 int
4899 mexPutVariable (const char *space, const char *name, const mxArray *ptr)
4900 {
4901  if (! ptr)
4902  return 1;
4903 
4904  if (! name)
4905  return 1;
4906 
4907  if (name[0] == '\0')
4908  name = ptr->get_name ();
4909 
4910  if (! name || name[0] == '\0')
4911  return 1;
4912 
4913  octave::interpreter& interp = octave::__get_interpreter__ ();
4914 
4915  if (! strcmp (space, "global"))
4916  {
4917 #if defined (OCTAVE_HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR)
4918 
4919  // Use allocator that doesn't free memory because Octave may mutate
4920  // the value (single element mxArray -> scalar octave_value object,
4921  // for example) and we need these objects to continue to exist after
4922  // mexCallMATLAB returns.
4923 
4924  octave::unwind_protect_var<std::pmr::memory_resource *>
4925  upv (current_mx_memory_resource, &the_mx_preserving_memory_resource);
4926 #endif
4927 
4928  interp.global_assign (name, mxArray::as_octave_value (ptr));
4929  }
4930  else
4931  {
4932  // FIXME: should this be in variables.cc?
4933 
4934  octave::unwind_protect frame;
4935 
4936  bool caller = ! strcmp (space, "caller");
4937  bool base = ! strcmp (space, "base");
4938 
4939  if (caller || base)
4940  {
4941  // MEX files don't create a separate frame in the call stack,
4942  // so we are already in the "caller" frame.
4943 
4944  if (base)
4945  {
4946  octave::tree_evaluator& tw = interp.get_evaluator ();
4947 
4948  frame.add (&octave::tree_evaluator::restore_frame, &tw,
4949  tw.current_call_stack_frame_number ());
4950 
4951  tw.goto_base_frame ();
4952  }
4953 
4954 #if defined (OCTAVE_HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR)
4955 
4956  // Use allocator that doesn't free memory because Octave may
4957  // mutate the value (single element mxArray -> scalar
4958  // octave_value object, for example) and we need these objects
4959  // to continue to exist after mexCallMATLAB returns.
4960 
4961  octave::unwind_protect_var<std::pmr::memory_resource *>
4962  upv (current_mx_memory_resource,
4963  &the_mx_preserving_memory_resource);
4964 #endif
4965 
4966  interp.assign (name, mxArray::as_octave_value (ptr));
4967  }
4968  else
4969  mexErrMsgTxt ("mexPutVariable: symbol table does not exist");
4970  }
4971 
4972  return 0;
4973 }
4974 
4975 void
4977 {
4978  maybe_unmark_array (ptr);
4979 }
4980 
4981 void
4983 {
4984  maybe_unmark (ptr);
4985 }
4986 
4987 int
4988 mexAtExit (void (*f) (void))
4989 {
4990  if (mex_context)
4991  {
4992  octave_mex_function& curr_mex_fcn = mex_context->current_mex_function ();
4993 
4994  curr_mex_fcn.atexit (f);
4995  }
4996 
4997  return 0;
4998 }
4999 
5000 const mxArray *
5001 mexGet_interleaved (double handle, const char *property)
5002 {
5003  mxArray *m = nullptr;
5004 
5005  octave_value ret
5006  = octave::get_property_from_handle (handle, property, "mexGet");
5007 
5008  if (ret.is_defined ())
5009  m = ret.as_mxArray (true);
5010 
5011  return m;
5012 }
5013 
5014 const mxArray *
5015 mexGet (double handle, const char *property)
5016 {
5017  mxArray *m = nullptr;
5018 
5019  octave_value ret
5020  = octave::get_property_from_handle (handle, property, "mexGet");
5021 
5022  if (ret.is_defined ())
5023  m = ret.as_mxArray (false);
5024 
5025  return m;
5026 }
5027 
5028 int
5029 mexIsGlobal (const mxArray *ptr)
5030 {
5031  return mxIsFromGlobalWS (ptr);
5032 }
5033 
5034 int
5036 {
5037  int retval = 0;
5038 
5039  if (mex_context)
5040  {
5041  const char *fname = mexFunctionName ();
5042 
5043  octave::interpreter& interp = octave::__get_interpreter__ ();
5044 
5045  retval = interp.mislocked (fname);
5046  }
5047 
5048  return retval;
5049 }
5050 
5051 std::map<std::string, int> mex_lock_count;
5052 
5053 void
5054 mexLock (void)
5055 {
5056  if (mex_context)
5057  {
5058  const char *fname = mexFunctionName ();
5059 
5060  if (mex_lock_count.find (fname) == mex_lock_count.end ())
5061  mex_lock_count[fname] = 1;
5062  else
5063  mex_lock_count[fname]++;
5064 
5065  octave::interpreter& interp = octave::__get_interpreter__ ();
5066 
5067  interp.mlock ();
5068  }
5069 }
5070 
5071 int
5072 mexSet (double handle, const char *property, mxArray *val)
5073 {
5074 #if defined (OCTAVE_HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR)
5075 
5076  // Use allocator that doesn't free memory because Octave may mutate
5077  // the value (single element mxArray -> scalar octave_value object,
5078  // for example) and we need these objects to continue to exist after
5079  // mexCallMATLAB returns.
5080 
5081  octave::unwind_protect_var<std::pmr::memory_resource *>
5082  upv (current_mx_memory_resource, &the_mx_preserving_memory_resource);
5083 
5084 #endif
5085 
5086  bool ret = octave::set_property_in_handle (handle, property,
5088  "mexSet");
5089  return (ret ? 0 : 1);
5090 }
5091 
5092 void
5094 {
5095  if (mex_context)
5096  {
5097  const char *fname = mexFunctionName ();
5098 
5099  auto p = mex_lock_count.find (fname);
5100 
5101  if (p != mex_lock_count.end ())
5102  {
5103  int count = --mex_lock_count[fname];
5104 
5105  if (count == 0)
5106  {
5107  octave::interpreter& interp = octave::__get_interpreter__ ();
5108 
5109  interp.munlock (fname);
5110 
5111  mex_lock_count.erase (p);
5112  }
5113  }
5114  }
5115 }
octave_value to_ov(const cdef_object &obj)
Definition: cdef-utils.cc:128
N Dimensional Array with copy-on-write semantics.
Definition: Array.h:130
const T * data() const
Size of the specified dimension.
Definition: Array.h:663
Definition: Cell.h:43
Definition: dMatrix.h:42
Definition: Sparse.h:49
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
void resize(int n, int fill_value=0)
Definition: dim-vector.h:272
virtual int set_int8s(mxInt8 *data)=0
virtual int set_complex_singles(mxComplexSingle *data)=0
OCTAVE_NORETURN void err_invalid_type(const char *op) const
Definition: mxarray.h:302
virtual mxInt8 * get_int8s() const =0
virtual bool is_octave_value() const
Definition: mxarray.h:107
virtual void set_n(mwSize n)=0
virtual void set_cell(mwIndex idx, mxArray *val)=0
virtual int add_field(const char *key)=0
virtual mxComplexDouble * get_complex_doubles() const =0
virtual mwIndex * get_jc() const =0
virtual void set_nzmax(mwSize nzmax)=0
virtual int set_uint16s(mxUint16 *data)=0
virtual mxDouble * get_doubles() const =0
virtual int is_logical() const =0
virtual int is_uint64() const =0
virtual char * array_to_string() const =0
virtual int set_uint64s(mxUint64 *data)=0
virtual int get_string(char *buf, mwSize buflen) const =0
virtual bool is_scalar() const =0
virtual mxSingle * get_singles() const =0
virtual mwIndex calc_single_subscript(mwSize nsubs, mwIndex *subs) const =0
virtual mxArray * get_cell(mwIndex) const
Definition: mxarray.h:207
virtual int set_doubles(mxDouble *data)=0
virtual int set_int64s(mxInt64 *data)=0
virtual int is_complex() const =0
virtual mxComplexSingle * get_complex_singles() const =0
virtual octave_value as_octave_value() const =0
virtual void set_imag_data(void *pi)=0
virtual int is_numeric() const =0
virtual mxArray * get_field_by_number(mwIndex index, int key_num) const =0
virtual int set_int16s(mxInt16 *data)=0
mxArray_base()=delete
virtual int is_double() const =0
virtual mwSize * get_dimensions() const =0
virtual int set_singles(mxSingle *data)=0
virtual int is_char() const =0
virtual void set_m(mwSize m)=0
virtual void set_data(void *pr)=0
virtual int is_logical_scalar_true() const =0
virtual void * get_data() const =0
virtual mxInt16 * get_int16s() const =0
virtual int is_uint16() const =0
virtual double get_scalar() const =0
virtual mwSize get_nzmax() const =0
std::size_t get_numeric_element_size(std::size_t size) const
Definition: mxarray.h:295
virtual mxArray_base * dup() const =0
virtual int iscell() const =0
virtual void set_property(mwIndex, const char *, const mxArray *)
Definition: mxarray.h:201
virtual int set_complex_doubles(mxComplexDouble *data)=0
virtual void * get_imag_data() const =0
virtual int isempty() const =0
virtual mwSize get_number_of_elements() const =0
virtual mxArray * as_mxArray() const
Definition: mxarray.h:103
virtual void set_jc(mwIndex *jc)=0
virtual std::size_t get_element_size() const =0
virtual int set_uint32s(mxUint32 *data)=0
virtual mxUint64 * get_uint64s() const =0
virtual mxUint8 * get_uint8s() const =0
virtual int set_uint8s(mxUint8 *data)=0
virtual bool mutation_needed() const
Definition: mxarray.h:287
virtual mxInt32 * get_int32s() const =0
virtual mwIndex * get_ir() const =0
virtual int set_dimensions(mwSize *dims_arg, mwSize ndims_arg)=0
virtual mxUint16 * get_uint16s() const =0
virtual int is_int16() const =0
virtual int is_single() const =0
virtual void set_class_name(const char *name_arg)=0
virtual mxUint32 * get_uint32s() const =0
virtual mxArray * mutate() const
Definition: mxarray.h:289
virtual mwSize get_number_of_dimensions() const =0
virtual int is_function_handle() const =0
virtual int is_uint8() const =0
virtual mwSize get_m() const =0
virtual int is_int8() const =0
virtual int is_int32() const =0
virtual int get_number_of_fields() const =0
virtual void set_ir(mwIndex *ir)=0
virtual void remove_field(int key_num)=0
virtual int is_uint32() const =0
virtual mxArray * get_property(mwIndex, const char *) const
Definition: mxarray.h:196
virtual const char * get_field_name_by_number(int key_num) const =0
virtual int is_int64() const =0
virtual void set_field_by_number(mwIndex index, int key_num, mxArray *val)=0
virtual const char * get_class_name() const =0
virtual int is_struct() const =0
virtual mxInt64 * get_int64s() const =0
virtual int get_field_number(const char *key) const =0
virtual mwSize get_n() const =0
virtual int set_int32s(mxInt32 *data)=0
virtual int is_sparse() const =0
virtual mxClassID get_class_id() const =0
int set_uint8s(mxUint8 *data)
Definition: mxarray.h:534
int set_complex_singles(mxComplexSingle *data)
Definition: mxarray.h:549
mxUint8 * get_uint8s() const
Definition: mxarray.h:493
int is_logical() const
Definition: mxarray.h:402
int is_logical_scalar() const
Definition: mxarray.h:420
int is_single() const
Definition: mxarray.h:406
mwSize get_m() const
Definition: mxarray.h:425
int set_uint32s(mxUint32 *data)
Definition: mxarray.h:540
int is_int64() const
Definition: mxarray.h:398
int get_number_of_fields() const
Definition: mxarray.h:577
mwIndex * get_ir() const
Definition: mxarray.h:554
mxInt64 * get_int64s() const
Definition: mxarray.h:490
mxUint64 * get_uint64s() const
Definition: mxarray.h:502
double get_scalar() const
Definition: mxarray.h:471
void set_name(const char *name)
Definition: mex.cc:3029
~mxArray()
Definition: mex.cc:3021
char * array_to_string() const
Definition: mxarray.h:589
void * get_imag_data() const
Definition: mxarray.h:511
void set_n(mwSize n)
Definition: mxarray.h:436
mwSize get_number_of_dimensions() const
Definition: mxarray.h:431
void set_property(mwIndex idx, const char *pname, const mxArray *pval)
Definition: mxarray.h:459
std::size_t get_element_size() const
Definition: mxarray.h:594
int set_singles(mxSingle *data)
Definition: mxarray.h:519
mwSize * get_dimensions() const
Definition: mxarray.h:429
const char * get_class_name() const
Definition: mxarray.h:454
int set_uint16s(mxUint16 *data)
Definition: mxarray.h:537
void set_m(mwSize m)
Definition: mxarray.h:434
static void * alloc(bool init, std::size_t n, std::size_t t)
Definition: mex.cc:3491
mxArray * get_property(mwIndex idx, const char *pname) const
Definition: mxarray.h:456
int is_function_handle() const
Definition: mxarray.h:392
mwIndex * get_jc() const
Definition: mxarray.h:556
mxInt16 * get_int16s() const
Definition: mxarray.h:484
int set_uint64s(mxUint64 *data)
Definition: mxarray.h:543
int is_double() const
Definition: mxarray.h:390
mwIndex calc_single_subscript(mwSize nsubs, mwIndex *subs) const
Definition: mxarray.h:591
int is_char() const
Definition: mxarray.h:384
mwSize get_number_of_elements() const
Definition: mxarray.h:441
int set_dimensions(mwSize *dims_arg, mwSize ndims_arg)
Definition: mxarray.h:438
mxUint16 * get_uint16s() const
Definition: mxarray.h:496
static char * strsave(const char *str)
Definition: mxarray.h:607
void set_data(void *pr)
Definition: mxarray.h:514
int isempty() const
Definition: mxarray.h:444
int is_struct() const
Definition: mxarray.h:410
mxComplexSingle * get_complex_singles() const
Definition: mxarray.h:508
static void * calloc(std::size_t n, std::size_t t)
Definition: mex.cc:3485
mxArray(bool interleaved, const octave_value &ov)
Definition: mex.cc:2949
int set_complex_doubles(mxComplexDouble *data)
Definition: mxarray.h:546
int get_field_number(const char *key) const
Definition: mxarray.h:583
int iscell() const
Definition: mxarray.h:382
mxArray * get_field_by_number(mwIndex index, int key_num) const
Definition: mxarray.h:571
int add_field(const char *key)
Definition: mxarray.h:566
mwSize get_nzmax() const
Definition: mxarray.h:558
int is_uint32() const
Definition: mxarray.h:414
mxInt32 * get_int32s() const
Definition: mxarray.h:487
bool is_scalar() const
Definition: mxarray.h:446
static octave_value as_octave_value(const mxArray *ptr, bool null_is_empty=true)
Definition: mex.cc:3036
int set_int32s(mxInt32 *data)
Definition: mxarray.h:528
int set_int64s(mxInt64 *data)
Definition: mxarray.h:531
int is_int32() const
Definition: mxarray.h:396
int set_doubles(mxDouble *data)
Definition: mxarray.h:516
void set_nzmax(mwSize nzmax)
Definition: mxarray.h:564
int is_logical_scalar_true() const
Definition: mxarray.h:422
int is_numeric() const
Definition: mxarray.h:404
mxArray * dup() const
Definition: mxarray.h:360
mwSize get_n() const
Definition: mxarray.h:427
void set_jc(mwIndex *jc)
Definition: mxarray.h:562
octave_value as_octave_value() const
Definition: mex.cc:3046
int set_int16s(mxInt16 *data)
Definition: mxarray.h:525
int is_complex() const
Definition: mxarray.h:388
mxClassID get_class_id() const
Definition: mxarray.h:452
mxSingle * get_singles() const
Definition: mxarray.h:478
const char * get_field_name_by_number(int key_num) const
Definition: mxarray.h:580
mxUint32 * get_uint32s() const
Definition: mxarray.h:499
int is_uint64() const
Definition: mxarray.h:416
int get_string(char *buf, mwSize buflen) const
Definition: mxarray.h:586
void * get_data() const
Definition: mxarray.h:473
int is_class(const char *name_arg) const
Definition: mxarray.h:386
int set_int8s(mxInt8 *data)
Definition: mxarray.h:522
void set_class_name(const char *name_arg)
Definition: mxarray.h:462
mxDouble * get_doubles() const
Definition: mxarray.h:475
void set_field_by_number(mwIndex index, int key_num, mxArray *val)
Definition: mxarray.h:574
void set_cell(mwIndex idx, mxArray *val)
Definition: mxarray.h:468
mxArray * get_cell(mwIndex idx) const
Definition: mxarray.h:465
int is_uint8() const
Definition: mxarray.h:418
mxComplexDouble * get_complex_doubles() const
Definition: mxarray.h:505
void set_ir(mwIndex *ir)
Definition: mxarray.h:560
static void * malloc(std::size_t n)
Definition: mex.cc:3479
void set_imag_data(void *pi)
Definition: mxarray.h:552
int is_uint16() const
Definition: mxarray.h:412
mxInt8 * get_int8s() const
Definition: mxarray.h:481
void remove_field(int key_num)
Definition: mxarray.h:568
const char * get_name() const
Definition: mxarray.h:448
int is_int8() const
Definition: mxarray.h:400
int is_sparse() const
Definition: mxarray.h:408
int is_int16() const
Definition: mxarray.h:394
octave_value get_property(octave_idx_type idx, const std::string &name) const
Definition: ov-classdef.h:138
void set_property(octave_idx_type idx, const std::string &name, const octave_value &pval)
Definition: ov-classdef.h:131
octave_classdef * classdef_object_value(bool=false)
Definition: ov-classdef.h:71
std::string name() const
Definition: ov-fcn.h:206
void * mex_fcn_ptr() const
Definition: ov-mex-fcn.h:100
bool is_fmex() const
Definition: ov-mex-fcn.h:102
void atexit(void(*fcn)())
Definition: ov-mex-fcn.h:96
void resize(octave_idx_type n, const octave_value &rfv=octave_value())
Definition: ovl.h:117
octave_idx_type length() const
Definition: ovl.h:113
bool is_defined() const
Definition: ov.h:592
mxArray * as_mxArray(bool interleaved=false) const
Definition: ov.h:1407
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void warning(const char *fmt,...)
Definition: error.cc:1063
void vwarning_with_id(const char *id, const char *fmt, va_list args)
Definition: error.cc:1072
void verror_with_id(const char *id, const char *fmt, va_list args)
Definition: error.cc:1027
void() error(const char *fmt,...)
Definition: error.cc:988
#define panic_impossible()
Definition: error.h:503
octave_f77_int_type F77_INT
Definition: f77-fcn.h:306
bool set_property_in_handle(double handle, const std::string &property, const octave_value &arg, const std::string &fcn)
Definition: graphics.cc:13597
octave_value get_property_from_handle(double handle, const std::string &property, const std::string &fcn)
Definition: graphics.cc:13581
interpreter & __get_interpreter__()
tree_evaluator & __get_evaluator__()
double lo_ieee_nan_value()
Definition: lo-ieee.cc:84
double lo_ieee_inf_value()
Definition: lo-ieee.cc:68
#define lo_ieee_isnan(x)
Definition: lo-ieee.h:116
#define lo_ieee_isinf(x)
Definition: lo-ieee.h:124
#define lo_ieee_isfinite(x)
Definition: lo-ieee.h:120
F77_RET_T(F77_CONST_CHAR_ARG_DECL, F77_CONST_CHAR_ARG_DECL, F77_CONST_CHAR_ARG_DECL, const F77_INT &, const F77_INT &, const F77_INT &, F77_INT &, F77_INT &, F77_DBLE *, const F77_INT &, F77_DBLE *, const F77_INT &, F77_DBLE *, F77_DBLE *, F77_DBLE *, const F77_INT &, F77_DBLE *, const F77_INT &, F77_DBLE *, const F77_INT &, F77_DBLE *, F77_INT *, F77_INT &F77_CHAR_ARG_LEN_DECL F77_CHAR_ARG_LEN_DECL F77_CHAR_ARG_LEN_DECL)
F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE * d
F77_RET_T const F77_DBLE const F77_DBLE * f
char * strsave(const char *s)
Definition: lo-utils.cc:78
void mxSetIr(mxArray *ptr, mwIndex *ir)
Definition: mex.cc:4362
mxUint16 * mxGetUint16s(const mxArray *p)
Definition: mex.cc:4171
void mxSetCell(mxArray *ptr, mwIndex idx, mxArray *val)
Definition: mex.cc:4337
bool mxIsUint16(const mxArray *ptr)
Definition: mex.cc:3970
std::size_t mxGetM(const mxArray *ptr)
Definition: mex.cc:4032
int mxSetDoubles(mxArray *p, mxDouble *d)
Definition: mex.cc:4214
mxDouble * mxGetDoubles(const mxArray *p)
Definition: mex.cc:4129
void mexWarnMsgIdAndTxt(const char *id, const char *fmt,...)
Definition: mex.cc:4812
int mxSetUint8s(mxArray *p, mxUint8 *d)
Definition: mex.cc:4250
#define CONST_MUTATION_METHOD(RET_TYPE, FCN_NAME, ARG_LIST, RET_VAL)
Definition: mex.cc:441
void * mxGetData(const mxArray *ptr)
Definition: mex.cc:4111
void * mxMalloc(std::size_t n)
Definition: mex.cc:3603
mwIndex mxCalcSingleSubscript(const mxArray *ptr, mwSize nsubs, mwIndex *subs)
Definition: mex.cc:4449
int mxSetInt16s(mxArray *p, mxInt16 *d)
Definition: mex.cc:4232
mxInt64 * mxGetInt64s(const mxArray *p)
Definition: mex.cc:4159
bool mxIsFunctionHandle(const mxArray *ptr)
Definition: mex.cc:3910
bool mxIsStruct(const mxArray *ptr)
Definition: mex.cc:3964
int mxGetFieldNumber(const mxArray *ptr, const char *key)
Definition: mex.cc:4431
void mexErrMsgTxt(const char *s)
Definition: mex.cc:4744
mex * mex_context
Definition: mex.cc:3476
void mxSetField(mxArray *ptr, mwIndex index, const char *key, mxArray *val)
Definition: mex.cc:4406
mxArray * mxCreateCellMatrix_interleaved(mwSize m, mwSize n)
Definition: mex.cc:3644
void(* cmex_fptr)(int nlhs, mxArray **plhs, int nrhs, mxArray **prhs)
Definition: mex.cc:4462
bool mxIsUint32(const mxArray *ptr)
Definition: mex.cc:3976
void mxSetProperty(mxArray *ptr, mwIndex idx, const char *property_name, const mxArray *property_value)
Definition: mex.cc:4317
int mxSetComplexDoubles(mxArray *p, mxComplexDouble *d)
Definition: mex.cc:4274
mxUint64 * mxGetUint64s(const mxArray *p)
Definition: mex.cc:4183
bool mxIsComplex(const mxArray *ptr)
Definition: mex.cc:3898
mxArray * mxCreateCharArray_interleaved(mwSize ndims, const mwSize *dims)
Definition: mex.cc:3656
mxComplexDouble * mxGetComplexDoubles(const mxArray *p)
Definition: mex.cc:4189
mxArray * mxCreateString(const char *str)
Definition: mex.cc:3830
mxArray * mxCreateSparseLogicalMatrix_interleaved(mwSize m, mwSize n, mwSize nzmax)
Definition: mex.cc:3812
mxArray * mxCreateCellArray(mwSize ndims, const mwSize *dims)
Definition: mex.cc:3638
int mxSetUint32s(mxArray *p, mxUint32 *d)
Definition: mex.cc:4262
int mxSetInt8s(mxArray *p, mxInt8 *d)
Definition: mex.cc:4226
mxArray * mxCreateNumericMatrix(mwSize m, mwSize n, mxClassID class_id, mxComplexity flag)
Definition: mex.cc:3761
int mexAtExit(void(*f)(void))
Definition: mex.cc:4988
int mxSetUint16s(mxArray *p, mxUint16 *d)
Definition: mex.cc:4256
bool mxIsFinite(const double v)
Definition: mex.cc:3560
mxSingle * mxGetSingles(const mxArray *p)
Definition: mex.cc:4135
bool mxIsScalar(const mxArray *ptr)
Definition: mex.cc:4015
bool mxIsFromGlobalWS(const mxArray *)
Definition: mex.cc:4023
void mxSetFieldByNumber(mxArray *ptr, mwIndex index, int key_num, mxArray *val)
Definition: mex.cc:4413
const char * mxGetClassName(const mxArray *ptr)
Definition: mex.cc:4305
bool mxIsLogicalScalarTrue(const mxArray *ptr)
Definition: mex.cc:4002
int mxSetInt32s(mxArray *p, mxInt32 *d)
Definition: mex.cc:4238
mxArray * mxCreateSparse(mwSize m, mwSize n, mwSize nzmax, mxComplexity flag)
Definition: mex.cc:3805
mxArray * mxCreateStructArray(mwSize ndims, const mwSize *dims, int num_keys, const char **keys)
Definition: mex.cc:3843
void * mxGetImagData(const mxArray *ptr)
Definition: mex.cc:4123
mxClassID mxGetClassID(const mxArray *ptr)
Definition: mex.cc:4299
bool mxIsLogical(const mxArray *ptr)
Definition: mex.cc:3940
mxArray * mxGetProperty(const mxArray *ptr, mwIndex idx, const char *property_name)
Definition: mex.cc:4324
std::map< std::string, int > mex_lock_count
Definition: mex.cc:5051
void mexWarnMsgTxt(const char *s)
Definition: mex.cc:4789
mxInt16 * mxGetInt16s(const mxArray *p)
Definition: mex.cc:4147
void mxSetData(mxArray *ptr, void *pr)
Definition: mex.cc:4208
const char * mexFunctionName(void)
Definition: mex.cc:4544
mwIndex * mxGetIr(const mxArray *ptr)
Definition: mex.cc:4344
int mxSetUint64s(mxArray *p, mxUint64 *d)
Definition: mex.cc:4268
mxInt8 * mxGetInt8s(const mxArray *p)
Definition: mex.cc:4141
bool mxIsInt64(const mxArray *ptr)
Definition: mex.cc:3928
mxArray * mxGetFieldByNumber(const mxArray *ptr, mwIndex index, int key_num)
Definition: mex.cc:4400
mxArray * mexCallMATLABWithTrap(int nargout, mxArray *argout[], int nargin, mxArray *argin[], const char *fname)
Definition: mex.cc:4646
int mxSetDimensions(mxArray *ptr, const mwSize *dims, mwSize ndims)
Definition: mex.cc:4075
std::size_t mxGetNumberOfElements(const mxArray *ptr)
Definition: mex.cc:4056
octave_value_list call_mex(octave_mex_function &mex_fcn, const octave_value_list &args, int nargout_arg)
Definition: mex.cc:4469
int mexPrintf(const char *fmt,...)
Definition: mex.cc:4831
bool mxIsChar(const mxArray *ptr)
Definition: mex.cc:3886
bool mxIsInf(const double v)
Definition: mex.cc:3566
bool mxIsUint8(const mxArray *ptr)
Definition: mex.cc:3988
void mxDestroyArray(mxArray *ptr)
Definition: mex.cc:3872
void mxSetNzmax(mxArray *ptr, mwSize nzmax)
Definition: mex.cc:4374
bool mxIsSingle(const mxArray *ptr)
Definition: mex.cc:3952
void mexErrMsgIdAndTxt(const char *id, const char *fmt,...)
Definition: mex.cc:4767
F77_RET_T(* fmex_fptr)(F77_INT &nlhs, mxArray **plhs, F77_INT &nrhs, mxArray **prhs)
Definition: mex.cc:4463
int mxAddField(mxArray *ptr, const char *key)
Definition: mex.cc:4381
void mexMakeMemoryPersistent(void *ptr)
Definition: mex.cc:4982
bool mxIsInt8(const mxArray *ptr)
Definition: mex.cc:3934
mxComplexSingle * mxGetComplexSingles(const mxArray *p)
Definition: mex.cc:4195
std::size_t mxGetElementSize(const mxArray *ptr)
Definition: mex.cc:4455
void mxSetImagData(mxArray *ptr, void *pi)
Definition: mex.cc:4292
mxArray * mxCreateLogicalArray(mwSize ndims, const mwSize *dims)
Definition: mex.cc:3710
int mxMakeArrayReal(mxArray *ptr)
int mexCallMATLAB(int nargout, mxArray *argout[], int nargin, mxArray *argin[], const char *fname)
Definition: mex.cc:4579
bool mxIsNaN(const double v)
Definition: mex.cc:3572
mxArray * mxCreateCharArray(mwSize ndims, const mwSize *dims)
Definition: mex.cc:3662
mxUint8 * mxGetUint8s(const mxArray *p)
Definition: mex.cc:4165
void mxSetPr(mxArray *ptr, double *pr)
Definition: mex.cc:4202
mxArray * mexEvalStringWithTrap(const char *s)
Definition: mex.cc:4706
mxArray * mexGetVariable(const char *space, const char *name)
Definition: mex.cc:4842
bool mxIsClass(const mxArray *ptr, const char *name)
Definition: mex.cc:3892
mxArray * mxCreateString_interleaved(const char *str)
Definition: mex.cc:3824
int mxMakeArrayComplex(mxArray *ptr)
mxInt32 * mxGetInt32s(const mxArray *p)
Definition: mex.cc:4153
mxArray * mxCreateUninitNumericMatrix_interleaved(mwSize m, mwSize n, mxClassID class_id, mxComplexity flag)
Definition: mex.cc:3784
int mxGetNumberOfFields(const mxArray *ptr)
Definition: mex.cc:4419
#define GET_DATA_METHOD(RT, FCN_NAME, ID, COMPLEXITY)
Definition: mex.cc:444
mxArray * mxCreateCellArray_interleaved(mwSize ndims, const mwSize *dims)
Definition: mex.cc:3632
void * mxCalloc(std::size_t n, std::size_t size)
Definition: mex.cc:3597
mxArray * mxCreateNumericArray_interleaved(mwSize ndims, const mwSize *dims, mxClassID class_id, mxComplexity flag)
Definition: mex.cc:3740
mwIndex * mxGetJc(const mxArray *ptr)
Definition: mex.cc:4350
int mexPutVariable(const char *space, const char *name, const mxArray *ptr)
Definition: mex.cc:4899
void mxSetN(mxArray *ptr, mwSize n)
Definition: mex.cc:4069
mxArray * mxCreateNumericArray(mwSize ndims, const mwSize *dims, mxClassID class_id, mxComplexity flag)
Definition: mex.cc:3747
int mxSetInt64s(mxArray *p, mxInt64 *d)
Definition: mex.cc:4244
mxArray * mxCreateSparseLogicalMatrix(mwSize m, mwSize n, mwSize nzmax)
Definition: mex.cc:3818
bool mxIsInt32(const mxArray *ptr)
Definition: mex.cc:3922
double * mxGetPi(const mxArray *ptr)
Definition: mex.cc:4117
mxArray * mxCreateCharMatrixFromStrings_interleaved(mwSize m, const char **str)
Definition: mex.cc:3668
void * mxRealloc(void *ptr, std::size_t size)
Definition: mex.cc:3609
void mexUnlock(void)
Definition: mex.cc:5093
int mexIsGlobal(const mxArray *ptr)
Definition: mex.cc:5029
void mxSetJc(mxArray *ptr, mwIndex *jc)
Definition: mex.cc:4368
bool mxIsInt16(const mxArray *ptr)
Definition: mex.cc:3916
const mwSize * mxGetDimensions(const mxArray *ptr)
Definition: mex.cc:4044
int mxSetComplexSingles(mxArray *p, mxComplexSingle *d)
Definition: mex.cc:4280
mxArray * mxCreateCellMatrix(mwSize m, mwSize n)
Definition: mex.cc:3650
int mexEvalString(const char *s)
Definition: mex.cc:4677
void mexSetTrapFlag(int flag)
Definition: mex.cc:4670
mwSize mxGetNzmax(const mxArray *ptr)
Definition: mex.cc:4356
mxArray * mxCreateLogicalScalar(mxLogical val)
Definition: mex.cc:3734
void mxSetClassName(mxArray *ptr, const char *name)
Definition: mex.cc:4311
const mxArray * mexGetVariablePtr(const char *space, const char *name)
Definition: mex.cc:4893
mxUint32 * mxGetUint32s(const mxArray *p)
Definition: mex.cc:4177
bool mxIsNumeric(const mxArray *ptr)
Definition: mex.cc:3946
mxArray * mxCreateSparse_interleaved(mwSize m, mwSize n, mwSize nzmax, mxComplexity flag)
Definition: mex.cc:3798
int mexIsLocked(void)
Definition: mex.cc:5035
mxArray * mxCreateDoubleMatrix(mwSize nr, mwSize nc, mxComplexity flag)
Definition: mex.cc:3686
bool mxIsCell(const mxArray *ptr)
Definition: mex.cc:3880
void mexMakeArrayPersistent(mxArray *ptr)
Definition: mex.cc:4976
mxArray * mxCreateCharMatrixFromStrings(mwSize m, const char **str)
Definition: mex.cc:3674
double mxGetScalar(const mxArray *ptr)
Definition: mex.cc:4090
#define VOID_MUTATION_METHOD(FCN_NAME, ARG_LIST)
Definition: mex.cc:432
void mxRemoveField(mxArray *ptr, int key_num)
Definition: mex.cc:4387
int mxGetString(const mxArray *ptr, char *buf, mwSize buflen)
Definition: mex.cc:4437
const char * mxGetFieldNameByNumber(const mxArray *ptr, int key_num)
Definition: mex.cc:4425
mxArray * mxCreateStructMatrix(mwSize rows, mwSize cols, int num_keys, const char **keys)
Definition: mex.cc:3857
bool mxIsLogicalScalar(const mxArray *ptr)
Definition: mex.cc:3995
mxArray * mxCreateDoubleScalar(double val)
Definition: mex.cc:3698
double mxGetInf(void)
Definition: mex.cc:3584
double mxGetNaN(void)
Definition: mex.cc:3590
mxArray * mxCreateUninitNumericArray(mwSize ndims, const mwSize *dims, mxClassID class_id, mxComplexity flag)
Definition: mex.cc:3776
std::size_t mxGetN(const mxArray *ptr)
Definition: mex.cc:4038
mxArray * mxCreateNumericMatrix_interleaved(mwSize m, mwSize n, mxClassID class_id, mxComplexity flag)
Definition: mex.cc:3754
mwSize mxGetNumberOfDimensions(const mxArray *ptr)
Definition: mex.cc:4050
mxLogical * mxGetLogicals(const mxArray *ptr)
Definition: mex.cc:4105
mxArray * mxCreateUninitNumericMatrix(mwSize m, mwSize n, mxClassID class_id, mxComplexity flag)
Definition: mex.cc:3791
double mxGetEps(void)
Definition: mex.cc:3578
double * mxGetPr(const mxArray *ptr)
Definition: mex.cc:4084
int mexSet(double handle, const char *property, mxArray *val)
Definition: mex.cc:5072
void mexLock(void)
Definition: mex.cc:5054
#define MUTATION_METHOD(RET_TYPE, FCN_NAME, ARG_LIST, RET_VAL)
Definition: mex.cc:438
const mxArray * mexGet(double handle, const char *property)
Definition: mex.cc:5015
mxArray * mxCreateStructMatrix_interleaved(mwSize rows, mwSize cols, int num_keys, const char **keys)
Definition: mex.cc:3850
bool mxIsEmpty(const mxArray *ptr)
Definition: mex.cc:4009
mxArray * mxCreateLogicalArray_interleaved(mwSize ndims, const mwSize *dims)
Definition: mex.cc:3704
mxArray * mxGetField(const mxArray *ptr, mwIndex index, const char *key)
Definition: mex.cc:4393
char * mxArrayToString(const mxArray *ptr)
Definition: mex.cc:4443
mxArray * mxCreateLogicalMatrix_interleaved(mwSize m, mwSize n)
Definition: mex.cc:3716
void mxFree(void *ptr)
Definition: mex.cc:3616
mxChar * mxGetChars(const mxArray *ptr)
Definition: mex.cc:4096
const mxArray * mexGet_interleaved(double handle, const char *property)
Definition: mex.cc:5001
bool mxIsSparse(const mxArray *ptr)
Definition: mex.cc:3958
bool mxIsUint64(const mxArray *ptr)
Definition: mex.cc:3982
mxArray * mxCreateDoubleScalar_interleaved(double val)
Definition: mex.cc:3692
bool mxIsDouble(const mxArray *ptr)
Definition: mex.cc:3904
mxArray * mxGetCell(const mxArray *ptr, mwIndex idx)
Definition: mex.cc:4331
mxArray * mxCreateStructArray_interleaved(mwSize ndims, const mwSize *dims, int num_keys, const char **keys)
Definition: mex.cc:3836
mxArray * mxCreateLogicalScalar_interleaved(mxLogical val)
Definition: mex.cc:3728
void mxSetPi(mxArray *ptr, double *pi)
Definition: mex.cc:4286
mxArray * mxCreateUninitNumericArray_interleaved(mwSize ndims, const mwSize *dims, mxClassID class_id, mxComplexity flag)
Definition: mex.cc:3768
int mxSetSingles(mxArray *p, mxSingle *d)
Definition: mex.cc:4220
void mxSetM(mxArray *ptr, mwSize m)
Definition: mex.cc:4063
mxArray * mxCreateLogicalMatrix(mwSize m, mwSize n)
Definition: mex.cc:3722
mxArray * mxCreateDoubleMatrix_interleaved(mwSize nr, mwSize nc, mxComplexity flag)
Definition: mex.cc:3680
mxArray * mxDuplicateArray(const mxArray *ptr)
Definition: mex.cc:3865
void mxArray
Definition: mex.h:58
T octave_idx_type m
Definition: mx-inlines.cc:781
octave_idx_type n
Definition: mx-inlines.cc:761
int16_t mxInt16
Definition: mxtypes.h:95
char mxChar
Definition: mxtypes.h:87
uint64_t mxUint64
Definition: mxtypes.h:102
int32_t mxInt32
Definition: mxtypes.h:96
float mxSingle
Definition: mxtypes.h:92
mxClassID
Definition: mxtypes.h:57
@ mxFUNCTION_CLASS
Definition: mxtypes.h:74
@ mxINT8_CLASS
Definition: mxtypes.h:66
@ mxINT64_CLASS
Definition: mxtypes.h:72
@ mxUINT8_CLASS
Definition: mxtypes.h:67
@ mxUNKNOWN_CLASS
Definition: mxtypes.h:58
@ mxLOGICAL_CLASS
Definition: mxtypes.h:61
@ mxSTRUCT_CLASS
Definition: mxtypes.h:60
@ mxINT32_CLASS
Definition: mxtypes.h:70
@ mxSINGLE_CLASS
Definition: mxtypes.h:65
@ mxDOUBLE_CLASS
Definition: mxtypes.h:64
@ mxUINT64_CLASS
Definition: mxtypes.h:73
@ mxCHAR_CLASS
Definition: mxtypes.h:62
@ mxUINT16_CLASS
Definition: mxtypes.h:69
@ mxCELL_CLASS
Definition: mxtypes.h:59
@ mxUINT32_CLASS
Definition: mxtypes.h:71
@ mxINT16_CLASS
Definition: mxtypes.h:68
int64_t mxInt64
Definition: mxtypes.h:97
int64_t mwIndex
Definition: mxtypes.h:125
double mxDouble
Definition: mxtypes.h:91
mxComplexity
Definition: mxtypes.h:79
@ mxREAL
Definition: mxtypes.h:80
@ mxCOMPLEX
Definition: mxtypes.h:81
uint32_t mxUint32
Definition: mxtypes.h:101
uint8_t mxUint8
Definition: mxtypes.h:99
uint16_t mxUint16
Definition: mxtypes.h:100
int8_t mxInt8
Definition: mxtypes.h:94
unsigned char mxLogical
Definition: mxtypes.h:89
int64_t mwSize
Definition: mxtypes.h:124
void get_dimensions(const octave_value &a, const char *warn_for, dim_vector &dim)
Definition: utils.cc:1348
std::size_t vformat(std::ostream &os, const char *fmt, va_list args)
Definition: utils.cc:1500
std::complex< double > Complex
Definition: oct-cmplx.h:33
std::complex< float > FloatComplex
Definition: oct-cmplx.h:34
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:44
T::size_type strlen(const typename T::value_type *str)
Definition: oct-string.cc:88
bool strcmp(const T &str_a, const T &str_b)
Octave string utility functions.
void * malloc(unsigned)
void free(void *)
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
#define octave_stdout
Definition: pager.h:309
F77_RET_T len
Definition: xerbla.cc:61