GNU Octave 11.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
mxarray.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 2006-2026 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 OCTAVE_MXARRAY_DEBUG 1
31
32#include <cstdarg>
33#include <cstdlib>
34#include <cstring>
35#include <cctype>
36
37#include <limits>
38#include <map>
39#if defined (OCTAVE_HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR)
40# include <memory_resource>
41#endif
42#include <set>
43#include <string>
44
45#if defined (OCTAVE_MXARRAY_DEBUG)
46# include <iostream>
47#endif
48
49#include "f77-fcn.h"
50#include "oct-locbuf.h"
51#include "quit.h"
52
53#include "Cell.h"
54#include "error.h"
55#include "interpreter-private.h"
56#include "interpreter.h"
57#include "mxarray.h"
58#include "oct-map.h"
59#include "ovl.h"
60#include "ov.h"
61#include "ov-classdef.h"
62#include "ov-mex-fcn.h"
63#include "ov-usr-fcn.h"
64#include "pager.h"
65#include "unwind-prot.h"
66#include "utils.h"
67#include "variables.h"
68#include "graphics.h"
69
70OCTAVE_NORETURN static void
71error_impossible_call (const char *fcn_name)
72{
73 error ("unexpected call to %s - please report this bug", fcn_name);
74}
75
76static void *
77xmalloc (size_t n)
78{
79 void *ptr = std::malloc (n);
80
81#if defined (OCTAVE_MXARRAY_DEBUG)
82 std::cerr << "xmalloc (" << n << ") = " << ptr << std::endl;
83#endif
84
85 return ptr;
86}
87
88static void *
89xrealloc (void *ptr, size_t n)
90{
91 void *newptr = std::realloc (ptr, n);
92
93#if defined (OCTAVE_MXARRAY_DEBUG)
94 std::cerr << "xrealloc (" << ptr << ", " << n << ") = " << newptr << std::endl;
95#endif
96
97 return newptr;
98}
99
100static void
101xfree (void *ptr)
102{
103#if defined (OCTAVE_MXARRAY_DEBUG)
104 std::cerr << "xfree (" << ptr << ")" << std::endl;
105#endif
106
107 std::free (ptr);
108}
109
110static mwSize
111max_str_len (mwSize m, const char **str)
112{
113 int max_len = 0;
114
115 for (mwSize i = 0; i < m; i++)
116 {
117 mwSize tmp = strlen (str[i]);
118
119 if (tmp > max_len)
120 max_len = tmp;
121 }
122
123 return max_len;
124}
125
126static void * mxRealloc (void *ptr, std::size_t size);
127
128static void mxFree (void *ptr);
129
130// FIXME: Is there a better/standard way to do this job?
131
132template <typename T>
133class fp_type_traits
134{
135public:
136 static const bool is_complex = false;
137};
138
139template <>
140class fp_type_traits<Complex>
141{
142public:
143 static const bool is_complex = true;
144};
145
146template <>
147class fp_type_traits<FloatComplex>
148{
149public:
150 static const bool is_complex = true;
151};
152
153#if defined (OCTAVE_HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR)
154
155class mx_deleting_memory_resource : public std::pmr::memory_resource
156{
157private:
158
159 void * do_allocate (std::size_t bytes, size_t /*alignment*/)
160 {
161 void *ptr = xmalloc (bytes);
162
163 if (! ptr)
164 throw std::bad_alloc ();
165
166 return ptr;
167 }
168
169 void do_deallocate (void *ptr, std::size_t /*bytes*/,
170 std::size_t /*alignment*/)
171 {
172 xfree (ptr);
173 }
174
175 bool do_is_equal (const std::pmr::memory_resource& other) const noexcept
176 {
177 return this == dynamic_cast<const mx_deleting_memory_resource *> (&other);
178 }
179};
180
181class mx_preserving_memory_resource : public std::pmr::memory_resource
182{
183private:
184
185 void * do_allocate (std::size_t bytes, size_t /*alignment*/)
186 {
187 void *ptr = xmalloc (bytes);
188
189 if (! ptr)
190 throw std::bad_alloc ();
191
192 return ptr;
193 }
194
195 void do_deallocate (void * /*ptr*/, std::size_t /*bytes*/,
196 std::size_t /*alignment*/)
197 { }
198
199 bool do_is_equal (const std::pmr::memory_resource& other) const noexcept
200 {
201 return this == dynamic_cast<const mx_preserving_memory_resource *> (&other);
202 }
203};
204
205// FIXME: Is it OK for the memory resource object to be defined this
206// way?
207static mx_deleting_memory_resource the_mx_deleting_memory_resource;
208OCTINTERP_API mx_preserving_memory_resource the_mx_preserving_memory_resource;
209
210OCTINTERP_API std::pmr::memory_resource *current_mx_memory_resource = &the_mx_deleting_memory_resource;
211
212#endif
213
215mx_to_ov_args (int nargin, mxArray *argin[])
216{
217 // Use a separate function for this job so that the
218 // current_mx_memory_resource will be restored immediately after the
219 // octave_value objects borrow the mxArray data. We could also use a
220 // dummy scope in mexCallMATLAB, but this function seems less likely
221 // to be accidentally deleted.
222
223 octave_value_list args (nargin);
224
225#if defined (OCTAVE_HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR)
226
227 // Use allocator that doesn't free memory because Octave may mutate
228 // the value (single element mxArray -> scalar octave_value object,
229 // for example) and we need these objects to continue to exist after
230 // mexCallMATLAB returns.
231
232 octave::unwind_protect_var<std::pmr::memory_resource *>
233 upv (current_mx_memory_resource, &the_mx_preserving_memory_resource);
234
235#endif
236
237 for (int i = 0; i < nargin; i++)
238 args(i) = mxArray::as_octave_value (argin[i]);
239
240 return args;
241}
242
243void
244mexErrMsgTxt_impl (const char *who, const char *s)
245{
246 std::size_t len;
247
248 if (s && (len = strlen (s)) > 0)
249 {
250 if (s[len - 1] == '\n')
251 {
252 std::string s_tmp (s, len - 1);
253 error ("%s: %s\n", who, s_tmp.c_str ());
254 }
255 else
256 error ("%s: %s", who, s);
257 }
258 else
259 {
260 // For compatibility with Matlab, print an empty message.
261 // Octave's error routine requires a non-null input so use a SPACE.
262 error (" ");
263 }
264}
265
266int
267mexPutVariable_impl (const char *space, const char *name, const mxArray *ptr)
268{
269 if (! ptr)
270 return 1;
271
272 if (! name)
273 return 1;
274
275 if (name[0] == '\0')
276 name = ptr->get_name ();
277
278 if (! name || name[0] == '\0')
279 return 1;
280
281 octave::interpreter& interp = octave::__get_interpreter__ ();
282
283 if (! strcmp (space, "global"))
284 {
285#if defined (OCTAVE_HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR)
286
287 // Use allocator that doesn't free memory because Octave may mutate
288 // the value (single element mxArray -> scalar octave_value object,
289 // for example) and we need these objects to continue to exist after
290 // mexCallMATLAB returns.
291
292 octave::unwind_protect_var<std::pmr::memory_resource *>
293 upv (current_mx_memory_resource, &the_mx_preserving_memory_resource);
294#endif
295
296 interp.global_assign (name, mxArray::as_octave_value (ptr));
297 }
298 else
299 {
300 // FIXME: should this be in variables.cc?
301
302 octave::unwind_protect frame;
303
304 bool caller = ! strcmp (space, "caller");
305 bool base = ! strcmp (space, "base");
306
307 if (caller || base)
308 {
309 // MEX files don't create a separate frame in the call stack,
310 // so we are already in the "caller" frame.
311
312 if (base)
313 {
314 octave::tree_evaluator& tw = interp.get_evaluator ();
315
316 frame.add (&octave::tree_evaluator::restore_frame, &tw,
317 tw.current_call_stack_frame_number ());
318
319 tw.goto_base_frame ();
320 }
321
322#if defined (OCTAVE_HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR)
323
324 // Use allocator that doesn't free memory because Octave may
325 // mutate the value (single element mxArray -> scalar
326 // octave_value object, for example) and we need these objects
327 // to continue to exist after mexCallMATLAB returns.
328
329 octave::unwind_protect_var<std::pmr::memory_resource *>
330 upv (current_mx_memory_resource,
331 &the_mx_preserving_memory_resource);
332#endif
333
334 interp.assign (name, mxArray::as_octave_value (ptr));
335 }
336 else
337 mexErrMsgTxt_impl ("mexPutVariable",
338 "symbol table does not exist");
339 }
340
341 return 0;
342}
343
344int
345mexSet_impl (double handle, const char *property, mxArray *val)
346{
347#if defined (OCTAVE_HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR)
348
349 // Use allocator that doesn't free memory because Octave may mutate
350 // the value (single element mxArray -> scalar octave_value object,
351 // for example) and we need these objects to continue to exist after
352 // mexCallMATLAB returns.
353
354 octave::unwind_protect_var<std::pmr::memory_resource *>
355 upv (current_mx_memory_resource, &the_mx_preserving_memory_resource);
356
357#endif
358
359 bool ret = octave::set_property_in_handle (handle, property,
361 "mexSet");
362 return (ret ? 0 : 1);
363}
364
365// ------------------------------------------------------------------
366
368 : m_interleaved (interleaved)
369{ }
370
371static mwIndex
372calc_single_subscript_internal (mwSize ndims, const mwSize *dims,
373 mwSize nsubs, const mwIndex *subs)
374{
375 mwIndex retval = 0;
376
377 switch (nsubs)
378 {
379 case 0:
380 break;
381
382 case 1:
383 retval = subs[0];
384 break;
385
386 default:
387 {
388 // Both nsubs and ndims should be at least 2 here.
389
390 mwSize n = (nsubs <= ndims ? nsubs : ndims);
391
392 retval = subs[--n];
393
394 while (--n >= 0)
395 retval = dims[n] * retval + subs[n];
396 }
397 break;
398 }
399
400 return retval;
401}
402
403// The object that handles values pass to MEX files from Octave. Some
404// methods in this class may set mutate_flag to TRUE to tell the
405// mxArray class to convert to the Matlab-style representation and
406// then invoke the method on that object instead (for example, getting
407// a pointer to real or imaginary data from a complex object requires
408// a mutation but getting a pointer to real data from a real object
409// does not). Changing the representation causes a copy so we try to
410// avoid it unless it is really necessary. Once the conversion
411// happens, we delete this representation, so the conversion can only
412// happen once per call to a MEX file.
413
414static inline void *maybe_mark_foreign (void *ptr);
415
416#if defined (OCTAVE_HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR)
417static inline void maybe_disown_ptr (void *ptr);
418#endif
419
420#define VOID_MUTATION_METHOD(FCN_NAME, ARG_LIST) \
421 void FCN_NAME ARG_LIST { request_mutation (); }
422
423#define CONST_VOID_MUTATION_METHOD(FCN_NAME, ARG_LIST) \
424 void FCN_NAME ARG_LIST const { request_mutation (); }
425
426#define MUTATION_METHOD(RET_TYPE, FCN_NAME, ARG_LIST, RET_VAL) \
427 RET_TYPE FCN_NAME ARG_LIST { request_mutation (); return RET_VAL; }
428
429#define CONST_MUTATION_METHOD(RET_TYPE, FCN_NAME, ARG_LIST, RET_VAL) \
430 RET_TYPE FCN_NAME ARG_LIST const { request_mutation (); return RET_VAL; }
431
432#define GET_DATA_METHOD(RT, FCN_NAME, ID, COMPLEXITY) \
433 RT * FCN_NAME () const { return get_data<RT> (ID, COMPLEXITY); }
434
435class mxArray_octave_value : public mxArray_base
436{
437public:
438
439 mxArray_octave_value () = delete;
440
441 mxArray_octave_value (bool interleaved, const octave_value& ov)
442 : mxArray_base (interleaved), m_val (ov), m_mutate_flag (false),
443 m_id (mxUNKNOWN_CLASS), m_class_name (nullptr), m_ndims (-1),
444 m_dims (nullptr)
445 { }
446
447 // No assignment! FIXME: should this be implemented? Note that we
448 // do have a copy constructor.
449
450 mxArray_octave_value& operator = (const mxArray_octave_value&) = delete;
451
452 mxArray_base * dup () const { return new mxArray_octave_value (*this); }
453
454 mxArray * as_mxArray () const
455 {
456 mxArray *retval = m_val.as_mxArray (m_interleaved);
457
458 // RETVAL is assumed to be an mxArray_matlab object. Should we
459 // panic_unless that condition here or just check and throw an
460 // error?
461
462 if (retval)
463 {
464 // Preserve cached values of class name and dimensions in case
465 // they will be used after we mutate.
466
467 // set_class_name will handle deleting class name that comes
468 // from as_mxArray conversion function.
469
470 if (m_class_name)
471 {
472 retval->set_class_name (m_class_name);
473
474 m_class_name = nullptr;
475 }
476
477 if (m_dims)
478 {
479 mwSize *xdims = retval->get_dimensions ();
480
481 mxFree (xdims);
482
483 retval->set_dimensions (m_dims, m_ndims);
484
485 m_dims = nullptr;
486 }
487 }
488
489 return retval;
490 }
491
492 ~mxArray_octave_value ()
493 {
494 mxFree (m_class_name);
495 mxFree (m_dims);
496 }
497
498 bool is_octave_value () const { return true; }
499
500 int iscell () const { return m_val.iscell (); }
501
502 int is_char () const { return m_val.is_string (); }
503
504 int is_complex () const { return m_val.iscomplex (); }
505
506 int is_double () const { return m_val.is_double_type (); }
507
508 int is_function_handle () const { return m_val.is_function_handle (); }
509
510 int is_int16 () const { return m_val.is_int16_type (); }
511
512 int is_int32 () const { return m_val.is_int32_type (); }
513
514 int is_int64 () const { return m_val.is_int64_type (); }
515
516 int is_int8 () const { return m_val.is_int8_type (); }
517
518 int is_logical () const { return m_val.islogical (); }
519
520 int is_numeric () const { return m_val.isnumeric (); }
521
522 int is_single () const { return m_val.is_single_type (); }
523
524 int is_sparse () const { return m_val.issparse (); }
525
526 int is_struct () const { return m_val.isstruct (); }
527
528 int is_uint16 () const { return m_val.is_uint16_type (); }
529
530 int is_uint32 () const { return m_val.is_uint32_type (); }
531
532 int is_uint64 () const { return m_val.is_uint64_type (); }
533
534 int is_uint8 () const { return m_val.is_uint8_type (); }
535
536 int is_range () const { return m_val.is_range (); }
537
538 int isreal () const { return m_val.isreal (); }
539
540 int is_logical_scalar_true () const
541 {
542 return (is_logical_scalar () && m_val.is_true ());
543 }
544
545 mwSize get_m () const { return m_val.rows (); }
546
547 mwSize get_n () const
548 {
549 mwSize n = 1;
550
551 // Force m_dims and m_ndims to be cached.
553
554 for (mwIndex i = m_ndims - 1; i > 0; i--)
555 n *= m_dims[i];
556
557 return n;
558 }
559
560 mwSize * get_dimensions () const
561 {
562 if (! m_dims)
563 {
564 m_ndims = m_val.ndims ();
565
566 m_dims = static_cast<mwSize *> (mxArray::malloc (m_ndims
567 * sizeof (mwSize)));
568
569 const dim_vector& dv = m_val.dims ();
570
571 for (mwIndex i = 0; i < m_ndims; i++)
572 m_dims[i] = dv(i);
573 }
574
575 return m_dims;
576 }
577
578 mwSize get_number_of_dimensions () const
579 {
580 // Force m_dims and m_ndims to be cached.
582
583 return m_ndims;
584 }
585
586 VOID_MUTATION_METHOD (set_m, (mwSize))
587 VOID_MUTATION_METHOD (set_n, (mwSize))
588
589 MUTATION_METHOD (int, set_dimensions, (mwSize *, mwSize), 0)
590
591 mwSize get_number_of_elements () const { return m_val.numel (); }
592
593 int isempty () const { return m_val.isempty (); }
594
595 bool is_scalar () const
596 {
597 // Force m_dims and m_ndims to be cached.
599
600 return m_ndims == 2 && m_dims[0] == 1 && m_dims[1] == 1;
601 }
602
603 mxClassID get_class_id () const
604 {
605 m_id = mxUNKNOWN_CLASS;
606
607 std::string cn = m_val.class_name ();
608
609 if (cn == "double")
610 m_id = mxDOUBLE_CLASS;
611 else if (cn == "single")
612 m_id = mxSINGLE_CLASS;
613 else if (cn == "char")
614 m_id = mxCHAR_CLASS;
615 else if (cn == "logical")
616 m_id = mxLOGICAL_CLASS;
617 else if (cn == "cell")
618 m_id = mxCELL_CLASS;
619 else if (cn == "struct")
620 m_id = mxSTRUCT_CLASS;
621 else if (cn == "function_handle")
622 m_id = mxFUNCTION_CLASS;
623 else if (cn == "int8")
624 m_id = mxINT8_CLASS;
625 else if (cn == "uint8")
626 m_id = mxUINT8_CLASS;
627 else if (cn == "int16")
628 m_id = mxINT16_CLASS;
629 else if (cn == "uint16")
630 m_id = mxUINT16_CLASS;
631 else if (cn == "int32")
632 m_id = mxINT32_CLASS;
633 else if (cn == "uint32")
634 m_id = mxUINT32_CLASS;
635 else if (cn == "int64")
636 m_id = mxINT64_CLASS;
637 else if (cn == "uint64")
638 m_id = mxUINT64_CLASS;
639
640 return m_id;
641 }
642
643 const char * get_class_name () const
644 {
645 if (! m_class_name)
646 {
647 std::string s = m_val.class_name ();
648 m_class_name = mxArray::strsave (s.c_str ());
649 }
650
651 return m_class_name;
652 }
653
654 // Not allowed.
655 VOID_MUTATION_METHOD (set_class_name, (const char *))
656
657 mxArray * get_property (mwIndex idx, const char *pname) const
658 {
659 mxArray *retval = nullptr;
660
661 if (m_val.is_classdef_object ())
662 {
663 octave_classdef *ov_cdef = m_val.classdef_object_value ();
664
665 if (ov_cdef)
666 {
667 octave_value pval = ov_cdef->get_property (idx, pname);
668
669 if (pval.is_defined())
670 retval = new mxArray (m_interleaved, pval);
671 }
672 }
673
674 return retval;
675 }
676
677 void set_property (mwIndex idx, const char *pname, const mxArray *pval)
678 {
679 if (m_val.is_classdef_object ())
680 {
681 octave_classdef *ov_cdef = m_val.classdef_object_value ();
682
683 if (ov_cdef)
684 ov_cdef->set_property (idx, pname, pval->as_octave_value ());
685 }
686 else
687 err_invalid_type ("set_property");
688 }
689
690 CONST_MUTATION_METHOD (mxArray *, get_cell, (mwIndex), nullptr)
691
692 // Not allowed.
693 VOID_MUTATION_METHOD (set_cell, (mwIndex, mxArray *))
694
695 double get_scalar () const
696 {
697 if (m_val.issparse ())
698 {
699 // For sparse arrays, return the first nonzero value.
700 const void *m_data = m_val.mex_get_data ();
701 if (m_data == nullptr)
702 return 0.0;
703
704 if (m_val.islogical ())
705 return *static_cast<const bool *> (m_data);
706 else if (m_val.isreal ())
707 return *static_cast<const double *> (m_data);
708 else // Complex type, only return real part
709 return *static_cast<const double *> (m_data);
710 }
711 else
712 return m_val.scalar_value (true);
713 }
714
715 void * get_data () const
716 {
717 // Casting away const required for MEX interface.
718
719 void *retval = const_cast<void *> (m_val.mex_get_data ());
720
721 if (retval && (m_val.isreal () || m_interleaved))
722 {
723 maybe_mark_foreign (retval);
724 return retval;
725 }
726
727 request_mutation ();
728 return nullptr;
729 }
730
731 template <typename T>
732 T * get_data (mxClassID class_id, mxComplexity complexity) const
733 {
734 // Casting away const required for MEX interface.
735
736 void *ptr = const_cast<void *> (m_val.mex_get_data (class_id, complexity));
737
738 T *retval = static_cast<T *> (ptr);
739
740 if (retval && (complexity == mxREAL || m_interleaved))
741 {
742 maybe_mark_foreign (retval);
743 return retval;
744 }
745
746 request_mutation ();
747 return nullptr;
748 }
749
750 GET_DATA_METHOD (mxDouble, get_doubles, mxDOUBLE_CLASS, mxREAL);
751
752 GET_DATA_METHOD (mxSingle, get_singles, mxSINGLE_CLASS, mxREAL);
753
754 GET_DATA_METHOD (mxInt8, get_int8s, mxINT8_CLASS, mxREAL);
755
756 GET_DATA_METHOD (mxInt16, get_int16s, mxINT16_CLASS, mxREAL);
757
758 GET_DATA_METHOD (mxInt32, get_int32s, mxINT32_CLASS, mxREAL);
759
760 GET_DATA_METHOD (mxInt64, get_int64s, mxINT64_CLASS, mxREAL);
761
762 GET_DATA_METHOD (mxUint8, get_uint8s, mxUINT8_CLASS, mxREAL);
763
764 GET_DATA_METHOD (mxUint16, get_uint16s, mxUINT16_CLASS, mxREAL);
765
766 GET_DATA_METHOD (mxUint32, get_uint32s, mxUINT32_CLASS, mxREAL);
767
768 GET_DATA_METHOD (mxUint64, get_uint64s, mxUINT64_CLASS, mxREAL);
769
770 GET_DATA_METHOD (mxComplexDouble, get_complex_doubles,
771 mxDOUBLE_CLASS, mxCOMPLEX);
772
773 GET_DATA_METHOD (mxComplexSingle, get_complex_singles,
774 mxDOUBLE_CLASS, mxCOMPLEX);
775
776 void * get_imag_data () const
777 {
778 void *retval = nullptr;
779
780 if (is_numeric () && isreal ())
781 retval = nullptr;
782 else
783 request_mutation ();
784
785 return retval;
786 }
787
788 // Not allowed.
789 VOID_MUTATION_METHOD (set_data, (void *))
790
791 MUTATION_METHOD (int, set_doubles, (mxDouble *), 0)
792 MUTATION_METHOD (int, set_singles, (mxSingle *), 0)
793 MUTATION_METHOD (int, set_int8s, (mxInt8 *), 0)
794 MUTATION_METHOD (int, set_int16s, (mxInt16 *), 0)
795 MUTATION_METHOD (int, set_int32s, (mxInt32 *), 0)
796 MUTATION_METHOD (int, set_int64s, (mxInt64 *), 0)
797 MUTATION_METHOD (int, set_uint8s, (mxUint8 *), 0)
798 MUTATION_METHOD (int, set_uint16s, (mxUint16 *), 0)
799 MUTATION_METHOD (int, set_uint32s, (mxUint32 *), 0)
800 MUTATION_METHOD (int, set_uint64s, (mxUint64 *), 0)
801
802 MUTATION_METHOD (int, set_complex_doubles, (mxComplexDouble *), 0)
803 MUTATION_METHOD (int, set_complex_singles, (mxComplexSingle *), 0)
804
805 // Not allowed.
806 VOID_MUTATION_METHOD (set_imag_data, (void *))
807
808 mwIndex * get_ir () const
809 {
810 // Casting away const required for MEX interface.
811
812 octave_idx_type *ptr = const_cast<octave_idx_type *> (m_val.mex_get_ir ());
813 return static_cast<mwIndex *> (maybe_mark_foreign (ptr));
814 }
815
816 mwIndex * get_jc () const
817 {
818 // Casting away const required for MEX interface.
819
820 octave_idx_type *ptr = const_cast<octave_idx_type *> (m_val.mex_get_jc ());
821 return static_cast<mwIndex *> (maybe_mark_foreign (ptr));
822 }
823
824 mwSize get_nzmax () const { return m_val.nzmax (); }
825
826 // Not allowed.
827 VOID_MUTATION_METHOD (set_ir, (mwIndex *))
828
829 // Not allowed.
830 VOID_MUTATION_METHOD (set_jc, (mwIndex *))
831
832 // Not allowed.
833 VOID_MUTATION_METHOD (set_nzmax, (mwSize))
834
835 // Not allowed.
836 MUTATION_METHOD (int, add_field, (const char *), 0)
837
838 // Not allowed.
839 VOID_MUTATION_METHOD (remove_field, (int))
840
841 CONST_MUTATION_METHOD (mxArray *, get_field_by_number, (mwIndex, int), nullptr)
842
843 // Not allowed.
844 VOID_MUTATION_METHOD (set_field_by_number, (mwIndex, int, mxArray *))
845
846 int get_number_of_fields () const { return m_val.nfields (); }
847
848 CONST_MUTATION_METHOD (const char *, get_field_name_by_number, (int), nullptr)
849
850 CONST_MUTATION_METHOD (int, get_field_number, (const char *), 0)
851
852 int get_string (char *buf, mwSize buflen) const
853 {
854 int retval = 1;
855
856 mwSize nel = get_number_of_elements ();
857
858 if (m_val.is_string () && nel < buflen)
859 {
860 charNDArray tmp = m_val.char_array_value ();
861
862 const char *p = tmp.data ();
863
864 for (mwIndex i = 0; i < nel; i++)
865 buf[i] = p[i];
866
867 buf[nel] = 0;
868
869 retval = 0;
870 }
871
872 return retval;
873 }
874
875 char * array_to_string () const
876 {
877 // FIXME: this is supposed to handle multi-byte character strings.
878
879 char *buf = nullptr;
880
881 if (m_val.is_string ())
882 {
883 mwSize nel = get_number_of_elements ();
884
885 buf = static_cast<char *> (mxArray::malloc (nel + 1));
886
887 if (buf)
888 {
889 charNDArray tmp = m_val.char_array_value ();
890
891 const char *p = tmp.data ();
892
893 for (mwIndex i = 0; i < nel; i++)
894 buf[i] = p[i];
895
896 buf[nel] = '\0';
897 }
898 }
899
900 return buf;
901 }
902
903 mwIndex calc_single_subscript (mwSize nsubs, mwIndex *subs) const
904 {
905 // Force m_ndims, n_dims to be cached.
907
908 return calc_single_subscript_internal (m_ndims, m_dims, nsubs, subs);
909 }
910
911 std::size_t get_element_size () const
912 {
913 // Force m_id to be cached.
914 get_class_id ();
915
916 switch (m_id)
917 {
918 case mxCELL_CLASS: return sizeof (mxArray *);
919 case mxSTRUCT_CLASS: return sizeof (mxArray *);
920 case mxLOGICAL_CLASS: return sizeof (mxLogical);
921 case mxCHAR_CLASS: return sizeof (mxChar);
922 case mxDOUBLE_CLASS: return get_numeric_element_size (sizeof (mxDouble));
923 case mxSINGLE_CLASS: return get_numeric_element_size (sizeof (mxSingle));
924 case mxINT8_CLASS: return get_numeric_element_size (sizeof (mxInt8));
925 case mxUINT8_CLASS: return get_numeric_element_size (sizeof (mxUint8));
926 case mxINT16_CLASS: return get_numeric_element_size (sizeof (mxInt16));
927 case mxUINT16_CLASS: return get_numeric_element_size (sizeof (mxUint16));
928 case mxINT32_CLASS: return get_numeric_element_size (sizeof (mxInt32));
929 case mxUINT32_CLASS: return get_numeric_element_size (sizeof (mxUint32));
930 case mxINT64_CLASS: return get_numeric_element_size (sizeof (mxInt64));
931 case mxUINT64_CLASS: return get_numeric_element_size (sizeof (mxUint64));
932 case mxFUNCTION_CLASS: return 0;
933 // FIXME: user-defined objects need their own class ID.
934 // What should they return, size of pointer?
935 default: return 0;
936 }
937 }
938
939 bool mutation_needed () const { return m_mutate_flag; }
940
941 void request_mutation () const
942 {
943 if (m_mutate_flag)
944 error ("unexpected: m_mutate_flag is true in mxArray_octave_value::request_mutation - please report this bug");
945
946 m_mutate_flag = true;
947 }
948
949 mxArray * mutate () const { return as_mxArray (); }
950
951 octave_value as_octave_value () const { return m_val; }
952
953protected:
954
955 mxArray_octave_value (const mxArray_octave_value& arg)
956 : mxArray_base (arg), m_val (arg.m_val), m_mutate_flag (arg.m_mutate_flag),
957 m_id (arg.m_id), m_class_name (mxArray::strsave (arg.m_class_name)),
958 m_ndims (arg.m_ndims),
959 m_dims (m_ndims > 0
960 ? static_cast<mwSize *> (mxArray::malloc (m_ndims * sizeof (mwSize)))
961 : nullptr)
962 {
963 if (m_dims)
964 {
965 for (mwIndex i = 0; i < m_ndims; i++)
966 m_dims[i] = arg.m_dims[i];
967 }
968 }
969
970private:
971
972 octave_value m_val;
973
974 mutable bool m_mutate_flag;
975
976 // Caching these does not cost much or lead to much duplicated
977 // code. For other things, we just request mutation to a
978 // Matlab-style mxArray object.
979
980 mutable mxClassID m_id;
981 mutable char *m_class_name;
982 mutable mwSize m_ndims;
983 mutable mwSize *m_dims;
984};
985
986// The base class for the Matlab-style representation, used to handle
987// things that are common to all Matlab-style objects.
988
989class mxArray_matlab : public mxArray_base
990{
991public:
992
993 mxArray_matlab () = delete;
994
995 // No assignment!
996 // FIXME: should this be implemented?
997 // Note that we *do* have a copy constructor.
998
999 mxArray_matlab& operator = (const mxArray_matlab&) = delete;
1000
1001 ~mxArray_matlab ()
1002 {
1003 mxFree (m_class_name);
1004 mxFree (m_dims);
1005 }
1006
1007 int iscell () const { return m_id == mxCELL_CLASS; }
1008
1009 int is_char () const { return m_id == mxCHAR_CLASS; }
1010
1011 int is_complex () const { return m_is_complex; }
1012
1013 int is_double () const { return m_id == mxDOUBLE_CLASS; }
1014
1015 int is_function_handle () const { return m_id == mxFUNCTION_CLASS; }
1016
1017 int is_int16 () const { return m_id == mxINT16_CLASS; }
1018
1019 int is_int32 () const { return m_id == mxINT32_CLASS; }
1020
1021 int is_int64 () const { return m_id == mxINT64_CLASS; }
1022
1023 int is_int8 () const { return m_id == mxINT8_CLASS; }
1024
1025 int is_logical () const { return m_id == mxLOGICAL_CLASS; }
1026
1027 int is_numeric () const
1028 {
1029 return (m_id == mxDOUBLE_CLASS || m_id == mxSINGLE_CLASS
1030 || m_id == mxINT8_CLASS || m_id == mxUINT8_CLASS
1031 || m_id == mxINT16_CLASS || m_id == mxUINT16_CLASS
1032 || m_id == mxINT32_CLASS || m_id == mxUINT32_CLASS
1033 || m_id == mxINT64_CLASS || m_id == mxUINT64_CLASS);
1034 }
1035
1036 int is_single () const { return m_id == mxSINGLE_CLASS; }
1037
1038 int is_sparse () const { return 0; }
1039
1040 int is_struct () const { return m_id == mxSTRUCT_CLASS; }
1041
1042 int is_uint16 () const { return m_id == mxUINT16_CLASS; }
1043
1044 int is_uint32 () const { return m_id == mxUINT32_CLASS; }
1045
1046 int is_uint64 () const { return m_id == mxUINT64_CLASS; }
1047
1048 int is_uint8 () const { return m_id == mxUINT8_CLASS; }
1049
1050 int is_logical_scalar_true () const
1051 {
1052 return (is_logical_scalar ()
1053 && static_cast<mxLogical *> (get_data ())[0] != 0);
1054 }
1055
1056 mwSize get_m () const { return m_dims[0]; }
1057
1058 mwSize get_n () const
1059 {
1060 mwSize n = 1;
1061
1062 for (mwSize i = m_ndims - 1 ; i > 0 ; i--)
1063 n *= m_dims[i];
1064
1065 return n;
1066 }
1067
1068 mwSize * get_dimensions () const { return m_dims; }
1069
1070 mwSize get_number_of_dimensions () const { return m_ndims; }
1071
1072 void set_m (mwSize m) { m_dims[0] = m; }
1073
1074 void set_n (mwSize n) { m_dims[1] = n; }
1075
1076 int set_dimensions (mwSize *dims, mwSize ndims)
1077 {
1078 m_ndims = ndims;
1079
1080 mxFree (m_dims);
1081
1082 if (m_ndims > 0)
1083 {
1084 m_dims
1085 = static_cast<mwSize *> (mxArray::malloc (m_ndims * sizeof (mwSize)));
1086
1087 if (m_dims == nullptr)
1088 return 1;
1089
1090 for (int i = 0; i < m_ndims; i++)
1091 m_dims[i] = dims[i];
1092
1093 return 0;
1094 }
1095 else
1096 {
1097 m_dims = nullptr;
1098 return 0;
1099 }
1100 }
1101
1102 mwSize get_number_of_elements () const
1103 {
1104 mwSize retval = m_dims[0];
1105
1106 for (mwIndex i = 1; i < m_ndims; i++)
1107 retval *= m_dims[i];
1108
1109 return retval;
1110 }
1111
1112 int isempty () const { return get_number_of_elements () == 0; }
1113
1114 bool is_scalar () const
1115 {
1116 return m_ndims == 2 && m_dims[0] == 1 && m_dims[1] == 1;
1117 }
1118
1119 mxClassID get_class_id () const { return m_id; }
1120
1121 static std::string get_class_name (mxClassID id)
1122 {
1123 switch (id)
1124 {
1125 case mxDOUBLE_CLASS: return "double";
1126 case mxSINGLE_CLASS: return "single";
1127 case mxCHAR_CLASS: return "char";
1128 case mxLOGICAL_CLASS: return "logical";
1129 case mxCELL_CLASS: return "cell";
1130 case mxSTRUCT_CLASS: return "struct";
1131 case mxFUNCTION_CLASS: return "function_handle";
1132 case mxINT8_CLASS: return "int8";
1133 case mxUINT8_CLASS: return "uint8";
1134 case mxINT16_CLASS: return "int16";
1135 case mxUINT16_CLASS: return "uint16";
1136 case mxINT32_CLASS: return "int32";
1137 case mxUINT32_CLASS: return "uint32";
1138 case mxINT64_CLASS: return "int64";
1139 case mxUINT64_CLASS: return "uint64";
1140 case mxUNKNOWN_CLASS: return "unknown";
1141 // FIXME: should return the classname of user-defined objects
1142 default: return "unknown";
1143 }
1144 }
1145
1146 const char * get_class_name () const
1147 {
1148 return m_class_name;
1149 }
1150
1151 void set_class_name (const char *name)
1152 {
1153 mxFree (m_class_name);
1154 m_class_name = static_cast<char *> (mxArray::malloc (strlen (name) + 1));
1155 strcpy (m_class_name, name);
1156 }
1157
1158 mxArray * get_cell (mwIndex /*idx*/) const
1159 {
1160 err_invalid_type ("get_cell");
1161 }
1162
1163 void set_cell (mwIndex /*idx*/, mxArray * /*val*/)
1164 {
1165 err_invalid_type ("set_cell");
1166 }
1167
1168 double get_scalar () const
1169 {
1170 err_invalid_type ("get_scalar");
1171 }
1172
1173 void * get_data () const
1174 {
1175 err_invalid_type ("get_data");
1176 }
1177
1178 mxDouble * get_doubles () const
1179 {
1180 err_invalid_type ("get_doubles");
1181 }
1182
1183 mxSingle * get_singles () const
1184 {
1185 err_invalid_type ("get_singles");
1186 }
1187
1188 mxInt8 * get_int8s () const
1189 {
1190 err_invalid_type ("get_int8s");
1191 }
1192
1193 mxInt16 * get_int16s () const
1194 {
1195 err_invalid_type ("get_int16s");
1196 }
1197
1198 mxInt32 * get_int32s () const
1199 {
1200 err_invalid_type ("get_int32s");
1201 }
1202
1203 mxInt64 * get_int64s () const
1204 {
1205 err_invalid_type ("get_int64s");
1206 }
1207
1208 mxUint8 * get_uint8s () const
1209 {
1210 err_invalid_type ("get_uint8s");
1211 }
1212
1213 mxUint16 * get_uint16s () const
1214 {
1215 err_invalid_type ("get_uint16s");
1216 }
1217
1218 mxUint32 * get_uint32s () const
1219 {
1220 err_invalid_type ("get_uint32s");
1221 }
1222
1223 mxUint64 * get_uint64s () const
1224 {
1225 err_invalid_type ("get_uint64s");
1226 }
1227
1228 mxComplexDouble * get_complex_doubles () const
1229 {
1230 err_invalid_type ("get_complex_doubles");
1231 }
1232
1233 mxComplexSingle * get_complex_singles () const
1234 {
1235 err_invalid_type ("get_complex_singles");
1236 }
1237
1238 void * get_imag_data () const
1239 {
1240 err_invalid_type ("get_imag_data");
1241 }
1242
1243 void set_data (void * /*pr*/)
1244 {
1245 err_invalid_type ("set_data");
1246 }
1247
1248 int set_doubles (mxDouble *)
1249 {
1250 err_invalid_type ("set_doubles");
1251 }
1252
1253 int set_singles (mxSingle *)
1254 {
1255 err_invalid_type ("set_singles");
1256 }
1257
1258 int set_int8s (mxInt8 *)
1259 {
1260 err_invalid_type ("set_int8s");
1261 }
1262
1263 int set_int16s (mxInt16 *)
1264 {
1265 err_invalid_type ("set_int16s");
1266 }
1267
1268 int set_int32s (mxInt32 *)
1269 {
1270 err_invalid_type ("set_int32s");
1271 }
1272
1273 int set_int64s (mxInt64 *)
1274 {
1275 err_invalid_type ("set_int64s");
1276 }
1277
1278 int set_uint8s (mxUint8 *)
1279 {
1280 err_invalid_type ("set_uint8s");
1281 }
1282
1283 int set_uint16s (mxUint16 *)
1284 {
1285 err_invalid_type ("set_uint16s");
1286 }
1287
1288 int set_uint32s (mxUint32 *)
1289 {
1290 err_invalid_type ("set_uint32s");
1291 }
1292
1293 int set_uint64s (mxUint64 *)
1294 {
1295 err_invalid_type ("set_uint64s");
1296 }
1297
1298 int set_complex_doubles (mxComplexDouble *)
1299 {
1300 err_invalid_type ("set_complex_doubles");
1301 }
1302
1303 int set_complex_singles (mxComplexSingle *)
1304 {
1305 err_invalid_type ("set_complex_singles");
1306 }
1307
1308 void set_imag_data (void * /*pi*/)
1309 {
1310 err_invalid_type ("set_imag_data");
1311 }
1312
1313 mwIndex * get_ir () const
1314 {
1315 err_invalid_type ("get_ir");
1316 }
1317
1318 mwIndex * get_jc () const
1319 {
1320 err_invalid_type ("get_jc");
1321 }
1322
1323 mwSize get_nzmax () const
1324 {
1325 err_invalid_type ("get_nzmax");
1326 }
1327
1328 void set_ir (mwIndex * /*ir*/)
1329 {
1330 err_invalid_type ("set_ir");
1331 }
1332
1333 void set_jc (mwIndex * /*jc*/)
1334 {
1335 err_invalid_type ("set_jc");
1336 }
1337
1338 void set_nzmax (mwSize /*nzmax*/)
1339 {
1340 err_invalid_type ("set_nzmax");
1341 }
1342
1343 int add_field (const char * /*key*/)
1344 {
1345 err_invalid_type ("add_field");
1346 }
1347
1348 void remove_field (int /*key_num*/)
1349 {
1350 err_invalid_type ("remove_field");
1351 }
1352
1353 mxArray * get_field_by_number (mwIndex /*index*/, int /*key_num*/) const
1354 {
1355 err_invalid_type ("get_field_by_number");
1356 }
1357
1358 void set_field_by_number (mwIndex /*index*/, int /*key_num*/,
1359 mxArray * /*val*/)
1360 {
1361 err_invalid_type ("set_field_by_number");
1362 }
1363
1364 int get_number_of_fields () const
1365 {
1366 err_invalid_type ("get_number_of_fields");
1367 }
1368
1369 const char * get_field_name_by_number (int /*key_num*/) const
1370 {
1371 err_invalid_type ("get_field_name_by_number");
1372 }
1373
1374 int get_field_number (const char * /*key*/) const
1375 {
1376 return -1;
1377 }
1378
1379 int get_string (char * /*buf*/, mwSize /*buflen*/) const
1380 {
1381 err_invalid_type ("get_string");
1382 }
1383
1384 char * array_to_string () const
1385 {
1386 err_invalid_type ("array_to_string");
1387 }
1388
1389 mwIndex calc_single_subscript (mwSize nsubs, mwIndex *subs) const
1390 {
1391 return calc_single_subscript_internal (m_ndims, m_dims, nsubs, subs);
1392 }
1393
1394 std::size_t get_element_size () const
1395 {
1396 switch (m_id)
1397 {
1398 case mxCELL_CLASS: return sizeof (mxArray *);
1399 case mxSTRUCT_CLASS: return sizeof (mxArray *);
1400 case mxLOGICAL_CLASS: return sizeof (mxLogical);
1401 case mxCHAR_CLASS: return sizeof (mxChar);
1402 case mxDOUBLE_CLASS: return get_numeric_element_size (sizeof (mxDouble));
1403 case mxSINGLE_CLASS: return get_numeric_element_size (sizeof (mxSingle));
1404 case mxINT8_CLASS: return get_numeric_element_size (sizeof (mxInt8));
1405 case mxUINT8_CLASS: return get_numeric_element_size (sizeof (mxUint8));
1406 case mxINT16_CLASS: return get_numeric_element_size (sizeof (mxInt16));
1407 case mxUINT16_CLASS: return get_numeric_element_size (sizeof (mxUint16));
1408 case mxINT32_CLASS: return get_numeric_element_size (sizeof (mxInt32));
1409 case mxUINT32_CLASS: return get_numeric_element_size (sizeof (mxUint32));
1410 case mxINT64_CLASS: return get_numeric_element_size (sizeof (mxInt64));
1411 case mxUINT64_CLASS: return get_numeric_element_size (sizeof (mxUint64));
1412 case mxFUNCTION_CLASS: return 0;
1413 // FIXME: user-defined objects need their own class ID.
1414 // What should they return, size of pointer?
1415 default: return 0;
1416 }
1417 }
1418
1419protected:
1420
1421 mxArray_matlab (bool interleaved, bool is_complex, mxClassID id,
1422 mwSize ndims, const mwSize *dims)
1423 : mxArray_base (interleaved), m_class_name (nullptr), m_id (id),
1424 m_is_complex (is_complex), m_ndims (ndims < 2 ? 2 : ndims),
1425 m_dims (static_cast<mwSize *> (mxArray::malloc (m_ndims * sizeof (mwSize))))
1426 {
1427 if (ndims == 0)
1428 {
1429 m_dims[0] = 0;
1430 m_dims[1] = 0;
1431 }
1432 else if (ndims < 2)
1433 {
1434 m_dims[0] = 1;
1435 m_dims[1] = 1;
1436 }
1437
1438 for (mwIndex i = 0; i < ndims; i++)
1439 m_dims[i] = dims[i];
1440
1441 for (mwIndex i = m_ndims - 1; i > 1; i--)
1442 {
1443 if (m_dims[i] == 1)
1444 m_ndims--;
1445 else
1446 break;
1447 }
1448 }
1449
1450 mxArray_matlab (bool interleaved, bool is_complex, mxClassID id,
1451 const dim_vector& dv)
1452 : mxArray_base (interleaved), m_class_name (nullptr), m_id (id),
1453 m_is_complex (is_complex), m_ndims (dv.ndims ()),
1454 m_dims (static_cast<mwSize *> (mxArray::malloc (m_ndims * sizeof (mwSize))))
1455 {
1456 for (mwIndex i = 0; i < m_ndims; i++)
1457 m_dims[i] = dv(i);
1458
1459 for (mwIndex i = m_ndims - 1; i > 1; i--)
1460 {
1461 if (m_dims[i] == 1)
1462 m_ndims--;
1463 else
1464 break;
1465 }
1466 }
1467
1468 mxArray_matlab (bool interleaved, bool is_complex, mxClassID id,
1469 mwSize m, mwSize n)
1470 : mxArray_base (interleaved), m_class_name (nullptr), m_id (id),
1471 m_is_complex (is_complex), m_ndims (2),
1472 m_dims (static_cast<mwSize *> (mxArray::malloc (m_ndims * sizeof (mwSize))))
1473 {
1474 m_dims[0] = m;
1475 m_dims[1] = n;
1476 }
1477
1478 mxArray_matlab (const mxArray_matlab& val)
1479 : mxArray_base (val), m_class_name (mxArray::strsave (val.m_class_name)),
1480 m_id (val.m_id), m_is_complex (val.m_is_complex), m_ndims (val.m_ndims),
1481 m_dims (static_cast<mwSize *> (mxArray::malloc (m_ndims * sizeof (mwSize))))
1482 {
1483 for (mwIndex i = 0; i < m_ndims; i++)
1484 m_dims[i] = val.m_dims[i];
1485 }
1486
1487 void set_complexity (bool is_complex) { m_is_complex = is_complex; }
1488
1490 dims_to_dim_vector () const
1491 {
1492 mwSize nd = get_number_of_dimensions ();
1493
1494 mwSize *d = get_dimensions ();
1495
1496 dim_vector dv;
1497 dv.resize (nd);
1498
1499 for (mwIndex i = 0; i < nd; i++)
1500 dv(i) = d[i];
1501
1502 return dv;
1503 }
1504
1505private:
1506
1507 char *m_class_name;
1508
1509 mxClassID m_id;
1510
1511 bool m_is_complex;
1512
1513 mwSize m_ndims;
1514 mwSize *m_dims;
1515};
1516
1517
1518// Matlab-style numeric, character, and logical data.
1519
1520class mxArray_base_full : public mxArray_matlab
1521{
1522public:
1523
1524 mxArray_base_full () = delete;
1525
1526 mxArray_base_full (bool interleaved, bool is_complex, mxClassID id,
1527 mwSize ndims, const mwSize *dims, bool init = true)
1528 : mxArray_matlab (interleaved, is_complex, id, ndims, dims),
1529 m_pr (mxArray::alloc (init, get_number_of_elements (), get_element_size ()))
1530 { }
1531
1532 mxArray_base_full (bool interleaved, bool is_complex, mxClassID id,
1533 const dim_vector& dv)
1534 : mxArray_matlab (interleaved, is_complex, id, dv),
1535 m_pr (mxArray::calloc (get_number_of_elements (), get_element_size ()))
1536 { }
1537
1538 mxArray_base_full (bool interleaved, bool is_complex, mxClassID id,
1539 mwSize m, mwSize n, bool init = true)
1540 : mxArray_matlab (interleaved, is_complex, id, m, n),
1541 m_pr (mxArray::alloc (init, get_number_of_elements (), get_element_size ()))
1542 { }
1543
1544 mxArray_base_full (bool interleaved, mxClassID id, double val)
1545 : mxArray_matlab (interleaved, false, id, 1, 1),
1546 m_pr (mxArray::calloc (get_number_of_elements (), get_element_size ()))
1547 {
1548 double *dpr = static_cast<double *> (m_pr);
1549 dpr[0] = val;
1550 }
1551
1552 mxArray_base_full (bool interleaved, mxClassID id, mxLogical val)
1553 : mxArray_matlab (interleaved, false, id, 1, 1),
1554 m_pr (mxArray::calloc (get_number_of_elements (), get_element_size ()))
1555 {
1556 mxLogical *lpr = static_cast<mxLogical *> (m_pr);
1557 lpr[0] = val;
1558 }
1559
1560 mxArray_base_full (bool interleaved, const char *str)
1561 : mxArray_matlab (interleaved, false, mxCHAR_CLASS,
1562 str ? (strlen (str) ? 1 : 0) : 0,
1563 str ? strlen (str) : 0),
1564 m_pr (mxArray::calloc (get_number_of_elements (), get_element_size ()))
1565 {
1566 mxChar *cpr = static_cast<mxChar *> (m_pr);
1567 mwSize nel = get_number_of_elements ();
1568 for (mwIndex i = 0; i < nel; i++)
1569 cpr[i] = str[i];
1570 }
1571
1572 // FIXME: ???
1573 mxArray_base_full (bool interleaved, mwSize m, const char **str)
1574 : mxArray_matlab (interleaved, false, mxCHAR_CLASS, m, max_str_len (m, str)),
1575 m_pr (mxArray::calloc (get_number_of_elements (), get_element_size ()))
1576 {
1577 mxChar *cpr = static_cast<mxChar *> (m_pr);
1578
1579 mwSize *dv = get_dimensions ();
1580
1581 mwSize nc = dv[1];
1582
1583 for (mwIndex j = 0; j < m; j++)
1584 {
1585 const char *ptr = str[j];
1586
1587 std::size_t tmp_len = strlen (ptr);
1588
1589 for (std::size_t i = 0; i < tmp_len; i++)
1590 cpr[m*i+j] = static_cast<mxChar> (ptr[i]);
1591
1592 for (std::size_t i = tmp_len; i < static_cast<std::size_t> (nc); i++)
1593 cpr[m*i+j] = static_cast<mxChar> (' ');
1594 }
1595 }
1596
1597 // No assignment! FIXME: should this be implemented? Note that we
1598 // do have a copy constructor.
1599
1600 mxArray_base_full& operator = (const mxArray_base_full&) = delete;
1601
1602 mxArray_base * dup () const
1603 {
1604 return new mxArray_base_full (*this);
1605 }
1606
1607 ~mxArray_base_full ()
1608 {
1609 mxFree (m_pr);
1610 }
1611
1612 double get_scalar () const
1613 {
1614 // FIXME: how does this work for interleaved complex arrays?
1615
1616 double retval = 0;
1617
1618 mxClassID id = get_class_id ();
1619
1620 switch (id)
1621 {
1622 case mxDOUBLE_CLASS:
1623 retval = *(static_cast<double *> (m_pr));
1624 break;
1625
1626 case mxSINGLE_CLASS:
1627 retval = *(static_cast<float *> (m_pr));
1628 break;
1629
1630 case mxCHAR_CLASS:
1631 retval = *(static_cast<mxChar *> (m_pr));
1632 break;
1633
1634 case mxLOGICAL_CLASS:
1635 retval = *(static_cast<bool *> (m_pr));
1636 break;
1637
1638 case mxINT8_CLASS:
1639 retval = *(static_cast<int8_t *> (m_pr));
1640 break;
1641
1642 case mxUINT8_CLASS:
1643 retval = *(static_cast<uint8_t *> (m_pr));
1644 break;
1645
1646 case mxINT16_CLASS:
1647 retval = *(static_cast<int16_t *> (m_pr));
1648 break;
1649
1650 case mxUINT16_CLASS:
1651 retval = *(static_cast<uint16_t *> (m_pr));
1652 break;
1653
1654 case mxINT32_CLASS:
1655 retval = *(static_cast<int32_t *> (m_pr));
1656 break;
1657
1658 case mxUINT32_CLASS:
1659 retval = *(static_cast<uint32_t *> (m_pr));
1660 break;
1661
1662 case mxINT64_CLASS:
1663 retval = *(static_cast<int64_t *> (m_pr));
1664 break;
1665
1666 case mxUINT64_CLASS:
1667 retval = *(static_cast<uint64_t *> (m_pr));
1668 break;
1669
1670 case mxCELL_CLASS:
1671 case mxFUNCTION_CLASS:
1672 case mxSTRUCT_CLASS:
1673 case mxUNKNOWN_CLASS:
1674 case mxVOID_CLASS:
1675 {
1676 std::string dest_cname = get_class_name (id);
1677 error ("invalid conversion from %s mxArray to %s scalar value", get_class_name (), dest_cname.c_str ());
1678 }
1679 break;
1680
1681 // We should have handled all possible enum values above. Rely
1682 // on compiler diagnostics to warn if we haven't. For example,
1683 // GCC's -Wswitch option, enabled by -Wall, will provide a
1684 // warning.
1685 }
1686
1687 return retval;
1688 }
1689
1690 void * get_data () const { return m_pr; }
1691
1692 void set_data (void *pr) { m_pr = pr; }
1693
1694 // The typed get and set functions only work for interleaved data but
1695 // they are defined here because this class owns PR. There are
1696 // definitions in the mxArray_separate_full class that override these
1697 // functions.
1698
1699 mxDouble * get_doubles () const
1700 {
1701 return static_cast<mxDouble *> (m_pr);
1702 }
1703
1704 mxSingle * get_singles () const
1705 {
1706 return static_cast<mxSingle *> (m_pr);
1707 }
1708
1709 mxInt8 * get_int8s () const
1710 {
1711 return static_cast<mxInt8 *> (m_pr);
1712 }
1713
1714 mxInt16 * get_int16s () const
1715 {
1716 return static_cast<mxInt16 *> (m_pr);
1717 }
1718
1719 mxInt32 * get_int32s () const
1720 {
1721 return static_cast<mxInt32 *> (m_pr);
1722 }
1723
1724 mxInt64 * get_int64s () const
1725 {
1726 return static_cast<mxInt64 *> (m_pr);
1727 }
1728
1729 mxUint8 * get_uint8s () const
1730 {
1731 return static_cast<mxUint8 *> (m_pr);
1732 }
1733
1734 mxUint16 * get_uint16s () const
1735 {
1736 return static_cast<mxUint16 *> (m_pr);
1737 }
1738
1739 mxUint32 * get_uint32s () const
1740 {
1741 return static_cast<mxUint32 *> (m_pr);
1742 }
1743
1744 mxUint64 * get_uint64s () const
1745 {
1746 return static_cast<mxUint64 *> (m_pr);
1747 }
1748
1749 mxComplexDouble * get_complex_doubles () const
1750 {
1751 return static_cast<mxComplexDouble *> (m_pr);
1752 }
1753
1754 mxComplexSingle * get_complex_singles () const
1755 {
1756 return static_cast<mxComplexSingle *> (m_pr);
1757 }
1758
1759 int set_doubles (mxDouble *d)
1760 {
1761 m_pr = d;
1762 return 0;
1763 }
1764
1765 int set_singles (mxSingle *d)
1766 {
1767 m_pr = d;
1768 return 0;
1769 }
1770
1771 int set_int8s (mxInt8 *d)
1772 {
1773 m_pr = d;
1774 return 0;
1775 }
1776
1777 int set_int16s (mxInt16 *d)
1778 {
1779 m_pr = d;
1780 return 0;
1781 }
1782
1783 int set_int32s (mxInt32 *d)
1784 {
1785 m_pr = d;
1786 return 0;
1787 }
1788
1789 int set_int64s (mxInt64 *d)
1790 {
1791 m_pr = d;
1792 return 0;
1793 }
1794
1795 int set_uint8s (mxUint8 *d)
1796 {
1797 m_pr = d;
1798 return 0;
1799 }
1800
1801 int set_uint16s (mxUint16 *d)
1802 {
1803 m_pr = d;
1804 return 0;
1805 }
1806
1807 int set_uint32s (mxUint32 *d)
1808 {
1809 m_pr = d;
1810 return 0;
1811 }
1812
1813 int set_uint64s (mxUint64 *d)
1814 {
1815 m_pr = d;
1816 return 0;
1817 }
1818
1819 int set_complex_doubles (mxComplexDouble *d)
1820 {
1821 m_pr = d;
1822 return 0;
1823 }
1824
1825 int set_complex_singles (mxComplexSingle *d)
1826 {
1827 m_pr = d;
1828 return 0;
1829 }
1830
1831 int get_string (char *buf, mwSize buflen) const
1832 {
1833 int retval = 0;
1834
1835 mwSize nel = get_number_of_elements ();
1836
1837 if (! (nel < buflen))
1838 {
1839 retval = 1;
1840 if (buflen > 0)
1841 nel = buflen-1;
1842 }
1843
1844 if (nel < buflen)
1845 {
1846 mxChar *ptr = static_cast<mxChar *> (m_pr);
1847
1848 for (mwIndex i = 0; i < nel; i++)
1849 buf[i] = static_cast<char> (ptr[i]);
1850
1851 buf[nel] = 0;
1852 }
1853
1854 return retval;
1855 }
1856
1857 char * array_to_string () const
1858 {
1859 // FIXME: this is supposed to handle multi-byte character strings.
1860
1861 mwSize nel = get_number_of_elements ();
1862
1863 char *buf = static_cast<char *> (mxArray::malloc (nel + 1));
1864
1865 if (buf)
1866 {
1867 mxChar *ptr = static_cast<mxChar *> (m_pr);
1868
1869 for (mwIndex i = 0; i < nel; i++)
1870 buf[i] = static_cast<char> (ptr[i]);
1871
1872 buf[nel] = '\0';
1873 }
1874
1875 return buf;
1876 }
1877
1878 octave_value as_octave_value () const
1879 {
1880 octave_value retval;
1881
1882 const dim_vector& dv = dims_to_dim_vector ();
1883
1884 switch (get_class_id ())
1885 {
1886 case mxDOUBLE_CLASS:
1887 return (is_complex ()
1888 ? fp_to_ov<Complex> (dv) : fp_to_ov<double> (dv));
1889
1890 case mxSINGLE_CLASS:
1891 return (is_complex ()
1892 ? fp_to_ov<FloatComplex> (dv) : fp_to_ov<float> (dv));
1893
1894 case mxCHAR_CLASS:
1895 return int_to_ov<mxChar, charNDArray, char> (dv);
1896
1897 case mxLOGICAL_CLASS:
1898 return int_to_ov<mxLogical, boolNDArray, bool> (dv);
1899
1900 case mxINT8_CLASS:
1901 return int_to_ov<int8_t, int8NDArray, octave_int8> (dv);
1902
1903 case mxUINT8_CLASS:
1904 return int_to_ov<uint8_t, uint8NDArray, octave_uint8> (dv);
1905
1906 case mxINT16_CLASS:
1907 return int_to_ov<int16_t, int16NDArray, octave_int16> (dv);
1908
1909 case mxUINT16_CLASS:
1910 return int_to_ov<uint16_t, uint16NDArray, octave_uint16> (dv);
1911
1912 case mxINT32_CLASS:
1913 return int_to_ov<int32_t, int32NDArray, octave_int32> (dv);
1914
1915 case mxUINT32_CLASS:
1916 return int_to_ov<uint32_t, uint32NDArray, octave_uint32> (dv);
1917
1918 case mxINT64_CLASS:
1919 return int_to_ov<int64_t, int64NDArray, octave_int64> (dv);
1920
1921 case mxUINT64_CLASS:
1922 return int_to_ov<uint64_t, uint64NDArray, octave_uint64> (dv);
1923
1924 case mxCELL_CLASS:
1925 case mxFUNCTION_CLASS:
1926 case mxSTRUCT_CLASS:
1927 case mxUNKNOWN_CLASS:
1928 case mxVOID_CLASS:
1929 error ("invalid conversion from %s%s mxArray to octave_value", (is_complex () ? "complex " : ""), get_class_name ());
1930 break;
1931
1932 // We should have handled all possible enum values above. Rely
1933 // on compiler diagnostics to warn if we haven't. For example,
1934 // GCC's -Wswitch option, enabled by -Wall, will provide a
1935 // warning.
1936 }
1937
1938 return retval;
1939 }
1940
1941protected:
1942
1943 mxArray_base_full (const mxArray_base_full& val)
1944 : mxArray_matlab (val),
1945 m_pr (mxArray::malloc (get_number_of_elements () * get_element_size ()))
1946 {
1947 if (m_pr)
1948 memcpy (m_pr, val.m_pr, get_number_of_elements () * get_element_size ());
1949 }
1950
1951 template <typename ELT_T>
1953 fp_to_ov (const dim_vector& dv) const
1954 {
1955 octave_value retval;
1956
1957 ELT_T *ppr = static_cast<ELT_T *> (m_pr);
1958
1959#if defined (OCTAVE_HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR)
1960
1961 if (current_mx_memory_resource == &the_mx_deleting_memory_resource)
1962 {
1963 octave::unwind_action act ([this] () { maybe_disown_ptr (m_pr); });
1964
1965 return octave_value (Array<ELT_T> (ppr, dv, current_mx_memory_resource));
1966 }
1967 else
1968 return octave_value (Array<ELT_T> (ppr, dv, current_mx_memory_resource));
1969
1970#else
1971
1972 // Copy data instead of allowing the octave_value object to borrow
1973 // the mxArray object data.
1974
1975 Array<ELT_T> val (dv);
1976
1977 ELT_T *ptr = val.rwdata ();
1978
1979 mwSize nel = get_number_of_elements ();
1980
1981 for (mwIndex i = 0; i < nel; i++)
1982 ptr[i] = ppr[i];
1983
1984 return octave_value (val);
1985
1986#endif
1987 }
1988
1989 template <typename ELT_T, typename ARRAY_T, typename ARRAY_ELT_T>
1991 int_to_ov (const dim_vector& dv) const
1992 {
1993 if (is_complex ())
1994 error ("complex integer types are not supported");
1995
1996 ELT_T *ppr = static_cast<ELT_T *> (m_pr);
1997
1998 // Copy data instead of allowing the octave_value object to borrow
1999 // the mxArray object data.
2000
2001 ARRAY_T val (dv);
2002
2003 ARRAY_ELT_T *ptr = val.rwdata ();
2004
2005 mwSize nel = get_number_of_elements ();
2006
2007 for (mwIndex i = 0; i < nel; i++)
2008 ptr[i] = ppr[i];
2009
2010 return octave_value (val);
2011
2012 }
2013
2014protected:
2015
2016 // If using interleaved complex storage, this is the pointer to data
2017 // (real, complex, or logical). Otherwise, it is the pointer to the
2018 // real part of the data.
2019 void *m_pr;
2020};
2021
2022class mxArray_interleaved_full : public mxArray_base_full
2023{
2024public:
2025
2026 mxArray_interleaved_full () = delete;
2027
2028 mxArray_interleaved_full (mxClassID id, mwSize ndims, const mwSize *dims,
2029 mxComplexity flag = mxREAL, bool init = true)
2030 : mxArray_base_full (true, flag == mxCOMPLEX, id, ndims, dims, init)
2031 { }
2032
2033 mxArray_interleaved_full (mxClassID id, const dim_vector& dv,
2034 mxComplexity flag = mxREAL)
2035 : mxArray_base_full (true, flag == mxCOMPLEX, id, dv)
2036 { }
2037
2038 mxArray_interleaved_full (mxClassID id, mwSize m, mwSize n,
2039 mxComplexity flag = mxREAL, bool init = true)
2040 : mxArray_base_full (true, flag == mxCOMPLEX, id, m, n, init)
2041 { }
2042
2043 mxArray_interleaved_full (mxClassID id, double val)
2044 : mxArray_base_full (true, id, val)
2045 { }
2046
2047 mxArray_interleaved_full (mxClassID id, mxLogical val)
2048 : mxArray_base_full (true, id, val)
2049 { }
2050
2051 mxArray_interleaved_full (const char *str)
2052 : mxArray_base_full (true, str)
2053 { }
2054
2055 // FIXME: ???
2056 mxArray_interleaved_full (mwSize m, const char **str)
2057 : mxArray_base_full (true, m, str)
2058 { }
2059
2060 // No assignment! FIXME: should this be implemented? Note that we
2061 // do have a copy constructor.
2062
2063 mxArray_interleaved_full& operator = (const mxArray_interleaved_full&) = delete;
2064
2065 mxArray_base * dup () const
2066 {
2067 return new mxArray_interleaved_full (*this);
2068 }
2069
2070 ~mxArray_interleaved_full () = default;
2071
2072 void * get_imag_data () const { error_impossible_call ("mxArray_interleaved_full::get_imag_data"); }
2073
2074 void set_imag_data (void */*pi*/) { error_impossible_call ("mxArray_interleaved_full::set_imag_data"); }
2075
2076protected:
2077
2078 mxArray_interleaved_full (const mxArray_interleaved_full& val)
2079 : mxArray_base_full (val)
2080 { }
2081};
2082
2083class mxArray_separate_full : public mxArray_base_full
2084{
2085public:
2086
2087 mxArray_separate_full () = delete;
2088
2089 mxArray_separate_full (mxClassID id, mwSize ndims, const mwSize *dims,
2090 mxComplexity flag = mxREAL, bool init = true)
2091 : mxArray_base_full (false, flag == mxCOMPLEX, id, ndims, dims, init),
2092 m_pi (flag == mxCOMPLEX
2093 ? mxArray::alloc (init, get_number_of_elements (), get_element_size ())
2094 : nullptr)
2095 { }
2096
2097 mxArray_separate_full (mxClassID id, const dim_vector& dv,
2098 mxComplexity flag = mxREAL)
2099 : mxArray_base_full (false, flag == mxCOMPLEX, id, dv),
2100 m_pi (is_complex ()
2101 ? mxArray::calloc (get_number_of_elements (), get_element_size ())
2102 : nullptr)
2103 { }
2104
2105 mxArray_separate_full (mxClassID id, mwSize m, mwSize n,
2106 mxComplexity flag = mxREAL, bool init = true)
2107 : mxArray_base_full (false, flag == mxCOMPLEX, id, m, n, init),
2108 m_pi (is_complex ()
2109 ? (mxArray::alloc (init, get_number_of_elements (), get_element_size ()))
2110 : nullptr)
2111 { }
2112
2113 mxArray_separate_full (mxClassID id, double val)
2114 : mxArray_base_full (false, id, val), m_pi (nullptr)
2115 { }
2116
2117 mxArray_separate_full (mxClassID id, mxLogical val)
2118 : mxArray_base_full (false, id, val), m_pi (nullptr)
2119 { }
2120
2121 mxArray_separate_full (const char *str)
2122 : mxArray_base_full (false, str), m_pi (nullptr)
2123 { }
2124
2125 // FIXME: ???
2126 mxArray_separate_full (mwSize m, const char **str)
2127 : mxArray_base_full (false, m, str), m_pi (nullptr)
2128 { }
2129
2130 // No assignment! FIXME: should this be implemented? Note that we
2131 // do have a copy constructor.
2132
2133 mxArray_separate_full& operator = (const mxArray_separate_full&) = delete;
2134
2135 mxArray_base * dup () const
2136 {
2137 return new mxArray_separate_full (*this);
2138 }
2139
2140 ~mxArray_separate_full ()
2141 {
2142 mxFree (m_pi);
2143 }
2144
2145 void * get_imag_data () const { return m_pi; }
2146
2147 void set_imag_data (void *pi)
2148 {
2149 m_pi = pi;
2150
2151 set_complexity (m_pi != nullptr);
2152 }
2153
2154 mxDouble * get_doubles () const { error_impossible_call ("mxArray_separate_full::get_doubles"); }
2155 mxSingle * get_singles () const { error_impossible_call ("mxArray_separate_full::get_singles"); }
2156 mxInt8 * get_int8s () const { error_impossible_call ("mxArray_separate_full::get_int8s"); }
2157 mxInt16 * get_int16s () const { error_impossible_call ("mxArray_separate_full::get_int16s"); }
2158 mxInt32 * get_int32s () const { error_impossible_call ("mxArray_separate_full::get_int32s"); }
2159 mxInt64 * get_int64s () const { error_impossible_call ("mxArray_separate_full::get_int64s"); }
2160 mxUint8 * get_uint8s () const { error_impossible_call ("mxArray_separate_full::get_uint8s"); }
2161 mxUint16 * get_uint16s () const { error_impossible_call ("mxArray_separate_full::get_uint16s"); }
2162 mxUint32 * get_uint32s () const { error_impossible_call ("mxArray_separate_full::get_uint32s"); }
2163 mxUint64 * get_uint64s () const { error_impossible_call ("mxArray_separate_full::get_uint64s"); }
2164
2165 mxComplexDouble * get_complex_doubles () const { error_impossible_call ("mxArray_separate_full::get_complex_doubles"); }
2166 mxComplexSingle * get_complex_singles () const { error_impossible_call ("mxArray_separate_full::get_complex_singles"); }
2167
2168 // We don't have complex integer types, but for separate storage they
2169 // still would not work.
2170 mxComplexInt8 * get_complex_int8s () const { error_impossible_call ("mxArray_separate_full::get_complex_int8s"); }
2171 mxComplexInt16 * get_complex_int16s () const { error_impossible_call ("mxArray_separate_full::get_complex_int16s"); }
2172 mxComplexInt32 * get_complex_int32s () const { error_impossible_call ("mxArray_separate_full::get_complex_int32s"); }
2173 mxComplexInt64 * get_complex_int64s () const { error_impossible_call ("mxArray_separate_full::get_complex_int64s"); }
2174 mxComplexUint8 * get_complex_uint8s () const { error_impossible_call ("mxArray_separate_full::get_complex_uint8s"); }
2175 mxComplexUint16 * get_complex_uint16s () const { error_impossible_call ("mxArray_separate_full::get_complex_uint16s"); }
2176 mxComplexUint32 * get_complex_uint32s () const { error_impossible_call ("mxArray_separate_full::get_complex_uint32s"); }
2177 mxComplexUint64 * get_complex_uint64s () const { error_impossible_call ("mxArray_separate_full::get_complex_uint64s"); }
2178
2179 int set_doubles (mxDouble *) { error_impossible_call ("mxArray_separate_full::set_doubles"); }
2180 int set_singles (mxSingle *) { error_impossible_call ("mxArray_separate_full::set_singles"); }
2181 int set_int8s (mxInt8 *) { error_impossible_call ("mxArray_separate_full::set_int8s"); }
2182 int set_int16s (mxInt16 *) { error_impossible_call ("mxArray_separate_full::set_int16s"); }
2183 int set_int32s (mxInt32 *) { error_impossible_call ("mxArray_separate_full::set_int32s"); }
2184 int set_int64s (mxInt64 *) { error_impossible_call ("mxArray_separate_full::set_int64s"); }
2185 int set_uint8s (mxUint8 *) { error_impossible_call ("mxArray_separate_full::set_uint8s"); }
2186 int set_uint16s (mxUint16 *) { error_impossible_call ("mxArray_separate_full::set_uint16s"); }
2187 int set_uint32s (mxUint32 *) { error_impossible_call ("mxArray_separate_full::set_uint32s"); }
2188 int set_uint64s (mxUint64 *) { error_impossible_call ("mxArray_separate_full::set_uint64s"); }
2189
2190 int set_complex_doubles (mxComplexDouble *) { error_impossible_call ("mxArray_separate_full::set_complex_doubles"); }
2191 int set_complex_singles (mxComplexSingle *) { error_impossible_call ("mxArray_separate_full::set_complex_singles"); }
2192
2193 // We don't have complex integer types, but for separate storage they
2194 // still would not work.
2195 int set_complex_int8s (mxComplexInt8 *) { error_impossible_call ("mxArray_separate_full::set_complex_int8s"); }
2196 int set_complex_int16s (mxComplexInt16 *) { error_impossible_call ("mxArray_separate_full::set_complex_int16s"); }
2197 int set_complex_int32s (mxComplexInt32 *) { error_impossible_call ("mxArray_separate_full::set_complex_int32s"); }
2198 int set_complex_int64s (mxComplexInt64 *) { error_impossible_call ("mxArray_separate_full::set_complex_int64s"); }
2199 int set_complex_uint8s (mxComplexUint8 *) { error_impossible_call ("mxArray_separate_full::set_complex_uint8s"); }
2200 int set_complex_uint16s (mxComplexUint16 *) { error_impossible_call ("mxArray_separate_full::set_complex_uint16s"); }
2201 int set_complex_uint32s (mxComplexUint32 *) { error_impossible_call ("mxArray_separate_full::set_complex_uint32s"); }
2202 int set_complex_uint64s (mxComplexUint64 *) { error_impossible_call ("mxArray_separate_full::set_complex_uint64s"); }
2203
2204 octave_value as_octave_value () const
2205 {
2206 if (! is_complex ())
2207 return mxArray_base_full::as_octave_value ();
2208
2209 octave_value retval;
2210
2211 const dim_vector& dv = dims_to_dim_vector ();
2212
2213 switch (get_class_id ())
2214 {
2215 case mxDOUBLE_CLASS:
2216 return to_ov<double> (dv);
2217
2218 case mxSINGLE_CLASS:
2219 return to_ov<float> (dv);
2220
2221 case mxLOGICAL_CLASS:
2222 case mxINT8_CLASS:
2223 case mxUINT8_CLASS:
2224 case mxINT16_CLASS:
2225 case mxUINT16_CLASS:
2226 case mxINT32_CLASS:
2227 case mxUINT32_CLASS:
2228 case mxINT64_CLASS:
2229 case mxUINT64_CLASS:
2230 error ("complex integer types are not supported");
2231
2232 case mxCELL_CLASS:
2233 case mxCHAR_CLASS:
2234 case mxFUNCTION_CLASS:
2235 case mxSTRUCT_CLASS:
2236 case mxUNKNOWN_CLASS:
2237 case mxVOID_CLASS:
2238 error ("invalid conversion from complex %s mxArray to octave_value", get_class_name ());
2239 break;
2240
2241 // We should have handled all possible enum values above. Rely
2242 // on compiler diagnostics to warn if we haven't. For example,
2243 // GCC's -Wswitch option, enabled by -Wall, will provide a
2244 // warning.
2245 }
2246
2247 return retval;
2248 }
2249
2250protected:
2251
2252 mxArray_separate_full (const mxArray_separate_full& val)
2253 : mxArray_base_full (val),
2254 m_pi (val.m_pi
2255 ? mxArray::malloc (get_number_of_elements () * get_element_size ())
2256 : nullptr)
2257 {
2258 if (m_pi)
2259 memcpy (m_pi, val.m_pi, get_number_of_elements () * get_element_size ());
2260 }
2261
2262private:
2263
2264 template <typename T>
2266 to_ov (const dim_vector& dv) const
2267 {
2268 mwSize nel = get_number_of_elements ();
2269
2270 T *ppr = static_cast<T *> (m_pr);
2271
2272 // We allocate in the Array<T> constructor and copy here, so we
2273 // don't need the custom allocator for this object.
2274
2275 Array<std::complex<T>> val (dv);
2276
2277 std::complex<T> *ptr = val.rwdata ();
2278
2279 T *ppi = static_cast<T *> (m_pi);
2280
2281 for (mwIndex i = 0; i < nel; i++)
2282 ptr[i] = std::complex<T> (ppr[i], ppi[i]);
2283
2284 return octave_value (val);
2285 }
2286
2287 // Pointer to the imaginary part of the data.
2288 void *m_pi;
2289};
2290
2291// Matlab-style sparse arrays.
2292
2293class mxArray_base_sparse : public mxArray_matlab
2294{
2295public:
2296
2297 mxArray_base_sparse () = delete;
2298
2299 mxArray_base_sparse (bool interleaved, bool is_complex,
2300 mxClassID id, mwSize m, mwSize n, mwSize nzmax)
2301 : mxArray_matlab (interleaved, is_complex, id, m, n),
2302
2303 m_nzmax (nzmax > 0 ? nzmax : 1),
2304 m_ir (static_cast<mwIndex *> (mxArray::calloc (m_nzmax, sizeof (mwIndex)))),
2305 m_jc (static_cast<mwIndex *> (mxArray::calloc (n + 1, sizeof (mwIndex)))),
2306 m_pr (mxArray::calloc (m_nzmax, get_element_size ()))
2307 { }
2308
2309protected:
2310
2311 mxArray_base_sparse (const mxArray_base_sparse& val)
2312 : mxArray_matlab (val), m_nzmax (val.m_nzmax),
2313 m_ir (static_cast<mwIndex *> (mxArray::malloc (m_nzmax * sizeof (mwIndex)))),
2314 m_jc (static_cast<mwIndex *> (mxArray::malloc (m_nzmax * sizeof (mwIndex)))),
2315 m_pr (mxArray::malloc (m_nzmax * get_element_size ()))
2316 {
2317 if (m_ir)
2318 memcpy (m_ir, val.m_ir, m_nzmax * sizeof (mwIndex));
2319
2320 if (m_jc)
2321 memcpy (m_jc, val.m_jc, (val.get_n () + 1) * sizeof (mwIndex));
2322
2323 if (m_pr)
2324 memcpy (m_pr, val.m_pr, m_nzmax * get_element_size ());
2325 }
2326
2327public:
2328
2329 // No assignment! FIXME: should this be implemented? Note that we
2330 // do have a copy constructor.
2331
2332 mxArray_base_sparse& operator = (const mxArray_base_sparse&) = delete;
2333
2334 mxArray_base * dup () const
2335 {
2336 return new mxArray_base_sparse (*this);
2337 }
2338
2339 ~mxArray_base_sparse ()
2340 {
2341 mxFree (m_ir);
2342 mxFree (m_jc);
2343 mxFree (m_pr);
2344 }
2345
2346 int is_sparse () const { return 1; }
2347
2348 void * get_data () const { return m_pr; }
2349
2350 void set_data (void *pr) { m_pr = pr; }
2351
2352 mxDouble * get_doubles () const
2353 {
2354 return static_cast<mxDouble *> (m_pr);
2355 }
2356
2357 mxComplexDouble * get_complex_doubles () const
2358 {
2359 return static_cast<mxComplexDouble *> (m_pr);
2360 }
2361
2362 int set_doubles (mxDouble *d)
2363 {
2364 m_pr = d;
2365 return 0;
2366 }
2367
2368 int set_complex_doubles (mxComplexDouble *d)
2369 {
2370 m_pr = d;
2371 return 0;
2372 }
2373
2374 mwIndex * get_ir () const { return m_ir; }
2375
2376 mwIndex * get_jc () const { return m_jc; }
2377
2378 mwSize get_nzmax () const { return m_nzmax; }
2379
2380 void set_ir (mwIndex *ir) { m_ir = ir; }
2381
2382 void set_jc (mwIndex *jc) { m_jc = jc; }
2383
2384 void set_nzmax (mwSize nzmax)
2385 {
2386 /* Require storage for at least 1 element */
2387 m_nzmax = (nzmax > 0 ? nzmax : 1);
2388 }
2389
2390 octave_value as_octave_value () const
2391 {
2392 octave_value retval;
2393
2394 const dim_vector& dv = dims_to_dim_vector ();
2395
2396 switch (get_class_id ())
2397 {
2398 case mxDOUBLE_CLASS:
2399 return is_complex () ? to_ov<Complex> (dv): to_ov<double> (dv);
2400
2401 case mxSINGLE_CLASS:
2402 error ("single precision sparse data type not supported");
2403
2404 case mxLOGICAL_CLASS:
2405 return to_ov<bool> (dv);
2406
2407 case mxINT8_CLASS:
2408 case mxUINT8_CLASS:
2409 case mxINT16_CLASS:
2410 case mxUINT16_CLASS:
2411 case mxINT32_CLASS:
2412 case mxUINT32_CLASS:
2413 case mxINT64_CLASS:
2414 case mxUINT64_CLASS:
2415 case mxCELL_CLASS:
2416 case mxCHAR_CLASS:
2417 case mxFUNCTION_CLASS:
2418 case mxSTRUCT_CLASS:
2419 case mxUNKNOWN_CLASS:
2420 case mxVOID_CLASS:
2421 error ("invalid conversion from %s%s sparse mxArray to octave_value", (is_complex () ? "complex " : ""), get_class_name ());
2422 break;
2423
2424 // We should have handled all possible enum values above. Rely
2425 // on compiler diagnostics to warn if we haven't. For example,
2426 // GCC's -Wswitch option, enabled by -Wall, will provide a
2427 // warning.
2428 }
2429
2430 return retval;
2431 }
2432
2433protected:
2434
2435 template <typename ELT_T>
2437 to_ov (const dim_vector& dv) const
2438 {
2439 ELT_T *ppr = static_cast<ELT_T *> (m_pr);
2440
2441#if defined (OCTAVE_HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR)
2442
2443 if (current_mx_memory_resource == &the_mx_deleting_memory_resource)
2444 {
2445 octave::unwind_action act ([this] ()
2446 {
2447 maybe_disown_ptr (m_pr);
2448 maybe_disown_ptr (m_ir);
2449 maybe_disown_ptr (m_jc);
2450 });
2451
2452 return octave_value
2453 (Sparse<ELT_T> (dv, static_cast<octave_idx_type> (m_nzmax),
2454 ppr, m_ir, m_jc, current_mx_memory_resource));
2455 }
2456 else
2457 return octave_value
2458 (Sparse<ELT_T> (dv, static_cast<octave_idx_type> (m_nzmax),
2459 ppr, m_ir, m_jc, current_mx_memory_resource));
2460#else
2461
2462 // Copy data instead of allowing the octave_value object to borrow
2463 // the mxArray object data.
2464
2465 octave_idx_type m = dv(0);
2466 octave_idx_type n = dv(1);
2467
2468 Sparse<ELT_T> val (m, n, static_cast<octave_idx_type> (m_nzmax));
2469
2470 for (mwIndex i = 0; i < m_nzmax; i++)
2471 {
2472 val.xdata (i) = ppr[i];
2473 val.xridx (i) = m_ir[i];
2474 }
2475
2476 for (mwIndex i = 0; i < n + 1; i++)
2477 val.xcidx (i) = m_jc[i];
2478
2479 return octave_value (val);
2480
2481#endif
2482 }
2483
2484 // Maximun number of nonzero elements.
2485 mwSize m_nzmax;
2486
2487 // Sparse storage indexing arrays.
2488 mwIndex *m_ir;
2489 mwIndex *m_jc;
2490
2491 // If using interleaved complex storage, this is the pointer to data
2492 // (real, complex, or logical). Otherwise, it is the pointer to the
2493 // real part of the data.
2494 void *m_pr;
2495};
2496
2497class mxArray_interleaved_sparse : public mxArray_base_sparse
2498{
2499public:
2500
2501 mxArray_interleaved_sparse () = delete;
2502
2503 mxArray_interleaved_sparse (mxClassID id, mwSize m, mwSize n, mwSize nzmax,
2504 mxComplexity flag = mxREAL)
2505 : mxArray_base_sparse (true, flag == mxCOMPLEX, id, m, n, nzmax)
2506 { }
2507
2508private:
2509
2510 mxArray_interleaved_sparse (const mxArray_interleaved_sparse& val)
2511 : mxArray_base_sparse (val)
2512 { }
2513
2514public:
2515
2516 // No assignment! FIXME: should this be implemented? Note that we
2517 // do have a copy constructor.
2518
2519 mxArray_interleaved_sparse& operator = (const mxArray_interleaved_sparse&) = delete;
2520
2521 mxArray_base * dup () const
2522 {
2523 return new mxArray_interleaved_sparse (*this);
2524 }
2525
2526 ~mxArray_interleaved_sparse () = default;
2527
2528 void * get_imag_data () const { error_impossible_call ("mxArray_interleaved_sparse::get_imag_data"); }
2529
2530 void set_imag_data (void */*pi*/) { error_impossible_call ("mxArray_interleaved_sparse::set_imag_data"); }
2531};
2532
2533class mxArray_separate_sparse : public mxArray_base_sparse
2534{
2535public:
2536
2537 mxArray_separate_sparse () = delete;
2538
2539 mxArray_separate_sparse (mxClassID id, mwSize m, mwSize n, mwSize nzmax,
2540 mxComplexity flag = mxREAL)
2541 : mxArray_base_sparse (false, flag == mxCOMPLEX, id, m, n, nzmax),
2542 m_pi (is_complex ()
2543 ? mxArray::calloc (m_nzmax, get_element_size ())
2544 : nullptr)
2545 { }
2546
2547private:
2548
2549 mxArray_separate_sparse (const mxArray_separate_sparse& val)
2550 : mxArray_base_sparse (val),
2551 m_pi (val.m_pi
2552 ? mxArray::malloc (m_nzmax * get_element_size ())
2553 : nullptr)
2554 {
2555 if (m_pi)
2556 memcpy (m_pi, val.m_pi, m_nzmax * get_element_size ());
2557 }
2558
2559public:
2560
2561 // No assignment! FIXME: should this be implemented? Note that we
2562 // do have a copy constructor.
2563
2564 mxArray_separate_sparse& operator = (const mxArray_separate_sparse&) = delete;
2565
2566 mxArray_base * dup () const
2567 {
2568 return new mxArray_separate_sparse (*this);
2569 }
2570
2571 ~mxArray_separate_sparse ()
2572 {
2573 mxFree (m_pi);
2574 }
2575
2576 void * get_imag_data () const { return m_pi; }
2577
2578 void set_imag_data (void *pi)
2579 {
2580 m_pi = pi;
2581 set_complexity (m_pi != nullptr);
2582 }
2583
2584 mxDouble * get_doubles () const { error_impossible_call ("mxArray_separate_sparse::get_doubles"); }
2585 mxComplexDouble * get_complex_doubles () const { error_impossible_call ("mxArray_separate_sparse::get_complex_doubles"); }
2586
2587 int set_doubles (mxDouble *) { error_impossible_call ("mxArray_separate_sparse::set_doubles"); }
2588 int set_complex_doubles (mxComplexDouble *) { error_impossible_call ("mxArray_separate_sparse::set_complex_doubles"); }
2589
2590 octave_value as_octave_value () const
2591 {
2592 if (! is_complex ())
2593 return mxArray_base_sparse::as_octave_value ();
2594
2595 octave_value retval;
2596
2597 switch (get_class_id ())
2598 {
2599 case mxDOUBLE_CLASS:
2600 {
2601 double *ppr = static_cast<double *> (m_pr);
2602 double *ppi = static_cast<double *> (m_pi);
2603
2604 SparseComplexMatrix val (get_m (), get_n (),
2605 static_cast<octave_idx_type> (m_nzmax));
2606
2607 for (mwIndex i = 0; i < m_nzmax; i++)
2608 {
2609 val.xdata (i) = Complex (ppr[i], ppi[i]);
2610 val.xridx (i) = m_ir[i];
2611 }
2612
2613 for (mwIndex i = 0; i < get_n () + 1; i++)
2614 val.xcidx (i) = m_jc[i];
2615
2616 retval = val;
2617 }
2618 break;
2619
2620 case mxSINGLE_CLASS:
2621 error ("single precision sparse data type not supported");
2622
2623 case mxLOGICAL_CLASS:
2624 case mxINT8_CLASS:
2625 case mxUINT8_CLASS:
2626 case mxINT16_CLASS:
2627 case mxUINT16_CLASS:
2628 case mxINT32_CLASS:
2629 case mxUINT32_CLASS:
2630 case mxINT64_CLASS:
2631 case mxUINT64_CLASS:
2632 case mxCELL_CLASS:
2633 case mxCHAR_CLASS:
2634 case mxFUNCTION_CLASS:
2635 case mxSTRUCT_CLASS:
2636 case mxUNKNOWN_CLASS:
2637 case mxVOID_CLASS:
2638 error ("invalid conversion from complex %s sparse mxArray to octave_value", get_class_name ());
2639 break;
2640
2641 // We should have handled all possible enum values above. Rely
2642 // on compiler diagnostics to warn if we haven't. For example,
2643 // GCC's -Wswitch option, enabled by -Wall, will provide a
2644 // warning.
2645 }
2646
2647 return retval;
2648 }
2649
2650private:
2651
2652 // Pointer to the imaginary part of the data.
2653 void *m_pi;
2654};
2655
2656// Matlab-style struct arrays.
2657
2658class mxArray_struct : public mxArray_matlab
2659{
2660public:
2661
2662 mxArray_struct () = delete;
2663
2664 mxArray_struct (bool interleaved, mwSize ndims, const mwSize *dims,
2665 int num_keys, const char **keys)
2666 : mxArray_matlab (interleaved, false, mxSTRUCT_CLASS, ndims, dims),
2667 m_nfields (num_keys),
2668 m_fields (static_cast<char **> (mxArray::calloc (m_nfields,
2669 sizeof (char *)))),
2670 m_data (static_cast<mxArray * *> (mxArray::calloc (m_nfields *
2671 get_number_of_elements (),
2672 sizeof (mxArray *))))
2673 {
2674 init (keys);
2675 }
2676
2677 mxArray_struct (bool interleaved, const dim_vector& dv, int num_keys,
2678 const char **keys)
2679 : mxArray_matlab (interleaved, false, mxSTRUCT_CLASS, dv),
2680 m_nfields (num_keys),
2681 m_fields (static_cast<char **> (mxArray::calloc (m_nfields,
2682 sizeof (char *)))),
2683 m_data (static_cast<mxArray * *> (mxArray::calloc (m_nfields *
2684 get_number_of_elements (),
2685 sizeof (mxArray *))))
2686 {
2687 init (keys);
2688 }
2689
2690 mxArray_struct (bool interleaved, mwSize m, mwSize n, int num_keys,
2691 const char **keys)
2692 : mxArray_matlab (interleaved, false, mxSTRUCT_CLASS, m, n),
2693 m_nfields (num_keys),
2694 m_fields (static_cast<char **> (mxArray::calloc (m_nfields,
2695 sizeof (char *)))),
2696 m_data (static_cast<mxArray * *> (mxArray::calloc (m_nfields *
2697 get_number_of_elements (),
2698 sizeof (mxArray *))))
2699 {
2700 init (keys);
2701 }
2702
2703private:
2704
2705 mxArray_struct (const mxArray_struct& val)
2706 : mxArray_matlab (val), m_nfields (val.m_nfields),
2707 m_fields (static_cast<char **> (mxArray::malloc (m_nfields
2708 * sizeof (char *)))),
2709 m_data (static_cast<mxArray * *> (mxArray::malloc (m_nfields *
2710 get_number_of_elements ()
2711 * sizeof (mxArray *))))
2712 {
2713 for (int i = 0; i < m_nfields; i++)
2714 m_fields[i] = mxArray::strsave (val.m_fields[i]);
2715
2716 mwSize nel = get_number_of_elements ();
2717
2718 for (mwIndex i = 0; i < nel * m_nfields; i++)
2719 {
2720 mxArray *ptr = val.m_data[i];
2721 m_data[i] = (ptr ? ptr->dup () : nullptr);
2722 }
2723 }
2724
2725public:
2726
2727 // No assignment! FIXME: should this be implemented? Note that we
2728 // do have a copy constructor.
2729
2730 mxArray_struct& operator = (const mxArray_struct& val) = delete;
2731
2732 void init (const char **keys)
2733 {
2734 for (int i = 0; i < m_nfields; i++)
2735 m_fields[i] = mxArray::strsave (keys[i]);
2736 }
2737
2738 mxArray_base * dup () const { return new mxArray_struct (*this); }
2739
2740 ~mxArray_struct ()
2741 {
2742 for (int i = 0; i < m_nfields; i++)
2743 mxFree (m_fields[i]);
2744
2745 mxFree (m_fields);
2746
2747 mwSize ntot = m_nfields * get_number_of_elements ();
2748
2749 for (mwIndex i = 0; i < ntot; i++)
2750 delete m_data[i];
2751
2752 mxFree (m_data);
2753 }
2754
2755 int add_field (const char *key)
2756 {
2757 int retval = -1;
2758
2759 m_nfields++;
2760
2761 m_fields = static_cast<char **>
2762 (mxRealloc (m_fields, m_nfields * sizeof (char *)));
2763
2764 if (m_fields)
2765 {
2766 m_fields[m_nfields-1] = mxArray::strsave (key);
2767
2768 mwSize nel = get_number_of_elements ();
2769
2770 mwSize ntot = m_nfields * nel;
2771
2772 mxArray **new_data;
2773 new_data = static_cast<mxArray **>
2774 (mxArray::malloc (ntot * sizeof (mxArray *)));
2775
2776 if (new_data)
2777 {
2778 mwIndex j = 0;
2779 mwIndex k = 0;
2780 mwIndex n = 0;
2781
2782 for (mwIndex i = 0; i < ntot; i++)
2783 {
2784 if (++n == m_nfields)
2785 {
2786 new_data[j++] = nullptr;
2787 n = 0;
2788 }
2789 else
2790 new_data[j++] = m_data[k++];
2791 }
2792
2793 mxFree (m_data);
2794
2795 m_data = new_data;
2796
2797 retval = m_nfields - 1;
2798 }
2799 }
2800
2801 return retval;
2802 }
2803
2804 void remove_field (int key_num)
2805 {
2806 if (key_num >= 0 && key_num < m_nfields)
2807 {
2808 mwSize nel = get_number_of_elements ();
2809
2810 mwSize ntot = m_nfields * nel;
2811
2812 int new_nfields = m_nfields - 1;
2813
2814 char **new_fields = static_cast<char **>
2815 (mxArray::malloc (new_nfields * sizeof (char *)));
2816
2817 mxArray **new_data = static_cast<mxArray **>
2818 (mxArray::malloc (new_nfields * nel
2819 * sizeof (mxArray *)));
2820
2821 for (int i = 0; i < key_num; i++)
2822 new_fields[i] = m_fields[i];
2823
2824 for (int i = key_num + 1; i < m_nfields; i++)
2825 new_fields[i-1] = m_fields[i];
2826
2827 if (new_nfields > 0)
2828 {
2829 mwIndex j = 0;
2830 mwIndex k = 0;
2831 mwIndex n = 0;
2832
2833 for (mwIndex i = 0; i < ntot; i++)
2834 {
2835 if (n == key_num)
2836 k++;
2837 else
2838 new_data[j++] = m_data[k++];
2839
2840 if (++n == m_nfields)
2841 n = 0;
2842 }
2843 }
2844
2845 m_nfields = new_nfields;
2846
2847 mxFree (m_fields);
2848 mxFree (m_data);
2849
2850 m_fields = new_fields;
2851 m_data = new_data;
2852 }
2853 }
2854
2855 mxArray * get_field_by_number (mwIndex index, int key_num) const
2856 {
2857 return key_num >= 0 && key_num < m_nfields
2858 ? m_data[m_nfields * index + key_num] : nullptr;
2859 }
2860
2861 void set_field_by_number (mwIndex index, int key_num, mxArray *val);
2862
2863 int get_number_of_fields () const { return m_nfields; }
2864
2865 const char * get_field_name_by_number (int key_num) const
2866 {
2867 return key_num >= 0 && key_num < m_nfields ? m_fields[key_num] : nullptr;
2868 }
2869
2870 int get_field_number (const char *key) const
2871 {
2872 int retval = -1;
2873
2874 for (int i = 0; i < m_nfields; i++)
2875 {
2876 if (! strcmp (key, m_fields[i]))
2877 {
2878 retval = i;
2879 break;
2880 }
2881 }
2882
2883 return retval;
2884 }
2885
2886 void * get_data () const { return m_data; }
2887
2888 void set_data (void *data) { m_data = static_cast<mxArray **> (data); }
2889
2890 octave_value as_octave_value () const
2891 {
2892 const dim_vector& dv = dims_to_dim_vector ();
2893
2894 string_vector keys (m_fields, m_nfields);
2895
2896 octave_map m (dv);
2897
2898 mwSize ntot = m_nfields * get_number_of_elements ();
2899
2900 for (int i = 0; i < m_nfields; i++)
2901 {
2902 Cell c (dv);
2903
2904 octave_value *p = c.rwdata ();
2905
2906 mwIndex k = 0;
2907 for (mwIndex j = i; j < ntot; j += m_nfields)
2908 p[k++] = mxArray::as_octave_value (m_data[j]);
2909
2910 m.assign (keys[i], c);
2911 }
2912
2913 return m;
2914 }
2915
2916private:
2917
2918 int m_nfields;
2919
2920 char **m_fields;
2921
2922 mxArray **m_data;
2923};
2924
2925// Matlab-style cell arrays.
2926
2927class mxArray_cell : public mxArray_matlab
2928{
2929public:
2930
2931 mxArray_cell () = delete;
2932
2933 mxArray_cell (bool interleaved, mwSize ndims, const mwSize *dims)
2934 : mxArray_matlab (interleaved, false, mxCELL_CLASS, ndims, dims),
2935 m_data (static_cast<mxArray **> (mxArray::calloc (get_number_of_elements (), sizeof (mxArray *))))
2936 { }
2937
2938 mxArray_cell (bool interleaved, const dim_vector& dv)
2939 : mxArray_matlab (interleaved, false, mxCELL_CLASS, dv),
2940 m_data (static_cast<mxArray **> (mxArray::calloc (get_number_of_elements (), sizeof (mxArray *))))
2941 { }
2942
2943 mxArray_cell (bool interleaved, mwSize m, mwSize n)
2944 : mxArray_matlab (interleaved, false, mxCELL_CLASS, m, n),
2945 m_data (static_cast<mxArray **> (mxArray::calloc (get_number_of_elements (), sizeof (mxArray *))))
2946 { }
2947
2948private:
2949
2950 mxArray_cell (const mxArray_cell& val)
2951 : mxArray_matlab (val),
2952 m_data (static_cast<mxArray **> (mxArray::malloc (get_number_of_elements () * sizeof (mxArray *))))
2953 {
2954 mwSize nel = get_number_of_elements ();
2955
2956 for (mwIndex i = 0; i < nel; i++)
2957 {
2958 mxArray *ptr = val.m_data[i];
2959 m_data[i] = (ptr ? ptr->dup () : nullptr);
2960 }
2961 }
2962
2963public:
2964
2965 // No assignment! FIXME: should this be implemented? Note that we
2966 // do have a copy constructor.
2967
2968 mxArray_cell& operator = (const mxArray_cell&) = delete;
2969
2970 mxArray_base * dup () const { return new mxArray_cell (*this); }
2971
2972 ~mxArray_cell ()
2973 {
2974 mwSize nel = get_number_of_elements ();
2975
2976 for (mwIndex i = 0; i < nel; i++)
2977 delete m_data[i];
2978
2979 mxFree (m_data);
2980 }
2981
2982 mxArray * get_cell (mwIndex idx) const
2983 {
2984 return idx >= 0 && idx < get_number_of_elements () ? m_data[idx] : nullptr;
2985 }
2986
2987 void set_cell (mwIndex idx, mxArray *val);
2988
2989 void * get_data () const { return m_data; }
2990
2991 void set_data (void *data) { m_data = static_cast<mxArray **> (data); }
2992
2993 octave_value as_octave_value () const
2994 {
2995 const dim_vector& dv = dims_to_dim_vector ();
2996
2997 Cell c (dv);
2998
2999 mwSize nel = get_number_of_elements ();
3000
3001 octave_value *p = c.rwdata ();
3002
3003 for (mwIndex i = 0; i < nel; i++)
3004 p[i] = mxArray::as_octave_value (m_data[i]);
3005
3006 return c;
3007 }
3008
3009private:
3010
3011 mxArray **m_data;
3012};
3013
3014// ------------------------------------------------------------------
3015
3016mxArray::mxArray (bool interleaved, const octave_value& ov)
3017 : m_rep (create_rep (interleaved, ov)), m_name (nullptr)
3018{ }
3019
3020mxArray::mxArray (bool interleaved, mxClassID id, mwSize ndims,
3021 const mwSize *dims, mxComplexity flag, bool init)
3022 : m_rep (create_rep (interleaved, id, ndims, dims, flag, init)),
3023 m_name (nullptr)
3024{ }
3025
3026mxArray::mxArray (bool interleaved, mxClassID id, const dim_vector& dv,
3027 mxComplexity flag)
3028 : m_rep (create_rep (interleaved, id, dv, flag)), m_name (nullptr)
3029{ }
3030
3031mxArray::mxArray (bool interleaved, mxClassID id, mwSize m, mwSize n,
3032 mxComplexity flag, bool init)
3033 : m_rep (create_rep (interleaved, id, m, n, flag, init)), m_name (nullptr)
3034{ }
3035
3036mxArray::mxArray (bool interleaved, mxClassID id, double val)
3037 : m_rep (create_rep (interleaved, id, val)), m_name (nullptr)
3038{ }
3039
3040mxArray::mxArray (bool interleaved, mxClassID id, mxLogical val)
3041 : m_rep (create_rep (interleaved, id, val)), m_name (nullptr)
3042{ }
3043
3044mxArray::mxArray (bool interleaved, const char *str)
3045 : m_rep (create_rep (interleaved, str)), m_name (nullptr)
3046{ }
3047
3048mxArray::mxArray (bool interleaved, mwSize m, const char **str)
3049 : m_rep (create_rep (interleaved, m, str)), m_name (nullptr)
3050{ }
3051
3052mxArray::mxArray (bool interleaved, mxClassID id, mwSize m, mwSize n,
3053 mwSize nzmax, mxComplexity flag)
3054 : m_rep (create_rep (interleaved, id, m, n, nzmax, flag)), m_name (nullptr)
3055{ }
3056
3057mxArray::mxArray (bool interleaved, mwSize ndims, const mwSize *dims,
3058 int num_keys,
3059 const char **keys)
3060 : m_rep (new mxArray_struct (interleaved, ndims, dims, num_keys, keys)),
3061 m_name (nullptr)
3062{ }
3063
3064mxArray::mxArray (bool interleaved, const dim_vector& dv, int num_keys,
3065 const char **keys)
3066 : m_rep (new mxArray_struct (interleaved, dv, num_keys, keys)),
3067 m_name (nullptr)
3068{ }
3069
3070mxArray::mxArray (bool interleaved, mwSize m, mwSize n, int num_keys,
3071 const char **keys)
3072 : m_rep (new mxArray_struct (interleaved, m, n, num_keys, keys)),
3073 m_name (nullptr)
3074{ }
3075
3076mxArray::mxArray (bool interleaved, mwSize ndims, const mwSize *dims)
3077 : m_rep (new mxArray_cell (interleaved, ndims, dims)), m_name (nullptr)
3078{ }
3079
3080mxArray::mxArray (bool interleaved, const dim_vector& dv)
3081 : m_rep (new mxArray_cell (interleaved, dv)), m_name (nullptr)
3082{ }
3083
3084mxArray::mxArray (bool interleaved, mwSize m, mwSize n)
3085 : m_rep (new mxArray_cell (interleaved, m, n)), m_name (nullptr)
3086{ }
3087
3089{
3090 mxFree (m_name);
3091
3092 delete m_rep;
3093}
3094
3095void
3096mxArray::set_name (const char *name)
3097{
3098 mxFree (m_name);
3099 m_name = mxArray::strsave (name);
3100}
3101
3103mxArray::as_octave_value (const mxArray *ptr, bool null_is_empty)
3104{
3105 static const octave_value empty_matrix = Matrix ();
3106
3107 return (ptr
3108 ? ptr->as_octave_value ()
3109 : (null_is_empty ? empty_matrix : octave_value ()));
3110}
3111
3114{
3115 return m_rep->as_octave_value ();
3116}
3117
3119mxArray::create_rep (bool interleaved, const octave_value& ov)
3120{
3121 return new mxArray_octave_value (interleaved, ov);
3122}
3123
3125mxArray::create_rep (bool interleaved, mxClassID id, mwSize ndims,
3126 const mwSize *dims, mxComplexity flag, bool init)
3127{
3128 if (interleaved)
3129 return new mxArray_interleaved_full (id, ndims, dims, flag, init);
3130 else
3131 return new mxArray_separate_full (id, ndims, dims, flag, init);
3132}
3133
3135mxArray::create_rep (bool interleaved, mxClassID id, const dim_vector& dv,
3136 mxComplexity flag)
3137{
3138 if (interleaved)
3139 return new mxArray_interleaved_full (id, dv, flag);
3140 else
3141 return new mxArray_separate_full (id, dv, flag);
3142}
3143
3145mxArray::create_rep (bool interleaved, mxClassID id, mwSize m, mwSize n,
3146 mxComplexity flag, bool init)
3147{
3148 if (interleaved)
3149 return new mxArray_interleaved_full (id, m, n, flag, init);
3150 else
3151 return new mxArray_separate_full (id, m, n, flag, init);
3152}
3153
3155mxArray::create_rep (bool interleaved, mxClassID id, double val)
3156{
3157 if (interleaved)
3158 return new mxArray_interleaved_full (id, val);
3159 else
3160 return new mxArray_separate_full (id, val);
3161}
3162
3164mxArray::create_rep (bool interleaved, mxClassID id, mxLogical val)
3165{
3166 if (interleaved)
3167 return new mxArray_interleaved_full (id, val);
3168 else
3169 return new mxArray_separate_full (id, val);
3170}
3171
3173mxArray::create_rep (bool interleaved, const char *str)
3174{
3175 if (interleaved)
3176 return new mxArray_interleaved_full (str);
3177 else
3178 return new mxArray_separate_full (str);
3179}
3180
3182mxArray::create_rep (bool interleaved, mwSize m, const char **str)
3183{
3184 if (interleaved)
3185 return new mxArray_interleaved_full (m, str);
3186 else
3187 return new mxArray_separate_full (m, str);
3188}
3189
3191mxArray::create_rep (bool interleaved, mxClassID id, mwSize m, mwSize n,
3192 mwSize nzmax, mxComplexity flag)
3193{
3194 if (interleaved)
3195 return new mxArray_interleaved_sparse (id, m, n, nzmax, flag);
3196 else
3197 return new mxArray_separate_sparse (id, m, n, nzmax, flag);
3198}
3199
3200void
3201mxArray::maybe_mutate () const
3202{
3203 if (m_rep->is_octave_value ())
3204 {
3205 // The mutate function returns a pointer to a complete new
3206 // mxArray object (or 0, if no mutation happened). We just want
3207 // to replace the existing rep with the rep from the new object.
3208
3209 mxArray *new_val = m_rep->mutate ();
3210
3211 if (new_val)
3212 {
3213 delete m_rep;
3214 m_rep = new_val->m_rep;
3215 new_val->m_rep = nullptr;
3216 delete new_val;
3217 }
3218 }
3219}
3220
3221// ------------------------------------------------------------------
3222
3223// A class to manage calls to MEX functions. Mostly deals with memory
3224// management.
3225
3227{
3228 // We can't use mex::free here because it modifies memlist.
3229 while (! m_memlist.empty ())
3230 {
3231 auto p = m_memlist.begin ();
3232 xfree (*p);
3233 m_memlist.erase (p);
3234 }
3235
3236 // We can't use mex::free_value here because it modifies arraylist.
3237 while (! m_arraylist.empty ())
3238 {
3239 auto p = m_arraylist.begin ();
3240 delete *p;
3241 m_arraylist.erase (p);
3242 }
3243
3244 if (! (m_memlist.empty () && m_arraylist.empty ()))
3245 error ("mex: %s: cleanup failed", function_name ());
3246
3247 mxFree (m_fname);
3248}
3249
3250const char *
3252{
3253 if (! m_fname)
3254 {
3255 octave::tree_evaluator& tw = octave::__get_evaluator__ ();
3256
3257 octave_function *fcn = tw.current_function ();
3258
3259 if (fcn)
3260 {
3261 std::string nm = fcn->name ();
3262 m_fname = mxArray::strsave (nm.c_str ());
3263 }
3264 else
3265 m_fname = mxArray::strsave ("unknown");
3266 }
3267
3268 return m_fname;
3269}
3270
3271// Allocate memory.
3272void *
3274{
3275 void *ptr = xmalloc (n);
3276
3277 if (! ptr)
3278 {
3279 // FIXME: could use "octave_new_handler();" instead
3280 error ("%s: failed to allocate %zd bytes of memory",
3281 function_name (), n);
3282 }
3283
3284 global_mark (ptr);
3285
3286 return ptr;
3287}
3288
3289// Reallocate a pointer obtained from malloc or calloc.
3290// If the pointer is NULL, allocate using malloc.
3291// We don't need an "unmarked" version of this.
3292void *
3293mex::realloc (void *ptr, std::size_t n)
3294{
3295 void *v;
3296
3297 if (ptr)
3298 {
3299 auto p_local = m_memlist.find (ptr);
3300 auto p_global = s_global_memlist.find (ptr);
3301
3302 v = xrealloc (ptr, n);
3303
3304 if (v)
3305 {
3306 if (p_local != m_memlist.end ())
3307 {
3308 m_memlist.erase (p_local);
3309 m_memlist.insert (v);
3310 }
3311
3312 if (p_global != s_global_memlist.end ())
3313 {
3314 s_global_memlist.erase (p_global);
3315 s_global_memlist.insert (v);
3316 }
3317 }
3318 }
3319 else
3320 v = malloc (n);
3321
3322 return v;
3323}
3324
3325// Free a pointer obtained from malloc or calloc.
3326void mex::free (void *ptr)
3327{
3328 if (ptr)
3329 {
3330 unmark (ptr);
3331
3332 auto p = s_global_memlist.find (ptr);
3333
3334 if (p != s_global_memlist.end ())
3335 {
3336 s_global_memlist.erase (p);
3337
3338 xfree (ptr);
3339 }
3340 else
3341 {
3342 p = m_foreign_memlist.find (ptr);
3343
3344 if (p != m_foreign_memlist.end ())
3345 m_foreign_memlist.erase (p);
3346#if defined (OCTAVE_MXARRAY_DEBUG)
3347 else
3348 warning ("mxFree: skipping memory not allocated by mxMalloc, mxCalloc, or mxRealloc");
3349#endif
3350 }
3351 }
3352}
3353
3354// List of memory resources we allocated.
3355std::set<void *> mex::s_global_memlist;
3356
3357// Current context.
3358OCTINTERP_API mex *mex_context = nullptr;
3359
3360void * mxRealloc (void *ptr, std::size_t size)
3361{
3362 return (mex_context
3363 ? mex_context->realloc (ptr, size) : xrealloc (ptr, size));
3364}
3365
3366void mxFree (void *ptr)
3367{
3368 if (mex_context)
3369 mex_context->free (ptr);
3370 else
3371 xfree (ptr);
3372}
3373
3374void *
3375mxArray::malloc (std::size_t n)
3376{
3377 return mex_context ? mex_context->malloc_unmarked (n) : xmalloc (n);
3378}
3379
3380void *
3381mxArray::calloc (std::size_t n, std::size_t t)
3382{
3383 return mex_context ? mex_context->calloc_unmarked (n, t) : ::calloc (n, t);
3384}
3385
3386void *
3387mxArray::alloc (bool init, std::size_t n, std::size_t t)
3388{
3389 return init ? mxArray::calloc (n, t) : mxArray::malloc (n * t);
3390}
3391
3392static inline void *
3393maybe_mark_foreign (void *ptr)
3394{
3395 if (mex_context)
3397
3398 return ptr;
3399}
3400
3401#if defined (OCTAVE_HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR)
3402
3403static inline void
3404maybe_disown_ptr (void *ptr)
3405{
3406 if (mex_context)
3407 {
3408 mex_context->unmark (ptr);
3411 }
3412}
3413
3414#endif
3415
3416static inline mxArray *
3417maybe_unmark_array (mxArray *ptr)
3418{
3419 if (mex_context)
3421
3422 return ptr;
3423}
3424
3425template <typename T>
3426static inline T *
3427maybe_unmark (T *ptr)
3428{
3429 if (mex_context)
3430 mex_context->unmark (ptr);
3431
3432 return ptr;
3433}
3434
3435void
3436mxArray_struct::set_field_by_number (mwIndex index, int key_num, mxArray *val)
3437{
3438 if (key_num >= 0 && key_num < m_nfields)
3439 m_data[m_nfields * index + key_num] = maybe_unmark_array (val);
3440}
3441
3442void
3443mxArray_cell::set_cell (mwIndex idx, mxArray *val)
3444{
3445 if (idx >= 0 && idx < get_number_of_elements ())
3446 m_data[idx] = maybe_unmark_array (val);
3447}
3448
3449// ------------------------------------------------------------------
3450
3451extern "C" {
3452 typedef void (*cmex_fptr) (int nlhs, mxArray *plhs[],
3453 int nrhs, const mxArray *prhs[]);
3454}
3455
3457
3460 int nargout_arg)
3461{
3462 octave_quit ();
3463
3464 // Use at least 1 for nargout since even for zero specified args,
3465 // still want to be able to return an ans.
3466
3467 int nargout = nargout_arg;
3468
3469 int nargin = args.length ();
3470 OCTAVE_LOCAL_BUFFER (mxArray *, argin, nargin);
3471 for (int i = 0; i < nargin; i++)
3472 argin[i] = nullptr;
3473
3474 int nout = (nargout == 0 ? 1 : nargout);
3475 OCTAVE_LOCAL_BUFFER (mxArray *, argout, nout);
3476 for (int i = 0; i < nout; i++)
3477 argout[i] = nullptr;
3478
3479 // Save old mex pointer.
3480 octave::unwind_protect_var<mex *> restore_var (mex_context);
3481
3482 mex context (mex_fcn);
3483
3484 for (int i = 0; i < nargin; i++)
3485 argin[i] = context.make_value (args(i));
3486
3487 mex_context = &context;
3488
3489 cmex_fptr fcn = reinterpret_cast<cmex_fptr> (mex_fcn.mex_fcn_ptr ());
3490
3491 fcn (nargout, argout, nargin, const_cast<const mxArray **> (argin));
3492
3493 // Convert returned array entries back into octave values.
3494
3495 octave_value_list retval;
3496
3497 if (nargout == 0 && argout[0])
3498 {
3499 // We have something for ans.
3500 nargout = 1;
3501 }
3502
3503 retval.resize (nargout);
3504
3505 // If using std::pmr::memory_resource object to manage memory, pass
3506 // default allocator here because we are done with these mxArray
3507 // values and want Octave to delete them.
3508
3509 for (int i = 0; i < nargout; i++)
3510 retval(i) = mxArray::as_octave_value (argout[i], false);
3511
3512 return retval;
3513}
3514
3515OCTAVE_END_NAMESPACE(octave)
octave_value to_ov(const cdef_object &obj)
N Dimensional Array with copy-on-write semantics.
Definition Array-base.h:130
const T * data() const
Size of the specified dimension.
Definition Array-base.h:687
Definition Cell.h:41
Vector representing the dimensions (size) of an Array.
Definition dim-vector.h:92
void resize(int n, int fill_value=0)
Definition dim-vector.h:278
Definition mxarray.h:688
~mex()
Definition mxarray.cc:3226
void unmark_array(mxArray *ptr)
Definition mxarray.h:772
void free(void *ptr)
Definition mxarray.cc:3326
mxArray * make_value(const octave_value &ov)
Definition mxarray.h:806
void * malloc(std::size_t n)
Definition mxarray.h:704
void * malloc_unmarked(std::size_t n)
Definition mxarray.cc:3273
void unmark(void *ptr)
Definition mxarray.h:754
void global_unmark(void *ptr)
Definition mxarray.h:854
void * realloc(void *ptr, std::size_t n)
Definition mxarray.cc:3293
void global_mark(void *ptr)
Definition mxarray.h:843
void mark_foreign(void *ptr)
Definition mxarray.h:781
const char * function_name() const
Definition mxarray.cc:3251
void * calloc_unmarked(std::size_t n, std::size_t t)
Definition mxarray.h:714
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:311
virtual mxArray * as_mxArray() const
Definition mxarray.h:112
virtual bool is_octave_value() const
Definition mxarray.h:116
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 mxInt64 * get_int64s() const =0
virtual mxUint32 * get_uint32s() const =0
virtual void set_nzmax(mwSize nzmax)=0
virtual int set_uint16s(mxUint16 *data)=0
virtual int is_logical() const =0
virtual int is_uint64() 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 mwIndex calc_single_subscript(mwSize nsubs, mwIndex *subs) const =0
virtual mxArray * get_property(mwIndex, const char *) const
Definition mxarray.h:205
virtual int set_doubles(mxDouble *data)=0
virtual int set_int64s(mxInt64 *data)=0
virtual int is_complex() const =0
virtual octave_value as_octave_value() const =0
virtual mxDouble * get_doubles() 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 int set_singles(mxSingle *data)=0
virtual int is_char() const =0
virtual void * get_imag_data() const =0
virtual void set_m(mwSize m)=0
virtual void set_data(void *pr)=0
virtual int is_logical_scalar_true() const =0
bool m_interleaved
Definition mxarray.h:319
virtual mxComplexSingle * get_complex_singles() const =0
virtual int is_uint16() const =0
virtual double get_scalar() const =0
virtual mxInt16 * get_int16s() const =0
virtual mxInt8 * get_int8s() const =0
virtual mwSize get_nzmax() const =0
virtual const char * get_field_name_by_number(int key_num) const =0
std::size_t get_numeric_element_size(std::size_t size) const
Definition mxarray.h:304
virtual int iscell() const =0
virtual void set_property(mwIndex, const char *, const mxArray *)
Definition mxarray.h:210
virtual int set_complex_doubles(mxComplexDouble *data)=0
virtual int isempty() const =0
virtual mwSize get_number_of_elements() const =0
virtual mxUint8 * get_uint8s() const =0
virtual int is_logical_scalar() const
Definition mxarray.h:166
virtual void set_jc(mwIndex *jc)=0
virtual std::size_t get_element_size() const =0
virtual int set_uint32s(mxUint32 *data)=0
virtual int set_uint8s(mxUint8 *data)=0
virtual bool mutation_needed() const
Definition mxarray.h:296
virtual mxArray * mutate() const
Definition mxarray.h:298
virtual int set_dimensions(mwSize *dims_arg, mwSize ndims_arg)=0
virtual int is_int16() const =0
virtual int is_single() const =0
virtual void set_class_name(const char *name_arg)=0
virtual mxUint16 * get_uint16s() const =0
virtual mwSize * get_dimensions() const =0
virtual mxArray_base * dup() const =0
virtual mxInt32 * get_int32s() const =0
virtual mwSize get_number_of_dimensions() const =0
virtual int is_function_handle() const =0
virtual int is_uint8() const =0
virtual mxComplexDouble * get_complex_doubles() const =0
virtual mwSize get_m() const =0
virtual int is_int8() const =0
virtual char * array_to_string() const =0
virtual void * get_data() const =0
virtual int is_int32() const =0
virtual int get_number_of_fields() const =0
virtual void set_ir(mwIndex *ir)=0
virtual mxSingle * get_singles() const =0
virtual void remove_field(int key_num)=0
virtual int is_uint32() const =0
virtual mwIndex * get_jc() const =0
virtual mwIndex * get_ir() const =0
virtual int is_int64() const =0
virtual void set_field_by_number(mwIndex index, int key_num, mxArray *val)=0
virtual int is_struct() const =0
virtual int get_field_number(const char *key) const =0
virtual const char * get_class_name() const =0
virtual mwSize get_n() const =0
virtual mxArray * get_cell(mwIndex) const
Definition mxarray.h:216
virtual mxUint64 * get_uint64s() const =0
virtual int set_int32s(mxInt32 *data)=0
virtual int is_sparse() const =0
virtual mxClassID get_class_id() const =0
void set_name(const char *name)
Definition mxarray.cc:3096
static void * alloc(bool init, std::size_t n, std::size_t t)
Definition mxarray.cc:3387
mxArray * dup() const
Definition mxarray.h:369
static char * strsave(const char *str)
Definition mxarray.h:616
int set_dimensions(mwSize *dims_arg, mwSize ndims_arg)
Definition mxarray.h:447
static void * calloc(std::size_t n, std::size_t t)
Definition mxarray.cc:3381
mxArray(bool interleaved, const octave_value &ov)
Definition mxarray.cc:3016
static octave_value as_octave_value(const mxArray *ptr, bool null_is_empty=true)
Definition mxarray.cc:3103
const char * get_name() const
Definition mxarray.h:457
octave_value as_octave_value() const
Definition mxarray.cc:3113
mwSize * get_dimensions() const
Definition mxarray.h:438
void set_class_name(const char *name_arg)
Definition mxarray.h:471
static void * malloc(std::size_t n)
Definition mxarray.cc:3375
octave_classdef * classdef_object_value(bool=false)
Definition ov-classdef.h:70
octave_value get_property(octave_idx_type idx, const std::string &name) const
void set_property(octave_idx_type idx, const std::string &name, const octave_value &pval)
std::string name() const
Definition ov-fcn.h:212
void * mex_fcn_ptr() const
Definition ov-mex-fcn.h:99
void resize(octave_idx_type n, const octave_value &rfv=octave_value())
Definition ovl.h:115
octave_idx_type length() const
Definition ovl.h:111
bool is_defined() const
Definition ov.h:590
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void warning(const char *fmt,...)
Definition error.cc:1083
void error(const char *fmt,...)
Definition error.cc:1008
char * strsave(const char *s)
Definition lo-utils.cc:78
void(* cmex_fptr)(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
Definition mxarray.cc:3452
#define CONST_MUTATION_METHOD(RET_TYPE, FCN_NAME, ARG_LIST, RET_VAL)
Definition mxarray.cc:429
mex * mex_context
Definition mxarray.cc:3358
int mexSet_impl(double handle, const char *property, mxArray *val)
Definition mxarray.cc:345
int mexPutVariable_impl(const char *space, const char *name, const mxArray *ptr)
Definition mxarray.cc:267
void mexErrMsgTxt_impl(const char *who, const char *s)
Definition mxarray.cc:244
octave_value_list call_mex(octave_mex_function &mex_fcn, const octave_value_list &args, int nargout_arg)
Definition mxarray.cc:3459
#define GET_DATA_METHOD(RT, FCN_NAME, ID, COMPLEXITY)
Definition mxarray.cc:432
octave_value_list mx_to_ov_args(int nargin, mxArray *argin[])
Definition mxarray.cc:215
#define VOID_MUTATION_METHOD(FCN_NAME, ARG_LIST)
Definition mxarray.cc:420
#define MUTATION_METHOD(RET_TYPE, FCN_NAME, ARG_LIST, RET_VAL)
Definition mxarray.cc:426
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:95
bool strcmp(const T &str_a, const T &str_b)
Octave string utility functions.
void * malloc(unsigned)
F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE * d
void get_dimensions(const octave_value &a, const char *warn_for, dim_vector &dim)
Definition utils.cc:1377
F77_RET_T len
Definition xerbla.cc:61