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