oct-map.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 1995-2012 John W. Eaton
00004 Copyright (C) 2010 VZLU Prague
00005 
00006 This file is part of Octave.
00007 
00008 Octave is free software; you can redistribute it and/or modify it
00009 under the terms of the GNU General Public License as published by the
00010 Free Software Foundation; either version 3 of the License, or (at your
00011 option) any later version.
00012 
00013 Octave is distributed in the hope that it will be useful, but WITHOUT
00014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00015 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00016 for more details.
00017 
00018 You should have received a copy of the GNU General Public License
00019 along with Octave; see the file COPYING.  If not, see
00020 <http://www.gnu.org/licenses/>.
00021 
00022 */
00023 
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027 
00028 #include "error.h"
00029 #include "str-vec.h"
00030 
00031 #include "oct-map.h"
00032 #include "utils.h"
00033 
00034 octave_fields::octave_fields (const string_vector& fields)
00035   : rep (new fields_rep)
00036 {
00037   octave_idx_type n = fields.numel ();
00038   for (octave_idx_type i = 0; i < n; i++)
00039     (*rep)[fields(i)] = i;
00040 }
00041 
00042 octave_fields::octave_fields (const char * const *fields)
00043   : rep (new fields_rep)
00044 {
00045   octave_idx_type n = 0;
00046   while (*fields)
00047     (*rep)[std::string (*fields++)] = n++;
00048 }
00049 
00050 bool
00051 octave_fields::isfield (const std::string& field) const
00052 {
00053   return rep->find (field) != rep->end ();
00054 }
00055 
00056 octave_idx_type
00057 octave_fields::getfield (const std::string& field) const
00058 {
00059   fields_rep::iterator p = rep->find (field);
00060   return (p != rep->end ()) ? p->second : -1;
00061 }
00062 
00063 octave_idx_type
00064 octave_fields::getfield (const std::string& field)
00065 {
00066   fields_rep::iterator p = rep->find (field);
00067   if (p != rep->end ())
00068     return p->second;
00069   else
00070     {
00071       make_unique ();
00072       octave_idx_type n = rep->size ();
00073       return (*rep)[field] = n;
00074     }
00075 }
00076 
00077 octave_idx_type
00078 octave_fields::rmfield (const std::string& field)
00079 {
00080   fields_rep::iterator p = rep->find (field);
00081   if (p == rep->end ())
00082     return -1;
00083   else
00084     {
00085       octave_idx_type n = p->second;
00086       make_unique ();
00087       rep->erase (field);
00088       for (fields_rep::iterator q = rep->begin (); q != rep->end (); q++)
00089         {
00090           if (q->second >= n)
00091             q->second--;
00092         }
00093 
00094       return n;
00095     }
00096 }
00097 
00098 void
00099 octave_fields::orderfields (Array<octave_idx_type>& perm)
00100 {
00101   octave_idx_type n = rep->size ();
00102   perm.clear (n, 1);
00103 
00104   make_unique ();
00105   octave_idx_type i = 0;
00106   for (fields_rep::iterator q = rep->begin (); q != rep->end (); q++)
00107     {
00108       octave_idx_type j = q->second;
00109       q->second = i;
00110       perm(i++) = j;
00111     }
00112 }
00113 
00114 bool
00115 octave_fields::equal_up_to_order (const octave_fields& other,
00116                                   octave_idx_type* perm) const
00117 {
00118   bool retval = true;
00119 
00120   iterator p = begin (), q = other.begin ();
00121   for (; p != end () && q != other.end (); p++, q++)
00122     {
00123       if (p->first == q->first)
00124         perm[p->second] = q->second;
00125       else
00126         {
00127           retval = false;
00128           break;
00129         }
00130     }
00131 
00132   retval = (p == end () && q == other.end ());
00133 
00134   return retval;
00135 }
00136 
00137 bool
00138 octave_fields::equal_up_to_order (const octave_fields& other,
00139                                   Array<octave_idx_type>& perm) const
00140 {
00141   octave_idx_type n = nfields ();
00142   if (perm.length () != n)
00143     perm.clear (1, n);
00144 
00145   return equal_up_to_order (other, perm.fortran_vec ());
00146 }
00147 
00148 string_vector
00149 octave_fields::fieldnames (void) const
00150 {
00151   octave_idx_type n = nfields ();
00152   string_vector retval(n);
00153 
00154   for (iterator p = begin (); p != end (); p++)
00155     retval.xelem(p->second) = p->first;
00156 
00157   return retval;
00158 }
00159 
00160 octave_value
00161 octave_scalar_map::getfield (const std::string& k) const
00162 {
00163   octave_idx_type idx = xkeys.getfield (k);
00164   return (idx >= 0) ? xvals[idx] : octave_value ();
00165 }
00166 
00167 void
00168 octave_scalar_map::setfield (const std::string& k, const octave_value& val)
00169 {
00170   octave_idx_type idx = xkeys.getfield (k);
00171   if (idx < static_cast<octave_idx_type> (xvals.size ()))
00172     xvals[idx] = val;
00173   else
00174     xvals.push_back (val);
00175 }
00176 
00177 void
00178 octave_scalar_map::rmfield (const std::string& k)
00179 {
00180   octave_idx_type idx = xkeys.rmfield (k);
00181   if (idx >= 0)
00182     xvals.erase (xvals.begin () + idx);
00183 }
00184 
00185 octave_scalar_map
00186 octave_scalar_map::orderfields (void) const
00187 {
00188   Array<octave_idx_type> perm;
00189   return orderfields (perm);
00190 }
00191 
00192 octave_scalar_map
00193 octave_scalar_map::orderfields (Array<octave_idx_type>& perm) const
00194 {
00195   octave_scalar_map retval (xkeys);
00196   retval.xkeys.orderfields (perm);
00197 
00198   octave_idx_type nf = nfields ();
00199   for (octave_idx_type i = 0; i < nf; i++)
00200     retval.xvals[i] = xvals[perm.xelem(i)];
00201 
00202   return retval;
00203 }
00204 
00205 octave_scalar_map
00206 octave_scalar_map::orderfields (const octave_scalar_map& other,
00207                                 Array<octave_idx_type>& perm) const
00208 {
00209   if (xkeys.is_same (other.xkeys))
00210     return *this;
00211   else
00212     {
00213       octave_scalar_map retval (other.xkeys);
00214       if (other.xkeys.equal_up_to_order (xkeys, perm))
00215         {
00216           octave_idx_type nf = nfields ();
00217           for (octave_idx_type i = 0; i < nf; i++)
00218             retval.xvals[i] = xvals[perm.xelem(i)];
00219         }
00220       else
00221         error ("orderfields: structs must have same fields up to order");
00222 
00223       return retval;
00224     }
00225 }
00226 
00227 octave_value
00228 octave_scalar_map::contents (const std::string& k) const
00229 {
00230   return getfield (k);
00231 }
00232 
00233 octave_value&
00234 octave_scalar_map::contents (const std::string& k)
00235 {
00236   octave_idx_type idx = xkeys.getfield (k);
00237   if (idx >= static_cast<octave_idx_type> (xvals.size ()))
00238     xvals.resize (idx+1);
00239   return xvals[idx];
00240 }
00241 
00242 octave_map::octave_map (const octave_scalar_map& m)
00243   : xkeys (m.xkeys), xvals (), dimensions (1, 1)
00244 {
00245   octave_idx_type nf = m.nfields ();
00246   xvals.reserve (nf);
00247   for (octave_idx_type i = 0; i < nf; i++)
00248     {
00249       xvals.push_back (Cell (dimensions));
00250       xvals[i].xelem(0) = m.xvals[i];
00251     }
00252 }
00253 
00254 octave_map::octave_map (const Octave_map& m)
00255   : xkeys (m.keys ()), xvals (m.nfields ()), dimensions (m.dims ())
00256 {
00257   for (iterator p = begin (); p != end (); p++)
00258     contents(p) = m.contents (key (p));
00259 
00260   optimize_dimensions ();
00261 }
00262 
00263 Cell
00264 octave_map::getfield (const std::string& k) const
00265 {
00266   octave_idx_type idx = xkeys.getfield (k);
00267   return (idx >= 0) ? xvals[idx] : Cell ();
00268 }
00269 
00270 void
00271 octave_map::setfield (const std::string& k, const Cell& val)
00272 {
00273   if (nfields () == 0)
00274     dimensions = val.dims ();
00275 
00276   if (val.dims () == dimensions)
00277     {
00278       octave_idx_type idx = xkeys.getfield (k);
00279       if (idx < static_cast<octave_idx_type> (xvals.size ()))
00280         xvals[idx] = val;
00281       else
00282         xvals.push_back (val);
00283     }
00284   else
00285     error ("octave_map::setfield: internal error");
00286 }
00287 
00288 void
00289 octave_map::rmfield (const std::string& k)
00290 {
00291   octave_idx_type idx = xkeys.rmfield (k);
00292   if (idx >= 0)
00293     xvals.erase (xvals.begin () + idx);
00294 }
00295 
00296 octave_map
00297 octave_map::orderfields (void) const
00298 {
00299   Array<octave_idx_type> perm;
00300   return orderfields (perm);
00301 }
00302 
00303 octave_map
00304 octave_map::orderfields (Array<octave_idx_type>& perm) const
00305 {
00306   octave_map retval (xkeys);
00307   retval.xkeys.orderfields (perm);
00308 
00309   octave_idx_type nf = nfields ();
00310   for (octave_idx_type i = 0; i < nf; i++)
00311     retval.xvals[i] = xvals[perm.xelem(i)];
00312 
00313   return retval;
00314 }
00315 
00316 octave_map
00317 octave_map::orderfields (const octave_map& other,
00318                          Array<octave_idx_type>& perm) const
00319 {
00320   if (xkeys.is_same (other.xkeys))
00321     return *this;
00322   else
00323     {
00324       octave_map retval (other.xkeys);
00325       if (other.xkeys.equal_up_to_order (xkeys, perm))
00326         {
00327           octave_idx_type nf = nfields ();
00328           for (octave_idx_type i = 0; i < nf; i++)
00329             retval.xvals[i] = xvals[perm.xelem(i)];
00330         }
00331       else
00332         error ("orderfields: structs must have same fields up to order");
00333 
00334       return retval;
00335     }
00336 }
00337 
00338 Cell
00339 octave_map::contents (const std::string& k) const
00340 {
00341   return getfield (k);
00342 }
00343 
00344 Cell&
00345 octave_map::contents (const std::string& k)
00346 {
00347   octave_idx_type idx = xkeys.getfield (k);
00348   if (idx >= static_cast<octave_idx_type> (xvals.size ()))
00349     xvals.push_back (Cell (dimensions)); // auto-set correct dims.
00350   return xvals[idx];
00351 }
00352 
00353 void
00354 octave_map::extract_scalar (octave_scalar_map& dest,
00355                             octave_idx_type idx) const
00356 {
00357   octave_idx_type nf = nfields ();
00358   for (octave_idx_type i = 0; i < nf; i++)
00359     dest.xvals[i] = xvals[i](idx);
00360 }
00361 
00362 octave_scalar_map
00363 octave_map::checkelem (octave_idx_type n) const
00364 {
00365   octave_scalar_map retval (xkeys);
00366 
00367   // Optimize this so that there is just one check.
00368   extract_scalar (retval, compute_index (n, dimensions));
00369 
00370   return retval;
00371 }
00372 
00373 octave_scalar_map
00374 octave_map::checkelem (octave_idx_type i, octave_idx_type j) const
00375 {
00376   octave_scalar_map retval (xkeys);
00377 
00378   // Optimize this so that there is just one check.
00379   extract_scalar (retval, compute_index (i, j, dimensions));
00380 
00381   return retval;
00382 }
00383 
00384 octave_scalar_map
00385 octave_map::checkelem (const Array<octave_idx_type>& ra_idx) const
00386 {
00387   octave_scalar_map retval (xkeys);
00388 
00389   // Optimize this so that there is just one check.
00390   extract_scalar (retval, compute_index (ra_idx, dimensions));
00391 
00392   return retval;
00393 }
00394 
00395 octave_scalar_map
00396 octave_map::fast_elem_extract (octave_idx_type n) const
00397 {
00398   octave_scalar_map retval (xkeys);
00399 
00400   extract_scalar (retval, n);
00401 
00402   return retval;
00403 }
00404 
00405 bool
00406 octave_map::fast_elem_insert (octave_idx_type n,
00407                               const octave_scalar_map& rhs)
00408 {
00409   bool retval = false;
00410 
00411   octave_idx_type nf = nfields ();
00412   if (rhs.xkeys.is_same (xkeys))
00413     {
00414       for (octave_idx_type i = 0; i < nf; i++)
00415         xvals[i](n) = rhs.xvals[i];
00416 
00417       retval = true;
00418     }
00419   else
00420     {
00421       OCTAVE_LOCAL_BUFFER (octave_idx_type, perm, nf);
00422       if (xkeys.equal_up_to_order (rhs.xkeys, perm))
00423         {
00424           for (octave_idx_type i = 0; i < nf; i++)
00425             xvals[i](n) = rhs.xvals[perm[i]];
00426 
00427           retval = true;
00428         }
00429     }
00430 
00431   return retval;
00432 }
00433 
00434 octave_map
00435 octave_map::squeeze (void) const
00436 {
00437   octave_map retval (*this);
00438   octave_idx_type nf = nfields ();
00439 
00440   retval.dimensions = dimensions.squeeze ();
00441 
00442   for (octave_idx_type i = 0; i < nf; i++)
00443     retval.xvals[i] = xvals[i].squeeze ();
00444 
00445   retval.optimize_dimensions ();
00446 
00447   return retval;
00448 }
00449 
00450 /*
00451 %!# test preservation of xkeys by squeeze
00452 %!test
00453 %!  x(1,1,1,1).d = 10; x(3,5,1,7).a = "b"; x(2,4,1,7).f = 27;
00454 %!  assert (fieldnames (squeeze (x)), {"d"; "a"; "f"});
00455 */
00456 
00457 octave_map
00458 octave_map::permute (const Array<int>& vec, bool inv) const
00459 {
00460   octave_map retval (xkeys);
00461   octave_idx_type nf = nfields ();
00462 
00463   for (octave_idx_type i = 0; i < nf; i++)
00464     retval.xvals[i] = xvals[i].permute (vec, inv);
00465 
00466   // FIXME:
00467   // There is no dim_vector::permute for technical reasons.
00468   // We pick the dim vector from results if possible, otherwise use a dummy
00469   // array to get it. Need (?) a better solution to this problem.
00470   if (nf > 0)
00471     retval.dimensions = retval.xvals[0].dims ();
00472   else
00473     {
00474       Array<char> dummy (dimensions);
00475       dummy = dummy.permute (vec, inv);
00476       retval.dimensions = dummy.dims ();
00477     }
00478 
00479   retval.optimize_dimensions ();
00480 
00481   return retval;
00482 }
00483 
00484 /*
00485 %!# test preservation of key order by permute
00486 %!test
00487 %!  x(1,1,1,1).d = 10; x(3,5,1,7).a = "b"; x(2,4,1,7).f = 27;
00488 %!  assert (fieldnames (permute (x, [3, 4, 1, 2])), {"d"; "a"; "f"});
00489 */
00490 
00491 octave_map
00492 octave_map::transpose (void) const
00493 {
00494   assert (ndims () == 2);
00495 
00496   octave_map retval (xkeys);
00497 
00498   retval.dimensions = dim_vector (dimensions (1), dimensions (0));
00499 
00500   octave_idx_type nf = nfields ();
00501   for (octave_idx_type i = 0; i < nf; i++)
00502     retval.xvals[i] = xvals[i].transpose ();
00503 
00504   retval.optimize_dimensions ();
00505 
00506   return retval;
00507 }
00508 
00509 /*
00510 %!# test preservation of key order by transpose
00511 %!test
00512 %!  x(1,1).d = 10; x(3,5).a = "b"; x(2,4).f = 27;
00513 %!  assert (fieldnames (transpose (x)), {"d"; "a"; "f"});
00514 %!  assert (fieldnames (x'), {"d"; "a"; "f"});
00515 %!  assert (fieldnames (x.'), {"d"; "a"; "f"});
00516 */
00517 
00518 octave_map
00519 octave_map::reshape (const dim_vector& dv) const
00520 {
00521   octave_map retval (xkeys);
00522   retval.dimensions = dv;
00523 
00524   octave_idx_type nf = nfields ();
00525   if (nf > 0)
00526     {
00527       retval.xvals.reserve (nf);
00528       for (octave_idx_type i = 0; i < nf; i++)
00529         retval.xvals[i] = xvals[i].reshape (dv);
00530     }
00531   else
00532     {
00533       // FIXME: Do it with a dummy array, to reuse error message.
00534       // Need (?) a better solution.
00535       Array<char> dummy (dimensions);
00536       dummy.reshape (dv);
00537     }
00538 
00539   retval.optimize_dimensions ();
00540 
00541   return retval;
00542 }
00543 
00544 /*
00545 %!# test preservation of key order by reshape
00546 %!test
00547 %!  x(1,1).d = 10; x(4,6).a = "b"; x(2,4).f = 27;
00548 %!  assert (fieldnames (reshape (x, 3, 8)), {"d"; "a"; "f"});
00549 */
00550 
00551 void
00552 octave_map::resize (const dim_vector& dv, bool fill)
00553 {
00554   octave_idx_type nf = nfields ();
00555   if (nf > 0)
00556     {
00557       for (octave_idx_type i = 0; i < nf; i++)
00558         {
00559           if (fill)
00560             xvals[i].resize (dv, Cell::resize_fill_value ());
00561           else
00562             xvals[i].resize (dv);
00563         }
00564     }
00565   else
00566     {
00567       // FIXME: Do it with a dummy array, to reuse error message.
00568       // Need (?) a better solution.
00569       Array<char> dummy (dimensions);
00570       dummy.resize (dv);
00571     }
00572 
00573   dimensions = dv;
00574   optimize_dimensions ();
00575 }
00576 
00577 void
00578 octave_map::do_cat (int dim, octave_idx_type n, const octave_scalar_map *map_list,
00579                     octave_map& retval)
00580 {
00581   octave_idx_type nf = retval.nfields ();
00582   retval.xvals.reserve (nf);
00583 
00584   dim_vector& rd = retval.dimensions;
00585   rd.resize (dim+1, 1);
00586   rd(0) = rd(1) = 1;
00587   rd(dim) = n;
00588 
00589   for (octave_idx_type j = 0; j < nf; j++)
00590     {
00591       retval.xvals.push_back (Cell (rd));
00592       assert (retval.xvals[j].numel () == n);
00593       for (octave_idx_type i = 0; i < n; i++)
00594         retval.xvals[j].xelem(i) = map_list[i].xvals[j];
00595     }
00596 }
00597 
00598 void
00599 octave_map::do_cat (int dim, octave_idx_type n, const octave_map *map_list,
00600                     octave_map& retval)
00601 {
00602   octave_idx_type nf = retval.nfields ();
00603   retval.xvals.reserve (nf);
00604 
00605   OCTAVE_LOCAL_BUFFER (Array<octave_value>, field_list, n);
00606 
00607   for (octave_idx_type j = 0; j < nf; j++)
00608     {
00609       for (octave_idx_type i = 0; i < n; i++)
00610         field_list[i] = map_list[i].xvals[j];
00611 
00612       retval.xvals.push_back (Array<octave_value>::cat (dim, n, field_list));
00613       if (j == 0)
00614         retval.dimensions = retval.xvals[j].dims ();
00615     }
00616 }
00617 
00618 // This is just a wrapper.
00619 void permute_to_correct_order1 (const octave_scalar_map& ref, const octave_scalar_map& src,
00620                                 octave_scalar_map& dest, Array<octave_idx_type>& perm)
00621 {
00622   dest = src.orderfields (ref, perm);
00623 }
00624 
00625 // In non-scalar case, we also promote empty structs without fields.
00626 void permute_to_correct_order1 (const octave_map& ref, const octave_map& src,
00627                                 octave_map& dest, Array<octave_idx_type>& perm)
00628 {
00629   if (src.nfields () == 0 && src.is_empty ())
00630      dest = octave_map (src.dims (), ref.keys ());
00631   else
00632      dest = src.orderfields (ref, perm);
00633 }
00634 
00635 template <class map>
00636 static void
00637 permute_to_correct_order (octave_idx_type n, octave_idx_type nf,
00638                           octave_idx_type idx, const map *map_list,
00639                           map *new_map_list)
00640 {
00641   new_map_list[idx] = map_list[idx];
00642 
00643   Array<octave_idx_type> perm (dim_vector (1, nf));
00644 
00645   for (octave_idx_type i = 0; i < n; i++)
00646     {
00647       if (i == idx)
00648          continue;
00649 
00650       permute_to_correct_order1 (map_list[idx], map_list[i], new_map_list[i], perm);
00651 
00652       if (error_state)
00653         {
00654           // Use liboctave exception to be consistent.
00655           (*current_liboctave_error_handler)
00656             ("cat: field names mismatch in concatenating structs");
00657           break;
00658         }
00659     }
00660 }
00661 
00662 
00663 octave_map
00664 octave_map::cat (int dim, octave_idx_type n, const octave_scalar_map *map_list)
00665 {
00666   octave_map retval;
00667 
00668   // Allow dim = -1, -2 for compatibility, though it makes no difference here.
00669   if (dim == -1 || dim == -2)
00670     dim = -dim - 1;
00671   else if (dim < 0)
00672     (*current_liboctave_error_handler)
00673       ("cat: invalid dimension");
00674 
00675   if (n == 1)
00676     retval = map_list[0];
00677   else if (n > 1)
00678     {
00679       octave_idx_type idx, nf = 0;
00680       for (idx = 0; idx < n; idx++)
00681         {
00682           nf = map_list[idx].nfields ();
00683           if (nf > 0)
00684             {
00685               retval.xkeys = map_list[idx].xkeys;
00686               break;
00687             }
00688         }
00689 
00690       if (nf > 0)
00691         {
00692           // Try the fast case.
00693           bool all_same = true;
00694           for (octave_idx_type i = 0; i < n; i++)
00695             {
00696               all_same = map_list[idx].xkeys.is_same (map_list[i].xkeys);
00697               if (! all_same)
00698                 break;
00699             }
00700 
00701           if (all_same)
00702             do_cat (dim, n, map_list, retval);
00703           else
00704             {
00705               // permute all structures to common order.
00706               OCTAVE_LOCAL_BUFFER (octave_scalar_map, new_map_list, n);
00707 
00708               permute_to_correct_order (n, nf, idx, map_list, new_map_list);
00709 
00710               do_cat (dim, n, new_map_list, retval);
00711             }
00712 
00713         }
00714       else
00715         {
00716           dim_vector& rd = retval.dimensions;
00717           rd.resize (dim+1, 1);
00718           rd(0) = rd(1) = 1;
00719           rd(dim) = n;
00720         }
00721 
00722       retval.optimize_dimensions ();
00723     }
00724 
00725   return retval;
00726 }
00727 
00728 octave_map
00729 octave_map::cat (int dim, octave_idx_type n, const octave_map *map_list)
00730 {
00731   octave_map retval;
00732 
00733   // Allow dim = -1, -2 for compatibility, though it makes no difference here.
00734   if (dim == -1 || dim == -2)
00735     dim = -dim - 1;
00736   else if (dim < 0)
00737     (*current_liboctave_error_handler)
00738       ("cat: invalid dimension");
00739 
00740   if (n == 1)
00741     retval = map_list[0];
00742   else if (n > 1)
00743     {
00744       octave_idx_type idx, nf = 0;
00745 
00746       for (idx = 0; idx < n; idx++)
00747         {
00748           nf = map_list[idx].nfields ();
00749           if (nf > 0)
00750             {
00751               retval.xkeys = map_list[idx].xkeys;
00752               break;
00753             }
00754         }
00755 
00756       // Try the fast case.
00757       bool all_same = true;
00758 
00759       if (nf > 0)
00760         {
00761           for (octave_idx_type i = 0; i < n; i++)
00762             {
00763               all_same = map_list[idx].xkeys.is_same (map_list[i].xkeys);
00764 
00765               if (! all_same)
00766                 break;
00767             }
00768         }
00769 
00770       if (all_same && nf > 0)
00771         do_cat (dim, n, map_list, retval);
00772       else
00773         {
00774           if (nf > 0)
00775             {
00776               // permute all structures to correct order.
00777               OCTAVE_LOCAL_BUFFER (octave_map, new_map_list, n);
00778 
00779               permute_to_correct_order (n, nf, idx, map_list, new_map_list);
00780 
00781               do_cat (dim, n, new_map_list, retval);
00782             }
00783           else
00784             {
00785               dim_vector dv = map_list[0].dimensions;
00786 
00787               for (octave_idx_type i = 1; i < n; i++)
00788                 {
00789                   if (! dv.concat (map_list[i].dimensions, dim))
00790                     {
00791                       error ("dimension mismatch in struct concatenation");
00792                       return retval;
00793                     }
00794                 }
00795 
00796               retval.dimensions = dv;
00797             }
00798         }
00799 
00800       retval.optimize_dimensions ();
00801     }
00802 
00803   return retval;
00804 }
00805 
00806 /*
00807 %!# test preservation of key order by concatenation
00808 %!test
00809 %!  x(1, 1).d = 10; x(4, 6).a = "b"; x(2, 4).f = 27;
00810 %!  y(1, 6).f = 11; y(1, 6).a = "c"; y(1, 6).d = 33;
00811 %!  assert (fieldnames ([x; y]), {"d"; "a"; "f"});
00812 
00813 %!test
00814 %!  s = struct ();
00815 %!  sr = [s,s];
00816 %!  sc = [s;s];
00817 %!  sm = [s,s;s,s];
00818 %!  assert (nfields (sr), 0);
00819 %!  assert (nfields (sc), 0);
00820 %!  assert (nfields (sm), 0);
00821 %!  assert (size (sr), [1, 2]);
00822 %!  assert (size (sc), [2, 1]);
00823 %!  assert (size (sm), [2, 2]);
00824 */
00825 
00826 octave_map
00827 octave_map::index (const idx_vector& i, bool resize_ok) const
00828 {
00829   octave_map retval (xkeys);
00830   octave_idx_type nf = nfields ();
00831 
00832   for (octave_idx_type k = 0; k < nf; k++)
00833     retval.xvals[k] = xvals[k].index (i, resize_ok);
00834 
00835   if (nf > 0)
00836     retval.dimensions = retval.xvals[0].dims ();
00837   else
00838     {
00839       // Use dummy array. FIXME: Need(?) a better solution.
00840       Array<char> dummy (dimensions);
00841       dummy = dummy.index (i, resize_ok);
00842       retval.dimensions = dummy.dims ();
00843     }
00844 
00845   retval.optimize_dimensions ();
00846 
00847   return retval;
00848 }
00849 
00850 octave_map
00851 octave_map::index (const idx_vector& i, const idx_vector& j,
00852                    bool resize_ok) const
00853 {
00854   octave_map retval (xkeys);
00855   octave_idx_type nf = nfields ();
00856 
00857   for (octave_idx_type k = 0; k < nf; k++)
00858     retval.xvals[k] = xvals[k].index (i, j, resize_ok);
00859 
00860   if (nf > 0)
00861     retval.dimensions = retval.xvals[0].dims ();
00862   else
00863     {
00864       // Use dummy array. FIXME: Need(?) a better solution.
00865       Array<char> dummy (dimensions);
00866       dummy = dummy.index (i, j, resize_ok);
00867       retval.dimensions = dummy.dims ();
00868     }
00869 
00870   retval.optimize_dimensions ();
00871 
00872   return retval;
00873 }
00874 
00875 octave_map
00876 octave_map::index (const Array<idx_vector>& ia, bool resize_ok) const
00877 {
00878   octave_map retval (xkeys);
00879   octave_idx_type nf = nfields ();
00880 
00881   for (octave_idx_type k = 0; k < nf; k++)
00882     retval.xvals[k] = xvals[k].index (ia, resize_ok);
00883 
00884   if (nf > 0)
00885     retval.dimensions = retval.xvals[0].dims ();
00886   else
00887     {
00888       // Use dummy array. FIXME: Need(?) a better solution.
00889       Array<char> dummy (dimensions);
00890       dummy = dummy.index (ia, resize_ok);
00891       retval.dimensions = dummy.dims ();
00892     }
00893 
00894   retval.optimize_dimensions ();
00895 
00896   return retval;
00897 }
00898 
00899 octave_map
00900 octave_map::index (const octave_value_list& idx, bool resize_ok) const
00901 {
00902   octave_idx_type n_idx = idx.length ();
00903   octave_map retval;
00904 
00905   switch (n_idx)
00906     {
00907     case 1:
00908       {
00909         idx_vector i = idx(0).index_vector ();
00910 
00911         if (! error_state)
00912           retval = index (i, resize_ok);
00913       }
00914       break;
00915 
00916     case 2:
00917       {
00918         idx_vector i = idx(0).index_vector ();
00919 
00920         if (! error_state)
00921           {
00922             idx_vector j = idx(1).index_vector ();
00923 
00924             retval = index (i, j, resize_ok);
00925           }
00926       }
00927       break;
00928 
00929     default:
00930       {
00931         Array<idx_vector> ia (dim_vector (n_idx, 1));
00932 
00933         for (octave_idx_type i = 0; i < n_idx; i++)
00934           {
00935             ia(i) = idx(i).index_vector ();
00936 
00937             if (error_state)
00938               break;
00939           }
00940 
00941         if (! error_state)
00942           retval = index (ia, resize_ok);
00943       }
00944       break;
00945     }
00946 
00947   return retval;
00948 }
00949 
00950 // Perhaps one day these will be optimized. Right now, they just call index.
00951 octave_map
00952 octave_map::column (octave_idx_type k) const
00953 {
00954   return index (idx_vector::colon, k);
00955 }
00956 
00957 octave_map
00958 octave_map::page (octave_idx_type k) const
00959 {
00960   static Array<idx_vector> ia (dim_vector (3, 1), idx_vector::colon);
00961 
00962   ia(2) = k;
00963   return index (ia);
00964 }
00965 
00966 void
00967 octave_map::assign (const idx_vector& i, const octave_map& rhs)
00968 {
00969   if (rhs.xkeys.is_same (xkeys))
00970     {
00971       octave_idx_type nf = nfields ();
00972 
00973       for (octave_idx_type k = 0; k < nf; k++)
00974         xvals[k].assign (i, rhs.xvals[k], Matrix ());
00975 
00976       if (nf > 0)
00977         dimensions = xvals[0].dims ();
00978       else
00979         {
00980           // Use dummy array. FIXME: Need(?) a better solution.
00981           Array<char> dummy (dimensions), rhs_dummy (rhs.dimensions);
00982           dummy.assign (i, rhs_dummy);;
00983           dimensions = dummy.dims ();
00984         }
00985 
00986       optimize_dimensions ();
00987     }
00988   else if (nfields () == 0)
00989     {
00990       octave_map tmp (dimensions, rhs.xkeys);
00991       tmp.assign (i, rhs);
00992       *this = tmp;
00993     }
00994   else
00995     {
00996       Array<octave_idx_type> perm;
00997       octave_map rhs1 = rhs.orderfields (*this, perm);
00998       if (! error_state)
00999         {
01000           assert (rhs1.xkeys.is_same (xkeys));
01001           assign (i, rhs1);
01002         }
01003       else
01004         error ("incompatible fields in struct assignment");
01005     }
01006 }
01007 
01008 void
01009 octave_map::assign (const idx_vector& i, const idx_vector& j,
01010                     const octave_map& rhs)
01011 {
01012   if (rhs.xkeys.is_same (xkeys))
01013     {
01014       octave_idx_type nf = nfields ();
01015 
01016       for (octave_idx_type k = 0; k < nf; k++)
01017         xvals[k].assign (i, j, rhs.xvals[k], Matrix ());
01018 
01019       if (nf > 0)
01020         dimensions = xvals[0].dims ();
01021       else
01022         {
01023           // Use dummy array. FIXME: Need(?) a better solution.
01024           Array<char> dummy (dimensions), rhs_dummy (rhs.dimensions);
01025           dummy.assign (i, j, rhs_dummy);;
01026           dimensions = dummy.dims ();
01027         }
01028 
01029       optimize_dimensions ();
01030     }
01031   else if (nfields () == 0)
01032     {
01033       octave_map tmp (dimensions, rhs.xkeys);
01034       tmp.assign (i, j, rhs);
01035       *this = tmp;
01036     }
01037   else
01038     {
01039       Array<octave_idx_type> perm;
01040       octave_map rhs1 = rhs.orderfields (*this, perm);
01041       if (! error_state)
01042         {
01043           assert (rhs1.xkeys.is_same (xkeys));
01044           assign (i, j, rhs1);
01045         }
01046       else
01047         error ("incompatible fields in struct assignment");
01048     }
01049 }
01050 
01051 void
01052 octave_map::assign (const Array<idx_vector>& ia,
01053                     const octave_map& rhs)
01054 {
01055   if (rhs.xkeys.is_same (xkeys))
01056     {
01057       octave_idx_type nf = nfields ();
01058 
01059       for (octave_idx_type k = 0; k < nf; k++)
01060         xvals[k].assign (ia, rhs.xvals[k], Matrix ());
01061 
01062       if (nf > 0)
01063         dimensions = xvals[0].dims ();
01064       else
01065         {
01066           // Use dummy array. FIXME: Need(?) a better solution.
01067           Array<char> dummy (dimensions), rhs_dummy (rhs.dimensions);
01068           dummy.assign (ia, rhs_dummy);;
01069           dimensions = dummy.dims ();
01070         }
01071 
01072       optimize_dimensions ();
01073     }
01074   else if (nfields () == 0)
01075     {
01076       octave_map tmp (dimensions, rhs.xkeys);
01077       tmp.assign (ia, rhs);
01078       *this = tmp;
01079     }
01080   else
01081     {
01082       Array<octave_idx_type> perm;
01083       octave_map rhs1 = rhs.orderfields (*this, perm);
01084       if (! error_state)
01085         {
01086           assert (rhs1.xkeys.is_same (xkeys));
01087           assign (ia, rhs1);
01088         }
01089       else
01090         error ("incompatible fields in struct assignment");
01091     }
01092 }
01093 
01094 void
01095 octave_map::assign (const octave_value_list& idx, const octave_map& rhs)
01096 {
01097   octave_idx_type n_idx = idx.length ();
01098 
01099   switch (n_idx)
01100     {
01101     case 1:
01102       {
01103         idx_vector i = idx(0).index_vector ();
01104 
01105         if (! error_state)
01106           assign (i, rhs);
01107       }
01108       break;
01109 
01110     case 2:
01111       {
01112         idx_vector i = idx(0).index_vector ();
01113 
01114         if (! error_state)
01115           {
01116             idx_vector j = idx(1).index_vector ();
01117 
01118             assign (i, j, rhs);
01119           }
01120       }
01121       break;
01122 
01123     default:
01124       {
01125         Array<idx_vector> ia (dim_vector (n_idx, 1));
01126 
01127         for (octave_idx_type i = 0; i < n_idx; i++)
01128           {
01129             ia(i) = idx(i).index_vector ();
01130 
01131             if (error_state)
01132               break;
01133           }
01134 
01135         if (! error_state)
01136           assign (ia, rhs);
01137       }
01138       break;
01139     }
01140 }
01141 
01142 void
01143 octave_map::assign (const octave_value_list& idx, const std::string& k,
01144                     const Cell& rhs)
01145 {
01146   Cell tmp;
01147   iterator p = seek (k);
01148   Cell& ref = p != end () ? contents (p) : tmp;
01149 
01150   if (&ref == &tmp)
01151     ref = Cell (dimensions);
01152 
01153   ref.assign (idx, rhs);
01154 
01155   if (! error_state && ref.dims () != dimensions)
01156     {
01157       dimensions = ref.dims ();
01158 
01159       octave_idx_type nf = nfields ();
01160       for (octave_idx_type i = 0; i < nf; i++)
01161         {
01162           if (&xvals[i] != &ref)
01163             xvals[i].resize (dimensions, Cell::resize_fill_value ());
01164         }
01165 
01166       optimize_dimensions ();
01167     }
01168 
01169   if (! error_state && &ref == &tmp)
01170     setfield (k, tmp);
01171 }
01172 
01173 /*
01174 %!test
01175 %! rhs.b = 1;
01176 %! a(3) = rhs;
01177 %! assert ({a.b}, {[], [], 1})
01178 */
01179 
01180 void
01181 octave_map::delete_elements (const idx_vector& i)
01182 {
01183   octave_idx_type nf = nfields ();
01184   for (octave_idx_type k = 0; k < nf; k++)
01185     xvals[k].delete_elements (i);
01186 
01187   if (nf > 0)
01188     dimensions = xvals[0].dims ();
01189   else
01190     {
01191       // Use dummy array. FIXME: Need(?) a better solution.
01192       Array<char> dummy (dimensions);
01193       dummy.delete_elements (i);
01194       dimensions = dummy.dims ();
01195     }
01196 
01197   optimize_dimensions ();
01198 }
01199 
01200 void
01201 octave_map::delete_elements (int dim, const idx_vector& i)
01202 {
01203   octave_idx_type nf = nfields ();
01204   for (octave_idx_type k = 0; k < nf; k++)
01205     xvals[k].delete_elements (dim, i);
01206 
01207   if (nf > 0)
01208     dimensions = xvals[0].dims ();
01209   else
01210     {
01211       // Use dummy array. FIXME: Need(?) a better solution.
01212       Array<char> dummy (dimensions);
01213       dummy.delete_elements (dim, i);
01214       dimensions = dummy.dims ();
01215     }
01216 
01217   optimize_dimensions ();
01218 }
01219 
01220 void
01221 octave_map::delete_elements (const Array<idx_vector>& ia)
01222 {
01223   octave_idx_type nf = nfields ();
01224   for (octave_idx_type k = 0; k < nf; k++)
01225     xvals[k].delete_elements (ia);
01226 
01227   if (nf > 0)
01228     dimensions = xvals[0].dims ();
01229   else
01230     {
01231       // Use dummy array. FIXME: Need(?) a better solution.
01232       Array<char> dummy (dimensions);
01233       dummy.delete_elements (ia);
01234       dimensions = dummy.dims ();
01235     }
01236 
01237   optimize_dimensions ();
01238 }
01239 
01240 void
01241 octave_map::delete_elements (const octave_value_list& idx)
01242 {
01243   octave_idx_type n_idx = idx.length ();
01244 
01245   Array<idx_vector> ia (dim_vector (n_idx, 1));
01246 
01247   for (octave_idx_type i = 0; i < n_idx; i++)
01248     {
01249       ia(i) = idx(i).index_vector ();
01250 
01251       if (error_state)
01252         break;
01253     }
01254 
01255   if (! error_state)
01256     delete_elements (ia);
01257 }
01258 
01259 /*
01260 %!# test preservation of key order by indexing
01261 %!test
01262 %!  x(1, 1).d = 10; x(4, 6).a = "b"; x(2, 4).f = 27;
01263 %!  assert (fieldnames (x([1, 2], [2:5])), {"d"; "a"; "f"});
01264 */
01265 
01266 octave_map
01267 octave_map::concat (const octave_map& rb, const Array<octave_idx_type>& ra_idx)
01268 {
01269   if (nfields () == rb.nfields ())
01270     {
01271       for (const_iterator pa = begin (); pa != end (); pa++)
01272         {
01273           const_iterator pb = rb.seek (key(pa));
01274 
01275           if (pb == rb.end ())
01276             {
01277               error ("field name mismatch in structure concatenation");
01278               break;
01279             }
01280 
01281           contents(pa).insert (rb.contents(pb), ra_idx);
01282         }
01283     }
01284   else
01285     {
01286       dim_vector dv = dims ();
01287 
01288       if (dv.all_zero ())
01289         *this = rb;
01290       else if (! rb.dims ().all_zero ())
01291         error ("invalid structure concatenation");
01292     }
01293 
01294   return *this;
01295 }
01296 
01297 void
01298 octave_map::optimize_dimensions (void)
01299 {
01300   octave_idx_type nf = nfields ();
01301 
01302   for (octave_idx_type i = 0; i < nf; i++)
01303     {
01304       if (! xvals[i].optimize_dimensions (dimensions))
01305         {
01306           error ("internal error: dimension mismatch across fields in struct");
01307           break;
01308         }
01309     }
01310 
01311 }
01312 
01313 Octave_map::Octave_map (const dim_vector& dv, const Cell& key_vals)
01314   : map (), key_list (), dimensions (dv)
01315 {
01316   Cell c (dv);
01317 
01318   if (key_vals.is_cellstr ())
01319     {
01320       for (octave_idx_type i = 0; i < key_vals.numel (); i++)
01321         {
01322           std::string k = key_vals(i).string_value ();
01323           map[k] = c;
01324           key_list.push_back (k);
01325         }
01326     }
01327   else
01328     error ("Octave_map: expecting keys to be cellstr");
01329 }
01330 
01331 Octave_map::Octave_map (const octave_map& m)
01332   : map (), key_list (), dimensions (m.dims ())
01333 {
01334   for (octave_map::const_iterator p = m.begin (); p != m.end (); p++)
01335     map[m.key (p)] = m.contents (p);
01336   const string_vector mkeys = m.fieldnames ();
01337   for (octave_idx_type i = 0; i < mkeys.numel (); i++)
01338     key_list.push_back (mkeys(i));
01339 }
01340 
01341 Octave_map
01342 Octave_map::squeeze (void) const
01343 {
01344   Octave_map retval (dims ().squeeze ());
01345 
01346   for (const_iterator pa = begin (); pa != end (); pa++)
01347     {
01348       Cell tmp = contents (pa).squeeze ();
01349 
01350       if (error_state)
01351         break;
01352 
01353       retval.assign (key (pa), tmp);
01354     }
01355 
01356   // Preserve order of keys.
01357   retval.key_list = key_list;
01358 
01359   return retval;
01360 }
01361 
01362 Octave_map
01363 Octave_map::permute (const Array<int>& vec, bool inv) const
01364 {
01365   Octave_map retval (dims ());
01366 
01367   for (const_iterator pa = begin (); pa != end (); pa++)
01368     {
01369       Cell tmp = contents (pa).permute (vec, inv);
01370 
01371       if (error_state)
01372         break;
01373 
01374       retval.assign (key (pa), tmp);
01375     }
01376 
01377   // Preserve order of keys.
01378   retval.key_list = key_list;
01379 
01380   return retval;
01381 }
01382 
01383 Cell&
01384 Octave_map::contents (const std::string& k)
01385 {
01386   maybe_add_to_key_list (k);
01387 
01388   return map[k];
01389 }
01390 
01391 Cell
01392 Octave_map::contents (const std::string& k) const
01393 {
01394   const_iterator p = seek (k);
01395 
01396   return p != end () ? p->second : Cell ();
01397 }
01398 
01399 int
01400 Octave_map::intfield (const std::string& k, int def_val) const
01401 {
01402   int retval = def_val;
01403 
01404   Cell c = contents (k);
01405 
01406   if (! c.is_empty ())
01407     retval = c(0).int_value ();
01408 
01409   return retval;
01410 }
01411 
01412 std::string
01413 Octave_map::stringfield (const std::string& k,
01414                          const std::string& def_val) const
01415 {
01416   std::string retval = def_val;
01417 
01418   Cell c = contents (k);
01419 
01420   if (! c.is_empty ())
01421     retval = c(0).string_value ();
01422 
01423   return retval;
01424 }
01425 
01426 string_vector
01427 Octave_map::keys (void) const
01428 {
01429   assert (nfields () == key_list.size ());
01430 
01431   return string_vector (key_list);
01432 }
01433 
01434 Octave_map
01435 Octave_map::transpose (void) const
01436 {
01437   assert (ndims () == 2);
01438 
01439   dim_vector dv = dims ();
01440 
01441   octave_idx_type nr = dv(0);
01442   octave_idx_type nc = dv(1);
01443 
01444   dim_vector new_dims (nc, nr);
01445 
01446   Octave_map retval (new_dims);
01447 
01448   for (const_iterator p = begin (); p != end (); p++)
01449     retval.assign (key(p), Cell (contents(p).transpose ()));
01450 
01451   // Preserve order of keys.
01452   retval.key_list = key_list;
01453 
01454   return retval;
01455 }
01456 
01457 Octave_map
01458 Octave_map::reshape (const dim_vector& new_dims) const
01459 {
01460   Octave_map retval;
01461 
01462   if (new_dims != dims ())
01463     {
01464       for (const_iterator p = begin (); p != end (); p++)
01465         retval.assign (key(p), contents(p).reshape (new_dims));
01466 
01467       retval.dimensions = new_dims;
01468 
01469       // Preserve order of keys.
01470       retval.key_list = key_list;
01471     }
01472   else
01473     retval = *this;
01474 
01475   return retval;
01476 }
01477 
01478 void
01479 Octave_map::resize (const dim_vector& dv, bool fill)
01480 {
01481   if (dv != dims ())
01482     {
01483       if (nfields () == 0)
01484         dimensions = dv;
01485       else
01486         {
01487           for (const_iterator p = begin (); p != end (); p++)
01488             {
01489               Cell tmp = contents(p);
01490 
01491               if (fill)
01492                 tmp.resize (dv, Cell::resize_fill_value ());
01493               else
01494                 tmp.resize (dv);
01495 
01496               dimensions = dv;
01497 
01498               assign (key(p), tmp);
01499             }
01500         }
01501     }
01502 }
01503 
01504 Octave_map
01505 Octave_map::concat (const Octave_map& rb, const Array<octave_idx_type>& ra_idx)
01506 {
01507   Octave_map retval;
01508 
01509   if (nfields () == rb.nfields ())
01510     {
01511       for (const_iterator pa = begin (); pa != end (); pa++)
01512         {
01513           const_iterator pb = rb.seek (key(pa));
01514 
01515           if (pb == rb.end ())
01516             {
01517               error ("field name mismatch in structure concatenation");
01518               break;
01519             }
01520 
01521           retval.assign (key(pa),
01522                          contents(pa).insert (rb.contents(pb), ra_idx));
01523         }
01524 
01525       // Preserve order of keys.
01526       retval.key_list = key_list;
01527     }
01528   else
01529     {
01530       dim_vector dv = dims ();
01531 
01532       if (dv.all_zero ())
01533         retval = rb;
01534       else
01535         {
01536           dv = rb.dims ();
01537 
01538           if (dv.all_zero ())
01539             retval = *this;
01540           else
01541             error ("invalid structure concatenation");
01542         }
01543     }
01544 
01545   return retval;
01546 }
01547 
01548 static bool
01549 keys_ok (const Octave_map& a, const Octave_map& b, string_vector& keys)
01550 {
01551   bool retval = false;
01552 
01553   keys = string_vector ();
01554 
01555   if (a.nfields () == 0)
01556     {
01557       keys = b.keys ();
01558       retval = true;
01559     }
01560   else
01561     {
01562       string_vector a_keys = a.keys().sort ();
01563       string_vector b_keys = b.keys().sort ();
01564 
01565       octave_idx_type a_len = a_keys.length ();
01566       octave_idx_type b_len = b_keys.length ();
01567 
01568       if (a_len == b_len)
01569         {
01570           for (octave_idx_type i = 0; i < a_len; i++)
01571             {
01572               if (a_keys[i] != b_keys[i])
01573                 goto done;
01574             }
01575 
01576           keys = a_keys;
01577           retval = true;
01578         }
01579     }
01580 
01581  done:
01582   return retval;
01583 }
01584 
01585 Octave_map&
01586 Octave_map::maybe_delete_elements (const octave_value_list& idx)
01587 {
01588   string_vector t_keys = keys();
01589   octave_idx_type len = t_keys.length ();
01590 
01591   if (len > 0)
01592     {
01593       for (octave_idx_type i = 0; i < len; i++)
01594         {
01595           std::string k = t_keys[i];
01596 
01597           contents(k).delete_elements (idx);
01598 
01599           if (error_state)
01600             break;
01601         }
01602 
01603       if (!error_state)
01604         dimensions = contents(t_keys[0]).dims();
01605     }
01606 
01607   return *this;
01608 }
01609 
01610 Octave_map&
01611 Octave_map::assign (const octave_value_list& idx, const Octave_map& rhs)
01612 {
01613   string_vector t_keys;
01614 
01615   if (keys_ok (*this, rhs, t_keys))
01616     {
01617       octave_idx_type len = t_keys.length ();
01618 
01619       if (len == 0)
01620         {
01621           Cell tmp_lhs (dims ());
01622           Cell tmp_rhs (rhs.dims ());
01623 
01624           tmp_lhs.assign (idx, tmp_rhs, Matrix ());
01625 
01626           if (! error_state)
01627             resize (tmp_lhs.dims ());
01628           else
01629             error ("size mismatch in structure assignment");
01630         }
01631       else
01632         {
01633           for (octave_idx_type i = 0; i < len; i++)
01634             {
01635               std::string k = t_keys[i];
01636 
01637               Cell t_rhs = rhs.contents (k);
01638 
01639               assign (idx, k, t_rhs);
01640 
01641               if (error_state)
01642                 break;
01643             }
01644         }
01645     }
01646   else
01647     error ("field name mismatch in structure assignment");
01648 
01649   return *this;
01650 }
01651 
01652 Octave_map&
01653 Octave_map::assign (const octave_value_list& idx, const std::string& k,
01654                     const Cell& rhs)
01655 {
01656   Cell tmp;
01657 
01658   if (contains (k))
01659     tmp = map[k];
01660   else
01661     tmp = Cell (dimensions);
01662 
01663   tmp.assign (idx, rhs);
01664 
01665   if (! error_state)
01666     {
01667       dim_vector tmp_dims = tmp.dims ();
01668 
01669       if (tmp_dims != dimensions)
01670         {
01671           for (iterator p = begin (); p != end (); p++)
01672             contents(p).resize (tmp_dims, Cell::resize_fill_value ());
01673 
01674           dimensions = tmp_dims;
01675         }
01676 
01677       maybe_add_to_key_list (k);
01678 
01679       map[k] = tmp;
01680     }
01681 
01682   return *this;
01683 }
01684 
01685 Octave_map&
01686 Octave_map::assign (const std::string& k, const octave_value& rhs)
01687 {
01688   if (nfields () == 0)
01689     {
01690       maybe_add_to_key_list (k);
01691 
01692       map[k] = Cell (rhs);
01693 
01694       dimensions = dim_vector (1, 1);
01695     }
01696   else
01697     {
01698       dim_vector dv = dims ();
01699 
01700       if (dv.all_ones ())
01701         {
01702           maybe_add_to_key_list (k);
01703 
01704           map[k] = Cell (rhs);
01705         }
01706       else
01707         error ("invalid structure assignment");
01708     }
01709 
01710   return *this;
01711 }
01712 
01713 Octave_map&
01714 Octave_map::assign (const std::string& k, const Cell& rhs)
01715 {
01716   if (nfields () == 0)
01717     {
01718       maybe_add_to_key_list (k);
01719 
01720       map[k] = rhs;
01721 
01722       dimensions = rhs.dims ();
01723     }
01724   else
01725     {
01726       if (dims () == rhs.dims ())
01727         {
01728           maybe_add_to_key_list (k);
01729 
01730           map[k] = rhs;
01731         }
01732       else
01733         error ("invalid structure assignment");
01734     }
01735 
01736   return *this;
01737 }
01738 
01739 Octave_map
01740 Octave_map::index (const octave_value_list& idx, bool resize_ok) const
01741 {
01742   Octave_map retval;
01743 
01744   octave_idx_type n_idx = idx.length ();
01745 
01746   if (n_idx > 0)
01747     {
01748       Array<idx_vector> ra_idx (dim_vector (n_idx, 1));
01749 
01750       for (octave_idx_type i = 0; i < n_idx; i++)
01751         {
01752           ra_idx(i) = idx(i).index_vector ();
01753           if (error_state)
01754             break;
01755         }
01756 
01757       if (! error_state)
01758         {
01759           for (const_iterator p = begin (); p != end (); p++)
01760             {
01761               Cell tmp = contents (p);
01762 
01763               tmp = tmp.Array<octave_value>::index (ra_idx, resize_ok);
01764 
01765               if (error_state)
01766                 break;
01767 
01768               retval.assign (key(p), tmp);
01769             }
01770 
01771           // Preserve order of keys.
01772           retval.key_list = key_list;
01773         }
01774     }
01775   else
01776     retval = *this;
01777 
01778   return retval;
01779 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines