Mercurial > hg > octave-lyh
comparison libinterp/parse-tree/pt-mat.cc @ 15195:2fc554ffbc28
split libinterp from src
* libinterp: New directory. Move all files from src directory here
except Makefile.am, main.cc, main-cli.cc, mkoctfile.in.cc,
mkoctfilr.in.sh, octave-config.in.cc, octave-config.in.sh.
* libinterp/Makefile.am: New file, extracted from src/Makefile.am.
* src/Makefile.am: Delete everything except targets and definitions
needed to build and link main and utility programs.
* Makefile.am (SUBDIRS): Include libinterp in the list.
* autogen.sh: Run config-module.sh in libinterp/dldfcn directory, not
src/dldfcn directory.
* configure.ac (AC_CONFIG_SRCDIR): Use libinterp/octave.cc, not
src/octave.cc.
(DL_LDFLAGS, LIBOCTINTERP): Use libinterp, not src.
(AC_CONFIG_FILES): Include libinterp/Makefile in the list.
* find-docstring-files.sh: Look in libinterp, not src.
* gui/src/Makefile.am (liboctgui_la_CPPFLAGS): Find header files in
libinterp, not src.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Sat, 18 Aug 2012 16:23:39 -0400 |
parents | src/parse-tree/pt-mat.cc@46b19589b593 |
children | 797ac81586d1 |
comparison
equal
deleted
inserted
replaced
15194:0f0b795044c3 | 15195:2fc554ffbc28 |
---|---|
1 /* | |
2 | |
3 Copyright (C) 1996-2012 John W. Eaton | |
4 | |
5 This file is part of Octave. | |
6 | |
7 Octave is free software; you can redistribute it and/or modify it | |
8 under the terms of the GNU General Public License as published by the | |
9 Free Software Foundation; either version 3 of the License, or (at your | |
10 option) any later version. | |
11 | |
12 Octave is distributed in the hope that it will be useful, but WITHOUT | |
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
15 for more details. | |
16 | |
17 You should have received a copy of the GNU General Public License | |
18 along with Octave; see the file COPYING. If not, see | |
19 <http://www.gnu.org/licenses/>. | |
20 | |
21 */ | |
22 | |
23 #ifdef HAVE_CONFIG_H | |
24 #include <config.h> | |
25 #endif | |
26 | |
27 #include <iostream> | |
28 | |
29 #include "quit.h" | |
30 | |
31 #include "data.h" | |
32 #include "defun.h" | |
33 #include "error.h" | |
34 #include "oct-obj.h" | |
35 #include "pt-arg-list.h" | |
36 #include "pt-bp.h" | |
37 #include "pt-exp.h" | |
38 #include "pt-mat.h" | |
39 #include "pt-walk.h" | |
40 #include "utils.h" | |
41 #include "ov.h" | |
42 #include "variables.h" | |
43 | |
44 #include "ov-cx-mat.h" | |
45 #include "ov-flt-cx-mat.h" | |
46 #include "ov-re-sparse.h" | |
47 #include "ov-cx-sparse.h" | |
48 | |
49 // The character to fill with when creating string arrays. | |
50 char Vstring_fill_char = ' '; | |
51 | |
52 // General matrices. This list type is much more work to handle than | |
53 // constant matrices, but it allows us to construct matrices from | |
54 // other matrices, variables, and functions. | |
55 | |
56 // But first, some internal classes that make our job much easier. | |
57 | |
58 class | |
59 tm_row_const | |
60 { | |
61 private: | |
62 | |
63 class | |
64 tm_row_const_rep : public octave_base_list<octave_value> | |
65 { | |
66 public: | |
67 | |
68 tm_row_const_rep (void) | |
69 : count (1), dv (0, 0), all_str (false), | |
70 all_sq_str (false), all_dq_str (false), | |
71 some_str (false), all_real (false), all_cmplx (false), | |
72 all_mt (true), any_cell (false), any_sparse (false), | |
73 any_class (false), all_1x1 (false), | |
74 first_elem_is_struct (false), class_nm (), ok (false) | |
75 { } | |
76 | |
77 tm_row_const_rep (const tree_argument_list& row) | |
78 : count (1), dv (0, 0), all_str (false), all_sq_str (false), | |
79 some_str (false), all_real (false), all_cmplx (false), | |
80 all_mt (true), any_cell (false), any_sparse (false), | |
81 any_class (false), all_1x1 (! row.empty ()), | |
82 first_elem_is_struct (false), class_nm (), ok (false) | |
83 { init (row); } | |
84 | |
85 ~tm_row_const_rep (void) { } | |
86 | |
87 octave_refcount<int> count; | |
88 | |
89 dim_vector dv; | |
90 | |
91 bool all_str; | |
92 bool all_sq_str; | |
93 bool all_dq_str; | |
94 bool some_str; | |
95 bool all_real; | |
96 bool all_cmplx; | |
97 bool all_mt; | |
98 bool any_cell; | |
99 bool any_sparse; | |
100 bool any_class; | |
101 bool all_1x1; | |
102 bool first_elem_is_struct; | |
103 | |
104 std::string class_nm; | |
105 | |
106 bool ok; | |
107 | |
108 void do_init_element (const octave_value&, bool&); | |
109 | |
110 void init (const tree_argument_list&); | |
111 | |
112 void cellify (void); | |
113 | |
114 private: | |
115 | |
116 tm_row_const_rep (const tm_row_const_rep&); | |
117 | |
118 tm_row_const_rep& operator = (const tm_row_const_rep&); | |
119 | |
120 }; | |
121 | |
122 public: | |
123 | |
124 typedef tm_row_const_rep::iterator iterator; | |
125 typedef tm_row_const_rep::const_iterator const_iterator; | |
126 | |
127 tm_row_const (void) | |
128 : rep (0) { } | |
129 | |
130 tm_row_const (const tree_argument_list& row) | |
131 : rep (new tm_row_const_rep (row)) { } | |
132 | |
133 tm_row_const (const tm_row_const& x) | |
134 : rep (x.rep) | |
135 { | |
136 if (rep) | |
137 rep->count++; | |
138 } | |
139 | |
140 tm_row_const& operator = (const tm_row_const& x) | |
141 { | |
142 if (this != &x && rep != x.rep) | |
143 { | |
144 if (rep && --rep->count == 0) | |
145 delete rep; | |
146 | |
147 rep = x.rep; | |
148 | |
149 if (rep) | |
150 rep->count++; | |
151 } | |
152 | |
153 return *this; | |
154 } | |
155 | |
156 ~tm_row_const (void) | |
157 { | |
158 if (rep && --rep->count == 0) | |
159 delete rep; | |
160 } | |
161 | |
162 octave_idx_type rows (void) { return rep->dv(0); } | |
163 octave_idx_type cols (void) { return rep->dv(1); } | |
164 | |
165 bool empty (void) const { return rep->empty (); } | |
166 | |
167 size_t length (void) const { return rep->length (); } | |
168 | |
169 dim_vector dims (void) { return rep->dv; } | |
170 | |
171 bool all_strings_p (void) const { return rep->all_str; } | |
172 bool all_sq_strings_p (void) const { return rep->all_sq_str; } | |
173 bool all_dq_strings_p (void) const { return rep->all_dq_str; } | |
174 bool some_strings_p (void) const { return rep->some_str; } | |
175 bool all_real_p (void) const { return rep->all_real; } | |
176 bool all_complex_p (void) const { return rep->all_cmplx; } | |
177 bool all_empty_p (void) const { return rep->all_mt; } | |
178 bool any_cell_p (void) const { return rep->any_cell; } | |
179 bool any_sparse_p (void) const { return rep->any_sparse; } | |
180 bool any_class_p (void) const { return rep->any_class; } | |
181 bool all_1x1_p (void) const { return rep->all_1x1; } | |
182 bool first_elem_struct_p (void) const { return rep->first_elem_is_struct; } | |
183 | |
184 std::string class_name (void) const { return rep->class_nm; } | |
185 | |
186 void cellify (void) { rep->cellify (); } | |
187 | |
188 operator bool () const { return (rep && rep->ok); } | |
189 | |
190 iterator begin (void) { return rep->begin (); } | |
191 const_iterator begin (void) const { return rep->begin (); } | |
192 | |
193 iterator end (void) { return rep->end (); } | |
194 const_iterator end (void) const { return rep->end (); } | |
195 | |
196 private: | |
197 | |
198 tm_row_const_rep *rep; | |
199 }; | |
200 | |
201 std::string | |
202 get_concat_class (const std::string& c1, const std::string& c2) | |
203 { | |
204 std::string retval = octave_base_value::static_class_name (); | |
205 | |
206 if (c1 == c2) | |
207 retval = c1; | |
208 else if (c1.empty ()) | |
209 retval = c2; | |
210 else if (c2.empty ()) | |
211 retval = c1; | |
212 else if (c1 == "class" || c2 == "class") | |
213 retval = "class"; | |
214 else | |
215 { | |
216 bool c1_is_int = (c1 == "int8" || c1 == "uint8" | |
217 || c1 == "int16" || c1 == "uint16" | |
218 || c1 == "int32" || c1 == "uint32" | |
219 || c1 == "int64" || c1 == "uint64"); | |
220 bool c2_is_int = (c2 == "int8" || c2 == "uint8" | |
221 || c2 == "int16" || c2 == "uint16" | |
222 || c2 == "int32" || c2 == "uint32" | |
223 || c2 == "int64" || c2 == "uint64"); | |
224 | |
225 bool c1_is_char = (c1 == "char"); | |
226 bool c2_is_char = (c2 == "char"); | |
227 | |
228 bool c1_is_double = (c1 == "double"); | |
229 bool c2_is_double = (c2 == "double"); | |
230 | |
231 bool c1_is_single = (c1 == "single"); | |
232 bool c2_is_single = (c2 == "single"); | |
233 | |
234 bool c1_is_logical = (c1 == "logical"); | |
235 bool c2_is_logical = (c2 == "logical"); | |
236 | |
237 bool c1_is_built_in_type | |
238 = (c1_is_int || c1_is_char || c1_is_double || c1_is_single | |
239 || c1_is_logical); | |
240 | |
241 bool c2_is_built_in_type | |
242 = (c2_is_int || c2_is_char || c2_is_double || c2_is_single | |
243 || c2_is_logical); | |
244 | |
245 // Order is important here... | |
246 | |
247 if (c1 == "struct" && c2 == c1) | |
248 retval = c1; | |
249 else if (c1 == "cell" || c2 == "cell") | |
250 retval = "cell"; | |
251 else if (c1_is_char && c2_is_built_in_type) | |
252 retval = c1; | |
253 else if (c2_is_char && c1_is_built_in_type) | |
254 retval = c2; | |
255 else if (c1_is_int && c2_is_built_in_type) | |
256 retval = c1; | |
257 else if (c2_is_int && c1_is_built_in_type) | |
258 retval = c2; | |
259 else if (c1_is_single && c2_is_built_in_type) | |
260 retval = c1; | |
261 else if (c2_is_single && c1_is_built_in_type) | |
262 retval = c2; | |
263 else if (c1_is_double && c2_is_built_in_type) | |
264 retval = c1; | |
265 else if (c2_is_double && c1_is_built_in_type) | |
266 retval = c2; | |
267 else if (c1_is_logical && c2_is_logical) | |
268 retval = c1; | |
269 } | |
270 | |
271 return retval; | |
272 } | |
273 | |
274 static void | |
275 eval_error (const char *msg, const dim_vector& x, const dim_vector& y) | |
276 { | |
277 ::error ("%s (%s vs %s)", msg, x.str ().c_str (), y.str ().c_str ()); | |
278 } | |
279 | |
280 void | |
281 tm_row_const::tm_row_const_rep::do_init_element (const octave_value& val, | |
282 bool& first_elem) | |
283 { | |
284 std::string this_elt_class_nm | |
285 = val.is_object () ? std::string ("class") : val.class_name (); | |
286 | |
287 class_nm = get_concat_class (class_nm, this_elt_class_nm); | |
288 | |
289 dim_vector this_elt_dv = val.dims (); | |
290 | |
291 if (! this_elt_dv.zero_by_zero ()) | |
292 { | |
293 all_mt = false; | |
294 | |
295 if (first_elem) | |
296 { | |
297 if (val.is_map ()) | |
298 first_elem_is_struct = true; | |
299 | |
300 first_elem = false; | |
301 } | |
302 } | |
303 | |
304 append (val); | |
305 | |
306 if (all_str && ! val.is_string ()) | |
307 all_str = false; | |
308 | |
309 if (all_sq_str && ! val.is_sq_string ()) | |
310 all_sq_str = false; | |
311 | |
312 if (all_dq_str && ! val.is_dq_string ()) | |
313 all_dq_str = false; | |
314 | |
315 if (! some_str && val.is_string ()) | |
316 some_str = true; | |
317 | |
318 if (all_real && ! val.is_real_type ()) | |
319 all_real = false; | |
320 | |
321 if (all_cmplx && ! (val.is_complex_type () || val.is_real_type ())) | |
322 all_cmplx = false; | |
323 | |
324 if (!any_cell && val.is_cell ()) | |
325 any_cell = true; | |
326 | |
327 if (!any_sparse && val.is_sparse_type ()) | |
328 any_sparse = true; | |
329 | |
330 if (!any_class && val.is_object ()) | |
331 any_class = true; | |
332 | |
333 all_1x1 = all_1x1 && val.numel () == 1; | |
334 } | |
335 | |
336 void | |
337 tm_row_const::tm_row_const_rep::init (const tree_argument_list& row) | |
338 { | |
339 all_str = true; | |
340 all_sq_str = true; | |
341 all_dq_str = true; | |
342 all_real = true; | |
343 all_cmplx = true; | |
344 any_cell = false; | |
345 any_sparse = false; | |
346 any_class = false; | |
347 | |
348 bool first_elem = true; | |
349 | |
350 for (tree_argument_list::const_iterator p = row.begin (); | |
351 p != row.end (); | |
352 p++) | |
353 { | |
354 octave_quit (); | |
355 | |
356 tree_expression *elt = *p; | |
357 | |
358 octave_value tmp = elt->rvalue1 (); | |
359 | |
360 if (error_state || tmp.is_undefined ()) | |
361 { | |
362 ok = ! error_state; | |
363 return; | |
364 } | |
365 else | |
366 { | |
367 if (tmp.is_cs_list ()) | |
368 { | |
369 octave_value_list tlst = tmp.list_value (); | |
370 | |
371 for (octave_idx_type i = 0; i < tlst.length (); i++) | |
372 { | |
373 octave_quit (); | |
374 | |
375 do_init_element (tlst(i), first_elem); | |
376 } | |
377 } | |
378 else | |
379 do_init_element (tmp, first_elem); | |
380 } | |
381 } | |
382 | |
383 if (any_cell && ! any_class && ! first_elem_is_struct) | |
384 cellify (); | |
385 | |
386 first_elem = true; | |
387 | |
388 for (iterator p = begin (); p != end (); p++) | |
389 { | |
390 octave_quit (); | |
391 | |
392 octave_value val = *p; | |
393 | |
394 dim_vector this_elt_dv = val.dims (); | |
395 | |
396 if (! this_elt_dv.zero_by_zero ()) | |
397 { | |
398 all_mt = false; | |
399 | |
400 if (first_elem) | |
401 { | |
402 first_elem = false; | |
403 dv = this_elt_dv; | |
404 } | |
405 else if (! dv.hvcat (this_elt_dv, 1)) | |
406 { | |
407 eval_error ("horizontal dimensions mismatch", dv, this_elt_dv); | |
408 break; | |
409 } | |
410 } | |
411 } | |
412 | |
413 ok = ! error_state; | |
414 } | |
415 | |
416 void | |
417 tm_row_const::tm_row_const_rep::cellify (void) | |
418 { | |
419 bool elt_changed = false; | |
420 | |
421 for (iterator p = begin (); p != end (); p++) | |
422 { | |
423 octave_quit (); | |
424 | |
425 if (! p->is_cell ()) | |
426 { | |
427 elt_changed = true; | |
428 | |
429 *p = Cell (*p); | |
430 } | |
431 } | |
432 | |
433 if (elt_changed) | |
434 { | |
435 bool first_elem = true; | |
436 | |
437 for (iterator p = begin (); p != end (); p++) | |
438 { | |
439 octave_quit (); | |
440 | |
441 octave_value val = *p; | |
442 | |
443 dim_vector this_elt_dv = val.dims (); | |
444 | |
445 if (! this_elt_dv.zero_by_zero ()) | |
446 { | |
447 if (first_elem) | |
448 { | |
449 first_elem = false; | |
450 dv = this_elt_dv; | |
451 } | |
452 else if (! dv.hvcat (this_elt_dv, 1)) | |
453 { | |
454 eval_error ("horizontal dimensions mismatch", dv, this_elt_dv); | |
455 break; | |
456 } | |
457 } | |
458 } | |
459 } | |
460 } | |
461 | |
462 class | |
463 tm_const : public octave_base_list<tm_row_const> | |
464 { | |
465 public: | |
466 | |
467 tm_const (const tree_matrix& tm) | |
468 : dv (0, 0), all_str (false), all_sq_str (false), all_dq_str (false), | |
469 some_str (false), all_real (false), all_cmplx (false), | |
470 all_mt (true), any_cell (false), any_sparse (false), | |
471 any_class (false), class_nm (), ok (false) | |
472 { init (tm); } | |
473 | |
474 ~tm_const (void) { } | |
475 | |
476 octave_idx_type rows (void) const { return dv.elem (0); } | |
477 octave_idx_type cols (void) const { return dv.elem (1); } | |
478 | |
479 dim_vector dims (void) const { return dv; } | |
480 | |
481 bool all_strings_p (void) const { return all_str; } | |
482 bool all_sq_strings_p (void) const { return all_sq_str; } | |
483 bool all_dq_strings_p (void) const { return all_dq_str; } | |
484 bool some_strings_p (void) const { return some_str; } | |
485 bool all_real_p (void) const { return all_real; } | |
486 bool all_complex_p (void) const { return all_cmplx; } | |
487 bool all_empty_p (void) const { return all_mt; } | |
488 bool any_cell_p (void) const { return any_cell; } | |
489 bool any_sparse_p (void) const { return any_sparse; } | |
490 bool any_class_p (void) const { return any_class; } | |
491 bool all_1x1_p (void) const { return all_1x1; } | |
492 | |
493 std::string class_name (void) const { return class_nm; } | |
494 | |
495 operator bool () const { return ok; } | |
496 | |
497 private: | |
498 | |
499 dim_vector dv; | |
500 | |
501 bool all_str; | |
502 bool all_sq_str; | |
503 bool all_dq_str; | |
504 bool some_str; | |
505 bool all_real; | |
506 bool all_cmplx; | |
507 bool all_mt; | |
508 bool any_cell; | |
509 bool any_sparse; | |
510 bool any_class; | |
511 bool all_1x1; | |
512 | |
513 std::string class_nm; | |
514 | |
515 bool ok; | |
516 | |
517 tm_const (void); | |
518 | |
519 tm_const (const tm_const&); | |
520 | |
521 tm_const& operator = (const tm_const&); | |
522 | |
523 void init (const tree_matrix& tm); | |
524 }; | |
525 | |
526 void | |
527 tm_const::init (const tree_matrix& tm) | |
528 { | |
529 all_str = true; | |
530 all_sq_str = true; | |
531 all_dq_str = true; | |
532 all_real = true; | |
533 all_cmplx = true; | |
534 any_cell = false; | |
535 any_sparse = false; | |
536 any_class = false; | |
537 all_1x1 = ! tm.empty (); | |
538 | |
539 bool first_elem = true; | |
540 bool first_elem_is_struct = false; | |
541 | |
542 // Just eval and figure out if what we have is complex or all | |
543 // strings. We can't check columns until we know that this is a | |
544 // numeric matrix -- collections of strings can have elements of | |
545 // different lengths. | |
546 | |
547 for (tree_matrix::const_iterator p = tm.begin (); p != tm.end (); p++) | |
548 { | |
549 octave_quit (); | |
550 | |
551 tree_argument_list *elt = *p; | |
552 | |
553 tm_row_const tmp (*elt); | |
554 | |
555 if (first_elem) | |
556 { | |
557 first_elem_is_struct = tmp.first_elem_struct_p (); | |
558 | |
559 first_elem = false; | |
560 } | |
561 | |
562 if (tmp && ! tmp.empty ()) | |
563 { | |
564 if (all_str && ! tmp.all_strings_p ()) | |
565 all_str = false; | |
566 | |
567 if (all_sq_str && ! tmp.all_sq_strings_p ()) | |
568 all_sq_str = false; | |
569 | |
570 if (all_dq_str && ! tmp.all_dq_strings_p ()) | |
571 all_dq_str = false; | |
572 | |
573 if (! some_str && tmp.some_strings_p ()) | |
574 some_str = true; | |
575 | |
576 if (all_real && ! tmp.all_real_p ()) | |
577 all_real = false; | |
578 | |
579 if (all_cmplx && ! tmp.all_complex_p ()) | |
580 all_cmplx = false; | |
581 | |
582 if (all_mt && ! tmp.all_empty_p ()) | |
583 all_mt = false; | |
584 | |
585 if (!any_cell && tmp.any_cell_p ()) | |
586 any_cell = true; | |
587 | |
588 if (!any_sparse && tmp.any_sparse_p ()) | |
589 any_sparse = true; | |
590 | |
591 if (!any_class && tmp.any_class_p ()) | |
592 any_class = true; | |
593 | |
594 all_1x1 = all_1x1 && tmp.all_1x1_p (); | |
595 | |
596 append (tmp); | |
597 } | |
598 else | |
599 break; | |
600 } | |
601 | |
602 if (! error_state) | |
603 { | |
604 if (any_cell && ! any_class && ! first_elem_is_struct) | |
605 { | |
606 for (iterator q = begin (); q != end (); q++) | |
607 { | |
608 octave_quit (); | |
609 | |
610 q->cellify (); | |
611 } | |
612 } | |
613 | |
614 first_elem = true; | |
615 | |
616 for (iterator q = begin (); q != end (); q++) | |
617 { | |
618 octave_quit (); | |
619 | |
620 tm_row_const elt = *q; | |
621 | |
622 octave_idx_type this_elt_nr = elt.rows (); | |
623 octave_idx_type this_elt_nc = elt.cols (); | |
624 | |
625 std::string this_elt_class_nm = elt.class_name (); | |
626 class_nm = get_concat_class (class_nm, this_elt_class_nm); | |
627 | |
628 dim_vector this_elt_dv = elt.dims (); | |
629 | |
630 all_mt = false; | |
631 | |
632 if (first_elem) | |
633 { | |
634 first_elem = false; | |
635 | |
636 dv = this_elt_dv; | |
637 } | |
638 else if (all_str && dv.length () == 2 | |
639 && this_elt_dv.length () == 2) | |
640 { | |
641 // FIXME: this is Octave's specialty. Character matrices allow | |
642 // rows of unequal length. | |
643 if (this_elt_nc > cols ()) | |
644 dv(1) = this_elt_nc; | |
645 dv(0) += this_elt_nr; | |
646 } | |
647 else if (! dv.hvcat (this_elt_dv, 0)) | |
648 { | |
649 eval_error ("vertical dimensions mismatch", dv, this_elt_dv); | |
650 return; | |
651 } | |
652 } | |
653 } | |
654 | |
655 ok = ! error_state; | |
656 } | |
657 | |
658 tree_matrix::~tree_matrix (void) | |
659 { | |
660 while (! empty ()) | |
661 { | |
662 iterator p = begin (); | |
663 delete *p; | |
664 erase (p); | |
665 } | |
666 } | |
667 | |
668 bool | |
669 tree_matrix::has_magic_end (void) const | |
670 { | |
671 for (const_iterator p = begin (); p != end (); p++) | |
672 { | |
673 octave_quit (); | |
674 | |
675 tree_argument_list *elt = *p; | |
676 | |
677 if (elt && elt->has_magic_end ()) | |
678 return true; | |
679 } | |
680 | |
681 return false; | |
682 } | |
683 | |
684 bool | |
685 tree_matrix::all_elements_are_constant (void) const | |
686 { | |
687 for (const_iterator p = begin (); p != end (); p++) | |
688 { | |
689 octave_quit (); | |
690 | |
691 tree_argument_list *elt = *p; | |
692 | |
693 if (! elt->all_elements_are_constant ()) | |
694 return false; | |
695 } | |
696 | |
697 return true; | |
698 } | |
699 | |
700 octave_value_list | |
701 tree_matrix::rvalue (int nargout) | |
702 { | |
703 octave_value_list retval; | |
704 | |
705 if (nargout > 1) | |
706 error ("invalid number of output arguments for matrix list"); | |
707 else | |
708 retval = rvalue1 (nargout); | |
709 | |
710 return retval; | |
711 } | |
712 | |
713 void | |
714 maybe_warn_string_concat (bool all_dq_strings_p, bool all_sq_strings_p) | |
715 { | |
716 if (! (all_dq_strings_p || all_sq_strings_p)) | |
717 warning_with_id ("Octave:mixed-string-concat", | |
718 "concatenation of different character string types may have unintended consequences"); | |
719 } | |
720 | |
721 template<class TYPE, class T> | |
722 static void | |
723 single_type_concat (Array<T>& result, | |
724 tm_const& tmp) | |
725 { | |
726 octave_idx_type r = 0, c = 0; | |
727 | |
728 for (tm_const::iterator p = tmp.begin (); p != tmp.end (); p++) | |
729 { | |
730 tm_row_const row = *p; | |
731 // Skip empty arrays to allow looser rules. | |
732 if (row.dims ().any_zero ()) | |
733 continue; | |
734 | |
735 for (tm_row_const::iterator q = row.begin (); | |
736 q != row.end (); | |
737 q++) | |
738 { | |
739 octave_quit (); | |
740 | |
741 TYPE ra = octave_value_extract<TYPE> (*q); | |
742 | |
743 // Skip empty arrays to allow looser rules. | |
744 if (! error_state) | |
745 { | |
746 if (! ra.is_empty ()) | |
747 { | |
748 result.insert (ra, r, c); | |
749 | |
750 if (! error_state) | |
751 c += ra.columns (); | |
752 else | |
753 return; | |
754 } | |
755 } | |
756 else | |
757 return; | |
758 } | |
759 | |
760 r += row.rows (); | |
761 c = 0; | |
762 } | |
763 } | |
764 | |
765 template<class TYPE, class T> | |
766 static void | |
767 single_type_concat (Array<T>& result, | |
768 const dim_vector& dv, | |
769 tm_const& tmp) | |
770 { | |
771 if (dv.any_zero ()) | |
772 { | |
773 result = Array<T> (dv); | |
774 return; | |
775 } | |
776 | |
777 if (tmp.length () == 1) | |
778 { | |
779 // If possible, forward the operation to liboctave. | |
780 // Single row. | |
781 tm_row_const& row = tmp.front (); | |
782 if (! (equal_types<T, char>::value || equal_types<T, octave_value>::value) | |
783 && row.all_1x1_p ()) | |
784 { | |
785 // Optimize all scalars case. | |
786 result.clear (dv); | |
787 assert (static_cast<size_t> (result.numel ()) == row.length ()); | |
788 octave_idx_type i = 0; | |
789 for (tm_row_const::iterator q = row.begin (); | |
790 q != row.end () && ! error_state; q++) | |
791 result(i++) = octave_value_extract<T> (*q); | |
792 | |
793 return; | |
794 } | |
795 | |
796 octave_idx_type ncols = row.length (), i = 0; | |
797 OCTAVE_LOCAL_BUFFER (Array<T>, array_list, ncols); | |
798 | |
799 for (tm_row_const::iterator q = row.begin (); | |
800 q != row.end () && ! error_state; | |
801 q++) | |
802 { | |
803 octave_quit (); | |
804 | |
805 array_list[i] = octave_value_extract<TYPE> (*q); | |
806 i++; | |
807 } | |
808 | |
809 if (! error_state) | |
810 result = Array<T>::cat (-2, ncols, array_list); | |
811 } | |
812 else | |
813 { | |
814 result = Array<T> (dv); | |
815 single_type_concat<TYPE> (result, tmp); | |
816 } | |
817 } | |
818 | |
819 template<class TYPE, class T> | |
820 static void | |
821 single_type_concat (Sparse<T>& result, | |
822 const dim_vector& dv, | |
823 tm_const& tmp) | |
824 { | |
825 if (dv.any_zero ()) | |
826 { | |
827 result = Sparse<T> (dv); | |
828 return; | |
829 } | |
830 | |
831 // Sparse matrices require preallocation for efficient indexing; besides, | |
832 // only horizontal concatenation can be efficiently handled by indexing. | |
833 // So we just cat all rows through liboctave, then cat the final column. | |
834 octave_idx_type nrows = tmp.length (), j = 0; | |
835 OCTAVE_LOCAL_BUFFER (Sparse<T>, sparse_row_list, nrows); | |
836 for (tm_const::iterator p = tmp.begin (); p != tmp.end (); p++) | |
837 { | |
838 tm_row_const row = *p; | |
839 octave_idx_type ncols = row.length (), i = 0; | |
840 OCTAVE_LOCAL_BUFFER (Sparse<T>, sparse_list, ncols); | |
841 | |
842 for (tm_row_const::iterator q = row.begin (); | |
843 q != row.end () && ! error_state; | |
844 q++) | |
845 { | |
846 octave_quit (); | |
847 | |
848 sparse_list[i] = octave_value_extract<TYPE> (*q); | |
849 i++; | |
850 } | |
851 | |
852 Sparse<T> stmp = Sparse<T>::cat (-2, ncols, sparse_list); | |
853 sparse_row_list[j] = stmp; | |
854 j++; | |
855 } | |
856 | |
857 result = Sparse<T>::cat (-1, nrows, sparse_row_list); | |
858 } | |
859 | |
860 template<class MAP> | |
861 static void | |
862 single_type_concat (octave_map& result, | |
863 const dim_vector& dv, | |
864 tm_const& tmp) | |
865 { | |
866 if (dv.any_zero ()) | |
867 { | |
868 result = octave_map (dv); | |
869 return; | |
870 } | |
871 | |
872 octave_idx_type nrows = tmp.length (), j = 0; | |
873 OCTAVE_LOCAL_BUFFER (octave_map, map_row_list, nrows); | |
874 for (tm_const::iterator p = tmp.begin (); p != tmp.end (); p++) | |
875 { | |
876 tm_row_const row = *p; | |
877 octave_idx_type ncols = row.length (), i = 0; | |
878 OCTAVE_LOCAL_BUFFER (MAP, map_list, ncols); | |
879 | |
880 for (tm_row_const::iterator q = row.begin (); | |
881 q != row.end () && ! error_state; | |
882 q++) | |
883 { | |
884 octave_quit (); | |
885 | |
886 map_list[i] = octave_value_extract<MAP> (*q); | |
887 i++; | |
888 } | |
889 | |
890 octave_map mtmp = octave_map::cat (-2, ncols, map_list); | |
891 map_row_list[j] = mtmp; | |
892 j++; | |
893 } | |
894 | |
895 result = octave_map::cat (-1, nrows, map_row_list); | |
896 } | |
897 | |
898 template<class TYPE> | |
899 static octave_value | |
900 do_single_type_concat (const dim_vector& dv, | |
901 tm_const& tmp) | |
902 { | |
903 TYPE result; | |
904 | |
905 single_type_concat<TYPE> (result, dv, tmp); | |
906 | |
907 return result; | |
908 } | |
909 | |
910 template<> | |
911 octave_value | |
912 do_single_type_concat<octave_map> (const dim_vector& dv, | |
913 tm_const& tmp) | |
914 { | |
915 octave_map result; | |
916 | |
917 if (tmp.all_1x1_p ()) | |
918 single_type_concat<octave_scalar_map> (result, dv, tmp); | |
919 else | |
920 single_type_concat<octave_map> (result, dv, tmp); | |
921 | |
922 return result; | |
923 } | |
924 | |
925 static octave_value | |
926 do_class_concat (tm_const& tmc) | |
927 { | |
928 octave_value retval; | |
929 | |
930 octave_value_list rows (tmc.length (), octave_value ()); | |
931 | |
932 octave_idx_type j = 0; | |
933 for (tm_const::iterator p = tmc.begin (); p != tmc.end (); p++) | |
934 { | |
935 octave_quit (); | |
936 | |
937 tm_row_const tmrc = *p; | |
938 | |
939 if (tmrc.length () == 1) | |
940 rows(j++) = *(tmrc.begin ()); | |
941 else | |
942 { | |
943 octave_value_list row (tmrc.length (), octave_value ()); | |
944 | |
945 octave_idx_type i = 0; | |
946 for (tm_row_const::iterator q = tmrc.begin (); q != tmrc.end (); q++) | |
947 row(i++) = *q; | |
948 | |
949 rows(j++) = do_class_concat (row, "horzcat", 1); | |
950 } | |
951 } | |
952 | |
953 if (! error_state) | |
954 { | |
955 if (rows.length () == 1) | |
956 retval = rows(0); | |
957 else | |
958 retval = do_class_concat (rows, "vertcat", 0); | |
959 } | |
960 | |
961 return retval; | |
962 } | |
963 | |
964 octave_value | |
965 tree_matrix::rvalue1 (int) | |
966 { | |
967 octave_value retval = Matrix (); | |
968 | |
969 bool all_sq_strings_p = false; | |
970 bool all_dq_strings_p = false; | |
971 bool all_empty_p = false; | |
972 bool all_real_p = false; | |
973 bool any_sparse_p = false; | |
974 bool any_class_p = false; | |
975 bool frc_str_conv = false; | |
976 | |
977 tm_const tmp (*this); | |
978 | |
979 if (tmp && ! tmp.empty ()) | |
980 { | |
981 dim_vector dv = tmp.dims (); | |
982 all_sq_strings_p = tmp.all_sq_strings_p (); | |
983 all_dq_strings_p = tmp.all_dq_strings_p (); | |
984 all_empty_p = tmp.all_empty_p (); | |
985 all_real_p = tmp.all_real_p (); | |
986 any_sparse_p = tmp.any_sparse_p (); | |
987 any_class_p = tmp.any_class_p (); | |
988 frc_str_conv = tmp.some_strings_p (); | |
989 | |
990 // Try to speed up the common cases. | |
991 | |
992 std::string result_type = tmp.class_name (); | |
993 | |
994 if (any_class_p) | |
995 { | |
996 retval = do_class_concat (tmp); | |
997 } | |
998 else if (result_type == "double") | |
999 { | |
1000 if (any_sparse_p) | |
1001 { | |
1002 if (all_real_p) | |
1003 retval = do_single_type_concat<SparseMatrix> (dv, tmp); | |
1004 else | |
1005 retval = do_single_type_concat<SparseComplexMatrix> (dv, tmp); | |
1006 } | |
1007 else | |
1008 { | |
1009 if (all_real_p) | |
1010 retval = do_single_type_concat<NDArray> (dv, tmp); | |
1011 else | |
1012 retval = do_single_type_concat<ComplexNDArray> (dv, tmp); | |
1013 } | |
1014 } | |
1015 else if (result_type == "single") | |
1016 { | |
1017 if (all_real_p) | |
1018 retval = do_single_type_concat<FloatNDArray> (dv, tmp); | |
1019 else | |
1020 retval = do_single_type_concat<FloatComplexNDArray> (dv, tmp); | |
1021 } | |
1022 else if (result_type == "char") | |
1023 { | |
1024 char type = all_dq_strings_p ? '"' : '\''; | |
1025 | |
1026 maybe_warn_string_concat (all_dq_strings_p, all_sq_strings_p); | |
1027 | |
1028 charNDArray result (dv, Vstring_fill_char); | |
1029 | |
1030 single_type_concat<charNDArray> (result, tmp); | |
1031 | |
1032 retval = octave_value (result, type); | |
1033 } | |
1034 else if (result_type == "logical") | |
1035 { | |
1036 if (any_sparse_p) | |
1037 retval = do_single_type_concat<SparseBoolMatrix> (dv, tmp); | |
1038 else | |
1039 retval = do_single_type_concat<boolNDArray> (dv, tmp); | |
1040 } | |
1041 else if (result_type == "int8") | |
1042 retval = do_single_type_concat<int8NDArray> (dv, tmp); | |
1043 else if (result_type == "int16") | |
1044 retval = do_single_type_concat<int16NDArray> (dv, tmp); | |
1045 else if (result_type == "int32") | |
1046 retval = do_single_type_concat<int32NDArray> (dv, tmp); | |
1047 else if (result_type == "int64") | |
1048 retval = do_single_type_concat<int64NDArray> (dv, tmp); | |
1049 else if (result_type == "uint8") | |
1050 retval = do_single_type_concat<uint8NDArray> (dv, tmp); | |
1051 else if (result_type == "uint16") | |
1052 retval = do_single_type_concat<uint16NDArray> (dv, tmp); | |
1053 else if (result_type == "uint32") | |
1054 retval = do_single_type_concat<uint32NDArray> (dv, tmp); | |
1055 else if (result_type == "uint64") | |
1056 retval = do_single_type_concat<uint64NDArray> (dv, tmp); | |
1057 else if (result_type == "cell") | |
1058 retval = do_single_type_concat<Cell> (dv, tmp); | |
1059 else if (result_type == "struct") | |
1060 retval = do_single_type_concat<octave_map> (dv, tmp); | |
1061 else | |
1062 { | |
1063 // The line below might seem crazy, since we take a copy of | |
1064 // the first argument, resize it to be empty and then resize | |
1065 // it to be full. This is done since it means that there is | |
1066 // no recopying of data, as would happen if we used a single | |
1067 // resize. It should be noted that resize operation is also | |
1068 // significantly slower than the do_cat_op function, so it | |
1069 // makes sense to have an empty matrix and copy all data. | |
1070 // | |
1071 // We might also start with a empty octave_value using | |
1072 // | |
1073 // ctmp = octave_value_typeinfo::lookup_type | |
1074 // (tmp.begin() -> begin() -> type_name()); | |
1075 // | |
1076 // and then directly resize. However, for some types there | |
1077 // might be some additional setup needed, and so this should | |
1078 // be avoided. | |
1079 | |
1080 octave_value ctmp; | |
1081 | |
1082 // Find the first non-empty object | |
1083 | |
1084 if (any_sparse_p) | |
1085 { | |
1086 // Start with sparse matrix to avoid issues memory issues | |
1087 // with things like [ones(1,4),sprandn(1e8,4,1e-4)] | |
1088 if (all_real_p) | |
1089 ctmp = octave_sparse_matrix ().resize (dv); | |
1090 else | |
1091 ctmp = octave_sparse_complex_matrix ().resize (dv); | |
1092 } | |
1093 else | |
1094 { | |
1095 for (tm_const::iterator p = tmp.begin (); p != tmp.end (); p++) | |
1096 { | |
1097 octave_quit (); | |
1098 | |
1099 tm_row_const row = *p; | |
1100 | |
1101 for (tm_row_const::iterator q = row.begin (); | |
1102 q != row.end (); q++) | |
1103 { | |
1104 octave_quit (); | |
1105 | |
1106 ctmp = *q; | |
1107 | |
1108 if (! ctmp.all_zero_dims ()) | |
1109 goto found_non_empty; | |
1110 } | |
1111 } | |
1112 | |
1113 ctmp = (*(tmp.begin () -> begin ())); | |
1114 | |
1115 found_non_empty: | |
1116 | |
1117 if (! all_empty_p) | |
1118 ctmp = ctmp.resize (dim_vector (0,0)).resize (dv); | |
1119 } | |
1120 | |
1121 if (! error_state) | |
1122 { | |
1123 // Now, extract the values from the individual elements and | |
1124 // insert them in the result matrix. | |
1125 | |
1126 int dv_len = dv.length (); | |
1127 octave_idx_type ntmp = dv_len > 1 ? dv_len : 2; | |
1128 Array<octave_idx_type> ra_idx (dim_vector (ntmp, 1), 0); | |
1129 | |
1130 for (tm_const::iterator p = tmp.begin (); p != tmp.end (); p++) | |
1131 { | |
1132 octave_quit (); | |
1133 | |
1134 tm_row_const row = *p; | |
1135 | |
1136 for (tm_row_const::iterator q = row.begin (); | |
1137 q != row.end (); | |
1138 q++) | |
1139 { | |
1140 octave_quit (); | |
1141 | |
1142 octave_value elt = *q; | |
1143 | |
1144 if (elt.is_empty ()) | |
1145 continue; | |
1146 | |
1147 ctmp = do_cat_op (ctmp, elt, ra_idx); | |
1148 | |
1149 if (error_state) | |
1150 goto done; | |
1151 | |
1152 ra_idx (1) += elt.columns (); | |
1153 } | |
1154 | |
1155 ra_idx (0) += row.rows (); | |
1156 ra_idx (1) = 0; | |
1157 } | |
1158 | |
1159 retval = ctmp; | |
1160 | |
1161 if (frc_str_conv && ! retval.is_string ()) | |
1162 retval = retval.convert_to_str (); | |
1163 } | |
1164 } | |
1165 } | |
1166 | |
1167 done: | |
1168 return retval; | |
1169 } | |
1170 | |
1171 tree_expression * | |
1172 tree_matrix::dup (symbol_table::scope_id scope, | |
1173 symbol_table::context_id context) const | |
1174 { | |
1175 tree_matrix *new_matrix = new tree_matrix (0, line (), column ()); | |
1176 | |
1177 for (const_iterator p = begin (); p != end (); p++) | |
1178 { | |
1179 const tree_argument_list *elt = *p; | |
1180 | |
1181 new_matrix->append (elt ? elt->dup (scope, context) : 0); | |
1182 } | |
1183 | |
1184 new_matrix->copy_base (*this); | |
1185 | |
1186 return new_matrix; | |
1187 } | |
1188 | |
1189 void | |
1190 tree_matrix::accept (tree_walker& tw) | |
1191 { | |
1192 tw.visit_matrix (*this); | |
1193 } | |
1194 | |
1195 /* | |
1196 ## test concatenation with all zero matrices | |
1197 %!assert ([ "" 65*ones(1,10) ], "AAAAAAAAAA"); | |
1198 %!assert ([ 65*ones(1,10) "" ], "AAAAAAAAAA"); | |
1199 | |
1200 %!test | |
1201 %! c = {"foo"; "bar"; "bazoloa"}; | |
1202 %! assert ([c; "a"; "bc"; "def"], {"foo"; "bar"; "bazoloa"; "a"; "bc"; "def"}); | |
1203 | |
1204 %!assert (class ([int64(1), int64(1)]), "int64") | |
1205 %!assert (class ([int64(1), int32(1)]), "int64") | |
1206 %!assert (class ([int64(1), int16(1)]), "int64") | |
1207 %!assert (class ([int64(1), int8(1)]), "int64") | |
1208 %!assert (class ([int64(1), uint64(1)]), "int64") | |
1209 %!assert (class ([int64(1), uint32(1)]), "int64") | |
1210 %!assert (class ([int64(1), uint16(1)]), "int64") | |
1211 %!assert (class ([int64(1), uint8(1)]), "int64") | |
1212 %!assert (class ([int64(1), single(1)]), "int64") | |
1213 %!assert (class ([int64(1), double(1)]), "int64") | |
1214 %!assert (class ([int64(1), cell(1)]), "cell") | |
1215 %!assert (class ([int64(1), true]), "int64") | |
1216 %!assert (class ([int64(1), "a"]), "char") | |
1217 | |
1218 %!assert (class ([int32(1), int64(1)]), "int32") | |
1219 %!assert (class ([int32(1), int32(1)]), "int32") | |
1220 %!assert (class ([int32(1), int16(1)]), "int32") | |
1221 %!assert (class ([int32(1), int8(1)]), "int32") | |
1222 %!assert (class ([int32(1), uint64(1)]), "int32") | |
1223 %!assert (class ([int32(1), uint32(1)]), "int32") | |
1224 %!assert (class ([int32(1), uint16(1)]), "int32") | |
1225 %!assert (class ([int32(1), uint8(1)]), "int32") | |
1226 %!assert (class ([int32(1), single(1)]), "int32") | |
1227 %!assert (class ([int32(1), double(1)]), "int32") | |
1228 %!assert (class ([int32(1), cell(1)]), "cell") | |
1229 %!assert (class ([int32(1), true]), "int32") | |
1230 %!assert (class ([int32(1), "a"]), "char") | |
1231 | |
1232 %!assert (class ([int16(1), int64(1)]), "int16") | |
1233 %!assert (class ([int16(1), int32(1)]), "int16") | |
1234 %!assert (class ([int16(1), int16(1)]), "int16") | |
1235 %!assert (class ([int16(1), int8(1)]), "int16") | |
1236 %!assert (class ([int16(1), uint64(1)]), "int16") | |
1237 %!assert (class ([int16(1), uint32(1)]), "int16") | |
1238 %!assert (class ([int16(1), uint16(1)]), "int16") | |
1239 %!assert (class ([int16(1), uint8(1)]), "int16") | |
1240 %!assert (class ([int16(1), single(1)]), "int16") | |
1241 %!assert (class ([int16(1), double(1)]), "int16") | |
1242 %!assert (class ([int16(1), cell(1)]), "cell") | |
1243 %!assert (class ([int16(1), true]), "int16") | |
1244 %!assert (class ([int16(1), "a"]), "char") | |
1245 | |
1246 %!assert (class ([int8(1), int64(1)]), "int8") | |
1247 %!assert (class ([int8(1), int32(1)]), "int8") | |
1248 %!assert (class ([int8(1), int16(1)]), "int8") | |
1249 %!assert (class ([int8(1), int8(1)]), "int8") | |
1250 %!assert (class ([int8(1), uint64(1)]), "int8") | |
1251 %!assert (class ([int8(1), uint32(1)]), "int8") | |
1252 %!assert (class ([int8(1), uint16(1)]), "int8") | |
1253 %!assert (class ([int8(1), uint8(1)]), "int8") | |
1254 %!assert (class ([int8(1), single(1)]), "int8") | |
1255 %!assert (class ([int8(1), double(1)]), "int8") | |
1256 %!assert (class ([int8(1), cell(1)]), "cell") | |
1257 %!assert (class ([int8(1), true]), "int8") | |
1258 %!assert (class ([int8(1), "a"]), "char") | |
1259 | |
1260 %!assert (class ([uint64(1), int64(1)]), "uint64") | |
1261 %!assert (class ([uint64(1), int32(1)]), "uint64") | |
1262 %!assert (class ([uint64(1), int16(1)]), "uint64") | |
1263 %!assert (class ([uint64(1), int8(1)]), "uint64") | |
1264 %!assert (class ([uint64(1), uint64(1)]), "uint64") | |
1265 %!assert (class ([uint64(1), uint32(1)]), "uint64") | |
1266 %!assert (class ([uint64(1), uint16(1)]), "uint64") | |
1267 %!assert (class ([uint64(1), uint8(1)]), "uint64") | |
1268 %!assert (class ([uint64(1), single(1)]), "uint64") | |
1269 %!assert (class ([uint64(1), double(1)]), "uint64") | |
1270 %!assert (class ([uint64(1), cell(1)]), "cell") | |
1271 %!assert (class ([uint64(1), true]), "uint64") | |
1272 %!assert (class ([uint64(1), "a"]), "char") | |
1273 | |
1274 %!assert (class ([uint32(1), int64(1)]), "uint32") | |
1275 %!assert (class ([uint32(1), int32(1)]), "uint32") | |
1276 %!assert (class ([uint32(1), int16(1)]), "uint32") | |
1277 %!assert (class ([uint32(1), int8(1)]), "uint32") | |
1278 %!assert (class ([uint32(1), uint64(1)]), "uint32") | |
1279 %!assert (class ([uint32(1), uint32(1)]), "uint32") | |
1280 %!assert (class ([uint32(1), uint16(1)]), "uint32") | |
1281 %!assert (class ([uint32(1), uint8(1)]), "uint32") | |
1282 %!assert (class ([uint32(1), single(1)]), "uint32") | |
1283 %!assert (class ([uint32(1), double(1)]), "uint32") | |
1284 %!assert (class ([uint32(1), cell(1)]), "cell") | |
1285 %!assert (class ([uint32(1), true]), "uint32") | |
1286 %!assert (class ([uint32(1), "a"]), "char") | |
1287 | |
1288 %!assert (class ([uint16(1), int64(1)]), "uint16") | |
1289 %!assert (class ([uint16(1), int32(1)]), "uint16") | |
1290 %!assert (class ([uint16(1), int16(1)]), "uint16") | |
1291 %!assert (class ([uint16(1), int8(1)]), "uint16") | |
1292 %!assert (class ([uint16(1), uint64(1)]), "uint16") | |
1293 %!assert (class ([uint16(1), uint32(1)]), "uint16") | |
1294 %!assert (class ([uint16(1), uint16(1)]), "uint16") | |
1295 %!assert (class ([uint16(1), uint8(1)]), "uint16") | |
1296 %!assert (class ([uint16(1), single(1)]), "uint16") | |
1297 %!assert (class ([uint16(1), double(1)]), "uint16") | |
1298 %!assert (class ([uint16(1), cell(1)]), "cell") | |
1299 %!assert (class ([uint16(1), true]), "uint16") | |
1300 %!assert (class ([uint16(1), "a"]), "char") | |
1301 | |
1302 %!assert (class ([uint8(1), int64(1)]), "uint8") | |
1303 %!assert (class ([uint8(1), int32(1)]), "uint8") | |
1304 %!assert (class ([uint8(1), int16(1)]), "uint8") | |
1305 %!assert (class ([uint8(1), int8(1)]), "uint8") | |
1306 %!assert (class ([uint8(1), uint64(1)]), "uint8") | |
1307 %!assert (class ([uint8(1), uint32(1)]), "uint8") | |
1308 %!assert (class ([uint8(1), uint16(1)]), "uint8") | |
1309 %!assert (class ([uint8(1), uint8(1)]), "uint8") | |
1310 %!assert (class ([uint8(1), single(1)]), "uint8") | |
1311 %!assert (class ([uint8(1), double(1)]), "uint8") | |
1312 %!assert (class ([uint8(1), cell(1)]), "cell") | |
1313 %!assert (class ([uint8(1), true]), "uint8") | |
1314 %!assert (class ([uint8(1), "a"]), "char") | |
1315 | |
1316 %!assert (class ([single(1), int64(1)]), "int64") | |
1317 %!assert (class ([single(1), int32(1)]), "int32") | |
1318 %!assert (class ([single(1), int16(1)]), "int16") | |
1319 %!assert (class ([single(1), int8(1)]), "int8") | |
1320 %!assert (class ([single(1), uint64(1)]), "uint64") | |
1321 %!assert (class ([single(1), uint32(1)]), "uint32") | |
1322 %!assert (class ([single(1), uint16(1)]), "uint16") | |
1323 %!assert (class ([single(1), uint8(1)]), "uint8") | |
1324 %!assert (class ([single(1), single(1)]), "single") | |
1325 %!assert (class ([single(1), double(1)]), "single") | |
1326 %!assert (class ([single(1), cell(1)]), "cell") | |
1327 %!assert (class ([single(1), true]), "single") | |
1328 %!assert (class ([single(1), "a"]), "char") | |
1329 | |
1330 %!assert (class ([double(1), int64(1)]), "int64") | |
1331 %!assert (class ([double(1), int32(1)]), "int32") | |
1332 %!assert (class ([double(1), int16(1)]), "int16") | |
1333 %!assert (class ([double(1), int8(1)]), "int8") | |
1334 %!assert (class ([double(1), uint64(1)]), "uint64") | |
1335 %!assert (class ([double(1), uint32(1)]), "uint32") | |
1336 %!assert (class ([double(1), uint16(1)]), "uint16") | |
1337 %!assert (class ([double(1), uint8(1)]), "uint8") | |
1338 %!assert (class ([double(1), single(1)]), "single") | |
1339 %!assert (class ([double(1), double(1)]), "double") | |
1340 %!assert (class ([double(1), cell(1)]), "cell") | |
1341 %!assert (class ([double(1), true]), "double") | |
1342 %!assert (class ([double(1), "a"]), "char") | |
1343 | |
1344 %!assert (class ([cell(1), int64(1)]), "cell") | |
1345 %!assert (class ([cell(1), int32(1)]), "cell") | |
1346 %!assert (class ([cell(1), int16(1)]), "cell") | |
1347 %!assert (class ([cell(1), int8(1)]), "cell") | |
1348 %!assert (class ([cell(1), uint64(1)]), "cell") | |
1349 %!assert (class ([cell(1), uint32(1)]), "cell") | |
1350 %!assert (class ([cell(1), uint16(1)]), "cell") | |
1351 %!assert (class ([cell(1), uint8(1)]), "cell") | |
1352 %!assert (class ([cell(1), single(1)]), "cell") | |
1353 %!assert (class ([cell(1), double(1)]), "cell") | |
1354 %!assert (class ([cell(1), cell(1)]), "cell") | |
1355 %!assert (class ([cell(1), true]), "cell") | |
1356 %!assert (class ([cell(1), "a"]), "cell") | |
1357 | |
1358 %!assert (class ([true, int64(1)]), "int64") | |
1359 %!assert (class ([true, int32(1)]), "int32") | |
1360 %!assert (class ([true, int16(1)]), "int16") | |
1361 %!assert (class ([true, int8(1)]), "int8") | |
1362 %!assert (class ([true, uint64(1)]), "uint64") | |
1363 %!assert (class ([true, uint32(1)]), "uint32") | |
1364 %!assert (class ([true, uint16(1)]), "uint16") | |
1365 %!assert (class ([true, uint8(1)]), "uint8") | |
1366 %!assert (class ([true, single(1)]), "single") | |
1367 %!assert (class ([true, double(1)]), "double") | |
1368 %!assert (class ([true, cell(1)]), "cell") | |
1369 %!assert (class ([true, true]), "logical") | |
1370 %!assert (class ([true, "a"]), "char") | |
1371 | |
1372 %!assert (class (["a", int64(1)]), "char") | |
1373 %!assert (class (["a", int32(1)]), "char") | |
1374 %!assert (class (["a", int16(1)]), "char") | |
1375 %!assert (class (["a", int8(1)]), "char") | |
1376 %!assert (class (["a", int64(1)]), "char") | |
1377 %!assert (class (["a", int32(1)]), "char") | |
1378 %!assert (class (["a", int16(1)]), "char") | |
1379 %!assert (class (["a", int8(1)]), "char") | |
1380 %!assert (class (["a", single(1)]), "char") | |
1381 %!assert (class (["a", double(1)]), "char") | |
1382 %!assert (class (["a", cell(1)]), "cell") | |
1383 %!assert (class (["a", true]), "char") | |
1384 %!assert (class (["a", "a"]), "char") | |
1385 | |
1386 %!assert (class ([cell(1), struct("foo", "bar")]), "cell") | |
1387 %!error [struct("foo", "bar"), cell(1)] | |
1388 */ | |
1389 | |
1390 DEFUN (string_fill_char, args, nargout, | |
1391 "-*- texinfo -*-\n\ | |
1392 @deftypefn {Built-in Function} {@var{val} =} string_fill_char ()\n\ | |
1393 @deftypefnx {Built-in Function} {@var{old_val} =} string_fill_char (@var{new_val})\n\ | |
1394 @deftypefnx {Built-in Function} {} string_fill_char (@var{new_val}, \"local\")\n\ | |
1395 Query or set the internal variable used to pad all rows of a character\n\ | |
1396 matrix to the same length. It must be a single character. The default\n\ | |
1397 value is @code{\" \"} (a single space). For example:\n\ | |
1398 \n\ | |
1399 @example\n\ | |
1400 @group\n\ | |
1401 string_fill_char (\"X\");\n\ | |
1402 [ \"these\"; \"are\"; \"strings\" ]\n\ | |
1403 @result{} \"theseXX\"\n\ | |
1404 \"areXXXX\"\n\ | |
1405 \"strings\"\n\ | |
1406 @end group\n\ | |
1407 @end example\n\ | |
1408 \n\ | |
1409 When called from inside a function with the \"local\" option, the variable is\n\ | |
1410 changed locally for the function and any subroutines it calls. The original\n\ | |
1411 variable value is restored when exiting the function.\n\ | |
1412 @end deftypefn") | |
1413 { | |
1414 return SET_INTERNAL_VARIABLE (string_fill_char); | |
1415 } | |
1416 | |
1417 /* | |
1418 ## string_fill_char() function call must be outside of %!test block | |
1419 ## due to the way a %!test block is wrapped inside a function | |
1420 %!shared orig_val, old_val | |
1421 %! orig_val = string_fill_char (); | |
1422 %! old_val = string_fill_char ("X"); | |
1423 %!test | |
1424 %! assert (orig_val, old_val); | |
1425 %! assert (string_fill_char (), "X"); | |
1426 %! assert (["these"; "are"; "strings"], ["theseXX"; "areXXXX"; "strings"]); | |
1427 %! string_fill_char (orig_val); | |
1428 %! assert (string_fill_char (), orig_val); | |
1429 | |
1430 %!error (string_fill_char (1, 2)) | |
1431 */ |