ov-struct.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 "Cell.h"
00030 #include "defun.h"
00031 #include "error.h"
00032 #include "gripes.h"
00033 #include "oct-lvalue.h"
00034 #include "ov-struct.h"
00035 #include "unwind-prot.h"
00036 #include "utils.h"
00037 #include "variables.h"
00038 
00039 #include "Array-util.h"
00040 #include "oct-locbuf.h"
00041 
00042 #include "byte-swap.h"
00043 #include "ls-oct-ascii.h"
00044 #include "ls-oct-binary.h"
00045 #include "ls-hdf5.h"
00046 #include "ls-utils.h"
00047 #include "pr-output.h"
00048 
00049 DEFINE_OCTAVE_ALLOCATOR(octave_struct);
00050 
00051 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(octave_struct, "struct", "struct");
00052 
00053 // How many levels of structure elements should we print?
00054 static int Vstruct_levels_to_print = 2;
00055 
00056 // TRUE means print struct array contents, up to the number of levels
00057 // specified by struct_levels_to_print.
00058 static bool Vprint_struct_array_contents = false;
00059 
00060 octave_base_value *
00061 octave_struct::try_narrowing_conversion (void)
00062 {
00063   octave_base_value *retval = 0;
00064 
00065   if (numel () == 1)
00066     retval = new octave_scalar_struct (map.checkelem (0));
00067 
00068   return retval;
00069 }
00070 
00071 Cell
00072 octave_struct::dotref (const octave_value_list& idx, bool auto_add)
00073 {
00074   Cell retval;
00075 
00076   assert (idx.length () == 1);
00077 
00078   std::string nm = idx(0).string_value ();
00079 
00080   octave_map::const_iterator p = map.seek (nm);
00081 
00082   if (p != map.end ())
00083     retval = map.contents (p);
00084   else if (auto_add)
00085     retval = (numel () == 0) ? Cell (dim_vector (1, 1)) : Cell (dims ());
00086   else
00087     error ("structure has no member '%s'", nm.c_str ());
00088 
00089   return retval;
00090 }
00091 
00092 #if 0
00093 static void
00094 gripe_invalid_index1 (void)
00095 {
00096   error ("invalid index for structure array");
00097 }
00098 #endif
00099 
00100 static void
00101 gripe_invalid_index_for_assignment (void)
00102 {
00103   error ("invalid index for structure array assignment");
00104 }
00105 
00106 static void
00107 gripe_invalid_index_type (const std::string& nm, char t)
00108 {
00109   error ("%s cannot be indexed with %c", nm.c_str (), t);
00110 }
00111 
00112 static void
00113 gripe_failed_assignment (void)
00114 {
00115   error ("assignment to structure element failed");
00116 }
00117 
00118 octave_value_list
00119 octave_struct::subsref (const std::string& type,
00120                         const std::list<octave_value_list>& idx,
00121                         int nargout)
00122 {
00123   octave_value_list retval;
00124 
00125   int skip = 1;
00126 
00127   switch (type[0])
00128     {
00129     case '(':
00130       {
00131         if (type.length () > 1 && type[1] == '.')
00132           {
00133             std::list<octave_value_list>::const_iterator p = idx.begin ();
00134             octave_value_list key_idx = *++p;
00135 
00136             const Cell tmp = dotref (key_idx);
00137 
00138             if (! error_state)
00139               {
00140                 const Cell t = tmp.index (idx.front ());
00141 
00142                 retval(0) = (t.length () == 1) ? t(0) : octave_value (t, true);
00143 
00144                 // We handled two index elements, so tell
00145                 // next_subsref to skip both of them.
00146 
00147                 skip++;
00148               }
00149           }
00150         else
00151           retval(0) = do_index_op (idx.front ());
00152       }
00153       break;
00154 
00155     case '.':
00156       {
00157         if (map.numel() > 0)
00158           {
00159             const Cell t = dotref (idx.front ());
00160 
00161             retval(0) = (t.length () == 1) ? t(0) : octave_value (t, true);
00162           }
00163       }
00164       break;
00165 
00166     case '{':
00167       gripe_invalid_index_type (type_name (), type[0]);
00168       break;
00169 
00170     default:
00171       panic_impossible ();
00172     }
00173 
00174   // FIXME -- perhaps there should be an
00175   // octave_value_list::next_subsref member function?  See also
00176   // octave_user_function::subsref.
00177 
00178   if (idx.size () > 1)
00179     retval = retval(0).next_subsref (nargout, type, idx, skip);
00180 
00181   return retval;
00182 }
00183 
00184 octave_value
00185 octave_struct::subsref (const std::string& type,
00186                         const std::list<octave_value_list>& idx,
00187                         bool auto_add)
00188 {
00189   octave_value retval;
00190 
00191   int skip = 1;
00192 
00193   switch (type[0])
00194     {
00195     case '(':
00196       {
00197         if (type.length () > 1 && type[1] == '.')
00198           {
00199             std::list<octave_value_list>::const_iterator p = idx.begin ();
00200             octave_value_list key_idx = *++p;
00201 
00202             const Cell tmp = dotref (key_idx, auto_add);
00203 
00204             if (! error_state)
00205               {
00206                 const Cell t = tmp.index (idx.front (), auto_add);
00207 
00208                 retval = (t.length () == 1) ? t(0) : octave_value (t, true);
00209 
00210                 // We handled two index elements, so tell
00211                 // next_subsref to skip both of them.
00212 
00213                 skip++;
00214               }
00215           }
00216         else
00217           retval = do_index_op (idx.front (), auto_add);
00218       }
00219       break;
00220 
00221     case '.':
00222       {
00223         if (map.numel() > 0)
00224           {
00225             const Cell t = dotref (idx.front (), auto_add);
00226 
00227             retval = (t.length () == 1) ? t(0) : octave_value (t, true);
00228           }
00229       }
00230       break;
00231 
00232     case '{':
00233       gripe_invalid_index_type (type_name (), type[0]);
00234       break;
00235 
00236     default:
00237       panic_impossible ();
00238     }
00239 
00240   // FIXME -- perhaps there should be an
00241   // octave_value_list::next_subsref member function?  See also
00242   // octave_user_function::subsref.
00243 
00244   if (idx.size () > 1)
00245     retval = retval.next_subsref (auto_add, type, idx, skip);
00246 
00247   return retval;
00248 }
00249 
00250 /*
00251 %!test
00252 %! x(1).a.a = 1; x(2).a.a = 2;
00253 %! assert (size (x), [1, 2]);
00254 %! assert (x(1).a.a, 1);
00255 %! assert (x(2).a.a, 2);
00256 */
00257 
00258 octave_value
00259 octave_struct::numeric_conv (const octave_value& val,
00260                              const std::string& type)
00261 {
00262   octave_value retval;
00263 
00264   if (type.length () > 0 && type[0] == '.' && ! val.is_map ())
00265     retval = octave_map ();
00266   else
00267     retval = val;
00268 
00269   return retval;
00270 }
00271 
00272 octave_value
00273 octave_struct::subsasgn (const std::string& type,
00274                          const std::list<octave_value_list>& idx,
00275                          const octave_value& rhs)
00276 {
00277   octave_value retval;
00278 
00279   int n = type.length ();
00280 
00281   octave_value t_rhs = rhs;
00282 
00283   if (idx.front ().empty ())
00284     {
00285       error ("missing index in indexed assignment");
00286       return retval;
00287     }
00288 
00289   if (n > 1 && ! (type.length () == 2 && type[0] == '(' && type[1] == '.'))
00290     {
00291       switch (type[0])
00292         {
00293         case '(':
00294           {
00295             if (type.length () > 1 && type[1] == '.')
00296               {
00297                 std::list<octave_value_list>::const_iterator p = idx.begin ();
00298                 octave_value_list t_idx = *p;
00299 
00300                 octave_value_list key_idx = *++p;
00301 
00302                 assert (key_idx.length () == 1);
00303 
00304                 std::string key = key_idx(0).string_value ();
00305 
00306                 std::list<octave_value_list> next_idx (idx);
00307 
00308                 // We handled two index elements, so subsasgn to
00309                 // needs to skip both of them.
00310 
00311                 next_idx.erase (next_idx.begin ());
00312                 next_idx.erase (next_idx.begin ());
00313 
00314                 std::string next_type = type.substr (2);
00315 
00316                 Cell tmpc (1, 1);
00317                 octave_map::iterator pkey = map.seek (key);
00318                 if (pkey != map.end ())
00319                   {
00320                     map.contents (pkey).make_unique ();
00321                     tmpc = map.contents (pkey).index (idx.front (), true);
00322                   }
00323 
00324                 // FIXME: better code reuse? cf. octave_cell::subsasgn and the case below.
00325                 if (! error_state)
00326                   {
00327                     if (tmpc.numel () == 1)
00328                       {
00329                         octave_value& tmp = tmpc(0);
00330 
00331                         bool orig_undefined = tmp.is_undefined ();
00332 
00333                         if (orig_undefined || tmp.is_zero_by_zero ())
00334                           {
00335                             tmp = octave_value::empty_conv (next_type, rhs);
00336                             tmp.make_unique (); // probably a no-op.
00337                           }
00338                         else
00339                           // optimization: ignore the copy still stored inside our map.
00340                           tmp.make_unique (1);
00341 
00342                         if (! error_state)
00343                           t_rhs = (orig_undefined
00344                                    ? tmp.undef_subsasgn (next_type, next_idx, rhs)
00345                                    : tmp.subsasgn (next_type, next_idx, rhs));
00346                       }
00347                     else
00348                       gripe_indexed_cs_list ();
00349                   }
00350               }
00351             else
00352               gripe_invalid_index_for_assignment ();
00353           }
00354           break;
00355 
00356         case '.':
00357           {
00358             octave_value_list key_idx = idx.front ();
00359 
00360             assert (key_idx.length () == 1);
00361 
00362             std::string key = key_idx(0).string_value ();
00363 
00364             std::list<octave_value_list> next_idx (idx);
00365 
00366             next_idx.erase (next_idx.begin ());
00367 
00368             std::string next_type = type.substr (1);
00369 
00370             Cell tmpc (1, 1);
00371             octave_map::iterator pkey = map.seek (key);
00372             if (pkey != map.end ())
00373               {
00374                 map.contents (pkey).make_unique ();
00375                 tmpc = map.contents (pkey);
00376               }
00377 
00378             // FIXME: better code reuse?
00379             if (! error_state)
00380               {
00381                 if (tmpc.numel () == 1)
00382                   {
00383                     octave_value& tmp = tmpc(0);
00384 
00385                     bool orig_undefined = tmp.is_undefined ();
00386 
00387                     if (orig_undefined || tmp.is_zero_by_zero ())
00388                       {
00389                         tmp = octave_value::empty_conv (next_type, rhs);
00390                         tmp.make_unique (); // probably a no-op.
00391                       }
00392                     else
00393                       // optimization: ignore the copy still stored inside our map.
00394                       tmp.make_unique (1);
00395 
00396                     if (! error_state)
00397                       t_rhs = (orig_undefined
00398                                ? tmp.undef_subsasgn (next_type, next_idx, rhs)
00399                                : tmp.subsasgn (next_type, next_idx, rhs));
00400                   }
00401                 else
00402                   gripe_indexed_cs_list ();
00403               }
00404           }
00405           break;
00406 
00407         case '{':
00408           gripe_invalid_index_type (type_name (), type[0]);
00409           break;
00410 
00411         default:
00412           panic_impossible ();
00413         }
00414     }
00415 
00416   if (! error_state)
00417     {
00418       switch (type[0])
00419         {
00420         case '(':
00421           {
00422             if (n > 1 && type[1] == '.')
00423               {
00424                 std::list<octave_value_list>::const_iterator p = idx.begin ();
00425                 octave_value_list key_idx = *++p;
00426                 octave_value_list idxf = idx.front ();
00427 
00428                 assert (key_idx.length () == 1);
00429 
00430                 std::string key = key_idx(0).string_value ();
00431 
00432                 if (! error_state)
00433                   {
00434                     if (t_rhs.is_cs_list ())
00435                       {
00436                         Cell tmp_cell = Cell (t_rhs.list_value ());
00437 
00438                         // Inquire the proper shape of the RHS.
00439 
00440                         dim_vector didx = dims ().redim (idxf.length ());
00441                         for (octave_idx_type k = 0; k < idxf.length (); k++)
00442                           if (! idxf(k).is_magic_colon ()) didx(k) = idxf(k).numel ();
00443 
00444                         if (didx.numel () == tmp_cell.numel ())
00445                           tmp_cell = tmp_cell.reshape (didx);
00446 
00447 
00448                         map.assign (idxf, key, tmp_cell);
00449 
00450                         if (! error_state)
00451                           {
00452                             count++;
00453                             retval = octave_value (this);
00454                           }
00455                         else
00456                           gripe_failed_assignment ();
00457                       }
00458                     else
00459                       {
00460                         const octave_map& cmap = const_cast<const octave_map &> (map);
00461                         // cast map to const reference to avoid forced key insertion.
00462                         if (idxf.all_scalars ()
00463                             || cmap.contents (key).index (idxf, true).numel () == 1)
00464                           {
00465                             map.assign (idxf, key, Cell (t_rhs.storable_value ()));
00466                             if (! error_state)
00467                               {
00468                                 count++;
00469                                 retval = octave_value (this);
00470                               }
00471                             else
00472                               gripe_failed_assignment ();
00473                           }
00474                         else if (! error_state)
00475                           gripe_nonbraced_cs_list_assignment ();
00476                       }
00477                   }
00478                 else
00479                   gripe_failed_assignment ();
00480               }
00481             else
00482               {
00483                 if (t_rhs.is_map() || t_rhs.is_object ())
00484                   {
00485                     octave_map rhs_map = t_rhs.map_value ();
00486 
00487                     if (! error_state)
00488                       {
00489                         map.assign (idx.front (), rhs_map);
00490 
00491                         if (! error_state)
00492                           {
00493                             count++;
00494                             retval = octave_value (this);
00495                           }
00496                         else
00497                           gripe_failed_assignment ();
00498                       }
00499                     else
00500                       error ("invalid structure assignment");
00501                   }
00502                 else
00503                   {
00504                     if (t_rhs.is_null_value())
00505                       {
00506                         map.delete_elements (idx.front());
00507 
00508                         if (! error_state)
00509                           {
00510                             count++;
00511                             retval = octave_value (this);
00512                           }
00513                         else
00514                           gripe_failed_assignment ();
00515                       }
00516                     else
00517                       error ("invalid structure assignment");
00518                   }
00519               }
00520           }
00521           break;
00522 
00523         case '.':
00524           {
00525             octave_value_list key_idx = idx.front ();
00526 
00527             assert (key_idx.length () == 1);
00528 
00529             std::string key = key_idx(0).string_value ();
00530 
00531             if (t_rhs.is_cs_list ())
00532               {
00533                 Cell tmp_cell = Cell (t_rhs.list_value ());
00534 
00535                 // The shape of the RHS is irrelevant, we just want
00536                 // the number of elements to agree and to preserve the
00537                 // shape of the left hand side of the assignment.
00538 
00539                 if (numel () == tmp_cell.numel ())
00540                   tmp_cell = tmp_cell.reshape (dims ());
00541 
00542                 map.setfield (key, tmp_cell);
00543               }
00544             else
00545               {
00546                 Cell tmp_cell(1, 1);
00547                 tmp_cell(0) = t_rhs.storable_value ();
00548                 map.setfield (key, tmp_cell);
00549               }
00550 
00551             if (! error_state)
00552               {
00553                 count++;
00554                 retval = octave_value (this);
00555               }
00556             else
00557               gripe_failed_assignment ();
00558           }
00559           break;
00560 
00561         case '{':
00562           gripe_invalid_index_type (type_name (), type[0]);
00563           break;
00564 
00565         default:
00566           panic_impossible ();
00567         }
00568     }
00569   else
00570     gripe_failed_assignment ();
00571 
00572   retval.maybe_mutate ();
00573 
00574   return retval;
00575 }
00576 
00577 octave_value
00578 octave_struct::do_index_op (const octave_value_list& idx, bool resize_ok)
00579 {
00580   // octave_map handles indexing itself.
00581   return map.index (idx, resize_ok);
00582 }
00583 
00584 size_t
00585 octave_struct::byte_size (void) const
00586 {
00587   // Neglect the size of the fieldnames.
00588 
00589   size_t retval = 0;
00590 
00591   for (octave_map::const_iterator p = map.begin (); p != map.end (); p++)
00592     {
00593       std::string key = map.key (p);
00594 
00595       octave_value val = octave_value (map.contents (p));
00596 
00597       retval += val.byte_size ();
00598     }
00599 
00600   return retval;
00601 }
00602 
00603 void
00604 octave_struct::print (std::ostream& os, bool) const
00605 {
00606   print_raw (os);
00607 }
00608 
00609 void
00610 octave_struct::print_raw (std::ostream& os, bool) const
00611 {
00612   unwind_protect frame;
00613 
00614   frame.protect_var (Vstruct_levels_to_print);
00615 
00616   if (Vstruct_levels_to_print >= 0)
00617     {
00618       bool max_depth_reached = Vstruct_levels_to_print-- == 0;
00619 
00620       bool print_fieldnames_only
00621         = (max_depth_reached || ! Vprint_struct_array_contents);
00622 
00623       increment_indent_level ();
00624 
00625       newline (os);
00626       indent (os);
00627       dim_vector dv = dims ();
00628       os << dv.str () << " struct array containing the fields:";
00629       newline (os);
00630 
00631       increment_indent_level ();
00632 
00633       string_vector key_list = map.fieldnames ();
00634 
00635       for (octave_idx_type i = 0; i < key_list.length (); i++)
00636         {
00637           std::string key = key_list[i];
00638 
00639           Cell val = map.contents (key);
00640 
00641           newline (os);
00642 
00643           if (print_fieldnames_only)
00644             {
00645               indent (os);
00646               os << key;
00647             }
00648           else
00649             {
00650               octave_value tmp (val);
00651               tmp.print_with_name (os, key);
00652             }
00653         }
00654 
00655       if (print_fieldnames_only)
00656         newline (os);
00657 
00658       decrement_indent_level ();
00659       decrement_indent_level ();
00660     }
00661   else
00662     {
00663       indent (os);
00664       os << "<structure>";
00665       newline (os);
00666     }
00667 }
00668 
00669 bool
00670 octave_struct::print_name_tag (std::ostream& os, const std::string& name) const
00671 {
00672   bool retval = false;
00673 
00674   indent (os);
00675 
00676   if (Vstruct_levels_to_print < 0)
00677     os << name << " = ";
00678   else
00679     {
00680       os << name << " =";
00681       newline (os);
00682       retval = true;
00683     }
00684 
00685   return retval;
00686 }
00687 
00688 static bool
00689 scalar (const dim_vector& dims)
00690 {
00691   return dims.length () == 2 && dims (0) == 1 && dims (1) == 1;
00692 }
00693 
00694 /*
00695 %!shared x
00696 %! x(1).a=1; x(2).a=2; x(1).b=3; x(2).b=3;
00697 %!assert(struct('a',1,'b',3),x(1))
00698 %!assert(isempty(x([])))
00699 %!assert(isempty(struct('a',{},'b',{})))
00700 %!assert(struct('a',{1,2},'b',{3,3}),x)
00701 %!assert(struct('a',{1,2},'b',3),x)
00702 %!assert(struct('a',{1,2},'b',{3}),x)
00703 %!assert(struct('b',3,'a',{1,2}),x)
00704 %!assert(struct('b',{3},'a',{1,2}),x)
00705 %!test x=struct([]);
00706 %!assert(size(x),[0,0]);
00707 %!assert(isstruct(x));
00708 %!assert(isempty(fieldnames(x)));
00709 %!fail("struct('a',{1,2},'b',{1,2,3})","dimensions of parameter 2 do not match those of parameter 4")
00710 %!fail("struct(1,2,3,4)","struct: expecting alternating \"field\", VALUE pairs");
00711 %!fail("struct('1',2,'3')","struct: expecting alternating \"field\", VALUE pairs");
00712 */
00713 
00714 bool
00715 octave_struct::save_ascii (std::ostream& os)
00716 {
00717   octave_map m = map_value ();
00718 
00719   octave_idx_type nf = m.nfields ();
00720 
00721   const dim_vector dv = dims ();
00722 
00723   os << "# ndims: " << dv.length () << "\n";
00724 
00725   for (int i = 0; i < dv.length (); i++)
00726     os << " " << dv (i);
00727   os << "\n";
00728 
00729   os << "# length: " << nf << "\n";
00730 
00731   // Iterating over the list of keys will preserve the order of the
00732   // fields.
00733   string_vector keys = m.fieldnames ();
00734 
00735   for (octave_idx_type i = 0; i < nf; i++)
00736     {
00737       std::string key = keys(i);
00738 
00739       octave_value val = map.contents (key);
00740 
00741       bool b = save_ascii_data (os, val, key, false, 0);
00742 
00743       if (! b)
00744         return os;
00745     }
00746 
00747   return true;
00748 }
00749 
00750 bool
00751 octave_struct::load_ascii (std::istream& is)
00752 {
00753   octave_idx_type len = 0;
00754   dim_vector dv (1, 1);
00755   bool success = true;
00756 
00757   // KLUGE: earlier Octave versions did not save extra dimensions with struct,
00758   // and as a result did not preserve dimensions for empty structs.
00759   // The default dimensions were 1x1, which we want to preserve.
00760   string_vector keywords(2);
00761 
00762   keywords[0] = "ndims";
00763   keywords[1] = "length";
00764 
00765   std::string kw;
00766 
00767   if (extract_keyword (is, keywords, kw, len, true))
00768     {
00769       if (kw == keywords[0])
00770         {
00771           int mdims = std::max (static_cast<int> (len), 2);
00772           dv.resize (mdims);
00773           for (int i = 0; i < mdims; i++)
00774             is >> dv(i);
00775 
00776           success = extract_keyword (is, keywords[1], len);
00777         }
00778     }
00779   else
00780     success = false;
00781 
00782   if (success && len >= 0)
00783     {
00784       if (len > 0)
00785         {
00786           octave_map m (dv);
00787 
00788           for (octave_idx_type j = 0; j < len; j++)
00789             {
00790               octave_value t2;
00791               bool dummy;
00792 
00793               // recurse to read cell elements
00794               std::string nm
00795                 = read_ascii_data (is, std::string (), dummy, t2, j);
00796 
00797               if (!is)
00798                 break;
00799 
00800               Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
00801 
00802               if (error_state)
00803                 {
00804                   error ("load: internal error loading struct elements");
00805                   return false;
00806                 }
00807 
00808               m.setfield (nm, tcell);
00809             }
00810 
00811           if (is)
00812             map = m;
00813           else
00814             {
00815               error ("load: failed to load structure");
00816               success = false;
00817             }
00818         }
00819       else if (len == 0 )
00820         map = octave_map (dv);
00821       else
00822         panic_impossible ();
00823     }
00824   else {
00825     error ("load: failed to extract number of elements in structure");
00826     success = false;
00827   }
00828 
00829   return success;
00830 }
00831 
00832 bool
00833 octave_struct::save_binary (std::ostream& os, bool& save_as_floats)
00834 {
00835   octave_map m = map_value ();
00836 
00837   octave_idx_type nf = m.nfields ();
00838 
00839   dim_vector d = dims ();
00840   if (d.length () < 1)
00841     return false;
00842 
00843   // Use negative value for ndims
00844   int32_t di = - d.length();
00845   os.write (reinterpret_cast<char *> (&di), 4);
00846   for (int i = 0; i < d.length (); i++)
00847     {
00848       di = d(i);
00849       os.write (reinterpret_cast<char *> (&di), 4);
00850     }
00851 
00852   int32_t len = nf;
00853   os.write (reinterpret_cast<char *> (&len), 4);
00854 
00855   // Iterating over the list of keys will preserve the order of the
00856   // fields.
00857   string_vector keys = m.fieldnames ();
00858 
00859   for (octave_idx_type i = 0; i < nf; i++)
00860     {
00861       std::string key = keys(i);
00862 
00863       octave_value val = map.contents (key);
00864 
00865       bool b = save_binary_data (os, val, key, "", 0, save_as_floats);
00866 
00867       if (! b)
00868         return os;
00869     }
00870 
00871   return true;
00872 }
00873 
00874 bool
00875 octave_struct::load_binary (std::istream& is, bool swap,
00876                             oct_mach_info::float_format fmt)
00877 {
00878   bool success = true;
00879   int32_t len;
00880   if (! is.read (reinterpret_cast<char *> (&len), 4))
00881     return false;
00882   if (swap)
00883     swap_bytes<4> (&len);
00884 
00885   dim_vector dv (1, 1);
00886 
00887   if (len < 0)
00888     {
00889       // We have explicit dimensions.
00890       int mdims = -len;
00891 
00892       int32_t di;
00893       dv.resize (mdims);
00894 
00895       for (int i = 0; i < mdims; i++)
00896         {
00897           if (! is.read (reinterpret_cast<char *> (&di), 4))
00898             return false;
00899           if (swap)
00900             swap_bytes<4> (&di);
00901           dv(i) = di;
00902         }
00903 
00904       if (! is.read (reinterpret_cast<char *> (&len), 4))
00905         return false;
00906       if (swap)
00907         swap_bytes<4> (&len);
00908     }
00909 
00910   if (len > 0)
00911     {
00912       octave_map m (dv);
00913 
00914       for (octave_idx_type j = 0; j < len; j++)
00915         {
00916           octave_value t2;
00917           bool dummy;
00918           std::string doc;
00919 
00920           // recurse to read cell elements
00921           std::string nm = read_binary_data (is, swap, fmt, std::string (),
00922                                              dummy, t2, doc);
00923 
00924           if (!is)
00925             break;
00926 
00927           Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
00928 
00929           if (error_state)
00930             {
00931               error ("load: internal error loading struct elements");
00932               return false;
00933             }
00934 
00935           m.setfield (nm, tcell);
00936         }
00937 
00938       if (is)
00939         map = m;
00940       else
00941         {
00942           error ("load: failed to load structure");
00943           success = false;
00944         }
00945     }
00946   else if (len == 0)
00947     map = octave_map (dv);
00948   else
00949     success = false;
00950 
00951   return success;
00952 }
00953 
00954 #if defined (HAVE_HDF5)
00955 
00956 bool
00957 octave_struct::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats)
00958 {
00959   hid_t data_hid = -1;
00960 
00961 #if HAVE_HDF5_18
00962   data_hid = H5Gcreate (loc_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
00963 #else
00964   data_hid = H5Gcreate (loc_id, name, 0);
00965 #endif
00966   if (data_hid < 0) return false;
00967 
00968   // recursively add each element of the structure to this group
00969   octave_map m = map_value ();
00970 
00971   octave_idx_type nf = m.nfields ();
00972 
00973   // Iterating over the list of keys will preserve the order of the
00974   // fields.
00975   string_vector keys = m.fieldnames ();
00976 
00977   for (octave_idx_type i = 0; i < nf; i++)
00978     {
00979       std::string key = keys(i);
00980 
00981       octave_value val = map.contents (key);
00982 
00983       bool retval2 = add_hdf5_data (data_hid, val, key, "", false,
00984                                     save_as_floats);
00985 
00986       if (! retval2)
00987         break;
00988     }
00989 
00990   H5Gclose (data_hid);
00991 
00992   return true;
00993 }
00994 
00995 bool
00996 octave_struct::load_hdf5 (hid_t loc_id, const char *name)
00997 {
00998   bool retval = false;
00999 
01000   hdf5_callback_data dsub;
01001 
01002   herr_t retval2 = 0;
01003   octave_map m (dim_vector (1, 1));
01004   int current_item = 0;
01005   hsize_t num_obj = 0;
01006 #if HAVE_HDF5_18
01007   hid_t group_id = H5Gopen (loc_id, name, H5P_DEFAULT);
01008 #else
01009   hid_t group_id = H5Gopen (loc_id, name);
01010 #endif
01011   H5Gget_num_objs (group_id, &num_obj);
01012   H5Gclose (group_id);
01013 
01014   // FIXME -- fields appear to be sorted alphabetically on loading.
01015   // Why is that happening?
01016 
01017   while (current_item < static_cast<int> (num_obj)
01018          && (retval2 = H5Giterate (loc_id, name, &current_item,
01019                                    hdf5_read_next_data, &dsub)) > 0)
01020     {
01021       octave_value t2 = dsub.tc;
01022 
01023       Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
01024 
01025       if (error_state)
01026         {
01027           error ("load: internal error loading struct elements");
01028           return false;
01029         }
01030 
01031       m.setfield (dsub.name, tcell);
01032 
01033     }
01034 
01035   if (retval2 >= 0)
01036     {
01037       map = m;
01038       retval = true;
01039     }
01040 
01041   return retval;
01042 }
01043 
01044 #endif
01045 
01046 mxArray *
01047 octave_struct::as_mxArray (void) const
01048 {
01049   int nf = nfields ();
01050   string_vector kv = map_keys ();
01051 
01052   OCTAVE_LOCAL_BUFFER (const char *, f, nf);
01053 
01054   for (int i = 0; i < nf; i++)
01055     f[i] = kv[i].c_str ();
01056 
01057   mxArray *retval = new mxArray (dims (), nf, f);
01058 
01059   mxArray **elts = static_cast<mxArray **> (retval->get_data ());
01060 
01061   mwSize nel = numel ();
01062 
01063   mwSize ntot = nf * nel;
01064 
01065   for (int i = 0; i < nf; i++)
01066     {
01067       Cell c = map.contents (kv[i]);
01068 
01069       const octave_value *p = c.data ();
01070 
01071       mwIndex k = 0;
01072       for (mwIndex j = i; j < ntot; j += nf)
01073         elts[j] = new mxArray (p[k++]);
01074     }
01075 
01076   return retval;
01077 }
01078 
01079 octave_value
01080 octave_struct::fast_elem_extract (octave_idx_type n) const
01081 {
01082   if (n < map.numel ())
01083     return map.checkelem (n);
01084   else
01085     return octave_value ();
01086 }
01087 
01088 bool
01089 octave_struct::fast_elem_insert (octave_idx_type n,
01090                                  const octave_value& x)
01091 {
01092   bool retval = false;
01093 
01094   if (n < map.numel ())
01095     {
01096       // To avoid copying the scalar struct, it just stores a pointer to
01097       // itself.
01098       const octave_scalar_map *sm_ptr;
01099       void *here = reinterpret_cast<void *>(&sm_ptr);
01100       return (x.get_rep().fast_elem_insert_self (here, btyp_struct)
01101               && map.fast_elem_insert (n, *sm_ptr));
01102     }
01103 
01104   return retval;
01105 }
01106 DEFINE_OCTAVE_ALLOCATOR(octave_scalar_struct);
01107 
01108 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(octave_scalar_struct, "scalar struct", "struct");
01109 
01110 octave_value
01111 octave_scalar_struct::dotref (const octave_value_list& idx, bool auto_add)
01112 {
01113   assert (idx.length () == 1);
01114 
01115   std::string nm = idx(0).string_value ();
01116 
01117   octave_value retval = map.getfield (nm);
01118 
01119   if (! auto_add && retval.is_undefined ())
01120     error ("structure has no member '%s'", nm.c_str ());
01121 
01122   return retval;
01123 }
01124 
01125 octave_value
01126 octave_scalar_struct::subsref (const std::string& type,
01127                                const std::list<octave_value_list>& idx)
01128 {
01129   octave_value retval;
01130 
01131   if (type[0] == '.')
01132     {
01133       int skip = 1;
01134 
01135       retval = dotref (idx.front ());
01136 
01137       if (idx.size () > 1)
01138         retval = retval.next_subsref (type, idx, skip);
01139     }
01140   else
01141     retval = to_array ().subsref (type, idx);
01142 
01143   return retval;
01144 }
01145 
01146 octave_value_list
01147 octave_scalar_struct::subsref (const std::string& type,
01148                                const std::list<octave_value_list>& idx,
01149                                int nargout)
01150 {
01151   octave_value_list retval;
01152 
01153   if (type[0] == '.')
01154     {
01155       int skip = 1;
01156 
01157       retval(0) = dotref (idx.front ());
01158 
01159       if (idx.size () > 1)
01160         retval = retval(0).next_subsref (nargout, type, idx, skip);
01161     }
01162   else
01163     retval = to_array ().subsref (type, idx, nargout);
01164 
01165   return retval;
01166 }
01167 
01168 octave_value
01169 octave_scalar_struct::subsref (const std::string& type,
01170                                const std::list<octave_value_list>& idx,
01171                                bool auto_add)
01172 {
01173   octave_value retval;
01174 
01175   if (type[0] == '.')
01176     {
01177       int skip = 1;
01178 
01179       retval = dotref (idx.front (), auto_add);
01180 
01181       if (idx.size () > 1)
01182         retval = retval.next_subsref (auto_add, type, idx, skip);
01183     }
01184   else
01185     retval = to_array ().subsref (type, idx, auto_add);
01186 
01187   return retval;
01188 }
01189 
01190 /*
01191 %!test
01192 %! x(1).a.a = 1; x(2).a.a = 2;
01193 %! assert (size (x), [1, 2]);
01194 %! assert (x(1).a.a, 1);
01195 %! assert (x(2).a.a, 2);
01196 */
01197 
01198 octave_value
01199 octave_scalar_struct::numeric_conv (const octave_value& val,
01200                                     const std::string& type)
01201 {
01202   octave_value retval;
01203 
01204   if (type.length () > 0 && type[0] == '.' && ! val.is_map ())
01205     retval = octave_map ();
01206   else
01207     retval = val;
01208 
01209   return retval;
01210 }
01211 
01212 octave_value
01213 octave_scalar_struct::subsasgn (const std::string& type,
01214                                 const std::list<octave_value_list>& idx,
01215                                 const octave_value& rhs)
01216 {
01217   octave_value retval;
01218 
01219   if (idx.front ().empty ())
01220     {
01221       error ("missing index in indexed assignment");
01222       return retval;
01223     }
01224 
01225   if (type[0] == '.')
01226     {
01227       int n = type.length ();
01228 
01229       octave_value t_rhs = rhs;
01230 
01231       octave_value_list key_idx = idx.front ();
01232 
01233       assert (key_idx.length () == 1);
01234 
01235       std::string key = key_idx(0).string_value ();
01236 
01237       if (n > 1)
01238         {
01239           std::list<octave_value_list> next_idx (idx);
01240 
01241           next_idx.erase (next_idx.begin ());
01242 
01243           std::string next_type = type.substr (1);
01244 
01245           octave_value tmp;
01246           octave_map::iterator pkey = map.seek (key);
01247           if (pkey != map.end ())
01248             {
01249               map.contents (pkey).make_unique ();
01250               tmp = map.contents (pkey);
01251             }
01252 
01253           if (! error_state)
01254             {
01255               bool orig_undefined = tmp.is_undefined ();
01256 
01257               if (orig_undefined || tmp.is_zero_by_zero ())
01258                 {
01259                   tmp = octave_value::empty_conv (next_type, rhs);
01260                   tmp.make_unique (); // probably a no-op.
01261                 }
01262               else
01263                 // optimization: ignore the copy still stored inside our map.
01264                 tmp.make_unique (1);
01265 
01266               if (! error_state)
01267                 t_rhs = (orig_undefined
01268                          ? tmp.undef_subsasgn (next_type, next_idx, rhs)
01269                          : tmp.subsasgn (next_type, next_idx, rhs));
01270             }
01271         }
01272 
01273       if (! error_state)
01274         map.setfield (key, t_rhs.storable_value ());
01275       else
01276         gripe_failed_assignment ();
01277 
01278       count++;
01279       retval = this;
01280     }
01281   else
01282     {
01283       // Forward this case to octave_struct.
01284       octave_value tmp (new octave_struct (octave_map (map)));
01285       retval = tmp.subsasgn (type, idx, rhs);
01286     }
01287 
01288   return retval;
01289 }
01290 
01291 octave_value
01292 octave_scalar_struct::do_index_op (const octave_value_list& idx, bool resize_ok)
01293 {
01294   // octave_map handles indexing itself.
01295   return octave_map (map).index (idx, resize_ok);
01296 }
01297 
01298 size_t
01299 octave_scalar_struct::byte_size (void) const
01300 {
01301   // Neglect the size of the fieldnames.
01302 
01303   size_t retval = 0;
01304 
01305   for (octave_map::const_iterator p = map.begin (); p != map.end (); p++)
01306     {
01307       std::string key = map.key (p);
01308 
01309       octave_value val = octave_value (map.contents (p));
01310 
01311       retval += val.byte_size ();
01312     }
01313 
01314   return retval;
01315 }
01316 
01317 void
01318 octave_scalar_struct::print (std::ostream& os, bool) const
01319 {
01320   print_raw (os);
01321 }
01322 
01323 void
01324 octave_scalar_struct::print_raw (std::ostream& os, bool) const
01325 {
01326   unwind_protect frame;
01327 
01328   frame.protect_var (Vstruct_levels_to_print);
01329 
01330   if (Vstruct_levels_to_print >= 0)
01331     {
01332       bool max_depth_reached = Vstruct_levels_to_print-- == 0;
01333 
01334       bool print_fieldnames_only = max_depth_reached;
01335 
01336       increment_indent_level ();
01337 
01338       if (! Vcompact_format)
01339         newline (os);
01340 
01341       indent (os);
01342       os << "scalar structure containing the fields:";
01343       newline (os);
01344       if (! Vcompact_format)
01345         newline (os);
01346 
01347       increment_indent_level ();
01348 
01349       string_vector key_list = map.fieldnames ();
01350 
01351       for (octave_idx_type i = 0; i < key_list.length (); i++)
01352         {
01353           std::string key = key_list[i];
01354 
01355           octave_value val = map.contents (key);
01356 
01357           if (print_fieldnames_only)
01358             {
01359               indent (os);
01360               os << key;
01361               dim_vector dv = val.dims ();
01362               os << ": " << dv.str () << " " << val.type_name ();
01363               newline (os);
01364             }
01365           else
01366             val.print_with_name (os, key);
01367         }
01368 
01369       decrement_indent_level ();
01370       decrement_indent_level ();
01371     }
01372   else
01373     {
01374       indent (os);
01375       os << "<structure>";
01376       newline (os);
01377     }
01378 }
01379 
01380 bool
01381 octave_scalar_struct::print_name_tag (std::ostream& os, const std::string& name) const
01382 {
01383   bool retval = false;
01384 
01385   indent (os);
01386 
01387   if (Vstruct_levels_to_print < 0)
01388     os << name << " = ";
01389   else
01390     {
01391       os << name << " =";
01392       newline (os);
01393       retval = true;
01394     }
01395 
01396   return retval;
01397 }
01398 
01399 bool
01400 octave_scalar_struct::save_ascii (std::ostream& os)
01401 {
01402   octave_map m = map_value ();
01403 
01404   octave_idx_type nf = m.nfields ();
01405 
01406   const dim_vector dv = dims ();
01407 
01408   os << "# ndims: " << dv.length () << "\n";
01409 
01410   for (int i = 0; i < dv.length (); i++)
01411     os << " " << dv (i);
01412   os << "\n";
01413 
01414   os << "# length: " << nf << "\n";
01415 
01416   // Iterating over the list of keys will preserve the order of the
01417   // fields.
01418   string_vector keys = m.fieldnames ();
01419 
01420   for (octave_idx_type i = 0; i < nf; i++)
01421     {
01422       std::string key = keys(i);
01423 
01424       octave_value val = map.contents (key);
01425 
01426       bool b = save_ascii_data (os, val, key, false, 0);
01427 
01428       if (! b)
01429         return os;
01430     }
01431 
01432   return true;
01433 }
01434 
01435 bool
01436 octave_scalar_struct::load_ascii (std::istream& is)
01437 {
01438   bool success = true;
01439   octave_idx_type len = 0;
01440 
01441   if (extract_keyword (is, "length", len) && len >= 0)
01442     {
01443       if (len > 0)
01444         {
01445           octave_scalar_map m;
01446 
01447           for (octave_idx_type j = 0; j < len; j++)
01448             {
01449               octave_value t2;
01450               bool dummy;
01451 
01452               // recurse to read cell elements
01453               std::string nm
01454                 = read_ascii_data (is, std::string (), dummy, t2, j);
01455 
01456               if (!is)
01457                 break;
01458 
01459               if (error_state)
01460                 {
01461                   error ("load: internal error loading struct elements");
01462                   return false;
01463                 }
01464 
01465               m.setfield (nm, t2);
01466             }
01467 
01468           if (is)
01469             map = m;
01470           else
01471             {
01472               error ("load: failed to load structure");
01473               success = false;
01474             }
01475         }
01476       else if (len == 0)
01477         map = octave_scalar_map ();
01478       else
01479         panic_impossible ();
01480     }
01481   else {
01482     error ("load: failed to extract number of elements in structure");
01483     success = false;
01484   }
01485 
01486   return success;
01487 }
01488 
01489 bool
01490 octave_scalar_struct::save_binary (std::ostream& os, bool& save_as_floats)
01491 {
01492   octave_map m = map_value ();
01493 
01494   octave_idx_type nf = m.nfields ();
01495 
01496   int32_t len = nf;
01497   os.write (reinterpret_cast<char *> (&len), 4);
01498 
01499   // Iterating over the list of keys will preserve the order of the
01500   // fields.
01501   string_vector keys = m.fieldnames ();
01502 
01503   for (octave_idx_type i = 0; i < nf; i++)
01504     {
01505       std::string key = keys(i);
01506 
01507       octave_value val = map.contents (key);
01508 
01509       bool b = save_binary_data (os, val, key, "", 0, save_as_floats);
01510 
01511       if (! b)
01512         return os;
01513     }
01514 
01515   return true;
01516 }
01517 
01518 bool
01519 octave_scalar_struct::load_binary (std::istream& is, bool swap,
01520                                    oct_mach_info::float_format fmt)
01521 {
01522   bool success = true;
01523   int32_t len;
01524   if (! is.read (reinterpret_cast<char *> (&len), 4))
01525     return false;
01526   if (swap)
01527     swap_bytes<4> (&len);
01528 
01529   dim_vector dv (1, 1);
01530 
01531   if (len > 0)
01532     {
01533       octave_scalar_map m;
01534 
01535       for (octave_idx_type j = 0; j < len; j++)
01536         {
01537           octave_value t2;
01538           bool dummy;
01539           std::string doc;
01540 
01541           // recurse to read cell elements
01542           std::string nm = read_binary_data (is, swap, fmt, std::string (),
01543                                              dummy, t2, doc);
01544 
01545           if (!is)
01546             break;
01547 
01548           if (error_state)
01549             {
01550               error ("load: internal error loading struct elements");
01551               return false;
01552             }
01553 
01554           m.setfield (nm, t2);
01555         }
01556 
01557       if (is)
01558         map = m;
01559       else
01560         {
01561           error ("load: failed to load structure");
01562           success = false;
01563         }
01564     }
01565   else if (len == 0)
01566     map = octave_scalar_map ();
01567   else
01568     success = false;
01569 
01570   return success;
01571 }
01572 
01573 #if defined (HAVE_HDF5)
01574 
01575 bool
01576 octave_scalar_struct::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats)
01577 {
01578   hid_t data_hid = -1;
01579 
01580 #if HAVE_HDF5_18
01581   data_hid = H5Gcreate (loc_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
01582 #else
01583   data_hid = H5Gcreate (loc_id, name, 0);
01584 #endif
01585   if (data_hid < 0) return false;
01586 
01587   // recursively add each element of the structure to this group
01588   octave_scalar_map m = scalar_map_value ();
01589 
01590   octave_idx_type nf = m.nfields ();
01591 
01592   // Iterating over the list of keys will preserve the order of the
01593   // fields.
01594   string_vector keys = m.fieldnames ();
01595 
01596   for (octave_idx_type i = 0; i < nf; i++)
01597     {
01598       std::string key = keys(i);
01599 
01600       octave_value val = map.contents (key);
01601 
01602       bool retval2 = add_hdf5_data (data_hid, val, key, "", false,
01603                                     save_as_floats);
01604 
01605       if (! retval2)
01606         break;
01607     }
01608 
01609   H5Gclose (data_hid);
01610 
01611   return true;
01612 }
01613 
01614 bool
01615 octave_scalar_struct::load_hdf5 (hid_t loc_id, const char *name)
01616 {
01617   bool retval = false;
01618 
01619   hdf5_callback_data dsub;
01620 
01621   herr_t retval2 = 0;
01622   octave_scalar_map m;
01623   int current_item = 0;
01624   hsize_t num_obj = 0;
01625 #if HAVE_HDF5_18
01626   hid_t group_id = H5Gopen (loc_id, name, H5P_DEFAULT);
01627 #else
01628   hid_t group_id = H5Gopen (loc_id, name);
01629 #endif
01630   H5Gget_num_objs (group_id, &num_obj);
01631   H5Gclose (group_id);
01632 
01633   // FIXME -- fields appear to be sorted alphabetically on loading.
01634   // Why is that happening?
01635 
01636   while (current_item < static_cast<int> (num_obj)
01637          && (retval2 = H5Giterate (loc_id, name, &current_item,
01638                                    hdf5_read_next_data, &dsub)) > 0)
01639     {
01640       octave_value t2 = dsub.tc;
01641 
01642       if (error_state)
01643         {
01644           error ("load: internal error loading struct elements");
01645           return false;
01646         }
01647 
01648       m.setfield (dsub.name, t2);
01649 
01650     }
01651 
01652   if (retval2 >= 0)
01653     {
01654       map = m;
01655       retval = true;
01656     }
01657 
01658   return retval;
01659 }
01660 
01661 #endif
01662 
01663 mxArray *
01664 octave_scalar_struct::as_mxArray (void) const
01665 {
01666   int nf = nfields ();
01667   string_vector kv = map_keys ();
01668 
01669   OCTAVE_LOCAL_BUFFER (const char *, f, nf);
01670 
01671   for (int i = 0; i < nf; i++)
01672     f[i] = kv[i].c_str ();
01673 
01674   mxArray *retval = new mxArray (dims (), nf, f);
01675 
01676   mxArray **elts = static_cast<mxArray **> (retval->get_data ());
01677 
01678   mwSize nel = numel ();
01679 
01680   mwSize ntot = nf * nel;
01681 
01682   for (int i = 0; i < nf; i++)
01683     {
01684       Cell c = map.contents (kv[i]);
01685 
01686       const octave_value *p = c.data ();
01687 
01688       mwIndex k = 0;
01689       for (mwIndex j = i; j < ntot; j += nf)
01690         elts[j] = new mxArray (p[k++]);
01691     }
01692 
01693   return retval;
01694 }
01695 
01696 
01697 octave_value
01698 octave_scalar_struct::to_array (void)
01699 {
01700   return new octave_struct (octave_map (map));
01701 }
01702 
01703 bool
01704 octave_scalar_struct::fast_elem_insert_self (void *where, builtin_type_t btyp) const
01705 {
01706 
01707   if (btyp == btyp_struct)
01708     {
01709       *(reinterpret_cast<const octave_scalar_map **>(where)) = &map;
01710       return true;
01711     }
01712   else
01713     return false;
01714 }
01715 /*
01716 %!shared x
01717 %! x(1).a=1; x(2).a=2; x(1).b=3; x(2).b=3;
01718 %!assert(struct('a',1,'b',3),x(1))
01719 %!assert(isempty(x([])))
01720 %!assert(isempty(struct('a',{},'b',{})))
01721 %!assert(struct('a',{1,2},'b',{3,3}),x)
01722 %!assert(struct('a',{1,2},'b',3),x)
01723 %!assert(struct('a',{1,2},'b',{3}),x)
01724 %!assert(struct('b',3,'a',{1,2}),x)
01725 %!assert(struct('b',{3},'a',{1,2}),x)
01726 %!test x=struct([]);
01727 %!assert(size(x),[0,0]);
01728 %!assert(isstruct(x));
01729 %!assert(isempty(fieldnames(x)));
01730 %!fail("struct('a',{1,2},'b',{1,2,3})","dimensions of parameter 2 do not match those of parameter 4")
01731 %!fail("struct(1,2,3,4)","struct: expecting alternating \"field\", VALUE pairs");
01732 %!fail("struct('1',2,'3')","struct: expecting alternating \"field\", VALUE pairs");
01733 */
01734 
01735 DEFUN (struct, args, ,
01736   "-*- texinfo -*-\n\
01737 @deftypefn {Built-in Function} {} struct (\"field\", @var{value}, \"field\", @var{value}, @dots{})\n\
01738 \n\
01739 Create a structure and initialize its value.\n\
01740 \n\
01741 If the values are cell arrays, create a structure array and initialize\n\
01742 its values.  The dimensions of each cell array of values must match.\n\
01743 Singleton cells and non-cell values are repeated so that they fill\n\
01744 the entire array.  If the cells are empty, create an empty structure\n\
01745 array with the specified field names.\n\
01746 \n\
01747 If the argument is an object, return the underlying struct.\n\
01748 @end deftypefn")
01749 {
01750   octave_value retval;
01751 
01752   int nargin = args.length ();
01753 
01754   // struct ([]) returns an empty struct.
01755 
01756   // struct (empty_matrix) returns an empty struct with the same
01757   // dimensions as the empty matrix.
01758 
01759   // Note that struct () creates a 1x1 struct with no fields for
01760   // compatibility with Matlab.
01761 
01762   if (nargin == 1 && args(0).is_map ())
01763     return args(0);
01764 
01765   if (nargin == 1 && args(0).is_object ())
01766     {
01767       retval = args(0).map_value ();
01768 
01769       return retval;
01770     }
01771 
01772   if ((nargin == 1 || nargin == 2)
01773       && args(0).is_empty () && args(0).is_real_matrix ())
01774     {
01775       Cell fields;
01776 
01777       if (nargin == 2)
01778         {
01779           if (args(1).is_cellstr ())
01780             retval = octave_map (args(0).dims (), args(1).cellstr_value ());
01781           else
01782             error ("struct: expecting cell array of field names as second argument");
01783         }
01784       else
01785         retval = octave_map (args(0).dims ());
01786 
01787       return retval;
01788     }
01789 
01790   // Check for "field", VALUE pairs.
01791 
01792   for (int i = 0; i < nargin; i += 2)
01793     {
01794       if (! args(i).is_string () || i + 1 >= nargin)
01795         {
01796           error ("struct: expecting alternating \"field\", VALUE pairs");
01797           return retval;
01798         }
01799     }
01800 
01801   // Check that the dimensions of the values correspond.
01802 
01803   dim_vector dims (1, 1);
01804 
01805   int first_dimensioned_value = 0;
01806 
01807   for (int i = 1; i < nargin; i += 2)
01808     {
01809       if (args(i).is_cell ())
01810         {
01811           dim_vector argdims (args(i).dims ());
01812 
01813           if (! scalar (argdims))
01814             {
01815               if (! first_dimensioned_value)
01816                 {
01817                   dims = argdims;
01818                   first_dimensioned_value = i + 1;
01819                 }
01820               else if (dims != argdims)
01821                 {
01822                   error ("struct: dimensions of parameter %d do not match those of parameter %d",
01823                          first_dimensioned_value, i+1);
01824                   return retval;
01825                 }
01826             }
01827         }
01828     }
01829 
01830   // Create the return value.
01831 
01832   octave_map map (dims);
01833 
01834   for (int i = 0; i < nargin; i+= 2)
01835     {
01836       // Get key.
01837 
01838       std::string key (args(i).string_value ());
01839 
01840       if (error_state)
01841         return retval;
01842 
01843       if (! valid_identifier (key))
01844         {
01845           error ("struct: invalid structure field name '%s'", key.c_str ());
01846           return retval;
01847         }
01848 
01849       // Value may be v, { v }, or { v1, v2, ... }
01850       // In the first two cases, we need to create a cell array of
01851       // the appropriate dimensions filled with v.  In the last case,
01852       // the cell array has already been determined to be of the
01853       // correct dimensions.
01854 
01855       if (args(i+1).is_cell ())
01856         {
01857           const Cell c (args(i+1).cell_value ());
01858 
01859           if (error_state)
01860             return retval;
01861 
01862           if (scalar (c.dims ()))
01863             map.setfield (key, Cell (dims, c(0)));
01864           else
01865             map.setfield (key, c);
01866         }
01867       else
01868         map.setfield (key, Cell (dims, args(i+1)));
01869 
01870       if (error_state)
01871         return retval;
01872     }
01873 
01874   return octave_value (map);
01875 }
01876 
01877 DEFUN (isstruct, args, ,
01878   "-*- texinfo -*-\n\
01879 @deftypefn {Built-in Function} {} isstruct (@var{x})\n\
01880 Return true if @var{x} is a structure or a structure array.\n\
01881 @seealso{ismatrix, iscell, isa}\n\
01882 @end deftypefn")
01883 {
01884   octave_value retval;
01885 
01886   if (args.length () == 1)
01887     retval = args(0).is_map ();
01888   else
01889     print_usage ();
01890 
01891   return retval;
01892 }
01893 
01894 DEFUN (fieldnames, args, ,
01895   "-*- texinfo -*-\n\
01896 @deftypefn {Built-in Function} {} fieldnames (@var{struct})\n\
01897 Return a cell array of strings naming the elements of the structure\n\
01898 @var{struct}.  It is an error to call @code{fieldnames} with an\n\
01899 argument that is not a structure.\n\
01900 @end deftypefn")
01901 {
01902   octave_value retval;
01903 
01904   int nargin = args.length ();
01905 
01906   if (nargin == 1)
01907     {
01908       octave_value arg = args(0);
01909 
01910       if (arg.is_map () || arg.is_object ())
01911         {
01912           octave_map m = arg.map_value ();
01913 
01914           string_vector keys = m.fieldnames ();
01915 
01916           if (keys.length () == 0)
01917             retval = Cell (0, 1);
01918           else
01919             retval = Cell (keys);
01920         }
01921       else
01922         gripe_wrong_type_arg ("fieldnames", args(0));
01923     }
01924   else
01925     print_usage ();
01926 
01927   return retval;
01928 }
01929 
01930 /*
01931 %!# test preservation of fieldname order
01932 %!test
01933 %!  x(3).d=1; x(2).a=2; x(1).b=3; x(2).c=3;
01934 %!  assert(fieldnames(x), {"d"; "a"; "b"; "c"});
01935 */
01936 
01937 DEFUN (isfield, args, ,
01938   "-*- texinfo -*-\n\
01939 @deftypefn {Built-in Function} {} isfield (@var{x}, @var{name})\n\
01940 Return true if the @var{x} is a structure and it\n\
01941 includes an element named @var{name}.  If @var{name} is a cell\n\
01942 array of strings then a logical array of equal dimension is returned.\n\
01943 @end deftypefn")
01944 {
01945   octave_value retval;
01946 
01947   int nargin = args.length ();
01948 
01949   if (nargin == 2)
01950     {
01951       retval = false;
01952 
01953       if (args(0).is_map ())
01954         {
01955           octave_map m = args(0).map_value ();
01956 
01957           // FIXME -- should this work for all types that can do
01958           // structure reference operations?
01959 
01960           if (args(1).is_string ())
01961             {
01962               std::string key = args(1).string_value ();
01963 
01964               retval = m.isfield (key);
01965             }
01966           else if (args(1).is_cell ())
01967             {
01968               Cell c = args(1).cell_value ();
01969               boolNDArray bm (c.dims ());
01970               octave_idx_type n = bm.numel ();
01971 
01972               for (octave_idx_type i = 0; i < n; i++)
01973                 {
01974                   if (c(i).is_string ())
01975                     {
01976                       std::string key = c(i).string_value ();
01977 
01978                       bm(i) = m.isfield (key);
01979                     }
01980                   else
01981                     bm(i) = false;
01982                 }
01983 
01984               retval = bm;
01985             }
01986         }
01987     }
01988   else
01989     print_usage ();
01990 
01991   return retval;
01992 }
01993 
01994 DEFUN (nfields, args, ,
01995   "-*- texinfo -*-\n\
01996 @deftypefn {Built-in Function} {} nfields (@var{s})\n\
01997 Return the number of fields of the structure @var{s}.\n\
01998 @end deftypefn")
01999 {
02000   octave_value retval;
02001 
02002   int nargin = args.length ();
02003 
02004   if (nargin == 1 && args(0).is_map ())
02005     {
02006       retval = static_cast<double> (args(0).nfields ());
02007     }
02008   else
02009     print_usage ();
02010 
02011   return retval;
02012 }
02013 
02014 /*
02015 %!# test isfield
02016 %!test
02017 %!  x(3).d=1; x(2).a=2; x(1).b=3; x(2).c=3;
02018 %!  assert (isfield (x, 'b'));
02019 %!assert (isfield (struct('a', '1'), 'a'));
02020 %!assert (isfield ({1}, 'c'), false);
02021 %!assert (isfield (struct('a', '1'), 10), false);
02022 %!assert (isfield (struct('a', 'b'), "a "), false);
02023 %!assert (isfield (struct('a', 1, 'b', 2), {'a', 'c'}), [true, false]);
02024 */
02025 
02026 DEFUN (cell2struct, args, ,
02027        "-*- texinfo -*-\n\
02028 @deftypefn {Built-in Function} {} cell2struct (@var{cell}, @var{fields}, @var{dim})\n\
02029 Convert @var{cell} to a structure.  The number of fields in @var{fields}\n\
02030 must match the number of elements in @var{cell} along dimension @var{dim},\n\
02031 that is @code{numel (@var{fields}) == size (@var{cell}, @var{dim})}.\n\
02032 If @var{dim} is omitted, a value of 1 is assumed.\n\
02033 \n\
02034 @example\n\
02035 @group\n\
02036 A = cell2struct (@{'Peter', 'Hannah', 'Robert';\n\
02037                    185, 170, 168@},\n\
02038                  @{'Name','Height'@}, 1);\n\
02039 A(1)\n\
02040      @result{} ans =\n\
02041         @{\n\
02042           Name   = Peter\n\
02043           Height = 185\n\
02044         @}\n\
02045 \n\
02046 @end group\n\
02047 @end example\n\
02048 @end deftypefn")
02049 {
02050   octave_value retval;
02051 
02052   int nargin = args.length ();
02053 
02054   if (nargin == 2 || nargin == 3)
02055     {
02056       if (! args(0).is_cell ())
02057         {
02058           error ("cell2struct: argument CELL must be of type cell");
02059           return retval;
02060         }
02061 
02062       if (! (args(1).is_cellstr () || args(1).is_char_matrix ()))
02063         {
02064           error ("cell2struct: FIELDS must be a cell array of strings or a character matrix");
02065           return retval;
02066         }
02067 
02068       const Cell vals = args(0).cell_value ();
02069       const Array<std::string> fields = args(1).cellstr_value ();
02070 
02071       octave_idx_type ext = 0;
02072 
02073       int dim = 0;
02074 
02075       if (nargin == 3)
02076         {
02077           if (args(2).is_real_scalar ())
02078             {
02079               dim = nargin == 2 ? 0 : args(2).int_value () - 1;
02080 
02081               if (error_state)
02082                 return retval;
02083             }
02084           else
02085             {
02086               error ("cell2struct: DIM must be a real scalar");
02087               return retval;
02088             }
02089         }
02090 
02091       if (dim < 0)
02092         {
02093           error ("cell2struct: DIM must be a valid dimension");
02094           return retval;
02095         }
02096 
02097       ext = vals.ndims () > dim ? vals.dims ()(dim) : 1;
02098 
02099       if (ext != fields.numel ())
02100         {
02101           error ("cell2struct: number of FIELDS does not match dimension");
02102           return retval;
02103         }
02104 
02105       int nd = std::max (dim+1, vals.ndims ());
02106       // result dimensions.
02107       dim_vector rdv = vals.dims ().redim (nd);
02108 
02109       assert (ext == rdv(dim));
02110       if (nd == 2)
02111         {
02112           rdv(0) = rdv(1-dim);
02113           rdv(1) = 1;
02114         }
02115       else
02116         {
02117           for (int i =  dim + 1; i < nd; i++)
02118             rdv(i-1) = rdv(i);
02119 
02120           rdv.resize (nd-1);
02121         }
02122 
02123       octave_map map (rdv);
02124       Array<idx_vector> ia (dim_vector (nd, 1), idx_vector::colon);
02125 
02126       for (octave_idx_type i = 0; i < ext; i++)
02127         {
02128           ia(dim) = i;
02129           map.setfield (fields(i), vals.index (ia).reshape (rdv));
02130         }
02131 
02132       retval = map;
02133     }
02134   else
02135     print_usage ();
02136 
02137   return retval;
02138 }
02139 
02140 /*
02141 %!# test cell2struct versus struct2cell
02142 %!test
02143 %!  keys = cellstr (char (floor (rand (100,10)*24+65)))';
02144 %!  vals = mat2cell(rand (100,1), ones (100,1), 1)';
02145 %!  s = struct ([keys; vals]{:});
02146 %!  t = cell2struct (vals, keys, 2);
02147 %!  assert (s, t);
02148 %!  assert (struct2cell (s), vals');
02149 %!  assert (fieldnames (s), keys');
02150 
02151 %!assert (cell2struct ({1; 2}, {"a"; "b"}), struct ("a", 1, "b", 2));
02152 
02153 %!assert (cell2struct ({}, {"f"}, 3), struct ("f", {}));
02154 */
02155 
02156 
02157 // So we can call Fcellstr directly.
02158 extern octave_value_list Fcellstr (const octave_value_list& args, int);
02159 
02160 DEFUN (rmfield, args, ,
02161        "-*- texinfo -*-\n\
02162 @deftypefn {Built-in Function} {} rmfield (@var{s}, @var{f})\n\
02163 Return a copy of the structure (array) @var{s} with the field @var{f}\n\
02164 removed.  If @var{f} is a cell array of strings or a character array, remove\n\
02165 the named fields.\n\
02166 @seealso{cellstr, iscellstr, setfield}\n\
02167 @end deftypefn")
02168 {
02169   octave_value retval;
02170 
02171   int nargin = args.length ();
02172 
02173   if (nargin == 2)
02174     {
02175       octave_map m = args(0).map_value ();
02176 
02177       octave_value_list fval = Fcellstr (args(1), 1);
02178 
02179       if (! error_state)
02180         {
02181           Cell fcell = fval(0).cell_value ();
02182 
02183           for (int i = 0; i < fcell.numel (); i++)
02184             {
02185               std::string key = fcell(i).string_value ();
02186 
02187               if (m.isfield (key))
02188                 m.rmfield (key);
02189               else
02190                 {
02191                   error ("rmfield: structure does not contain field %s",
02192                          key.c_str ());
02193 
02194                   break;
02195                 }
02196             }
02197 
02198           if (! error_state)
02199             retval = m;
02200         }
02201     }
02202   else
02203     print_usage ();
02204 
02205   return retval;
02206 }
02207 
02208 /*
02209 %!# test rmfield
02210 %!test
02211 %!  x(3).d=1; x(2).a=2; x(1).b=3; x(2).c=3; x(6).f="abc123";
02212 %!  y = rmfield (x, {"a", "f"});
02213 %!  assert (fieldnames (y), {"d"; "b"; "c"});
02214 %!  assert (size (y), [1, 6]);
02215 */
02216 
02217 DEFUN (struct_levels_to_print, args, nargout,
02218   "-*- texinfo -*-\n\
02219 @deftypefn  {Built-in Function} {@var{val} =} struct_levels_to_print ()\n\
02220 @deftypefnx {Built-in Function} {@var{old_val} =} struct_levels_to_print (@var{new_val})\n\
02221 @deftypefnx {Built-in Function} {} struct_levels_to_print (@var{new_val}, \"local\")\n\
02222 Query or set the internal variable that specifies the number of\n\
02223 structure levels to display.\n\
02224 \n\
02225 When called from inside a function with the \"local\" option, the variable is\n\
02226 changed locally for the function and any subroutines it calls.  The original\n\
02227 variable value is restored when exiting the function.\n\
02228 @end deftypefn")
02229 {
02230   return SET_INTERNAL_VARIABLE_WITH_LIMITS (struct_levels_to_print,
02231                                             -1, INT_MAX);
02232 }
02233 
02234 DEFUN (print_struct_array_contents, args, nargout,
02235   "-*- texinfo -*-\n\
02236 @deftypefn  {Built-in Function} {@var{val} =} print_struct_array_contents ()\n\
02237 @deftypefnx {Built-in Function} {@var{old_val} =} print_struct_array_contents (@var{new_val})\n\
02238 @deftypefnx {Built-in Function} {} print_struct_array_contents (@var{new_val}, \"local\")\n\
02239 Query or set the internal variable that specifies whether to print struct\n\
02240 array contents.  If true, values of struct array elements are printed.\n\
02241 This variable does not affect scalar structures.  Their elements\n\
02242 are always printed.  In both cases, however, printing will be limited to\n\
02243 the number of levels specified by @var{struct_levels_to_print}.\n\
02244 \n\
02245 When called from inside a function with the \"local\" option, the variable is\n\
02246 changed locally for the function and any subroutines it calls.  The original\n\
02247 variable value is restored when exiting the function.\n\
02248 @end deftypefn")
02249 {
02250   return SET_INTERNAL_VARIABLE (print_struct_array_contents);
02251 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines