1 // %NO_EDIT_WARNING%
2 
3 ////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (C) 2001-2021 The Octave Project Developers
6 //
7 // See the file COPYRIGHT.md in the top-level directory of this
8 // distribution or <https://octave.org/copyright/>.
9 //
10 // This file is part of Octave.
11 //
12 // Octave is free software: you can redistribute it and/or modify it
13 // under the terms of the GNU General Public License as published by
14 // the Free Software Foundation, either version 3 of the License, or
15 // (at your option) any later version.
16 //
17 // Octave is distributed in the hope that it will be useful, but
18 // WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 // GNU General Public License for more details.
21 //
22 // You should have received a copy of the GNU General Public License
23 // along with Octave; see the file COPYING.  If not, see
24 // <https://www.gnu.org/licenses/>.
25 //
26 ////////////////////////////////////////////////////////////////////////
27 
28 /*
29 
30 Part of this code was originally distributed as part of Octave Forge under
31 the following terms:
32 
33 Author: Paul Kienzle
34 I grant this code to the public domain.
35 2001-03-22
36 
37 THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
38 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
40 ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
41 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
42 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
43 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
45 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 SUCH DAMAGE.
48 
49 */
50 
51 #if ! defined (octave_mxarray_h)
52 #define octave_mxarray_h 1
53 
54 #include "octave-config.h"
55 
56 typedef enum
57 {
58   mxUNKNOWN_CLASS = 0,
59   mxCELL_CLASS,
60   mxSTRUCT_CLASS,
61   mxLOGICAL_CLASS,
62   mxCHAR_CLASS,
63   mxVOID_CLASS,
64   mxDOUBLE_CLASS,
65   mxSINGLE_CLASS,
66   mxINT8_CLASS,
67   mxUINT8_CLASS,
68   mxINT16_CLASS,
69   mxUINT16_CLASS,
70   mxINT32_CLASS,
71   mxUINT32_CLASS,
72   mxINT64_CLASS,
73   mxUINT64_CLASS,
74   mxFUNCTION_CLASS
75 }
76 mxClassID;
77 
78 typedef enum
79 {
80   mxREAL = 0,
81   mxCOMPLEX = 1
82 }
83 mxComplexity;
84 
85 /* Matlab uses a wide char (uint16) internally, but Octave uses plain char. */
86 /* typedef Uint16 mxChar; */
87 typedef char mxChar;
88 
89 typedef unsigned char mxLogical;
90 
91 /*
92  * FIXME: Mathworks says mwSize, mwIndex should be int generally.
93  * But on 64-bit systems, or when mex -largeArrayDims is used, it is size_t.
94  * mwSignedIndex is supposed to be ptrdiff_t.  All of this is confusing.
95  * Its better to conform to the same indexing as the rest of Octave.
96  */
97 typedef %OCTAVE_IDX_TYPE% mwSize;
98 typedef %OCTAVE_IDX_TYPE% mwIndex;
99 typedef %OCTAVE_IDX_TYPE% mwSignedIndex;
100 
101 #if ! defined (MXARRAY_TYPEDEFS_ONLY)
102 
103 #include <cstring>
104 #include "error.h"
105 
106 class octave_value;
107 class dim_vector;
108 
109 #define DO_MUTABLE_METHOD(RET_T, METHOD_CALL)   \
110   RET_T retval = rep->METHOD_CALL;              \
111                                                 \
112   if (rep->mutation_needed ())                  \
113     {                                           \
114       maybe_mutate ();                          \
115       retval = rep->METHOD_CALL;                \
116     }                                           \
117                                                 \
118   return retval
119 
120 #define DO_VOID_MUTABLE_METHOD(METHOD_CALL)     \
121   rep->METHOD_CALL;                             \
122                                                 \
123   if (rep->mutation_needed ())                  \
124     {                                           \
125       maybe_mutate ();                          \
126       rep->METHOD_CALL;                         \
127     }
128 
129 class mxArray;
130 
131 // A class to provide the default implementation of some of the
132 // virtual functions declared in the mxArray class.
133 
134 class mxArray_base
135 {
136 protected:
137 
mxArray_base(void)138   mxArray_base (void) { }
139 
140 public:
141 
142   virtual mxArray_base * dup (void) const = 0;
143 
as_mxArray(void)144   virtual mxArray * as_mxArray (void) const { return nullptr; }
145 
146   virtual ~mxArray_base (void) = default;
147 
is_octave_value(void)148   virtual bool is_octave_value (void) const { return false; }
149 
150   virtual int iscell (void) const = 0;
151 
152   virtual int is_char (void) const = 0;
153 
is_class(const char * name_arg)154   virtual int is_class (const char *name_arg) const
155   {
156     int retval = 0;
157 
158     const char *cname = get_class_name ();
159 
160     if (cname && name_arg)
161       retval = ! strcmp (cname, name_arg);
162 
163     return retval;
164   }
165 
166   virtual int is_complex (void) const = 0;
167 
168   virtual int is_double (void) const = 0;
169 
170   virtual int is_function_handle (void) const = 0;
171 
172   virtual int is_int16 (void) const = 0;
173 
174   virtual int is_int32 (void) const = 0;
175 
176   virtual int is_int64 (void) const = 0;
177 
178   virtual int is_int8 (void) const = 0;
179 
180   virtual int is_logical (void) const = 0;
181 
182   virtual int is_numeric (void) const = 0;
183 
184   virtual int is_single (void) const = 0;
185 
186   virtual int is_sparse (void) const = 0;
187 
188   virtual int is_struct (void) const = 0;
189 
190   virtual int is_uint16 (void) const = 0;
191 
192   virtual int is_uint32 (void) const = 0;
193 
194   virtual int is_uint64 (void) const = 0;
195 
196   virtual int is_uint8 (void) const = 0;
197 
is_logical_scalar(void)198   virtual int is_logical_scalar (void) const
199   {
200     return is_logical () && get_number_of_elements () == 1;
201   }
202 
203   virtual int is_logical_scalar_true (void) const = 0;
204 
205   virtual mwSize get_m (void) const = 0;
206 
207   virtual mwSize get_n (void) const = 0;
208 
209   virtual mwSize * get_dimensions (void) const = 0;
210 
211   virtual mwSize get_number_of_dimensions (void) const = 0;
212 
213   virtual void set_m (mwSize m) = 0;
214 
215   virtual void set_n (mwSize n) = 0;
216 
217   virtual int set_dimensions (mwSize *dims_arg, mwSize ndims_arg) = 0;
218 
219   virtual mwSize get_number_of_elements (void) const = 0;
220 
221   virtual int isempty (void) const = 0;
222 
223   virtual bool is_scalar (void) const = 0;
224 
225   virtual mxClassID get_class_id (void) const = 0;
226 
227   virtual const char * get_class_name (void) const = 0;
228 
229   virtual void set_class_name (const char *name_arg) = 0;
230 
231   // The following functions aren't pure virtual because they are only
232   // valid for one type.  Making them pure virtual would mean that they
233   // have to be implemented for all derived types, and all of those
234   // would need to throw errors instead of just doing it once here.
235 
236   virtual mxArray *
get_property(mwIndex,const char *)237   get_property (mwIndex /*idx*/, const char * /*pname*/) const
238   {
239     return nullptr;
240   }
241 
set_property(mwIndex,const char *,const mxArray *)242   virtual void set_property (mwIndex /*idx*/, const char * /*pname*/,
243                              const mxArray * /*pval*/)
244   {
245     err_invalid_type ();
246   }
247 
get_cell(mwIndex)248   virtual mxArray * get_cell (mwIndex /*idx*/) const
249   {
250     err_invalid_type ();
251   }
252 
253   virtual void set_cell (mwIndex idx, mxArray *val) = 0;
254 
255   virtual double get_scalar (void) const = 0;
256 
257   virtual void * get_data (void) const = 0;
258 
259   virtual void * get_imag_data (void) const = 0;
260 
261   virtual void set_data (void *pr) = 0;
262 
263   virtual void set_imag_data (void *pi) = 0;
264 
265   virtual mwIndex * get_ir (void) const = 0;
266 
267   virtual mwIndex * get_jc (void) const = 0;
268 
269   virtual mwSize get_nzmax (void) const = 0;
270 
271   virtual void set_ir (mwIndex *ir) = 0;
272 
273   virtual void set_jc (mwIndex *jc) = 0;
274 
275   virtual void set_nzmax (mwSize nzmax) = 0;
276 
277   virtual int add_field (const char *key) = 0;
278 
279   virtual void remove_field (int key_num) = 0;
280 
281   virtual mxArray * get_field_by_number (mwIndex index, int key_num) const = 0;
282 
283   virtual void
284   set_field_by_number (mwIndex index, int key_num, mxArray *val) = 0;
285 
286   virtual int get_number_of_fields (void) const = 0;
287 
288   virtual const char * get_field_name_by_number (int key_num) const = 0;
289 
290   virtual int get_field_number (const char *key) const = 0;
291 
292   virtual int get_string (char *buf, mwSize buflen) const = 0;
293 
294   virtual char * array_to_string (void) const = 0;
295 
296   virtual mwIndex calc_single_subscript (mwSize nsubs, mwIndex *subs) const = 0;
297 
298   virtual std::size_t get_element_size (void) const = 0;
299 
mutation_needed(void)300   virtual bool mutation_needed (void) const { return false; }
301 
mutate(void)302   virtual mxArray * mutate (void) const { return nullptr; }
303 
304   virtual octave_value as_octave_value (void) const = 0;
305 
306 protected:
307 
mxArray_base(const mxArray_base &)308   mxArray_base (const mxArray_base&) { }
309 
err_invalid_type(void)310   OCTAVE_NORETURN void err_invalid_type (void) const
311   {
312     error ("invalid type for operation");
313   }
314 };
315 
316 // The main interface class.  The representation can be based on an
317 // octave_value object or a separate object that tries to reproduce
318 // the semantics of mxArray objects in Matlab more directly.
319 
320 class mxArray
321 {
322 public:
323 
324   mxArray (const octave_value& ov);
325 
326   mxArray (mxClassID id, mwSize ndims, const mwSize *dims,
327            mxComplexity flag = mxREAL, bool init = true);
328 
329   mxArray (mxClassID id, const dim_vector& dv, mxComplexity flag = mxREAL);
330 
331   mxArray (mxClassID id, mwSize m, mwSize n,
332            mxComplexity flag = mxREAL, bool init = true);
333 
334   mxArray (mxClassID id, double val);
335 
336   mxArray (mxClassID id, mxLogical val);
337 
338   mxArray (const char *str);
339 
340   mxArray (mwSize m, const char **str);
341 
342   mxArray (mxClassID id, mwSize m, mwSize n, mwSize nzmax,
343            mxComplexity flag = mxREAL);
344 
345   mxArray (mwSize ndims, const mwSize *dims, int num_keys, const char **keys);
346 
347   mxArray (const dim_vector& dv, int num_keys, const char **keys);
348 
349   mxArray (mwSize m, mwSize n, int num_keys, const char **keys);
350 
351   mxArray (mwSize ndims, const mwSize *dims);
352 
353   mxArray (const dim_vector& dv);
354 
355   mxArray (mwSize m, mwSize n);
356 
dup(void)357   mxArray * dup (void) const
358   {
359     mxArray *retval = rep->as_mxArray ();
360 
361     if (retval)
362       retval->set_name (name);
363     else
364       {
365         mxArray_base *new_rep = rep->dup ();
366 
367         retval = new mxArray (new_rep, name);
368       }
369 
370     return retval;
371   }
372 
373   // No copying!
374 
375   mxArray (const mxArray&) = delete;
376 
377   mxArray& operator = (const mxArray&) = delete;
378 
379   ~mxArray (void);
380 
is_octave_value(void)381   bool is_octave_value (void) const { return rep->is_octave_value (); }
382 
iscell(void)383   int iscell (void) const { return rep->iscell (); }
384 
is_char(void)385   int is_char (void) const { return rep->is_char (); }
386 
is_class(const char * name_arg)387   int is_class (const char *name_arg) const { return rep->is_class (name_arg); }
388 
is_complex(void)389   int is_complex (void) const { return rep->is_complex (); }
390 
is_double(void)391   int is_double (void) const { return rep->is_double (); }
392 
is_function_handle(void)393   int is_function_handle (void) const { return rep->is_function_handle (); }
394 
is_int16(void)395   int is_int16 (void) const { return rep->is_int16 (); }
396 
is_int32(void)397   int is_int32 (void) const { return rep->is_int32 (); }
398 
is_int64(void)399   int is_int64 (void) const { return rep->is_int64 (); }
400 
is_int8(void)401   int is_int8 (void) const { return rep->is_int8 (); }
402 
is_logical(void)403   int is_logical (void) const { return rep->is_logical (); }
404 
is_numeric(void)405   int is_numeric (void) const { return rep->is_numeric (); }
406 
is_single(void)407   int is_single (void) const { return rep->is_single (); }
408 
is_sparse(void)409   int is_sparse (void) const { return rep->is_sparse (); }
410 
is_struct(void)411   int is_struct (void) const { return rep->is_struct (); }
412 
is_uint16(void)413   int is_uint16 (void) const { return rep->is_uint16 (); }
414 
is_uint32(void)415   int is_uint32 (void) const { return rep->is_uint32 (); }
416 
is_uint64(void)417   int is_uint64 (void) const { return rep->is_uint64 (); }
418 
is_uint8(void)419   int is_uint8 (void) const { return rep->is_uint8 (); }
420 
is_logical_scalar(void)421   int is_logical_scalar (void) const { return rep->is_logical_scalar (); }
422 
is_logical_scalar_true(void)423   int is_logical_scalar_true (void) const
424   { return rep->is_logical_scalar_true (); }
425 
get_m(void)426   mwSize get_m (void) const { return rep->get_m (); }
427 
get_n(void)428   mwSize get_n (void) const { return rep->get_n (); }
429 
get_dimensions(void)430   mwSize * get_dimensions (void) const { return rep->get_dimensions (); }
431 
get_number_of_dimensions(void)432   mwSize get_number_of_dimensions (void) const
433   { return rep->get_number_of_dimensions (); }
434 
set_m(mwSize m)435   void set_m (mwSize m) { DO_VOID_MUTABLE_METHOD (set_m (m)); }
436 
set_n(mwSize n)437   void set_n (mwSize n) { DO_VOID_MUTABLE_METHOD (set_n (n)); }
438 
set_dimensions(mwSize * dims_arg,mwSize ndims_arg)439   int set_dimensions (mwSize *dims_arg, mwSize ndims_arg)
440   { DO_MUTABLE_METHOD (int, set_dimensions (dims_arg, ndims_arg)); }
441 
get_number_of_elements(void)442   mwSize get_number_of_elements (void) const
443   { return rep->get_number_of_elements (); }
444 
isempty(void)445   int isempty (void) const { return get_number_of_elements () == 0; }
446 
is_scalar(void)447   bool is_scalar (void) const { return rep->is_scalar (); }
448 
get_name(void)449   const char * get_name (void) const { return name; }
450 
451   void set_name (const char *name_arg);
452 
get_class_id(void)453   mxClassID get_class_id (void) const { return rep->get_class_id (); }
454 
get_class_name(void)455   const char * get_class_name (void) const { return rep->get_class_name (); }
456 
get_property(mwIndex idx,const char * pname)457   mxArray * get_property (mwIndex idx, const char *pname) const
458   { return rep->get_property (idx, pname); }
459 
set_property(mwIndex idx,const char * pname,const mxArray * pval)460   void set_property (mwIndex idx, const char *pname, const mxArray *pval)
461   { rep->set_property (idx, pname, pval); }
462 
set_class_name(const char * name_arg)463   void set_class_name (const char *name_arg)
464   { DO_VOID_MUTABLE_METHOD (set_class_name (name_arg)); }
465 
get_cell(mwIndex idx)466   mxArray * get_cell (mwIndex idx) const
467   { DO_MUTABLE_METHOD (mxArray *, get_cell (idx)); }
468 
set_cell(mwIndex idx,mxArray * val)469   void set_cell (mwIndex idx, mxArray *val)
470   { DO_VOID_MUTABLE_METHOD (set_cell (idx, val)); }
471 
get_scalar(void)472   double get_scalar (void) const { return rep->get_scalar (); }
473 
get_data(void)474   void * get_data (void) const { DO_MUTABLE_METHOD (void *, get_data ()); }
475 
get_imag_data(void)476   void * get_imag_data (void) const
477   { DO_MUTABLE_METHOD (void *, get_imag_data ()); }
478 
set_data(void * pr)479   void set_data (void *pr) { DO_VOID_MUTABLE_METHOD (set_data (pr)); }
480 
set_imag_data(void * pi)481   void set_imag_data (void *pi) { DO_VOID_MUTABLE_METHOD (set_imag_data (pi)); }
482 
get_ir(void)483   mwIndex * get_ir (void) const { DO_MUTABLE_METHOD (mwIndex *, get_ir ()); }
484 
get_jc(void)485   mwIndex * get_jc (void) const { DO_MUTABLE_METHOD (mwIndex *, get_jc ()); }
486 
get_nzmax(void)487   mwSize get_nzmax (void) const { return rep->get_nzmax (); }
488 
set_ir(mwIndex * ir)489   void set_ir (mwIndex *ir) { DO_VOID_MUTABLE_METHOD (set_ir (ir)); }
490 
set_jc(mwIndex * jc)491   void set_jc (mwIndex *jc) { DO_VOID_MUTABLE_METHOD (set_jc (jc)); }
492 
set_nzmax(mwSize nzmax)493   void set_nzmax (mwSize nzmax) { DO_VOID_MUTABLE_METHOD (set_nzmax (nzmax)); }
494 
add_field(const char * key)495   int add_field (const char *key) { DO_MUTABLE_METHOD (int, add_field (key)); }
496 
remove_field(int key_num)497   void remove_field (int key_num)
498   { DO_VOID_MUTABLE_METHOD (remove_field (key_num)); }
499 
get_field_by_number(mwIndex index,int key_num)500   mxArray * get_field_by_number (mwIndex index, int key_num) const
501   { DO_MUTABLE_METHOD (mxArray *, get_field_by_number (index, key_num)); }
502 
set_field_by_number(mwIndex index,int key_num,mxArray * val)503   void set_field_by_number (mwIndex index, int key_num, mxArray *val)
504   { DO_VOID_MUTABLE_METHOD (set_field_by_number (index, key_num, val)); }
505 
get_number_of_fields(void)506   int get_number_of_fields (void) const { return rep->get_number_of_fields (); }
507 
get_field_name_by_number(int key_num)508   const char * get_field_name_by_number (int key_num) const
509   { DO_MUTABLE_METHOD (const char*, get_field_name_by_number (key_num)); }
510 
get_field_number(const char * key)511   int get_field_number (const char *key) const
512   { DO_MUTABLE_METHOD (int, get_field_number (key)); }
513 
get_string(char * buf,mwSize buflen)514   int get_string (char *buf, mwSize buflen) const
515   { return rep->get_string (buf, buflen); }
516 
array_to_string(void)517   char * array_to_string (void) const { return rep->array_to_string (); }
518 
calc_single_subscript(mwSize nsubs,mwIndex * subs)519   mwIndex calc_single_subscript (mwSize nsubs, mwIndex *subs) const
520   { return rep->calc_single_subscript (nsubs, subs); }
521 
get_element_size(void)522   std::size_t get_element_size (void) const { return rep->get_element_size (); }
523 
mutation_needed(void)524   bool mutation_needed (void) const { return rep->mutation_needed (); }
525 
mutate(void)526   mxArray * mutate (void) const { return rep->mutate (); }
527 
528   static void * malloc (std::size_t n);
529 
530   static void * calloc (std::size_t n, std::size_t t);
531 
strsave(const char * str)532   static char * strsave (const char *str)
533   {
534     char *retval = nullptr;
535 
536     if (str)
537       {
538         mwSize sz = sizeof (mxChar) * (strlen (str) + 1);
539 
540         retval = static_cast<char *> (mxArray::malloc (sz));
541 
542         if (retval)
543           strcpy (retval, str);
544       }
545 
546     return retval;
547   }
548 
549   static octave_value
550   as_octave_value (const mxArray *ptr, bool null_is_empty = true);
551 
552   octave_value as_octave_value (void) const;
553 
554 private:
555 
556   mutable mxArray_base *rep;
557 
558   char *name;
559 
mxArray(mxArray_base * r,const char * n)560   mxArray (mxArray_base *r, const char *n)
561     : rep (r), name (mxArray::strsave (n)) { }
562 
563   void maybe_mutate (void) const;
564 };
565 
566 #undef DO_MUTABLE_METHOD
567 #undef DO_VOID_MUTABLE_METHOD
568 
569 #endif
570 #endif
571