pt-mat.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 1996-2012 John W. Eaton
00004 
00005 This file is part of Octave.
00006 
00007 Octave is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 Octave is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Octave; see the file COPYING.  If not, see
00019 <http://www.gnu.org/licenses/>.
00020 
00021 */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026 
00027 #include <iostream>
00028 
00029 #include "quit.h"
00030 
00031 #include "data.h"
00032 #include "defun.h"
00033 #include "error.h"
00034 #include "oct-obj.h"
00035 #include "pt-arg-list.h"
00036 #include "pt-bp.h"
00037 #include "pt-exp.h"
00038 #include "pt-mat.h"
00039 #include "pt-walk.h"
00040 #include "utils.h"
00041 #include "ov.h"
00042 #include "variables.h"
00043 
00044 #include "ov-cx-mat.h"
00045 #include "ov-flt-cx-mat.h"
00046 #include "ov-re-sparse.h"
00047 #include "ov-cx-sparse.h"
00048 
00049 // The character to fill with when creating string arrays.
00050 char Vstring_fill_char = ' ';
00051 
00052 // General matrices.  This list type is much more work to handle than
00053 // constant matrices, but it allows us to construct matrices from
00054 // other matrices, variables, and functions.
00055 
00056 // But first, some internal classes that make our job much easier.
00057 
00058 class
00059 tm_row_const
00060 {
00061 private:
00062 
00063   class
00064   tm_row_const_rep : public octave_base_list<octave_value>
00065   {
00066   public:
00067 
00068     tm_row_const_rep (void)
00069       : count (1), dv (0, 0), all_str (false),
00070         all_sq_str (false), all_dq_str (false),
00071         some_str (false), all_real (false), all_cmplx (false),
00072         all_mt (true), any_cell (false), any_sparse (false),
00073         any_class (false), all_1x1 (false),
00074         first_elem_is_struct (false), class_nm (), ok (false)
00075     { }
00076 
00077     tm_row_const_rep (const tree_argument_list& row)
00078       : count (1), dv (0, 0), all_str (false), all_sq_str (false),
00079         some_str (false), all_real (false), all_cmplx (false),
00080         all_mt (true), any_cell (false), any_sparse (false),
00081         any_class (false), all_1x1 (! row.empty ()),
00082         first_elem_is_struct (false), class_nm (), ok (false)
00083     { init (row); }
00084 
00085     ~tm_row_const_rep (void) { }
00086 
00087     octave_refcount<int> count;
00088 
00089     dim_vector dv;
00090 
00091     bool all_str;
00092     bool all_sq_str;
00093     bool all_dq_str;
00094     bool some_str;
00095     bool all_real;
00096     bool all_cmplx;
00097     bool all_mt;
00098     bool any_cell;
00099     bool any_sparse;
00100     bool any_class;
00101     bool all_1x1;
00102     bool first_elem_is_struct;
00103 
00104     std::string class_nm;
00105 
00106     bool ok;
00107 
00108     void do_init_element (const octave_value&, bool&);
00109 
00110     void init (const tree_argument_list&);
00111 
00112     void cellify (void);
00113 
00114   private:
00115 
00116     tm_row_const_rep (const tm_row_const_rep&);
00117 
00118     tm_row_const_rep& operator = (const tm_row_const_rep&);
00119 
00120   };
00121 
00122 public:
00123 
00124   typedef tm_row_const_rep::iterator iterator;
00125   typedef tm_row_const_rep::const_iterator const_iterator;
00126 
00127   tm_row_const (void)
00128     : rep (0) { }
00129 
00130   tm_row_const (const tree_argument_list& row)
00131     : rep (new tm_row_const_rep (row)) { }
00132 
00133   tm_row_const (const tm_row_const& x)
00134     : rep (x.rep)
00135   {
00136     if (rep)
00137       rep->count++;
00138   }
00139 
00140   tm_row_const& operator = (const tm_row_const& x)
00141   {
00142     if (this != &x && rep != x.rep)
00143       {
00144         if (rep && --rep->count == 0)
00145           delete rep;
00146 
00147         rep = x.rep;
00148 
00149         if (rep)
00150           rep->count++;
00151       }
00152 
00153     return *this;
00154   }
00155 
00156   ~tm_row_const (void)
00157   {
00158     if (rep && --rep->count == 0)
00159       delete rep;
00160   }
00161 
00162   octave_idx_type rows (void) { return rep->dv(0); }
00163   octave_idx_type cols (void) { return rep->dv(1); }
00164 
00165   bool empty (void) const { return rep->empty (); }
00166 
00167   size_t length (void) const { return rep->length (); }
00168 
00169   dim_vector dims (void) { return rep->dv; }
00170 
00171   bool all_strings_p (void) const { return rep->all_str; }
00172   bool all_sq_strings_p (void) const { return rep->all_sq_str; }
00173   bool all_dq_strings_p (void) const { return rep->all_dq_str; }
00174   bool some_strings_p (void) const { return rep->some_str; }
00175   bool all_real_p (void) const { return rep->all_real; }
00176   bool all_complex_p (void) const { return rep->all_cmplx; }
00177   bool all_empty_p (void) const { return rep->all_mt; }
00178   bool any_cell_p (void) const { return rep->any_cell; }
00179   bool any_sparse_p (void) const { return rep->any_sparse; }
00180   bool any_class_p (void) const { return rep->any_class; }
00181   bool all_1x1_p (void) const { return rep->all_1x1; }
00182   bool first_elem_struct_p (void) const { return rep->first_elem_is_struct; }
00183 
00184   std::string class_name (void) const { return rep->class_nm; }
00185 
00186   void cellify (void) { rep->cellify (); }
00187 
00188   operator bool () const { return (rep && rep->ok); }
00189 
00190   iterator begin (void) { return rep->begin (); }
00191   const_iterator begin (void) const { return rep->begin (); }
00192 
00193   iterator end (void) { return rep->end (); }
00194   const_iterator end (void) const { return rep->end (); }
00195 
00196 private:
00197 
00198   tm_row_const_rep *rep;
00199 };
00200 
00201 std::string
00202 get_concat_class (const std::string& c1, const std::string& c2)
00203 {
00204   std::string retval = octave_base_value::static_class_name ();
00205 
00206   if (c1 == c2)
00207     retval = c1;
00208   else if (c1.empty ())
00209     retval = c2;
00210   else if (c2.empty ())
00211     retval = c1;
00212   else if (c1 == "class" || c2 == "class")
00213     retval = "class";
00214   else
00215     {
00216       bool c1_is_int = (c1 == "int8" || c1 == "uint8"
00217                         || c1 == "int16" || c1 == "uint16"
00218                         || c1 == "int32" || c1 == "uint32"
00219                         || c1 == "int64" || c1 == "uint64");
00220       bool c2_is_int = (c2 == "int8" || c2 == "uint8"
00221                         || c2 == "int16" || c2 == "uint16"
00222                         || c2 == "int32" || c2 == "uint32"
00223                         || c2 == "int64" || c2 == "uint64");
00224 
00225       bool c1_is_char = (c1 == "char");
00226       bool c2_is_char = (c2 == "char");
00227 
00228       bool c1_is_double = (c1 == "double");
00229       bool c2_is_double = (c2 == "double");
00230 
00231       bool c1_is_single = (c1 == "single");
00232       bool c2_is_single = (c2 == "single");
00233 
00234       bool c1_is_logical = (c1 == "logical");
00235       bool c2_is_logical = (c2 == "logical");
00236 
00237       bool c1_is_built_in_type
00238         = (c1_is_int || c1_is_char || c1_is_double || c1_is_single
00239            || c1_is_logical);
00240 
00241       bool c2_is_built_in_type
00242         = (c2_is_int || c2_is_char ||  c2_is_double || c2_is_single
00243            || c2_is_logical);
00244 
00245       // Order is important here...
00246 
00247       if (c1 == "struct" && c2 == c1)
00248         retval = c1;
00249       else if (c1 == "cell" || c2 == "cell")
00250         retval = "cell";
00251       else if (c1_is_char && c2_is_built_in_type)
00252         retval = c1;
00253       else if (c2_is_char && c1_is_built_in_type)
00254         retval = c2;
00255       else if (c1_is_int && c2_is_built_in_type)
00256         retval = c1;
00257       else if (c2_is_int && c1_is_built_in_type)
00258         retval = c2;
00259       else if (c1_is_single && c2_is_built_in_type)
00260         retval = c1;
00261       else if (c2_is_single && c1_is_built_in_type)
00262         retval = c2;
00263       else if (c1_is_double && c2_is_built_in_type)
00264         retval = c1;
00265       else if (c2_is_double && c1_is_built_in_type)
00266         retval = c2;
00267       else if (c1_is_logical && c2_is_logical)
00268         retval = c1;
00269     }
00270 
00271   return retval;
00272 }
00273 
00274 static void
00275 eval_error (const char *msg, const dim_vector& x, const dim_vector& y)
00276 {
00277   ::error ("%s (%s vs %s)", msg, x.str ().c_str (), y.str ().c_str ());
00278 }
00279 
00280 void
00281 tm_row_const::tm_row_const_rep::do_init_element (const octave_value& val,
00282                                                  bool& first_elem)
00283 {
00284   std::string this_elt_class_nm
00285     = val.is_object () ? std::string ("class") : val.class_name ();
00286 
00287   class_nm = get_concat_class (class_nm, this_elt_class_nm);
00288 
00289   dim_vector this_elt_dv = val.dims ();
00290 
00291   if (! this_elt_dv.zero_by_zero ())
00292     {
00293       all_mt = false;
00294 
00295       if (first_elem)
00296         {
00297           if (val.is_map ())
00298             first_elem_is_struct = true;
00299 
00300           first_elem = false;
00301         }
00302     }
00303 
00304   append (val);
00305 
00306   if (all_str && ! val.is_string ())
00307     all_str = false;
00308 
00309   if (all_sq_str && ! val.is_sq_string ())
00310     all_sq_str = false;
00311 
00312   if (all_dq_str && ! val.is_dq_string ())
00313     all_dq_str = false;
00314 
00315   if (! some_str && val.is_string ())
00316     some_str = true;
00317 
00318   if (all_real && ! val.is_real_type ())
00319     all_real = false;
00320 
00321   if (all_cmplx && ! (val.is_complex_type () || val.is_real_type ()))
00322     all_cmplx = false;
00323 
00324   if (!any_cell && val.is_cell ())
00325     any_cell = true;
00326 
00327   if (!any_sparse && val.is_sparse_type ())
00328     any_sparse = true;
00329 
00330   if (!any_class && val.is_object ())
00331     any_class = true;
00332 
00333   all_1x1 = all_1x1 && val.numel () == 1;
00334 }
00335 
00336 void
00337 tm_row_const::tm_row_const_rep::init (const tree_argument_list& row)
00338 {
00339   all_str = true;
00340   all_sq_str = true;
00341   all_dq_str = true;
00342   all_real = true;
00343   all_cmplx = true;
00344   any_cell = false;
00345   any_sparse = false;
00346   any_class = false;
00347 
00348   bool first_elem = true;
00349 
00350   for (tree_argument_list::const_iterator p = row.begin ();
00351        p != row.end ();
00352        p++)
00353     {
00354       octave_quit ();
00355 
00356       tree_expression *elt = *p;
00357 
00358       octave_value tmp = elt->rvalue1 ();
00359 
00360       if (error_state || tmp.is_undefined ())
00361         {
00362           ok = ! error_state;
00363           return;
00364         }
00365       else
00366         {
00367           if (tmp.is_cs_list ())
00368             {
00369               octave_value_list tlst = tmp.list_value ();
00370 
00371               for (octave_idx_type i = 0; i < tlst.length (); i++)
00372                 {
00373                   octave_quit ();
00374 
00375                   do_init_element (tlst(i), first_elem);
00376                 }
00377             }
00378           else
00379             do_init_element (tmp, first_elem);
00380         }
00381     }
00382 
00383   if (any_cell && ! any_class && ! first_elem_is_struct)
00384     cellify ();
00385 
00386   first_elem = true;
00387 
00388   for (iterator p = begin (); p != end (); p++)
00389     {
00390       octave_quit ();
00391 
00392       octave_value val = *p;
00393 
00394       dim_vector this_elt_dv = val.dims ();
00395 
00396       if (! this_elt_dv.zero_by_zero ())
00397         {
00398           all_mt = false;
00399 
00400           if (first_elem)
00401             {
00402               first_elem = false;
00403               dv = this_elt_dv;
00404             }
00405           else if (! dv.hvcat (this_elt_dv, 1))
00406             {
00407               eval_error ("horizontal dimensions mismatch", dv, this_elt_dv);
00408               break;
00409             }
00410         }
00411     }
00412 
00413   ok = ! error_state;
00414 }
00415 
00416 void
00417 tm_row_const::tm_row_const_rep::cellify (void)
00418 {
00419   bool elt_changed = false;
00420 
00421   for (iterator p = begin (); p != end (); p++)
00422     {
00423       octave_quit ();
00424 
00425       if (! p->is_cell ())
00426         {
00427           elt_changed = true;
00428 
00429           *p = Cell (*p);
00430         }
00431     }
00432 
00433   if (elt_changed)
00434     {
00435       bool first_elem = true;
00436 
00437       for (iterator p = begin (); p != end (); p++)
00438         {
00439           octave_quit ();
00440 
00441           octave_value val = *p;
00442 
00443           dim_vector this_elt_dv = val.dims ();
00444 
00445           if (! this_elt_dv.zero_by_zero ())
00446             {
00447               if (first_elem)
00448                 {
00449                   first_elem = false;
00450                   dv = this_elt_dv;
00451                 }
00452               else if (! dv.hvcat (this_elt_dv, 1))
00453                 {
00454                   eval_error ("horizontal dimensions mismatch", dv, this_elt_dv);
00455                   break;
00456                 }
00457             }
00458         }
00459     }
00460 }
00461 
00462 class
00463 tm_const : public octave_base_list<tm_row_const>
00464 {
00465 public:
00466 
00467   tm_const (const tree_matrix& tm)
00468     : dv (0, 0), all_str (false), all_sq_str (false), all_dq_str (false),
00469       some_str (false), all_real (false), all_cmplx (false),
00470       all_mt (true), any_cell (false), any_sparse (false),
00471       any_class (false), class_nm (), ok (false)
00472   { init (tm); }
00473 
00474   ~tm_const (void) { }
00475 
00476   octave_idx_type rows (void) const { return dv.elem (0); }
00477   octave_idx_type cols (void) const { return dv.elem (1); }
00478 
00479   dim_vector dims (void) const { return dv; }
00480 
00481   bool all_strings_p (void) const { return all_str; }
00482   bool all_sq_strings_p (void) const { return all_sq_str; }
00483   bool all_dq_strings_p (void) const { return all_dq_str; }
00484   bool some_strings_p (void) const { return some_str; }
00485   bool all_real_p (void) const { return all_real; }
00486   bool all_complex_p (void) const { return all_cmplx; }
00487   bool all_empty_p (void) const { return all_mt; }
00488   bool any_cell_p (void) const { return any_cell; }
00489   bool any_sparse_p (void) const { return any_sparse; }
00490   bool any_class_p (void) const { return any_class; }
00491   bool all_1x1_p (void) const { return all_1x1; }
00492 
00493   std::string class_name (void) const { return class_nm; }
00494 
00495   operator bool () const { return ok; }
00496 
00497 private:
00498 
00499   dim_vector dv;
00500 
00501   bool all_str;
00502   bool all_sq_str;
00503   bool all_dq_str;
00504   bool some_str;
00505   bool all_real;
00506   bool all_cmplx;
00507   bool all_mt;
00508   bool any_cell;
00509   bool any_sparse;
00510   bool any_class;
00511   bool all_1x1;
00512 
00513   std::string class_nm;
00514 
00515   bool ok;
00516 
00517   tm_const (void);
00518 
00519   tm_const (const tm_const&);
00520 
00521   tm_const& operator = (const tm_const&);
00522 
00523   void init (const tree_matrix& tm);
00524 };
00525 
00526 void
00527 tm_const::init (const tree_matrix& tm)
00528 {
00529   all_str = true;
00530   all_sq_str = true;
00531   all_dq_str = true;
00532   all_real = true;
00533   all_cmplx = true;
00534   any_cell = false;
00535   any_sparse = false;
00536   any_class = false;
00537   all_1x1 = ! tm.empty ();
00538 
00539   bool first_elem = true;
00540   bool first_elem_is_struct = false;
00541 
00542   // Just eval and figure out if what we have is complex or all
00543   // strings.  We can't check columns until we know that this is a
00544   // numeric matrix -- collections of strings can have elements of
00545   // different lengths.
00546 
00547   for (tree_matrix::const_iterator p = tm.begin (); p != tm.end (); p++)
00548     {
00549       octave_quit ();
00550 
00551       tree_argument_list *elt = *p;
00552 
00553       tm_row_const tmp (*elt);
00554 
00555       if (first_elem)
00556         {
00557           first_elem_is_struct = tmp.first_elem_struct_p ();
00558 
00559           first_elem = false;
00560         }
00561 
00562       if (tmp && ! tmp.empty ())
00563         {
00564           if (all_str && ! tmp.all_strings_p ())
00565             all_str = false;
00566 
00567           if (all_sq_str && ! tmp.all_sq_strings_p ())
00568             all_sq_str = false;
00569 
00570           if (all_dq_str && ! tmp.all_dq_strings_p ())
00571             all_dq_str = false;
00572 
00573           if (! some_str && tmp.some_strings_p ())
00574             some_str = true;
00575 
00576           if (all_real && ! tmp.all_real_p ())
00577             all_real = false;
00578 
00579           if (all_cmplx && ! tmp.all_complex_p ())
00580             all_cmplx = false;
00581 
00582           if (all_mt && ! tmp.all_empty_p ())
00583             all_mt = false;
00584 
00585           if (!any_cell && tmp.any_cell_p ())
00586             any_cell = true;
00587 
00588           if (!any_sparse && tmp.any_sparse_p ())
00589             any_sparse = true;
00590 
00591           if (!any_class && tmp.any_class_p ())
00592             any_class = true;
00593 
00594           all_1x1 = all_1x1 && tmp.all_1x1_p ();
00595 
00596           append (tmp);
00597         }
00598       else
00599         break;
00600     }
00601 
00602   if (! error_state)
00603     {
00604       if (any_cell && ! any_class && ! first_elem_is_struct)
00605         {
00606           for (iterator q = begin (); q != end (); q++)
00607             {
00608               octave_quit ();
00609 
00610               q->cellify ();
00611             }
00612         }
00613 
00614       first_elem = true;
00615 
00616       for (iterator q = begin (); q != end (); q++)
00617         {
00618           octave_quit ();
00619 
00620           tm_row_const elt = *q;
00621 
00622           octave_idx_type this_elt_nr = elt.rows ();
00623           octave_idx_type this_elt_nc = elt.cols ();
00624 
00625           std::string this_elt_class_nm = elt.class_name ();
00626           class_nm = get_concat_class (class_nm, this_elt_class_nm);
00627 
00628           dim_vector this_elt_dv = elt.dims ();
00629 
00630           all_mt = false;
00631 
00632           if (first_elem)
00633             {
00634               first_elem = false;
00635 
00636               dv = this_elt_dv;
00637             }
00638           else if (all_str && dv.length () == 2
00639                    && this_elt_dv.length () == 2)
00640             {
00641               // FIXME: this is Octave's specialty. Character matrices allow
00642               // rows of unequal length.
00643               if (this_elt_nc > cols ())
00644                 dv(1) = this_elt_nc;
00645               dv(0) += this_elt_nr;
00646             }
00647           else if (! dv.hvcat (this_elt_dv, 0))
00648             {
00649               eval_error ("vertical dimensions mismatch", dv, this_elt_dv);
00650               return;
00651             }
00652         }
00653     }
00654 
00655   ok = ! error_state;
00656 }
00657 
00658 tree_matrix::~tree_matrix (void)
00659 {
00660   while (! empty ())
00661     {
00662       iterator p = begin ();
00663       delete *p;
00664       erase (p);
00665     }
00666 }
00667 
00668 bool
00669 tree_matrix::has_magic_end (void) const
00670 {
00671   for (const_iterator p = begin (); p != end (); p++)
00672     {
00673       octave_quit ();
00674 
00675       tree_argument_list *elt = *p;
00676 
00677       if (elt && elt->has_magic_end ())
00678         return true;
00679     }
00680 
00681   return false;
00682 }
00683 
00684 bool
00685 tree_matrix::all_elements_are_constant (void) const
00686 {
00687   for (const_iterator p = begin (); p != end (); p++)
00688     {
00689       octave_quit ();
00690 
00691       tree_argument_list *elt = *p;
00692 
00693       if (! elt->all_elements_are_constant ())
00694         return false;
00695     }
00696 
00697   return true;
00698 }
00699 
00700 octave_value_list
00701 tree_matrix::rvalue (int nargout)
00702 {
00703   octave_value_list retval;
00704 
00705   if (nargout > 1)
00706     error ("invalid number of output arguments for matrix list");
00707   else
00708     retval = rvalue1 (nargout);
00709 
00710   return retval;
00711 }
00712 
00713 void
00714 maybe_warn_string_concat (bool all_dq_strings_p, bool all_sq_strings_p)
00715 {
00716   if (! (all_dq_strings_p || all_sq_strings_p))
00717     warning_with_id ("Octave:mixed-string-concat",
00718                      "concatenation of different character string types may have unintended consequences");
00719 }
00720 
00721 template<class TYPE, class T>
00722 static void
00723 single_type_concat (Array<T>& result,
00724                     tm_const& tmp)
00725 {
00726   octave_idx_type r = 0, c = 0;
00727 
00728   for (tm_const::iterator p = tmp.begin (); p != tmp.end (); p++)
00729     {
00730       tm_row_const row = *p;
00731       // Skip empty arrays to allow looser rules.
00732       if (row.dims ().any_zero ())
00733         continue;
00734 
00735       for (tm_row_const::iterator q = row.begin ();
00736            q != row.end ();
00737            q++)
00738         {
00739           octave_quit ();
00740 
00741           TYPE ra = octave_value_extract<TYPE> (*q);
00742 
00743           // Skip empty arrays to allow looser rules.
00744           if (! error_state)
00745             {
00746               if (! ra.is_empty ())
00747                 {
00748                   result.insert (ra, r, c);
00749 
00750                   if (! error_state)
00751                     c += ra.columns ();
00752                   else
00753                     return;
00754                 }
00755             }
00756           else
00757             return;
00758         }
00759 
00760       r += row.rows ();
00761       c = 0;
00762     }
00763 }
00764 
00765 template<class TYPE, class T>
00766 static void
00767 single_type_concat (Array<T>& result,
00768                     const dim_vector& dv,
00769                     tm_const& tmp)
00770 {
00771   if (dv.any_zero ())
00772     {
00773       result = Array<T> (dv);
00774       return;
00775     }
00776 
00777   if (tmp.length () == 1)
00778     {
00779       // If possible, forward the operation to liboctave.
00780       // Single row.
00781       tm_row_const& row = tmp.front ();
00782       if (! (equal_types<T, char>::value || equal_types<T, octave_value>::value)
00783           && row.all_1x1_p ())
00784         {
00785           // Optimize all scalars case.
00786           result.clear (dv);
00787           assert (result.numel () == row.length ());
00788           octave_idx_type i = 0;
00789           for (tm_row_const::iterator q = row.begin ();
00790                q != row.end () && ! error_state; q++)
00791              result(i++) = octave_value_extract<T> (*q);
00792 
00793           return;
00794         }
00795 
00796       octave_idx_type ncols = row.length (), i = 0;
00797       OCTAVE_LOCAL_BUFFER (Array<T>, array_list, ncols);
00798 
00799       for (tm_row_const::iterator q = row.begin ();
00800            q != row.end () && ! error_state;
00801            q++)
00802         {
00803           octave_quit ();
00804 
00805           array_list[i] = octave_value_extract<TYPE> (*q);
00806           i++;
00807         }
00808 
00809       if (! error_state)
00810         result = Array<T>::cat (-2, ncols, array_list);
00811     }
00812   else
00813     {
00814       result = Array<T> (dv);
00815       single_type_concat<TYPE> (result, tmp);
00816     }
00817 }
00818 
00819 template<class TYPE, class T>
00820 static void
00821 single_type_concat (Sparse<T>& result,
00822                     const dim_vector& dv,
00823                     tm_const& tmp)
00824 {
00825   if (dv.any_zero ())
00826     {
00827       result = Sparse<T> (dv);
00828       return;
00829     }
00830 
00831   // Sparse matrices require preallocation for efficient indexing; besides,
00832   // only horizontal concatenation can be efficiently handled by indexing.
00833   // So we just cat all rows through liboctave, then cat the final column.
00834   octave_idx_type nrows = tmp.length (), j = 0;
00835   OCTAVE_LOCAL_BUFFER (Sparse<T>, sparse_row_list, nrows);
00836   for (tm_const::iterator p = tmp.begin (); p != tmp.end (); p++)
00837     {
00838       tm_row_const row = *p;
00839       octave_idx_type ncols = row.length (), i = 0;
00840       OCTAVE_LOCAL_BUFFER (Sparse<T>, sparse_list, ncols);
00841 
00842       for (tm_row_const::iterator q = row.begin ();
00843            q != row.end () && ! error_state;
00844            q++)
00845         {
00846           octave_quit ();
00847 
00848           sparse_list[i] = octave_value_extract<TYPE> (*q);
00849           i++;
00850         }
00851 
00852       Sparse<T> stmp = Sparse<T>::cat (-2, ncols, sparse_list);
00853       sparse_row_list[j] = stmp;
00854       j++;
00855     }
00856 
00857   result = Sparse<T>::cat (-1, nrows, sparse_row_list);
00858 }
00859 
00860 template<class MAP>
00861 static void
00862 single_type_concat (octave_map& result,
00863                     const dim_vector& dv,
00864                     tm_const& tmp)
00865 {
00866   if (dv.any_zero ())
00867     {
00868       result = octave_map (dv);
00869       return;
00870     }
00871 
00872   octave_idx_type nrows = tmp.length (), j = 0;
00873   OCTAVE_LOCAL_BUFFER (octave_map, map_row_list, nrows);
00874   for (tm_const::iterator p = tmp.begin (); p != tmp.end (); p++)
00875     {
00876       tm_row_const row = *p;
00877       octave_idx_type ncols = row.length (), i = 0;
00878       OCTAVE_LOCAL_BUFFER (MAP, map_list, ncols);
00879 
00880       for (tm_row_const::iterator q = row.begin ();
00881            q != row.end () && ! error_state;
00882            q++)
00883         {
00884           octave_quit ();
00885 
00886           map_list[i] = octave_value_extract<MAP> (*q);
00887           i++;
00888         }
00889 
00890       octave_map mtmp = octave_map::cat (-2, ncols, map_list);
00891       map_row_list[j] = mtmp;
00892       j++;
00893     }
00894 
00895   result = octave_map::cat (-1, nrows, map_row_list);
00896 }
00897 
00898 template<class TYPE>
00899 static octave_value
00900 do_single_type_concat (const dim_vector& dv,
00901                        tm_const& tmp)
00902 {
00903   TYPE result;
00904 
00905   single_type_concat<TYPE> (result, dv, tmp);
00906 
00907   return result;
00908 }
00909 
00910 template<>
00911 octave_value
00912 do_single_type_concat<octave_map> (const dim_vector& dv,
00913                                    tm_const& tmp)
00914 {
00915   octave_map result;
00916 
00917   if (tmp.all_1x1_p ())
00918     single_type_concat<octave_scalar_map> (result, dv, tmp);
00919   else
00920     single_type_concat<octave_map> (result, dv, tmp);
00921 
00922   return result;
00923 }
00924 
00925 static octave_value
00926 do_class_concat (tm_const& tmc)
00927 {
00928   octave_value retval;
00929 
00930   octave_value_list rows (tmc.length (), octave_value ());
00931 
00932   octave_idx_type j = 0;
00933   for (tm_const::iterator p = tmc.begin (); p != tmc.end (); p++)
00934     {
00935       octave_quit ();
00936 
00937       tm_row_const tmrc = *p;
00938 
00939       if (tmrc.length () == 1)
00940         rows(j++) = *(tmrc.begin ());
00941       else
00942         {
00943           octave_value_list row (tmrc.length (), octave_value ());
00944 
00945           octave_idx_type i = 0;
00946           for (tm_row_const::iterator q = tmrc.begin (); q != tmrc.end (); q++)
00947             row(i++) = *q;
00948 
00949           rows(j++) = do_class_concat (row, "horzcat", 1);
00950         }
00951     }
00952 
00953   if (! error_state)
00954     {
00955       if (rows.length () == 1)
00956         retval = rows(0);
00957       else
00958         retval = do_class_concat (rows, "vertcat", 0);
00959     }
00960 
00961   return retval;
00962 }
00963 
00964 octave_value
00965 tree_matrix::rvalue1 (int)
00966 {
00967   octave_value retval = Matrix ();
00968 
00969   bool all_sq_strings_p = false;
00970   bool all_dq_strings_p = false;
00971   bool all_empty_p = false;
00972   bool all_real_p = false;
00973   bool any_sparse_p = false;
00974   bool any_class_p = false;
00975   bool frc_str_conv = false;
00976 
00977   tm_const tmp (*this);
00978 
00979   if (tmp && ! tmp.empty ())
00980     {
00981       dim_vector dv = tmp.dims ();
00982       all_sq_strings_p = tmp.all_sq_strings_p ();
00983       all_dq_strings_p = tmp.all_dq_strings_p ();
00984       all_empty_p = tmp.all_empty_p ();
00985       all_real_p = tmp.all_real_p ();
00986       any_sparse_p = tmp.any_sparse_p ();
00987       any_class_p = tmp.any_class_p ();
00988       frc_str_conv = tmp.some_strings_p ();
00989 
00990       // Try to speed up the common cases.
00991 
00992       std::string result_type = tmp.class_name ();
00993 
00994       if (any_class_p)
00995         {
00996           retval = do_class_concat (tmp);
00997         }
00998       else if (result_type == "double")
00999         {
01000           if (any_sparse_p)
01001             {
01002               if (all_real_p)
01003                 retval = do_single_type_concat<SparseMatrix> (dv, tmp);
01004               else
01005                 retval = do_single_type_concat<SparseComplexMatrix> (dv, tmp);
01006             }
01007           else
01008             {
01009               if (all_real_p)
01010                 retval = do_single_type_concat<NDArray> (dv, tmp);
01011               else
01012                 retval = do_single_type_concat<ComplexNDArray> (dv, tmp);
01013             }
01014         }
01015       else if (result_type == "single")
01016         {
01017           if (all_real_p)
01018             retval = do_single_type_concat<FloatNDArray> (dv, tmp);
01019           else
01020             retval = do_single_type_concat<FloatComplexNDArray> (dv, tmp);
01021         }
01022       else if (result_type == "char")
01023         {
01024           char type = all_dq_strings_p ? '"' : '\'';
01025 
01026           maybe_warn_string_concat (all_dq_strings_p, all_sq_strings_p);
01027 
01028           charNDArray result (dv, Vstring_fill_char);
01029 
01030           single_type_concat<charNDArray> (result, tmp);
01031 
01032           retval = octave_value (result, type);
01033         }
01034       else if (result_type == "logical")
01035         {
01036           if (any_sparse_p)
01037             retval = do_single_type_concat<SparseBoolMatrix> (dv, tmp);
01038           else
01039             retval = do_single_type_concat<boolNDArray> (dv, tmp);
01040         }
01041       else if (result_type == "int8")
01042         retval = do_single_type_concat<int8NDArray> (dv, tmp);
01043       else if (result_type == "int16")
01044         retval = do_single_type_concat<int16NDArray> (dv, tmp);
01045       else if (result_type == "int32")
01046         retval = do_single_type_concat<int32NDArray> (dv, tmp);
01047       else if (result_type == "int64")
01048         retval = do_single_type_concat<int64NDArray> (dv, tmp);
01049       else if (result_type == "uint8")
01050         retval = do_single_type_concat<uint8NDArray> (dv, tmp);
01051       else if (result_type == "uint16")
01052         retval = do_single_type_concat<uint16NDArray> (dv, tmp);
01053       else if (result_type == "uint32")
01054         retval = do_single_type_concat<uint32NDArray> (dv, tmp);
01055       else if (result_type == "uint64")
01056         retval = do_single_type_concat<uint64NDArray> (dv, tmp);
01057       else if (result_type == "cell")
01058         retval = do_single_type_concat<Cell> (dv, tmp);
01059       else if (result_type == "struct")
01060         retval = do_single_type_concat<octave_map> (dv, tmp);
01061       else
01062         {
01063           // The line below might seem crazy, since we take a copy of
01064           // the first argument, resize it to be empty and then resize
01065           // it to be full. This is done since it means that there is
01066           // no recopying of data, as would happen if we used a single
01067           // resize.  It should be noted that resize operation is also
01068           // significantly slower than the do_cat_op function, so it
01069           // makes sense to have an empty matrix and copy all data.
01070           //
01071           // We might also start with a empty octave_value using
01072           //
01073           //    ctmp = octave_value_typeinfo::lookup_type
01074           //          (tmp.begin() -> begin() -> type_name());
01075           //
01076           // and then directly resize. However, for some types there
01077           // might be some additional setup needed, and so this should
01078           // be avoided.
01079 
01080           octave_value ctmp;
01081 
01082           // Find the first non-empty object
01083 
01084           if (any_sparse_p)
01085             {
01086               // Start with sparse matrix to avoid issues memory issues
01087               // with things like [ones(1,4),sprandn(1e8,4,1e-4)]
01088               if (all_real_p)
01089                 ctmp = octave_sparse_matrix ().resize (dv);
01090               else
01091                 ctmp = octave_sparse_complex_matrix ().resize (dv);
01092             }
01093           else
01094             {
01095               for (tm_const::iterator p = tmp.begin (); p != tmp.end (); p++)
01096                 {
01097                   octave_quit ();
01098 
01099                   tm_row_const row = *p;
01100 
01101                   for (tm_row_const::iterator q = row.begin ();
01102                        q != row.end (); q++)
01103                     {
01104                       octave_quit ();
01105 
01106                       ctmp = *q;
01107 
01108                       if (! ctmp.all_zero_dims ())
01109                         goto found_non_empty;
01110                     }
01111                 }
01112 
01113               ctmp = (*(tmp.begin() -> begin()));
01114 
01115             found_non_empty:
01116 
01117               if (! all_empty_p)
01118                 ctmp = ctmp.resize (dim_vector (0,0)).resize (dv);
01119             }
01120 
01121           if (! error_state)
01122             {
01123               // Now, extract the values from the individual elements and
01124               // insert them in the result matrix.
01125 
01126               int dv_len = dv.length ();
01127               octave_idx_type ntmp = dv_len > 1 ? dv_len : 2;
01128               Array<octave_idx_type> ra_idx (dim_vector (ntmp, 1), 0);
01129 
01130               for (tm_const::iterator p = tmp.begin (); p != tmp.end (); p++)
01131                 {
01132                   octave_quit ();
01133 
01134                   tm_row_const row = *p;
01135 
01136                   for (tm_row_const::iterator q = row.begin ();
01137                        q != row.end ();
01138                        q++)
01139                     {
01140                       octave_quit ();
01141 
01142                       octave_value elt = *q;
01143 
01144                       if (elt.is_empty ())
01145                         continue;
01146 
01147                       ctmp = do_cat_op (ctmp, elt, ra_idx);
01148 
01149                       if (error_state)
01150                         goto done;
01151 
01152                       ra_idx (1) += elt.columns ();
01153                     }
01154 
01155                   ra_idx (0) += row.rows ();
01156                   ra_idx (1) = 0;
01157                 }
01158 
01159               retval = ctmp;
01160 
01161               if (frc_str_conv && ! retval.is_string ())
01162                 retval = retval.convert_to_str ();
01163             }
01164         }
01165     }
01166 
01167 done:
01168   return retval;
01169 }
01170 
01171 tree_expression *
01172 tree_matrix::dup (symbol_table::scope_id scope,
01173                   symbol_table::context_id context) const
01174 {
01175   tree_matrix *new_matrix = new tree_matrix (0, line (), column ());
01176 
01177   for (const_iterator p = begin (); p != end (); p++)
01178     {
01179       const tree_argument_list *elt = *p;
01180 
01181       new_matrix->append (elt ? elt->dup (scope, context) : 0);
01182     }
01183 
01184   new_matrix->copy_base (*this);
01185 
01186   return new_matrix;
01187 }
01188 
01189 void
01190 tree_matrix::accept (tree_walker& tw)
01191 {
01192   tw.visit_matrix (*this);
01193 }
01194 
01195 /*
01196 %% test concatenation with all zero matrices
01197 %!assert([ '' 65*ones(1,10) ], 'AAAAAAAAAA');
01198 %!assert([ 65*ones(1,10) '' ], 'AAAAAAAAAA');
01199 
01200 %!test
01201 %! c = {'foo'; 'bar'; 'bazoloa'};
01202 %! assert ([c; 'a'; 'bc'; 'def'], {'foo'; 'bar'; 'bazoloa'; 'a'; 'bc'; 'def'});
01203 
01204 %!assert (class ([int64(1), int64(1)]), 'int64')
01205 %!assert (class ([int64(1), int32(1)]), 'int64')
01206 %!assert (class ([int64(1), int16(1)]), 'int64')
01207 %!assert (class ([int64(1), int8(1)]), 'int64')
01208 %!assert (class ([int64(1), uint64(1)]), 'int64')
01209 %!assert (class ([int64(1), uint32(1)]), 'int64')
01210 %!assert (class ([int64(1), uint16(1)]), 'int64')
01211 %!assert (class ([int64(1), uint8(1)]), 'int64')
01212 %!assert (class ([int64(1), single(1)]), 'int64')
01213 %!assert (class ([int64(1), double(1)]), 'int64')
01214 %!assert (class ([int64(1), cell(1)]), 'cell')
01215 %!assert (class ([int64(1), true]), 'int64')
01216 %!assert (class ([int64(1), 'a']), 'char')
01217 
01218 %!assert (class ([int32(1), int64(1)]), 'int32')
01219 %!assert (class ([int32(1), int32(1)]), 'int32')
01220 %!assert (class ([int32(1), int16(1)]), 'int32')
01221 %!assert (class ([int32(1), int8(1)]), 'int32')
01222 %!assert (class ([int32(1), uint64(1)]), 'int32')
01223 %!assert (class ([int32(1), uint32(1)]), 'int32')
01224 %!assert (class ([int32(1), uint16(1)]), 'int32')
01225 %!assert (class ([int32(1), uint8(1)]), 'int32')
01226 %!assert (class ([int32(1), single(1)]), 'int32')
01227 %!assert (class ([int32(1), double(1)]), 'int32')
01228 %!assert (class ([int32(1), cell(1)]), 'cell')
01229 %!assert (class ([int32(1), true]), 'int32')
01230 %!assert (class ([int32(1), 'a']), 'char')
01231 
01232 %!assert (class ([int16(1), int64(1)]), 'int16')
01233 %!assert (class ([int16(1), int32(1)]), 'int16')
01234 %!assert (class ([int16(1), int16(1)]), 'int16')
01235 %!assert (class ([int16(1), int8(1)]), 'int16')
01236 %!assert (class ([int16(1), uint64(1)]), 'int16')
01237 %!assert (class ([int16(1), uint32(1)]), 'int16')
01238 %!assert (class ([int16(1), uint16(1)]), 'int16')
01239 %!assert (class ([int16(1), uint8(1)]), 'int16')
01240 %!assert (class ([int16(1), single(1)]), 'int16')
01241 %!assert (class ([int16(1), double(1)]), 'int16')
01242 %!assert (class ([int16(1), cell(1)]), 'cell')
01243 %!assert (class ([int16(1), true]), 'int16')
01244 %!assert (class ([int16(1), 'a']), 'char')
01245 
01246 %!assert (class ([int8(1), int64(1)]), 'int8')
01247 %!assert (class ([int8(1), int32(1)]), 'int8')
01248 %!assert (class ([int8(1), int16(1)]), 'int8')
01249 %!assert (class ([int8(1), int8(1)]), 'int8')
01250 %!assert (class ([int8(1), uint64(1)]), 'int8')
01251 %!assert (class ([int8(1), uint32(1)]), 'int8')
01252 %!assert (class ([int8(1), uint16(1)]), 'int8')
01253 %!assert (class ([int8(1), uint8(1)]), 'int8')
01254 %!assert (class ([int8(1), single(1)]), 'int8')
01255 %!assert (class ([int8(1), double(1)]), 'int8')
01256 %!assert (class ([int8(1), cell(1)]), 'cell')
01257 %!assert (class ([int8(1), true]), 'int8')
01258 %!assert (class ([int8(1), 'a']), 'char')
01259 
01260 %!assert (class ([uint64(1), int64(1)]), 'uint64')
01261 %!assert (class ([uint64(1), int32(1)]), 'uint64')
01262 %!assert (class ([uint64(1), int16(1)]), 'uint64')
01263 %!assert (class ([uint64(1), int8(1)]), 'uint64')
01264 %!assert (class ([uint64(1), uint64(1)]), 'uint64')
01265 %!assert (class ([uint64(1), uint32(1)]), 'uint64')
01266 %!assert (class ([uint64(1), uint16(1)]), 'uint64')
01267 %!assert (class ([uint64(1), uint8(1)]), 'uint64')
01268 %!assert (class ([uint64(1), single(1)]), 'uint64')
01269 %!assert (class ([uint64(1), double(1)]), 'uint64')
01270 %!assert (class ([uint64(1), cell(1)]), 'cell')
01271 %!assert (class ([uint64(1), true]), 'uint64')
01272 %!assert (class ([uint64(1), 'a']), 'char')
01273 
01274 %!assert (class ([uint32(1), int64(1)]), 'uint32')
01275 %!assert (class ([uint32(1), int32(1)]), 'uint32')
01276 %!assert (class ([uint32(1), int16(1)]), 'uint32')
01277 %!assert (class ([uint32(1), int8(1)]), 'uint32')
01278 %!assert (class ([uint32(1), uint64(1)]), 'uint32')
01279 %!assert (class ([uint32(1), uint32(1)]), 'uint32')
01280 %!assert (class ([uint32(1), uint16(1)]), 'uint32')
01281 %!assert (class ([uint32(1), uint8(1)]), 'uint32')
01282 %!assert (class ([uint32(1), single(1)]), 'uint32')
01283 %!assert (class ([uint32(1), double(1)]), 'uint32')
01284 %!assert (class ([uint32(1), cell(1)]), 'cell')
01285 %!assert (class ([uint32(1), true]), 'uint32')
01286 %!assert (class ([uint32(1), 'a']), 'char')
01287 
01288 %!assert (class ([uint16(1), int64(1)]), 'uint16')
01289 %!assert (class ([uint16(1), int32(1)]), 'uint16')
01290 %!assert (class ([uint16(1), int16(1)]), 'uint16')
01291 %!assert (class ([uint16(1), int8(1)]), 'uint16')
01292 %!assert (class ([uint16(1), uint64(1)]), 'uint16')
01293 %!assert (class ([uint16(1), uint32(1)]), 'uint16')
01294 %!assert (class ([uint16(1), uint16(1)]), 'uint16')
01295 %!assert (class ([uint16(1), uint8(1)]), 'uint16')
01296 %!assert (class ([uint16(1), single(1)]), 'uint16')
01297 %!assert (class ([uint16(1), double(1)]), 'uint16')
01298 %!assert (class ([uint16(1), cell(1)]), 'cell')
01299 %!assert (class ([uint16(1), true]), 'uint16')
01300 %!assert (class ([uint16(1), 'a']), 'char')
01301 
01302 %!assert (class ([uint8(1), int64(1)]), 'uint8')
01303 %!assert (class ([uint8(1), int32(1)]), 'uint8')
01304 %!assert (class ([uint8(1), int16(1)]), 'uint8')
01305 %!assert (class ([uint8(1), int8(1)]), 'uint8')
01306 %!assert (class ([uint8(1), uint64(1)]), 'uint8')
01307 %!assert (class ([uint8(1), uint32(1)]), 'uint8')
01308 %!assert (class ([uint8(1), uint16(1)]), 'uint8')
01309 %!assert (class ([uint8(1), uint8(1)]), 'uint8')
01310 %!assert (class ([uint8(1), single(1)]), 'uint8')
01311 %!assert (class ([uint8(1), double(1)]), 'uint8')
01312 %!assert (class ([uint8(1), cell(1)]), 'cell')
01313 %!assert (class ([uint8(1), true]), 'uint8')
01314 %!assert (class ([uint8(1), 'a']), 'char')
01315 
01316 %!assert (class ([single(1), int64(1)]), 'int64')
01317 %!assert (class ([single(1), int32(1)]), 'int32')
01318 %!assert (class ([single(1), int16(1)]), 'int16')
01319 %!assert (class ([single(1), int8(1)]), 'int8')
01320 %!assert (class ([single(1), uint64(1)]), 'uint64')
01321 %!assert (class ([single(1), uint32(1)]), 'uint32')
01322 %!assert (class ([single(1), uint16(1)]), 'uint16')
01323 %!assert (class ([single(1), uint8(1)]), 'uint8')
01324 %!assert (class ([single(1), single(1)]), 'single')
01325 %!assert (class ([single(1), double(1)]), 'single')
01326 %!assert (class ([single(1), cell(1)]), 'cell')
01327 %!assert (class ([single(1), true]), 'single')
01328 %!assert (class ([single(1), 'a']), 'char')
01329 
01330 %!assert (class ([double(1), int64(1)]), 'int64')
01331 %!assert (class ([double(1), int32(1)]), 'int32')
01332 %!assert (class ([double(1), int16(1)]), 'int16')
01333 %!assert (class ([double(1), int8(1)]), 'int8')
01334 %!assert (class ([double(1), uint64(1)]), 'uint64')
01335 %!assert (class ([double(1), uint32(1)]), 'uint32')
01336 %!assert (class ([double(1), uint16(1)]), 'uint16')
01337 %!assert (class ([double(1), uint8(1)]), 'uint8')
01338 %!assert (class ([double(1), single(1)]), 'single')
01339 %!assert (class ([double(1), double(1)]), 'double')
01340 %!assert (class ([double(1), cell(1)]), 'cell')
01341 %!assert (class ([double(1), true]), 'double')
01342 %!assert (class ([double(1), 'a']), 'char')
01343 
01344 %!assert (class ([cell(1), int64(1)]), 'cell')
01345 %!assert (class ([cell(1), int32(1)]), 'cell')
01346 %!assert (class ([cell(1), int16(1)]), 'cell')
01347 %!assert (class ([cell(1), int8(1)]), 'cell')
01348 %!assert (class ([cell(1), uint64(1)]), 'cell')
01349 %!assert (class ([cell(1), uint32(1)]), 'cell')
01350 %!assert (class ([cell(1), uint16(1)]), 'cell')
01351 %!assert (class ([cell(1), uint8(1)]), 'cell')
01352 %!assert (class ([cell(1), single(1)]), 'cell')
01353 %!assert (class ([cell(1), double(1)]), 'cell')
01354 %!assert (class ([cell(1), cell(1)]), 'cell')
01355 %!assert (class ([cell(1), true]), 'cell')
01356 %!assert (class ([cell(1), 'a']), 'cell')
01357 
01358 %!assert (class ([true, int64(1)]), 'int64')
01359 %!assert (class ([true, int32(1)]), 'int32')
01360 %!assert (class ([true, int16(1)]), 'int16')
01361 %!assert (class ([true, int8(1)]), 'int8')
01362 %!assert (class ([true, uint64(1)]), 'uint64')
01363 %!assert (class ([true, uint32(1)]), 'uint32')
01364 %!assert (class ([true, uint16(1)]), 'uint16')
01365 %!assert (class ([true, uint8(1)]), 'uint8')
01366 %!assert (class ([true, single(1)]), 'single')
01367 %!assert (class ([true, double(1)]), 'double')
01368 %!assert (class ([true, cell(1)]), 'cell')
01369 %!assert (class ([true, true]), 'logical')
01370 %!assert (class ([true, 'a']), 'char')
01371 
01372 %!assert (class (['a', int64(1)]), 'char')
01373 %!assert (class (['a', int32(1)]), 'char')
01374 %!assert (class (['a', int16(1)]), 'char')
01375 %!assert (class (['a', int8(1)]), 'char')
01376 %!assert (class (['a', int64(1)]), 'char')
01377 %!assert (class (['a', int32(1)]), 'char')
01378 %!assert (class (['a', int16(1)]), 'char')
01379 %!assert (class (['a', int8(1)]), 'char')
01380 %!assert (class (['a', single(1)]), 'char')
01381 %!assert (class (['a', double(1)]), 'char')
01382 %!assert (class (['a', cell(1)]), 'cell')
01383 %!assert (class (['a', true]), 'char')
01384 %!assert (class (['a', 'a']), 'char')
01385 
01386 %!assert (class ([cell(1), struct('foo', 'bar')]), 'cell')
01387 %!error [struct('foo', 'bar'), cell(1)];
01388 */
01389 
01390 DEFUN (string_fill_char, args, nargout,
01391   "-*- texinfo -*-\n\
01392 @deftypefn  {Built-in Function} {@var{val} =} string_fill_char ()\n\
01393 @deftypefnx {Built-in Function} {@var{old_val} =} string_fill_char (@var{new_val})\n\
01394 @deftypefnx {Built-in Function} {} string_fill_char (@var{new_val}, \"local\")\n\
01395 Query or set the internal variable used to pad all rows of a character\n\
01396 matrix to the same length.  It must be a single character.  The default\n\
01397 value is @code{\" \"} (a single space).  For example:\n\
01398 \n\
01399 @example\n\
01400 @group\n\
01401 string_fill_char (\"X\");\n\
01402 [ \"these\"; \"are\"; \"strings\" ]\n\
01403      @result{} \"theseXX\"\n\
01404         \"areXXXX\"\n\
01405         \"strings\"\n\
01406 @end group\n\
01407 @end example\n\
01408 \n\
01409 When called from inside a function with the \"local\" option, the variable is\n\
01410 changed locally for the function and any subroutines it calls.  The original\n\
01411 variable value is restored when exiting the function.\n\
01412 @end deftypefn")
01413 {
01414   return SET_INTERNAL_VARIABLE (string_fill_char);
01415 }
01416 
01417 /*
01418 %!error (string_fill_char (1, 2));
01419 %% string_fill_char() function call must be outside of %!test block
01420 %% due to the way a %!test block is wrapped inside a function
01421 %!shared orig_val, old_val
01422 %! orig_val = string_fill_char ();
01423 %! old_val  = string_fill_char ("X");
01424 %!test
01425 %! assert (orig_val, old_val);
01426 %! assert (string_fill_char (), "X");
01427 %! assert (["these"; "are"; "strings"], ["theseXX"; "areXXXX"; "strings"]);
01428 %! string_fill_char (orig_val);
01429 %! assert (string_fill_char (), orig_val);
01430 */
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines