changeset 10742:604e13a89c7f

initial code for structs rewrite
author Jaroslav Hajek <highegg@gmail.com>
date Tue, 22 Jun 2010 15:22:36 +0200
parents b8d76f4be94a
children cb3ed842bd30
files src/DLD-FUNCTIONS/onCleanup.cc src/oct-map.cc src/oct-map.h src/ov-base.cc src/ov-base.h src/ov-cell.h src/ov-class.cc src/ov-class.h src/ov-fcn-inline.cc src/ov-fcn-inline.h src/ov-struct.cc src/ov-struct.h src/ov.cc src/ov.h
diffstat 14 files changed, 2723 insertions(+), 484 deletions(-) [+]
line wrap: on
line diff
--- a/src/DLD-FUNCTIONS/onCleanup.cc
+++ b/src/DLD-FUNCTIONS/onCleanup.cc
@@ -58,7 +58,10 @@
 
   bool is_object (void) const { return true; } // do we want this?
 
-  Octave_map map_value (void) const;
+  octave_map map_value (void) const
+    { return scalar_map_value (); }
+
+  octave_scalar_map scalar_map_value (void) const;
 
   dim_vector dims (void) const { static dim_vector dv (1, 1); return dv; }
 
@@ -169,11 +172,11 @@
     }
 }
 
-Octave_map 
-octave_oncleanup::map_value (void) const
+octave_scalar_map 
+octave_oncleanup::scalar_map_value (void) const
 {
-  Octave_map retval;
-  retval.assign ("task", fcn);
+  octave_scalar_map retval;
+  retval.setfield ("task", fcn);
   return retval;
 }
 
--- a/src/oct-map.cc
+++ b/src/oct-map.cc
@@ -2,6 +2,7 @@
 
 Copyright (C) 1995, 1996, 1997, 2002, 2003, 2004, 2005, 2006, 2007,
               2008, 2009 John W. Eaton
+Copyright (C) 2010 VZLU Prague
 
 This file is part of Octave.
 
@@ -31,6 +32,1072 @@
 #include "oct-map.h"
 #include "utils.h"
 
+octave_fields::fields_rep octave_fields::nil_rep;
+
+octave_fields::octave_fields (const string_vector& fields)
+  : rep (new fields_rep)
+{
+  octave_idx_type n = fields.numel ();
+  for (octave_idx_type i = 0; i < n; i++)
+    (*rep)[fields(i)] = i;
+}
+
+bool
+octave_fields::isfield (const std::string& field) const
+{
+  return rep->find (field) != rep->end ();
+}
+
+octave_idx_type
+octave_fields::getfield (const std::string& field) const
+{
+  fields_rep::iterator p = rep->find (field);
+  return (p != rep->end ()) ? p->second : -1;
+}
+
+octave_idx_type
+octave_fields::getfield (const std::string& field)
+{
+  fields_rep::iterator p = rep->find (field);
+  if (p != rep->end ())
+    return p->second;
+  else
+    {
+      make_unique ();
+      octave_idx_type n = rep->size ();
+      return (*rep)[field] = n;
+    }
+}
+
+octave_idx_type
+octave_fields::rmfield (const std::string& field)
+{
+  fields_rep::iterator p = rep->find (field);
+  if (p == rep->end ())
+    return -1;
+  else
+    {
+      octave_idx_type n = p->second;
+      make_unique ();
+      rep->erase (field);
+      for (fields_rep::iterator q = rep->begin (); q != rep->end (); q++)
+        {
+          if (q->second >= n)
+            q->second--;
+        }
+
+      return n;
+    }
+}
+
+void 
+octave_fields::orderfields (Array<octave_idx_type>& perm)
+{
+  octave_idx_type n = rep->size ();
+  perm.clear (n, 1);
+
+  make_unique ();
+  octave_idx_type i = 0;
+  for (fields_rep::iterator q = rep->begin (); q != rep->end (); q++)
+    {
+      octave_idx_type j = q->second;
+      q->second = i;
+      perm(i++) = j;
+    }
+}
+
+bool 
+octave_fields::equal_up_to_order (const octave_fields& other,
+                                  Array<octave_idx_type>& perm) const
+{
+  bool retval = true;
+
+  octave_idx_type n = nfields ();
+  if (perm.length () != n)
+    perm.clear (1, n);
+  else
+    perm.make_unique (); // optimization
+
+  iterator p = begin (), q = other.begin ();
+  for (; p != end () && q != other.end (); p++, q++)
+    {
+      if (p->first == q->first)
+        perm.xelem(p->second) = q->second;
+      else
+        {
+          retval = false;
+          break;
+        }
+    }
+
+  retval = (p == end () && q == other.end ());
+
+  return retval;
+}
+
+string_vector
+octave_fields::fieldnames (void) const
+{
+  octave_idx_type n = nfields ();
+  string_vector retval(n);
+
+  for (iterator p = begin (); p != end (); p++)
+    retval.xelem(p->second) = p->first;
+
+  return retval;
+}
+
+octave_value
+octave_scalar_map::getfield (const std::string& k) const
+{
+  octave_idx_type idx = keys.getfield (k);
+  return (idx >= 0) ? vals[idx] : octave_value ();
+}
+
+void
+octave_scalar_map::setfield (const std::string& k, const octave_value& val)
+{
+  octave_idx_type idx = keys.getfield (k);
+  if (idx < static_cast<octave_idx_type> (vals.size ()))
+    vals[idx] = val;
+  else
+    vals.push_back (val);
+}
+
+void
+octave_scalar_map::rmfield (const std::string& k)
+{
+  octave_idx_type idx = keys.rmfield (k);
+  if (idx >= 0)
+    vals.erase (vals.begin () + idx);
+}
+
+octave_scalar_map 
+octave_scalar_map::orderfields (void) const
+{
+  Array<octave_idx_type> perm;
+  return orderfields (perm);
+}
+
+octave_scalar_map
+octave_scalar_map::orderfields (Array<octave_idx_type>& perm) const
+{
+  octave_scalar_map retval (keys);
+  retval.keys.orderfields (perm);
+
+  octave_idx_type nf = nfields ();
+  for (octave_idx_type i = 0; i < nf; i++)
+    retval.vals[i] = vals[perm.xelem(i)];
+
+  return retval;
+}
+
+octave_scalar_map
+octave_scalar_map::orderfields (const octave_scalar_map& other,
+                                Array<octave_idx_type>& perm) const
+{
+  if (keys.is_same (other.keys))
+    return *this;
+  else
+    {
+      octave_scalar_map retval (other.keys);
+      if (other.keys.equal_up_to_order (keys, perm))
+        {
+          octave_idx_type nf = nfields ();
+          for (octave_idx_type i = 0; i < nf; i++)
+            retval.vals[i] = vals[perm.xelem(i)];
+        }
+      else
+        error ("orderfields: structs must have same fields up to order");
+
+      return retval;
+    }
+}
+
+octave_value
+octave_scalar_map::contents (const std::string& k) const
+{
+  return getfield (k);
+}
+
+octave_value& 
+octave_scalar_map::contents (const std::string& k)
+{
+  octave_idx_type idx = keys.getfield (k);
+  if (idx >= static_cast<octave_idx_type> (vals.size ()))
+    vals.resize (idx);
+  return vals[idx];
+}
+
+octave_map::octave_map (const octave_scalar_map& m)
+  : keys (m.keys), vals (), dimensions (1, 1)
+{
+  octave_idx_type nf = m.nfields ();
+  vals.reserve (nf);
+  for (octave_idx_type i = 0; i < nf; i++)
+    {
+      vals.push_back (Cell (dimensions));
+      vals[i].xelem(0) = m.vals[i];
+    }
+}
+
+octave_map::octave_map (const Octave_map& m)
+  : keys (m.keys ()), vals (m.nfields ()), dimensions (m.dims ())
+{
+  for (iterator p = begin (); p != end (); p++)
+    contents(p) = m.contents (key (p));
+
+  optimize_dimensions ();
+}
+
+Cell
+octave_map::getfield (const std::string& k) const
+{
+  octave_idx_type idx = keys.getfield (k);
+  return (idx >= 0) ? vals[idx] : Cell ();
+}
+
+void
+octave_map::setfield (const std::string& k, const Cell& val)
+{
+  if (nfields () == 0)
+    dimensions = val.dims ();
+
+  if (val.dims () == dimensions)
+    {
+      octave_idx_type idx = keys.getfield (k);
+      if (idx < static_cast<octave_idx_type> (vals.size ()))
+        vals[idx] = val;
+      else
+        vals.push_back (val);
+    }
+  else
+    error ("octave_map::setfield: internal error");
+}
+
+void
+octave_map::rmfield (const std::string& k)
+{
+  octave_idx_type idx = keys.rmfield (k);
+  if (idx >= 0)
+    vals.erase (vals.begin () + idx);
+}
+
+octave_map 
+octave_map::orderfields (void) const
+{
+  Array<octave_idx_type> perm;
+  return orderfields (perm);
+}
+
+octave_map
+octave_map::orderfields (Array<octave_idx_type>& perm) const
+{
+  octave_map retval (keys);
+  retval.keys.orderfields (perm);
+
+  octave_idx_type nf = nfields ();
+  for (octave_idx_type i = 0; i < nf; i++)
+    retval.vals[i] = vals[perm.xelem(i)];
+
+  return retval;
+}
+
+octave_map
+octave_map::orderfields (const octave_map& other,
+                         Array<octave_idx_type>& perm) const
+{
+  if (keys.is_same (other.keys))
+    return *this;
+  else
+    {
+      octave_map retval (other.keys);
+      if (other.keys.equal_up_to_order (keys, perm))
+        {
+          octave_idx_type nf = nfields ();
+          for (octave_idx_type i = 0; i < nf; i++)
+            retval.vals[i] = vals[perm.xelem(i)];
+        }
+      else
+        error ("orderfields: structs must have same fields up to order");
+
+      return retval;
+    }
+}
+
+Cell
+octave_map::contents (const std::string& k) const
+{
+  return getfield (k);
+}
+
+Cell& 
+octave_map::contents (const std::string& k)
+{
+  octave_idx_type idx = keys.getfield (k);
+  if (idx >= static_cast<octave_idx_type> (vals.size ()))
+    vals.push_back (Cell (dimensions)); // auto-set correct dims.
+  return vals[idx];
+}
+
+void 
+octave_map::extract_scalar (octave_scalar_map& dest, 
+                            octave_idx_type idx) const
+{
+  octave_idx_type nf = nfields ();
+  dest.vals.reserve (nf);
+  for (octave_idx_type i = 0; i < nf; i++)
+    dest.vals.push_back (vals[i](idx));
+}
+
+octave_scalar_map
+octave_map::checkelem (octave_idx_type n) const
+{
+  octave_scalar_map retval (keys);
+
+  // Optimize this so that there is just one check.
+  extract_scalar (retval, compute_index (n, dimensions));
+
+  return retval;
+}
+
+octave_scalar_map
+octave_map::checkelem (octave_idx_type i, octave_idx_type j) const
+{
+  octave_scalar_map retval (keys);
+
+  // Optimize this so that there is just one check.
+  extract_scalar (retval, compute_index (i, j, dimensions));
+
+  return retval;
+}
+
+octave_scalar_map
+octave_map::checkelem (const Array<octave_idx_type>& ra_idx) const
+{
+  octave_scalar_map retval (keys);
+
+  // Optimize this so that there is just one check.
+  extract_scalar (retval, compute_index (ra_idx, dimensions));
+
+  return retval;
+}
+
+octave_map
+octave_map::squeeze (void) const
+{
+  octave_map retval (*this);
+  octave_idx_type nf = nfields ();
+
+  retval.dimensions = dimensions.squeeze ();
+  
+  for (octave_idx_type i = 0; i < nf; i++)
+    retval.vals[i] = vals[i].squeeze ();
+
+  retval.optimize_dimensions ();
+
+  return retval;
+}
+
+/*
+%!# test preservation of keys by squeeze
+%!test
+%!  x(1,1,1,1).d = 10; x(3,5,1,7).a = "b"; x(2,4,1,7).f = 27;
+%!  assert (fieldnames (squeeze (x)), {"d"; "a"; "f"});
+*/
+
+octave_map
+octave_map::permute (const Array<int>& vec, bool inv) const
+{
+  octave_map retval (keys);
+  octave_idx_type nf = nfields ();
+
+  for (octave_idx_type i = 0; i < nf; i++)
+    retval.vals[i] = vals[i].permute (vec, inv);
+
+  // FIXME:
+  // There is no dim_vector::permute for technical reasons.
+  // We pick the dim vector from results if possible, otherwise use a dummy
+  // array to get it. Need (?) a better solution to this problem.
+  if (nf > 0)
+    retval.dimensions = retval.vals[0].dims ();
+  else
+    {
+      Array<char> dummy (dimensions);
+      dummy = dummy.permute (vec, inv);
+      retval.dimensions = dummy.dims ();
+    }
+
+  retval.optimize_dimensions ();
+
+  return retval;
+}
+
+/*
+%!# test preservation of key order by permute
+%!test
+%!  x(1,1,1,1).d = 10; x(3,5,1,7).a = "b"; x(2,4,1,7).f = 27;
+%!  assert (fieldnames (permute (x, [3, 4, 1, 2])), {"d"; "a"; "f"});
+*/
+
+octave_map
+octave_map::transpose (void) const
+{
+  assert (ndims () == 2);
+
+  octave_map retval (keys);
+
+  retval.dimensions = dim_vector (dimensions (1), dimensions (0));
+
+  octave_idx_type nf = nfields ();
+  for (octave_idx_type i = 0; i < nf; i++)
+    retval.vals[i] = vals[i].transpose ();
+
+  retval.optimize_dimensions ();
+
+  return retval;
+}
+
+/*
+%!# test preservation of key order by transpose
+%!test
+%!  x(1,1).d = 10; x(3,5).a = "b"; x(2,4).f = 27;
+%!  assert (fieldnames (transpose (x)), {"d"; "a"; "f"});
+%!  assert (fieldnames (x'), {"d"; "a"; "f"});
+%!  assert (fieldnames (x.'), {"d"; "a"; "f"});
+*/
+
+octave_map
+octave_map::reshape (const dim_vector& dv) const
+{
+  octave_map retval (keys);
+  retval.dimensions = dv;
+
+  octave_idx_type nf = nfields ();
+  if (nf > 0)
+    {
+      retval.vals.reserve (nf);
+      for (octave_idx_type i = 0; i < nf; i++)
+        retval.vals[i] = vals[i].reshape (dv);
+    }
+  else
+    {
+      // FIXME: Do it with a dummy array, to reuse error message.
+      // Need (?) a better solution.
+      Array<char> dummy (dimensions);
+      dummy.reshape (dv);
+    }
+
+  retval.optimize_dimensions ();
+
+  return retval;
+}
+
+/*
+%!# test preservation of key order by reshape
+%!test
+%!  x(1,1).d = 10; x(4,6).a = "b"; x(2,4).f = 27;
+%!  assert (fieldnames (reshape (x, 3, 8)), {"d"; "a"; "f"});
+*/
+
+void
+octave_map::resize (const dim_vector& dv)
+{
+  octave_idx_type nf = nfields ();
+  if (nf > 0)
+    {
+      for (octave_idx_type i = 0; i < nf; i++)
+        vals[i].resize (dv);
+    }
+  else
+    {
+      // FIXME: Do it with a dummy array, to reuse error message.
+      // Need (?) a better solution.
+      Array<char> dummy (dimensions);
+      dummy.resize (dv);
+    }
+
+  dimensions = dv;
+  optimize_dimensions ();
+}
+
+void
+octave_map::do_cat (int dim, octave_idx_type n, const octave_scalar_map *map_list,
+                    octave_map& retval)
+{
+  octave_idx_type nf = retval.nfields ();
+  retval.vals.reserve (nf);
+
+  dim_vector& rd = retval.dimensions;
+  rd.resize (dim+1, 1);
+  rd(0) = rd(1) = 1;
+  rd(dim) = n;
+
+  for (octave_idx_type j = 0; j < nf; j++)
+    {
+      retval.vals.push_back (Cell (rd));
+      assert (retval.vals[j].numel () == n);
+      for (octave_idx_type i = 0; i < n; i++)
+        retval.vals[j].xelem(i) = map_list[i].vals[j];
+    }
+}
+
+void
+octave_map::do_cat (int dim, octave_idx_type n, const octave_map *map_list,
+                    octave_map& retval)
+{
+  octave_idx_type nf = retval.nfields ();
+  retval.vals.reserve (nf);
+
+  OCTAVE_LOCAL_BUFFER (Array<octave_value>, field_list, n);
+
+  for (octave_idx_type j = 0; j < nf; j++)
+    {
+      for (octave_idx_type i = 0; i < n; i++)
+        field_list[i] = map_list[i].vals[j];
+
+      retval.vals.push_back (Array<octave_value>::cat (dim, n, field_list));
+    }
+}
+
+template <class map>
+static void
+permute_to_correct_order (octave_idx_type n, octave_idx_type nf,
+                          const map *map_list, map *new_map_list)
+{
+  new_map_list[0] = map_list[0];
+
+  Array<octave_idx_type> perm (1, nf);
+
+  for (octave_idx_type i = 1; i < n; i++)
+    {
+      new_map_list[i] = map_list[i].orderfields (map_list[0], perm);
+
+      if (error_state)
+        {
+          // Use liboctave exception to be consistent.
+          (*current_liboctave_error_handler)
+            ("cat: field names mismatch in concatenating structs");
+          break;
+        }
+    }
+}
+
+
+octave_map
+octave_map::cat (int dim, octave_idx_type n, const octave_scalar_map *map_list)
+{
+  octave_map retval;
+  if (n > 0)
+    {
+      retval.keys = map_list[0].keys;
+      octave_idx_type nf = map_list[0].nfields ();
+      if (nf > 0)
+        {
+          // Try the fast case.
+          bool all_same = true;
+          for (octave_idx_type i = 1; i < n; i++)
+            {
+              all_same = map_list[0].keys.is_same (map_list[i].keys);
+              if (! all_same)
+                break;
+            }
+
+          if (all_same)
+            do_cat (dim, n, map_list, retval);
+          else
+            {
+              // permute all structures to common order.
+              OCTAVE_LOCAL_BUFFER (octave_scalar_map, new_map_list, n);
+
+              permute_to_correct_order (n, nf, map_list, new_map_list);
+
+              do_cat (dim, n, new_map_list, retval);
+            }
+
+        }
+      else
+        {
+          dim_vector& rd = retval.dimensions;
+          rd.resize (dim+1, 1);
+          rd(0) = rd(1) = 1;
+          rd(dim) = n;
+        }
+
+      retval.optimize_dimensions ();
+    }
+
+  return retval;
+}
+
+octave_map
+octave_map::cat (int dim, octave_idx_type n, const octave_map *map_list)
+{
+  octave_map retval;
+  if (n > 0)
+    {
+      retval.keys = map_list[0].keys;
+      octave_idx_type nf = map_list[0].nfields ();
+
+      // Try the fast case.
+      bool all_same = true;
+      for (octave_idx_type i = 1; i < n; i++)
+        {
+          all_same = map_list[0].keys.is_same (map_list[i].keys);
+          if (! all_same)
+            break;
+        }
+
+      if (all_same)
+        do_cat (dim, n, map_list, retval);
+      else
+        {
+          // permute all structures to correct order.
+          OCTAVE_LOCAL_BUFFER (octave_map, new_map_list, n);
+
+          permute_to_correct_order (n, nf, map_list, new_map_list);
+
+          if (nf > 0)
+            do_cat (dim, n, new_map_list, retval);
+          else
+            {
+              // Use dummy arrays. FIXME: Need(?) a better solution.
+              OCTAVE_LOCAL_BUFFER (Array<char>, dummy, n);
+              for (octave_idx_type i = 0; i < n; i++)
+                dummy[i].clear (map_list[0].dimensions);
+              Array<char>::cat (dim, n, dummy);
+            }
+        }
+
+      retval.optimize_dimensions ();
+    }
+
+  return retval;
+}
+
+/*
+%!# test preservation of key order by concatenation
+%!test
+%!  x(1, 1).d = 10; x(4, 6).a = "b"; x(2, 4).f = 27;
+%!  y(1, 6).f = 11; y(1, 6).a = "c"; y(1, 6).d = 33;
+%!  assert (fieldnames ([x; y]), {"d"; "a"; "f"});
+*/
+
+octave_map
+octave_map::index (const idx_vector& i, bool resize_ok) const
+{
+  octave_map retval (keys);
+  octave_idx_type nf = nfields ();
+
+  for (octave_idx_type k = 0; k < nf; k++)
+    retval.vals[k] = vals[k].index (i, resize_ok);
+
+  if (nf > 0)
+    retval.dimensions = retval.vals[0].dims ();
+  else
+    {
+      // Use dummy array. FIXME: Need(?) a better solution.
+      Array<char> dummy (dimensions);
+      dummy = dummy.index (i, resize_ok);
+      retval.dimensions = dummy.dims ();
+    }
+
+  retval.optimize_dimensions ();
+
+  return retval;
+}
+
+octave_map
+octave_map::index (const idx_vector& i, const idx_vector& j,
+                   bool resize_ok) const
+{
+  octave_map retval (keys);
+  octave_idx_type nf = nfields ();
+
+  for (octave_idx_type k = 0; k < nf; k++)
+    retval.vals[k] = vals[k].index (i, j, resize_ok);
+
+  if (nf > 0)
+    retval.dimensions = retval.vals[0].dims ();
+  else
+    {
+      // Use dummy array. FIXME: Need(?) a better solution.
+      Array<char> dummy (dimensions);
+      dummy = dummy.index (i, j, resize_ok);
+      retval.dimensions = dummy.dims ();
+    }
+
+  retval.optimize_dimensions ();
+
+  return retval;
+}
+
+octave_map 
+octave_map::index (const Array<idx_vector>& ia, bool resize_ok) const
+{
+  octave_map retval (keys);
+  octave_idx_type nf = nfields ();
+
+  for (octave_idx_type k = 0; k < nf; k++)
+    retval.vals[k] = vals[k].index (ia, resize_ok);
+
+  if (nf > 0)
+    retval.dimensions = retval.vals[0].dims ();
+  else
+    {
+      // Use dummy array. FIXME: Need(?) a better solution.
+      Array<char> dummy (dimensions);
+      dummy = dummy.index (ia, resize_ok);
+      retval.dimensions = dummy.dims ();
+    }
+
+  retval.optimize_dimensions ();
+
+  return retval;
+}
+
+octave_map 
+octave_map::index (const octave_value_list& idx, bool resize_ok) const
+{
+  octave_idx_type n_idx = idx.length ();
+  octave_map retval;
+
+  switch (n_idx)
+    {
+    case 1:
+      {
+        idx_vector i = idx(0).index_vector ();
+
+        if (! error_state)
+          retval = index (i, resize_ok);
+      }
+      break;
+
+    case 2:
+      {
+        idx_vector i = idx(0).index_vector ();
+
+        if (! error_state)
+          {
+            idx_vector j = idx(1).index_vector ();
+
+            retval = index (i, j, resize_ok);
+          }
+      }
+      break;
+
+    default:
+      {
+        Array<idx_vector> ia (n_idx, 1);
+
+        for (octave_idx_type i = 0; i < n_idx; i++)
+          {
+            ia(i) = idx(i).index_vector ();
+
+            if (error_state)
+              break;
+          }
+
+        if (! error_state)
+          retval = index (ia, resize_ok);
+      }
+      break;
+    }
+
+  return retval;
+}
+
+void
+octave_map::assign (const idx_vector& i, const octave_map& rhs)
+{
+  if (rhs.keys.is_same (keys))
+    {
+      octave_idx_type nf = nfields ();
+
+      for (octave_idx_type k = 0; k < nf; k++)
+        vals[k].assign (i, rhs.vals[k]);
+
+      if (nf > 0)
+        dimensions = vals[0].dims ();
+      else
+        {
+          // Use dummy array. FIXME: Need(?) a better solution.
+          Array<char> dummy (dimensions), rhs_dummy (rhs.dimensions);
+          dummy.assign (i, rhs_dummy);;
+          dimensions = dummy.dims ();
+        }
+
+      optimize_dimensions ();
+    }
+  else
+    {
+      Array<octave_idx_type> perm;
+      octave_map rhs1 = rhs.orderfields (*this, perm);
+      if (! error_state)
+        {
+          assert (rhs1.keys.is_same (rhs.keys));
+          assign (i, rhs1);
+        }
+      else
+        error ("incompatible fields in struct assignment");
+    }
+}
+
+void
+octave_map::assign (const idx_vector& i, const idx_vector& j,
+                    const octave_map& rhs)
+{
+  if (rhs.keys.is_same (keys))
+    {
+      octave_idx_type nf = nfields ();
+
+      for (octave_idx_type k = 0; k < nf; k++)
+        vals[k].assign (i, j, rhs.vals[k]);
+
+      if (nf > 0)
+        dimensions = vals[0].dims ();
+      else
+        {
+          // Use dummy array. FIXME: Need(?) a better solution.
+          Array<char> dummy (dimensions), rhs_dummy (rhs.dimensions);
+          dummy.assign (i, j, rhs_dummy);;
+          dimensions = dummy.dims ();
+        }
+
+      optimize_dimensions ();
+    }
+  else
+    {
+      Array<octave_idx_type> perm;
+      octave_map rhs1 = rhs.orderfields (*this, perm);
+      if (! error_state)
+        {
+          assert (rhs1.keys.is_same (rhs.keys));
+          assign (i, j, rhs1);
+        }
+      else
+        error ("incompatible fields in struct assignment");
+    }
+}
+
+void
+octave_map::assign (const Array<idx_vector>& ia,
+                    const octave_map& rhs)
+{
+  if (rhs.keys.is_same (keys))
+    {
+      octave_idx_type nf = nfields ();
+
+      for (octave_idx_type k = 0; k < nf; k++)
+        vals[k].assign (ia, rhs.vals[k]);
+
+      if (nf > 0)
+        dimensions = vals[0].dims ();
+      else
+        {
+          // Use dummy array. FIXME: Need(?) a better solution.
+          Array<char> dummy (dimensions), rhs_dummy (rhs.dimensions);
+          dummy.assign (ia, rhs_dummy);;
+          dimensions = dummy.dims ();
+        }
+
+      optimize_dimensions ();
+    }
+  else
+    {
+      Array<octave_idx_type> perm;
+      octave_map rhs1 = rhs.orderfields (*this, perm);
+      if (! error_state)
+        {
+          assert (rhs1.keys.is_same (rhs.keys));
+          assign (ia, rhs1);
+        }
+      else
+        error ("incompatible fields in struct assignment");
+    }
+}
+
+void
+octave_map::assign (const octave_value_list& idx, const octave_map& rhs)
+{
+  octave_idx_type n_idx = idx.length ();
+
+  switch (n_idx)
+    {
+    case 1:
+      {
+        idx_vector i = idx(0).index_vector ();
+
+        if (! error_state)
+          assign (i, rhs);
+      }
+      break;
+
+    case 2:
+      {
+        idx_vector i = idx(0).index_vector ();
+
+        if (! error_state)
+          {
+            idx_vector j = idx(1).index_vector ();
+
+            assign (i, j, rhs);
+          }
+      }
+      break;
+
+    default:
+      {
+        Array<idx_vector> ia (n_idx, 1);
+
+        for (octave_idx_type i = 0; i < n_idx; i++)
+          {
+            ia(i) = idx(i).index_vector ();
+
+            if (error_state)
+              break;
+          }
+
+        if (! error_state)
+          assign (ia, rhs);
+      }
+      break;
+    }
+}
+
+void
+octave_map::delete_elements (const idx_vector& i)
+{
+  octave_idx_type nf = nfields ();
+  for (octave_idx_type k = 0; k < nf; k++)
+    vals[k].delete_elements (i);
+
+  if (nf > 0)
+    dimensions = vals[0].dims ();
+  else
+    {
+      // Use dummy array. FIXME: Need(?) a better solution.
+      Array<char> dummy (dimensions);
+      dummy.delete_elements (i);
+      dimensions = dummy.dims ();
+    }
+
+  optimize_dimensions ();
+}
+
+void
+octave_map::delete_elements (int dim, const idx_vector& i)
+{
+  octave_idx_type nf = nfields ();
+  for (octave_idx_type k = 0; k < nf; k++)
+    vals[k].delete_elements (dim, i);
+
+  if (nf > 0)
+    dimensions = vals[0].dims ();
+  else
+    {
+      // Use dummy array. FIXME: Need(?) a better solution.
+      Array<char> dummy (dimensions);
+      dummy.delete_elements (dim, i);
+      dimensions = dummy.dims ();
+    }
+
+  optimize_dimensions ();
+}
+
+void
+octave_map::delete_elements (const Array<idx_vector>& ia)
+{
+  octave_idx_type nf = nfields ();
+  for (octave_idx_type k = 0; k < nf; k++)
+    vals[k].delete_elements (ia);
+
+  if (nf > 0)
+    dimensions = vals[0].dims ();
+  else
+    {
+      // Use dummy array. FIXME: Need(?) a better solution.
+      Array<char> dummy (dimensions);
+      dummy.delete_elements (ia);
+      dimensions = dummy.dims ();
+    }
+
+  optimize_dimensions ();
+}
+
+void
+octave_map::delete_elements (const octave_value_list& idx)
+{
+  octave_idx_type n_idx = idx.length ();
+
+  Array<idx_vector> ia (n_idx, 1);
+
+  for (octave_idx_type i = 0; i < n_idx; i++)
+    {
+      ia(i) = idx(i).index_vector ();
+
+      if (error_state)
+        break;
+    }
+
+  if (! error_state)
+    delete_elements (ia);
+}
+
+/*
+%!# test preservation of key order by indexing
+%!test
+%!  x(1, 1).d = 10; x(4, 6).a = "b"; x(2, 4).f = 27;
+%!  assert (fieldnames (x([1, 2], [2:5])), {"d"; "a"; "f"});
+*/
+
+octave_map
+octave_map::concat (const octave_map& rb, const Array<octave_idx_type>& ra_idx)
+{
+  if (nfields () == rb.nfields ())
+    {
+      for (const_iterator pa = begin (); pa != end (); pa++)
+        {
+          const_iterator pb = rb.seek (key(pa));
+
+          if (pb == rb.end ())
+            {
+              error ("field name mismatch in structure concatenation");
+              break;
+            }
+        
+          contents(pa).insert (rb.contents(pb), ra_idx);
+        }
+    }
+  else
+    {
+      dim_vector dv = dims ();
+
+      if (dv.all_zero ())
+        *this = rb;
+      else if (! rb.dims ().all_zero ())
+        error ("invalid structure concatenation");
+    }
+
+  return *this;
+}
+
+void
+octave_map::optimize_dimensions (void)
+{
+  octave_idx_type nf = nfields ();
+
+  for (octave_idx_type i = 0; i < nf; i++)
+    {
+      if (! vals[i].optimize_dimensions (dimensions))
+        {
+          error ("internal error: dimension mismatch across fields in struct");
+          break;
+        }
+    }
+
+}
+
 Octave_map::Octave_map (const dim_vector& dv, const Cell& key_vals)
   : map (), key_list (), dimensions (dv)
 {
@@ -49,6 +1116,16 @@
     error ("Octave_map: expecting keys to be cellstr");
 }
 
+Octave_map::Octave_map (const octave_map& m)
+  : map (), key_list (), dimensions (m.dims ())
+{
+  for (octave_map::const_iterator p = m.begin (); p != m.end (); p++)
+    map[m.key (p)] = m.contents (p);
+  const string_vector mkeys = m.fieldnames ();
+  for (octave_idx_type i = 0; i < mkeys.numel (); i++)
+    key_list.push_back (mkeys(i));
+}
+
 Octave_map
 Octave_map::squeeze (void) const
 {
@@ -70,13 +1147,6 @@
   return retval;
 }
 
-/*
-%!# test preservation of keys by squeeze
-%!test
-%!  x(1,1,1,1).d = 10; x(3,5,1,7).a = "b"; x(2,4,1,7).f = 27;
-%!  assert (fieldnames (squeeze (x)), {"d"; "a"; "f"});
-*/
-
 Octave_map
 Octave_map::permute (const Array<int>& vec, bool inv) const
 {
@@ -98,13 +1168,6 @@
   return retval;
 }
 
-/*
-%!# test preservation of key order by permute
-%!test
-%!  x(1,1,1,1).d = 10; x(3,5,1,7).a = "b"; x(2,4,1,7).f = 27;
-%!  assert (fieldnames (permute (x, [3, 4, 1, 2])), {"d"; "a"; "f"});
-*/
-
 Cell&
 Octave_map::contents (const std::string& k)
 {
@@ -179,15 +1242,6 @@
   return retval;
 }
 
-/*
-%!# test preservation of key order by transpose
-%!test
-%!  x(1,1).d = 10; x(3,5).a = "b"; x(2,4).f = 27;
-%!  assert (fieldnames (transpose (x)), {"d"; "a"; "f"});
-%!  assert (fieldnames (x'), {"d"; "a"; "f"});
-%!  assert (fieldnames (x.'), {"d"; "a"; "f"});
-*/
-
 Octave_map
 Octave_map::reshape (const dim_vector& new_dims) const
 {
@@ -209,13 +1263,6 @@
   return retval;
 }
 
-/*
-%!# test preservation of key order by reshape
-%!test
-%!  x(1,1).d = 10; x(4,6).a = "b"; x(2,4).f = 27;
-%!  assert (fieldnames (reshape (x, 3, 8)), {"d"; "a"; "f"});
-*/
-
 void
 Octave_map::resize (const dim_vector& dv, bool fill)
 {
@@ -286,14 +1333,6 @@
   return retval;
 }
 
-/*
-%!# test preservation of key order by concatenation
-%!test
-%!  x(1, 1).d = 10; x(4, 6).a = "b"; x(2, 4).f = 27;
-%!  y(1, 6).f = 11; y(1, 6).a = "c"; y(1, 6).d = 33;
-%!  assert (fieldnames ([x; y]), {"d"; "a"; "f"});
-*/
-
 static bool
 keys_ok (const Octave_map& a, const Octave_map& b, string_vector& keys)
 {
@@ -526,10 +1565,3 @@
 
   return retval;
 }
-
-/*
-%!# test preservation of key order by indexing
-%!test
-%!  x(1, 1).d = 10; x(4, 6).a = "b"; x(2, 4).f = 27;
-%!  assert (fieldnames (x([1, 2], [2:5])), {"d"; "a"; "f"});
-*/
--- a/src/oct-map.h
+++ b/src/oct-map.h
@@ -2,6 +2,7 @@
 
 Copyright (C) 1994, 1995, 1996, 1997, 2000, 2002, 2003, 2004, 2005,
               2006, 2007, 2009 John W. Eaton
+Copyright (C) 2010 VZLU Prague
 
 This file is part of Octave.
 
@@ -32,6 +33,385 @@
 
 class string_vector;
 
+// A class holding a map field->index. Supports reference-counting.
+class OCTINTERP_API 
+octave_fields
+{
+  class fields_rep : public std::map<std::string, octave_idx_type>
+  {
+  public:
+    fields_rep (void) : std::map<std::string, octave_idx_type> (), count (1) { }
+    fields_rep (const fields_rep& other)
+      : std::map<std::string, octave_idx_type> (other), count (1) { }
+
+    int count;
+
+  private:
+    fields_rep& operator = (const fields_rep&); // no assignment!
+  };
+
+  fields_rep *rep;
+
+  static fields_rep nil_rep; 
+
+public:
+
+  octave_fields (void) : rep (&nil_rep) { rep->count++; }
+  octave_fields (const string_vector&);
+
+  ~octave_fields (void)
+    {
+      if (--rep->count == 0)
+        delete rep;
+    }
+
+  void make_unique (void)
+    {
+      if (rep->count > 1)
+        {
+          --rep->count;
+          rep = new fields_rep (*rep);
+        }
+    }
+
+  octave_fields (const octave_fields& o) : rep (o.rep) { rep->count++; }
+
+  octave_fields& 
+  operator = (const octave_fields& o)
+    {
+      o.rep->count++;
+      if (--rep->count)
+        delete rep;
+      rep = o.rep;
+
+      return *this;
+    }
+
+  // constant iteration support. non-const iteration intentionally unsupported.
+
+  typedef std::map<std::string, octave_idx_type>::const_iterator const_iterator;
+  typedef const_iterator iterator;
+
+  const_iterator begin (void) const { return rep->begin (); }
+  const_iterator end (void) const { return rep->end (); }
+
+  std::string key (const_iterator p) const { return p->first; }
+  octave_idx_type index (const_iterator p) const { return p->second; }
+
+  const_iterator seek (const std::string& k) const 
+    { return rep->find (k); }
+
+  // high-level methods.
+
+  // number of fields.
+  octave_idx_type nfields (void) const { return rep->size (); }
+
+  // check whether a field exists.
+  bool isfield (const std::string& name) const;
+
+  // get index of field. return -1 if not exist
+  octave_idx_type getfield (const std::string& name) const;
+  // get index of field. add if not exist
+  octave_idx_type getfield (const std::string& name);
+  // remove field and return the index. -1 if didn't exist.
+  octave_idx_type rmfield (const std::string& name);
+
+  // order the fields of this map. creates a permutation
+  // used to order the fields.
+  void orderfields (Array<octave_idx_type>& perm);
+
+  // compares two instances for equality up to order of fields.
+  // returns a permutation needed to bring the fields of *other*
+  // into the order of *this*.
+  bool equal_up_to_order (const octave_fields& other,
+                          Array<octave_idx_type>& perm) const;
+
+  bool is_same (const octave_fields& other) const
+    { return rep == other.rep; }
+
+  // Returns the fields as a vector of strings.
+  string_vector fieldnames (void) const;
+
+  void clear (void)
+    {
+      *this = octave_fields ();
+    }
+};
+
+
+class OCTINTERP_API
+octave_scalar_map
+{
+  octave_scalar_map (const octave_fields& k)
+    : keys (k), vals (k.nfields ()) { }
+
+public:
+
+  octave_scalar_map (void) : keys (), vals () { }
+
+  octave_scalar_map (const string_vector& k)
+    : keys (k), vals (k.length ()) { }
+
+  octave_scalar_map (const octave_scalar_map& m)
+    : keys (m.keys), vals(m.vals) { }
+
+  octave_scalar_map& operator = (const octave_scalar_map& m)
+    {
+      keys = m.keys;
+      vals = m.vals;
+
+      return *this;
+    }
+
+  // iteration support. note that both const and non-const iterators are the
+  // same. The const/non-const distinction is made by the key & contents method.
+  typedef octave_fields::const_iterator const_iterator;
+  typedef const_iterator iterator;
+
+  const_iterator begin (void) const { return keys.begin (); }
+  const_iterator end (void) const { return keys.end (); }
+
+  const_iterator seek (const std::string& k) const { return keys.seek (k); }
+
+  std::string key (const_iterator p) const 
+    { return keys.key (p); }
+  octave_idx_type index (const_iterator p) const
+    { return keys.index (p); }
+
+  const octave_value& contents (const_iterator p) const 
+    { return vals[keys.index (p)]; }
+
+  octave_value& contents (iterator p)
+    { return vals[keys.index (p)]; }
+
+  const octave_value& contents (octave_idx_type i) const
+    { return vals[i]; }
+
+  octave_value& contents (octave_idx_type i)
+    { return vals[i]; }
+
+  // number of fields.
+  octave_idx_type nfields (void) const { return keys.nfields (); }
+
+  // check whether a field exists.
+  bool isfield (const std::string& name) const 
+    { return keys.isfield (name); }
+
+  string_vector fieldnames (void) const
+    { return keys.fieldnames (); }
+
+  // get contents of a given field. empty value if not exist.
+  octave_value getfield (const std::string& key) const;
+
+  // set contents of a given field. add if not exist.
+  void setfield (const std::string& key, const octave_value& val);
+
+  // remove a given field. do nothing if not exist.
+  void rmfield (const std::string& key);
+
+  // return a copy with fields ordered, optionally along with permutation.
+  octave_scalar_map orderfields (void) const;
+  octave_scalar_map orderfields (Array<octave_idx_type>& perm) const;
+  octave_scalar_map orderfields (const octave_scalar_map& other,
+                                 Array<octave_idx_type>& perm) const;
+
+  // aka getfield/setfield, but the latter returns a reference.
+  octave_value contents (const std::string& k) const;
+  octave_value& contents (const std::string& k);
+
+  void clear (void)
+    {
+      keys.clear ();
+      vals.clear ();
+    }
+
+  friend class octave_map;
+
+private:
+
+  octave_fields keys;
+  std::vector<octave_value> vals;
+
+};
+
+class OCTINTERP_API
+octave_map
+{
+  octave_map (const octave_fields& k)
+    : keys (k), vals (k.nfields ()), dimensions () { }
+
+public:
+
+  octave_map (void) : keys (), vals (), dimensions () { }
+
+  octave_map (const dim_vector& dv) : keys (), vals (), dimensions (dv) { }
+
+  octave_map (const string_vector& k)
+    : keys (k), vals (k.length ()), dimensions (1, 1) { }
+
+  octave_map (const dim_vector& dv, const string_vector& k)
+    : keys (k), vals (k.length ()), dimensions (dv) { }
+
+  octave_map (const octave_map& m)
+    : keys (m.keys), vals (m.vals), dimensions (m.dimensions) { }
+
+  octave_map (const octave_scalar_map& m);
+
+  octave_map (const Octave_map& m);
+
+  octave_map& operator = (const octave_map& m)
+    {
+      keys = m.keys;
+      vals = m.vals;
+      dimensions = m.dimensions;
+
+      return *this;
+    }
+
+  // iteration support. note that both const and non-const iterators are the
+  // same. The const/non-const distinction is made by the key & contents method.
+  typedef octave_fields::const_iterator const_iterator;
+  typedef const_iterator iterator;
+
+  const_iterator begin (void) const { return keys.begin (); }
+  const_iterator end (void) const { return keys.end (); }
+
+  const_iterator seek (const std::string& k) const { return keys.seek (k); }
+
+  std::string key (const_iterator p) const 
+    { return keys.key (p); }
+  octave_idx_type index (const_iterator p) const
+    { return keys.index (p); }
+
+  const Cell& contents (const_iterator p) const 
+    { return vals[keys.index (p)]; }
+
+  Cell& contents (iterator p)
+    { return vals[keys.index (p)]; }
+
+  const Cell& contents (octave_idx_type i) const
+    { return vals[i]; }
+
+  Cell& contents (octave_idx_type i)
+    { return vals[i]; }
+
+  // number of fields.
+  octave_idx_type nfields (void) const { return keys.nfields (); }
+
+  // check whether a field exists.
+  bool isfield (const std::string& name) const 
+    { return keys.isfield (name); }
+
+  string_vector fieldnames (void) const
+    { return keys.fieldnames (); }
+
+  // get contents of a given field. empty value if not exist.
+  Cell getfield (const std::string& key) const;
+
+  // set contents of a given field. add if not exist. checks for
+  // correct dimensions.
+  void setfield (const std::string& key, const Cell& val);
+
+  // remove a given field. do nothing if not exist.
+  void rmfield (const std::string& key);
+
+  // return a copy with fields ordered, optionally along with permutation.
+  octave_map orderfields (void) const;
+  octave_map orderfields (Array<octave_idx_type>& perm) const;
+  octave_map orderfields (const octave_map& other,
+                          Array<octave_idx_type>& perm) const;
+
+  // aka getfield/setfield, but the latter returns a reference.
+  Cell contents (const std::string& k) const;
+  Cell& contents (const std::string& k);
+
+  void clear (void)
+    {
+      keys.clear ();
+      vals.clear ();
+    }
+
+  // The Array-like methods.
+  octave_idx_type numel (void) const { return dimensions.numel (); }
+  octave_idx_type length (void) const { return numel (); }
+
+  octave_idx_type rows (void) const { return dimensions(0); }
+  octave_idx_type cols (void) const { return dimensions(1); }
+  octave_idx_type columns (void) const { return dimensions(1); }
+
+  // Extract a scalar substructure.
+  octave_scalar_map checkelem (octave_idx_type n) const;
+  octave_scalar_map checkelem (octave_idx_type i, octave_idx_type j) const;
+
+  octave_scalar_map
+  checkelem (const Array<octave_idx_type>& ra_idx) const;
+
+  octave_map squeeze (void) const; 
+
+  octave_map permute (const Array<int>& vec, bool inv = false) const; 
+
+  dim_vector dims (void) const { return dimensions; }
+
+  int ndims (void) const { return dimensions.length (); }
+
+  octave_map transpose (void) const;
+
+  octave_map reshape (const dim_vector& dv) const;
+
+  void resize (const dim_vector& dv);
+
+  static octave_map
+  cat (int dim, octave_idx_type n, const octave_scalar_map *map_list);
+
+  static octave_map
+  cat (int dim, octave_idx_type n, const octave_map *map_list);
+
+  octave_map index (const idx_vector& i, bool resize_ok) const;
+
+  octave_map index (const idx_vector& i, const idx_vector& j,
+                    bool resize_ok) const;
+
+  octave_map index (const Array<idx_vector>& ia,
+                    bool resize_ok) const;
+
+  octave_map index (const octave_value_list&, bool resize_ok) const;
+  
+  void assign (const idx_vector& i, const octave_map& rhs);
+
+  void assign (const idx_vector& i, const idx_vector& j, const octave_map& rhs);
+
+  void assign (const Array<idx_vector>& ia, const octave_map& rhs);
+
+  void assign (const octave_value_list&, const octave_map& rhs);
+  
+  void delete_elements (const idx_vector& i);
+
+  void delete_elements (int dim, const idx_vector& i);
+
+  void delete_elements (const Array<idx_vector>& ia);
+
+  void delete_elements (const octave_value_list&);
+
+  octave_map concat (const octave_map& rb, const Array<octave_idx_type>& ra_idx);
+
+private:
+
+  octave_fields keys;
+  std::vector<Cell> vals;
+  dim_vector dimensions;
+
+  void optimize_dimensions (void);
+  void extract_scalar (octave_scalar_map& dest, 
+                       octave_idx_type index) const;
+  static void do_cat (int dim, octave_idx_type n, 
+                      const octave_scalar_map *map_list, octave_map& retval);
+  static void do_cat (int dim, octave_idx_type n, 
+                      const octave_map *map_list, octave_map& retval);
+};
+
+// The original Octave_map object. Octave_map and octave_map are convertible to
+// each other.
+
 class
 OCTINTERP_API
 Octave_map
@@ -85,6 +465,8 @@
   Octave_map (const Octave_map& m)
     : map (m.map), key_list (m.key_list), dimensions (m.dimensions) { }
 
+  Octave_map (const octave_map& m);
+
   Octave_map& operator = (const Octave_map& m)
     {
       if (this != &m)
--- a/src/ov-base.cc
+++ b/src/ov-base.cc
@@ -885,14 +885,36 @@
   return retval;
 }
 
-Octave_map
+octave_map
 octave_base_value::map_value (void) const
 {
-  Octave_map retval;
+  octave_map retval;
   gripe_wrong_type_arg ("octave_base_value::map_value()", type_name ());
   return retval;
 }
 
+octave_scalar_map
+octave_base_value::scalar_map_value (void) const
+{
+  octave_map tmp = map_value ();
+
+  if (tmp.numel () == 1)
+    return tmp.checkelem (0);
+  else
+    {
+      if (! error_state)
+        error ("invalid conversion of multidimensional struct to scalar struct");
+
+      return octave_scalar_map ();
+    }
+}
+
+Octave_map
+octave_base_value::old_map_value (void) const
+{
+  return map_value ();
+}
+
 string_vector
 octave_base_value::map_keys (void) const
 {
--- a/src/ov-base.h
+++ b/src/ov-base.h
@@ -42,6 +42,8 @@
 
 class Cell;
 class Octave_map;
+class octave_map;
+class octave_scalar_map;
 class octave_value;
 class octave_value_list;
 class octave_stream;
@@ -542,7 +544,11 @@
 
   virtual Range range_value (void) const;
 
-  virtual Octave_map map_value (void) const;
+  virtual octave_map map_value (void) const;
+
+  virtual octave_scalar_map scalar_map_value (void) const;
+
+  virtual Octave_map old_map_value (void) const;
 
   virtual string_vector map_keys (void) const;
 
--- a/src/ov-cell.h
+++ b/src/ov-cell.h
@@ -40,7 +40,6 @@
 #include "ov-base-mat.h"
 #include "ov-typeinfo.h"
 
-class Octave_map;
 class octave_value_list;
 
 class tree_walker;
--- a/src/ov-class.cc
+++ b/src/ov-class.cc
@@ -261,7 +261,7 @@
 
   Octave_map my_map;
 
-  my_map = obvp ? obvp->map_value () : map;
+  my_map = obvp ? obvp->old_map_value () : map;
 
   std::string nm = idx(0).string_value ();
 
@@ -721,7 +721,7 @@
               {
                 if (t_rhs.is_object () || t_rhs.is_map ())
                   {
-                    Octave_map rhs_map = t_rhs.map_value ();
+                    Octave_map rhs_map = t_rhs.old_map_value ();
 
                     if (! error_state)
                       {
@@ -1108,12 +1108,12 @@
       octave_value in = new octave_class (*this);
       octave_value_list tmp = feval ("saveobj", in, 1);
       if (! error_state)
-        m = tmp(0).map_value ();
+        m = tmp(0).old_map_value ();
       else
         return false;
     }
   else
-    m = map_value ();
+    m = old_map_value ();
 
   os << "# length: " << m.nfields () << "\n";
 
@@ -1189,7 +1189,7 @@
                           octave_value_list tmp = feval ("loadobj", in, 1);
 
                           if (! error_state)
-                            map = tmp(0).map_value ();
+                            map = tmp(0).old_map_value ();
                           else
                             success = false;
                         }
@@ -1238,12 +1238,12 @@
       octave_value in = new octave_class (*this);
       octave_value_list tmp = feval ("saveobj", in, 1);
       if (! error_state)
-        m = tmp(0).map_value ();
+        m = tmp(0).old_map_value ();
       else
         return false;
     }
   else
-    m = map_value ();
+    m = old_map_value ();
 
   int32_t len = m.nfields();
   os.write (reinterpret_cast<char *> (&len), 4);
@@ -1335,7 +1335,7 @@
                   octave_value_list tmp = feval ("loadobj", in, 1);
 
                   if (! error_state)
-                    map = tmp(0).map_value ();
+                    map = tmp(0).old_map_value ();
                   else
                     success = false;
                 }
@@ -1410,12 +1410,12 @@
       octave_value in = new octave_class (*this);
       octave_value_list tmp = feval ("saveobj", in, 1);
       if (! error_state)
-        m = tmp(0).map_value ();
+        m = tmp(0).old_map_value ();
       else
         goto error_cleanup;
     }
   else
-    m = map_value ();
+    m = old_map_value ();
 
   // recursively add each element of the class to this group
   i = m.begin ();
@@ -1576,7 +1576,7 @@
 
               if (! error_state)
                 {
-                  map = tmp(0).map_value ();
+                  map = tmp(0).old_map_value ();
                   retval = true;
                 }
               else
@@ -1624,7 +1624,7 @@
 {
   if (obj.is_object ())
     {
-      Octave_map m = obj.map_value ();
+      Octave_map m = obj.old_map_value ();
       field_names = m.keys ();
 
       parent_class_names = obj.parent_class_name_list ();
@@ -1646,7 +1646,7 @@
     {
       if (nfields () == obj.nfields ())
         {
-          Octave_map obj_map = obj.map_value ();
+          Octave_map obj_map = obj.old_map_value ();
           string_vector obj_fnames = obj_map.keys ();
           string_vector fnames = fields ();
 
@@ -1725,7 +1725,7 @@
 
       if (fcn && fcn->is_class_constructor ())
         {
-          Octave_map m = args(0).map_value ();
+          Octave_map m = args(0).old_map_value ();
 
           if (! error_state)
             {
--- a/src/ov-class.h
+++ b/src/ov-class.h
@@ -130,7 +130,9 @@
 
   bool is_object (void) const { return true; }
 
-  Octave_map map_value (void) const { return map; }
+  octave_map map_value (void) const { return map; }
+
+  Octave_map old_map_value (void) const { return map; }
 
   string_vector map_keys (void) const;
 
--- a/src/ov-fcn-inline.cc
+++ b/src/ov-fcn-inline.cc
@@ -117,7 +117,7 @@
 
 // This function is supplied to allow a Matlab style class structure
 // to be returned..
-Octave_map
+octave_map
 octave_fcn_inline::map_value (void) const
 {
   Octave_map m;
--- a/src/ov-fcn-inline.h
+++ b/src/ov-fcn-inline.h
@@ -67,7 +67,7 @@
 
   octave_value convert_to_str_internal (bool, bool, char) const;
 
-  Octave_map map_value (void) const;
+  octave_map map_value (void) const;
 
   bool save_ascii (std::ostream& os);
 
--- a/src/ov-struct.cc
+++ b/src/ov-struct.cc
@@ -51,6 +51,17 @@
 
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(octave_struct, "struct", "struct");
 
+octave_base_value *
+octave_struct::try_narrowing_conversion (void)
+{
+  octave_base_value *retval = 0;
+
+  if (numel () == 1)
+    retval = new octave_scalar_struct (map.checkelem (0));
+
+  return retval;
+}
+
 Cell
 octave_struct::dotref (const octave_value_list& idx, bool auto_add)
 {
@@ -60,7 +71,7 @@
 
   std::string nm = idx(0).string_value ();
 
-  Octave_map::const_iterator p = map.seek (nm);
+  octave_map::const_iterator p = map.seek (nm);
 
   if (p != map.end ())
     retval = map.contents (p);
@@ -131,7 +142,7 @@
               }
           }
         else
-          retval(0) = map.index (idx.front ());
+          retval(0) = do_index_op (idx.front ());
       }
       break;
 
@@ -197,7 +208,7 @@
               }
           }
         else
-          retval = map.index (idx.front (), auto_add);
+          retval = do_index_op (idx.front (), auto_add);
       }
       break;
 
@@ -245,7 +256,7 @@
   octave_value retval;
 
   if (type.length () > 0 && type[0] == '.' && ! val.is_map ())
-    retval = Octave_map ();
+    retval = octave_map ();
   else
     retval = val;
 
@@ -297,11 +308,11 @@
                 std::string next_type = type.substr (2);
 
                 Cell tmpc (1, 1);
-                Octave_map::iterator pkey = map.seek (key);
+                octave_map::iterator pkey = map.seek (key);
                 if (pkey != map.end ())
                   {
-                    pkey->second.make_unique ();
-                    tmpc = pkey->second.index (idx.front (), true);
+                    map.contents (pkey).make_unique ();
+                    tmpc = map.contents (pkey).index (idx.front (), true);
                   }
 
                 // FIXME: better code reuse? cf. octave_cell::subsasgn and the case below.
@@ -347,11 +358,11 @@
             std::string next_type = type.substr (1);
 
             Cell tmpc (1, 1);
-            Octave_map::iterator pkey = map.seek (key);
+            octave_map::iterator pkey = map.seek (key);
             if (pkey != map.end ())
               {
-                pkey->second.make_unique ();
-                tmpc = pkey->second;
+                map.contents (pkey).make_unique ();
+                tmpc = map.contents (pkey);
               }
 
             // FIXME: better code reuse?
@@ -420,7 +431,7 @@
                           tmp_cell = tmp_cell.reshape (didx);
 
 
-                        map.assign (idxf, key, tmp_cell);
+                        map.contents (key).assign (idxf, tmp_cell);
 
                         if (! error_state)
                           {
@@ -432,12 +443,12 @@
                       }
                     else 
                       {
-                        const Octave_map& cmap = const_cast<const Octave_map &> (map);
+                        const octave_map& cmap = const_cast<const octave_map &> (map);
                         // cast map to const reference to avoid forced key insertion.
                         if (idxf.all_scalars () 
                             || cmap.contents (key).index (idxf, true).numel () == 1)
                           {
-                            map.assign (idxf, key, t_rhs.storable_value ());
+                            map.contents (key).assign (idxf, Cell (t_rhs.storable_value ()));
                             if (! error_state)
                               {
                                 count++;
@@ -457,7 +468,7 @@
               {
                 if (t_rhs.is_map())
                   {
-                    Octave_map rhs_map = t_rhs.map_value ();
+                    octave_map rhs_map = t_rhs.map_value ();
 
                     if (! error_state)
                       {
@@ -478,7 +489,7 @@
                   {
                     if (t_rhs.is_null_value()) 
                       {
-                        map.maybe_delete_elements (idx.front());
+                        map.delete_elements (idx.front());
 
                         if (! error_state)
                           {
@@ -514,11 +525,14 @@
                 if (numel () == tmp_cell.numel ())
                   tmp_cell = tmp_cell.reshape (dims ());
 
-                map.assign (key, tmp_cell);
+                map.setfield (key, tmp_cell);
               }
             else
-              // Regularize a null matrix if stored into a struct component.
-              map.assign (key, t_rhs.storable_value ());
+              {
+                Cell tmp_cell(1, 1);
+                tmp_cell(0) = t_rhs.storable_value ();
+                map.setfield (key, tmp_cell);
+              }
 
             if (! error_state)
               {
@@ -547,7 +561,7 @@
 octave_value
 octave_struct::do_index_op (const octave_value_list& idx, bool resize_ok)
 {
-  // Octave_map handles indexing itself.
+  // octave_map handles indexing itself.
   return map.index (idx, resize_ok);
 }
 
@@ -558,7 +572,7 @@
 
   size_t retval = 0;
 
-  for (Octave_map::const_iterator p = map.begin (); p != map.end (); p++)
+  for (octave_map::const_iterator p = map.begin (); p != map.end (); p++)
     {
       std::string key = map.key (p);
 
@@ -606,7 +620,7 @@
           increment_indent_level ();
         }
 
-      string_vector key_list = map.keys ();
+      string_vector key_list = map.fieldnames ();
 
       for (octave_idx_type i = 0; i < key_list.length (); i++)
         {
@@ -693,6 +707,996 @@
 %!fail("struct('1',2,'3')","struct expects alternating \"field\", VALUE pairs");
 */
 
+bool
+octave_struct::save_ascii (std::ostream& os)
+{
+  octave_map m = map_value ();
+
+  octave_idx_type nf = m.nfields ();
+
+  const dim_vector dv = dims ();
+
+  os << "# ndims: " << dv.length () << "\n";
+
+  for (int i = 0; i < dv.length (); i++)
+    os << " " << dv (i);
+  os << "\n";
+
+  os << "# length: " << nf << "\n";
+
+  // Iterating over the list of keys will preserve the order of the
+  // fields.
+  string_vector keys = m.fieldnames ();
+
+  for (octave_idx_type i = 0; i < nf; i++)
+    {
+      std::string key = keys(i);
+
+      octave_value val = map.contents (key);
+
+      bool b = save_ascii_data (os, val, key, false, 0);
+      
+      if (! b)
+        return os;
+    }
+
+  return true;
+}
+
+bool 
+octave_struct::load_ascii (std::istream& is)
+{
+  octave_idx_type len = 0;
+  dim_vector dv (1, 1);
+  bool success = true;
+
+  // KLUGE: earlier Octave versions did not save extra dimensions with struct,
+  // and as a result did not preserve dimensions for empty structs.
+  // The default dimensions were 1x1, which we want to preserve.
+  string_vector keywords(2);
+
+  keywords[0] = "ndims";
+  keywords[1] = "length";
+
+  std::string kw;
+
+  if (extract_keyword (is, keywords, kw, len, true))
+    {
+      if (kw == keywords[0])
+        {
+          int mdims = std::max (static_cast<int> (len), 2);
+          dv.resize (mdims);
+          for (int i = 0; i < mdims; i++)
+            is >> dv(i);
+
+          success = extract_keyword (is, keywords[1], len);
+        }
+    }
+  else
+    success = false;
+
+  if (success && len >= 0)
+    {
+      if (len > 0)
+        {
+          octave_map m (dv);
+
+          for (octave_idx_type j = 0; j < len; j++)
+            {
+              octave_value t2;
+              bool dummy;
+
+              // recurse to read cell elements
+              std::string nm
+                = read_ascii_data (is, std::string (), dummy, t2, j);
+
+              if (!is)
+                break;
+
+              Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
+
+              if (error_state)
+                {
+                  error ("load: internal error loading struct elements");
+                  return false;
+                }
+
+              m.setfield (nm, tcell);
+            }
+
+          if (is) 
+            map = m;
+          else
+            {
+              error ("load: failed to load structure");
+              success = false;
+            }
+        }
+      else if (len == 0 )
+        map = octave_map (dv);
+      else
+        panic_impossible ();
+    }
+  else {
+    error ("load: failed to extract number of elements in structure");
+    success = false;
+  }
+
+  return success;
+}
+
+bool 
+octave_struct::save_binary (std::ostream& os, bool& save_as_floats)
+{
+  octave_map m = map_value ();
+
+  octave_idx_type nf = m.nfields ();
+
+  dim_vector d = dims ();
+  if (d.length () < 1)
+    return false;
+
+  // Use negative value for ndims
+  int32_t di = - d.length();
+  os.write (reinterpret_cast<char *> (&di), 4);
+  for (int i = 0; i < d.length (); i++)
+    {
+      di = d(i);
+      os.write (reinterpret_cast<char *> (&di), 4);
+    }
+  
+  int32_t len = nf;
+  os.write (reinterpret_cast<char *> (&len), 4);
+
+  // Iterating over the list of keys will preserve the order of the
+  // fields.
+  string_vector keys = m.fieldnames ();
+
+  for (octave_idx_type i = 0; i < nf; i++)
+    {
+      std::string key = keys(i);
+
+      octave_value val = map.contents (key);
+
+      bool b = save_binary_data (os, val, key, "", 0, save_as_floats);
+      
+      if (! b)
+        return os;
+    }
+
+  return true;
+}
+
+bool 
+octave_struct::load_binary (std::istream& is, bool swap,
+                            oct_mach_info::float_format fmt)
+{
+  bool success = true;
+  int32_t len;
+  if (! is.read (reinterpret_cast<char *> (&len), 4))
+    return false;
+  if (swap)
+    swap_bytes<4> (&len);
+
+  dim_vector dv (1, 1);
+
+  if (len < 0)
+    {
+      // We have explicit dimensions.
+      int mdims = -len;
+
+      int32_t di;
+      dv.resize (mdims);
+
+      for (int i = 0; i < mdims; i++)
+        {
+          if (! is.read (reinterpret_cast<char *> (&di), 4))
+            return false;
+          if (swap)
+            swap_bytes<4> (&di);
+          dv(i) = di;
+        }
+
+      if (! is.read (reinterpret_cast<char *> (&len), 4))
+        return false;
+      if (swap)
+        swap_bytes<4> (&len);
+    }
+
+  if (len > 0)
+    {
+      octave_map m (dv);
+
+      for (octave_idx_type j = 0; j < len; j++)
+        {
+          octave_value t2;
+          bool dummy;
+          std::string doc;
+
+          // recurse to read cell elements
+          std::string nm = read_binary_data (is, swap, fmt, std::string (), 
+                                             dummy, t2, doc);
+
+          if (!is)
+            break;
+
+          Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
+ 
+          if (error_state)
+            {
+              error ("load: internal error loading struct elements");
+              return false;
+            }
+
+          m.setfield (nm, tcell);
+        }
+
+      if (is) 
+        map = m;
+      else
+        {
+          error ("load: failed to load structure");
+          success = false;
+        }
+    }
+  else if (len == 0)
+    map = octave_map (dv);
+  else
+    success = false;
+
+  return success;
+}
+
+#if defined (HAVE_HDF5)
+
+bool
+octave_struct::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats)
+{
+  hid_t data_hid = -1;
+
+#if HAVE_HDF5_18
+  data_hid = H5Gcreate (loc_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
+#else
+  data_hid = H5Gcreate (loc_id, name, 0);
+#endif
+  if (data_hid < 0) return false;
+
+  // recursively add each element of the structure to this group
+  octave_map m = map_value ();
+
+  octave_idx_type nf = m.nfields ();
+
+  // Iterating over the list of keys will preserve the order of the
+  // fields.
+  string_vector keys = m.fieldnames ();
+
+  for (octave_idx_type i = 0; i < nf; i++)
+    {
+      std::string key = keys(i);
+
+      octave_value val = map.contents (key);
+
+      bool retval2 = add_hdf5_data (data_hid, val, key, "", false, 
+                                    save_as_floats);
+
+      if (! retval2)
+        break;
+    }
+
+  H5Gclose (data_hid);
+
+  return true;
+}
+
+bool 
+octave_struct::load_hdf5 (hid_t loc_id, const char *name)
+{
+  bool retval = false;
+
+  hdf5_callback_data dsub;
+
+  herr_t retval2 = 0;
+  octave_map m (dim_vector (1, 1));
+  int current_item = 0;
+  hsize_t num_obj = 0;
+#if HAVE_HDF5_18
+  hid_t group_id = H5Gopen (loc_id, name, H5P_DEFAULT);
+#else
+  hid_t group_id = H5Gopen (loc_id, name);
+#endif
+  H5Gget_num_objs (group_id, &num_obj);
+  H5Gclose (group_id);
+
+  // FIXME -- fields appear to be sorted alphabetically on loading.
+  // Why is that happening?
+
+  while (current_item < static_cast<int> (num_obj)
+         && (retval2 = H5Giterate (loc_id, name, &current_item,
+                                   hdf5_read_next_data, &dsub)) > 0)
+    {
+      octave_value t2 = dsub.tc;
+
+      Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
+ 
+      if (error_state)
+        {
+          error ("load: internal error loading struct elements");
+          return false;
+        }
+
+      m.setfield (dsub.name, tcell);
+
+    }
+
+  if (retval2 >= 0)
+    {
+      map = m;
+      retval = true;
+    }
+  
+  return retval;
+}
+
+#endif
+
+mxArray *
+octave_struct::as_mxArray (void) const
+{
+  int nf = nfields ();
+  string_vector kv = map_keys ();
+
+  OCTAVE_LOCAL_BUFFER (const char *, f, nf);
+
+  for (int i = 0; i < nf; i++)
+    f[i] = kv[i].c_str ();
+
+  mxArray *retval = new mxArray (dims (), nf, f);
+
+  mxArray **elts = static_cast<mxArray **> (retval->get_data ());
+
+  mwSize nel = numel ();
+
+  mwSize ntot = nf * nel;
+
+  for (int i = 0; i < nf; i++)
+    {
+      Cell c = map.contents (kv[i]);
+
+      const octave_value *p = c.data ();
+
+      mwIndex k = 0;
+      for (mwIndex j = i; j < ntot; j += nf)
+        elts[j] = new mxArray (p[k++]);
+    }
+
+  return retval;
+}
+
+DEFINE_OCTAVE_ALLOCATOR(octave_scalar_struct);
+
+DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(octave_scalar_struct, "scalar struct", "struct");
+
+octave_value
+octave_scalar_struct::dotref (const octave_value_list& idx, bool auto_add)
+{
+  assert (idx.length () == 1);
+
+  std::string nm = idx(0).string_value ();
+
+  octave_value retval = map.getfield (nm);
+
+  if (! auto_add && retval.is_undefined ())
+    error ("structure has no member `%s'", nm.c_str ());
+
+  return retval;
+}
+
+octave_value
+octave_scalar_struct::subsref (const std::string& type,
+                               const std::list<octave_value_list>& idx)
+{
+  octave_value retval;
+
+  if (type[0] == '.')
+    {
+      int skip = 1;
+
+      retval = dotref (idx.front ());
+
+      if (idx.size () > 1)
+        retval = retval.next_subsref (type, idx, skip);
+    }
+  else
+    retval = to_array ().subsref (type, idx);
+
+  return retval;
+}
+
+octave_value_list
+octave_scalar_struct::subsref (const std::string& type,
+                               const std::list<octave_value_list>& idx,
+                               int nargout)
+{
+  octave_value_list retval;
+
+  if (type[0] == '.')
+    {
+      int skip = 1;
+
+      retval(0) = dotref (idx.front ());
+
+      if (idx.size () > 1)
+        retval = retval(0).next_subsref (nargout, type, idx, skip);
+    }
+  else
+    retval = to_array ().subsref (type, idx, nargout);
+
+  return retval;
+}
+
+octave_value
+octave_scalar_struct::subsref (const std::string& type,
+                               const std::list<octave_value_list>& idx,
+                               bool auto_add)
+{
+  octave_value retval;
+
+  if (type[0] == '.')
+    {
+      int skip = 1;
+
+      retval = dotref (idx.front (), auto_add);
+
+      if (idx.size () > 1)
+        retval = retval.next_subsref (auto_add, type, idx, skip);
+    }
+  else
+    retval = to_array ().subsref (type, idx, auto_add);
+
+  return retval;
+}
+
+/*
+%!test
+%! x(1).a.a = 1; x(2).a.a = 2;
+%! assert (size (x), [1, 2]);
+%! assert (x(1).a.a, 1);
+%! assert (x(2).a.a, 2);
+*/
+
+octave_value
+octave_scalar_struct::numeric_conv (const octave_value& val,
+                                    const std::string& type)
+{
+  octave_value retval;
+
+  if (type.length () > 0 && type[0] == '.' && ! val.is_map ())
+    retval = octave_map ();
+  else
+    retval = val;
+
+  return retval;
+}
+
+octave_value
+octave_scalar_struct::subsasgn (const std::string& type,
+                                const std::list<octave_value_list>& idx,
+                                const octave_value& rhs)
+{
+  octave_value retval;
+
+  if (idx.front ().empty ())
+    {
+      error ("missing index in indexed assignment");
+      return retval;
+    }
+
+  if (type[0] == '.')
+    {
+      int n = type.length ();
+
+      octave_value t_rhs = rhs;
+
+      octave_value_list key_idx = idx.front ();
+
+      assert (key_idx.length () == 1);
+
+      std::string key = key_idx(0).string_value ();
+
+      if (n > 1)
+        {
+          std::list<octave_value_list> next_idx (idx);
+
+          next_idx.erase (next_idx.begin ());
+
+          std::string next_type = type.substr (1);
+
+          octave_value tmp;
+          octave_map::iterator pkey = map.seek (key);
+          if (pkey != map.end ())
+            {
+              map.contents (pkey).make_unique ();
+              tmp = map.contents (pkey);
+            }
+
+          if (! error_state)
+            {
+              if (! tmp.is_defined () || tmp.is_zero_by_zero ())
+                {
+                  tmp = octave_value::empty_conv (next_type, rhs);
+                  tmp.make_unique (); // probably a no-op.
+                }
+              else
+                // optimization: ignore the copy still stored inside our map.
+                tmp.make_unique (1);
+
+              if (! error_state)
+                t_rhs = tmp.subsasgn (next_type, next_idx, rhs);
+            }
+        }
+
+      if (! error_state)
+        map.setfield (key, t_rhs.storable_value ());
+      else
+        gripe_failed_assignment ();
+    }
+  else
+    {
+      // Forward this case to octave_struct.
+      octave_value tmp (new octave_struct (octave_map (map)));
+      retval = tmp.subsasgn (type, idx, rhs);
+    }
+
+  return retval;
+}
+
+octave_value
+octave_scalar_struct::do_index_op (const octave_value_list& idx, bool resize_ok)
+{
+  // octave_map handles indexing itself.
+  return octave_map (map).index (idx, resize_ok);
+}
+
+size_t
+octave_scalar_struct::byte_size (void) const
+{
+  // Neglect the size of the fieldnames.
+
+  size_t retval = 0;
+
+  for (octave_map::const_iterator p = map.begin (); p != map.end (); p++)
+    {
+      std::string key = map.key (p);
+
+      octave_value val = octave_value (map.contents (p));
+
+      retval += val.byte_size ();
+    }
+
+  return retval;
+}
+
+void
+octave_scalar_struct::print (std::ostream& os, bool) const
+{
+  print_raw (os);
+}
+
+void
+octave_scalar_struct::print_raw (std::ostream& os, bool) const
+{
+  unwind_protect frame;
+
+  frame.protect_var (Vstruct_levels_to_print);
+
+  if (Vstruct_levels_to_print >= 0)
+    {
+      bool print_keys_only = Vstruct_levels_to_print-- == 0;
+
+      indent (os);
+      os << "{";
+      newline (os);
+
+      increment_indent_level ();
+
+      octave_idx_type n = 1;
+
+      if (n != 1 || print_keys_only)
+        {
+          indent (os);
+          dim_vector dv = dims ();
+          os << dv.str () << " struct array containing the fields:";
+          newline (os);
+          newline (os);
+
+          increment_indent_level ();
+        }
+
+      string_vector key_list = map.fieldnames ();
+
+      for (octave_idx_type i = 0; i < key_list.length (); i++)
+        {
+          std::string key = key_list[i];
+
+          Cell val = map.contents (key);
+
+          octave_value tmp = (n == 1) ? val(0) : octave_value (val, true);
+
+          if (n != 1 || print_keys_only)
+            {
+              indent (os);
+              os << key;
+              if (n == 1)
+                {
+                  dim_vector dv = tmp.dims ();
+                  os << ": " << dv.str () << " " << tmp.type_name ();
+                }
+              newline (os);
+            }
+          else
+            tmp.print_with_name (os, key);
+        }
+
+      if (n != 1 || print_keys_only)
+        decrement_indent_level ();
+
+      decrement_indent_level ();
+
+      indent (os);
+      os << "}";
+      newline (os);
+    }
+  else
+    {
+      indent (os);
+      os << "<structure>";
+      newline (os);
+    }
+}
+
+bool
+octave_scalar_struct::print_name_tag (std::ostream& os, const std::string& name) const
+{
+  bool retval = false;
+
+  indent (os);
+
+  if (Vstruct_levels_to_print < 0)
+    os << name << " = ";
+  else
+    {
+      os << name << " =";
+      newline (os);
+      retval = true;
+    }
+
+  return retval;
+}
+
+bool
+octave_scalar_struct::save_ascii (std::ostream& os)
+{
+  octave_map m = map_value ();
+
+  octave_idx_type nf = m.nfields ();
+
+  const dim_vector dv = dims ();
+
+  os << "# ndims: " << dv.length () << "\n";
+
+  for (int i = 0; i < dv.length (); i++)
+    os << " " << dv (i);
+  os << "\n";
+
+  os << "# length: " << nf << "\n";
+
+  // Iterating over the list of keys will preserve the order of the
+  // fields.
+  string_vector keys = m.fieldnames ();
+
+  for (octave_idx_type i = 0; i < nf; i++)
+    {
+      std::string key = keys(i);
+
+      octave_value val = map.contents (key);
+
+      bool b = save_ascii_data (os, val, key, false, 0);
+      
+      if (! b)
+        return os;
+    }
+
+  return true;
+}
+
+bool
+octave_scalar_struct::load_ascii (std::istream& is)
+{
+  bool success = true;
+  octave_idx_type len = 0;
+
+  if (extract_keyword (is, "length", len, true) && len >= 0)
+    {
+      if (len > 0)
+        {
+          octave_scalar_map m;
+
+          for (octave_idx_type j = 0; j < len; j++)
+            {
+              octave_value t2;
+              bool dummy;
+
+              // recurse to read cell elements
+              std::string nm
+                = read_ascii_data (is, std::string (), dummy, t2, j);
+
+              if (!is)
+                break;
+
+              if (error_state)
+                {
+                  error ("load: internal error loading struct elements");
+                  return false;
+                }
+
+              m.setfield (nm, t2);
+            }
+
+          if (is) 
+            map = m;
+          else
+            {
+              error ("load: failed to load structure");
+              success = false;
+            }
+        }
+      else if (len == 0)
+        map = octave_scalar_map ();
+      else
+        panic_impossible ();
+    }
+  else {
+    error ("load: failed to extract number of elements in structure");
+    success = false;
+  }
+
+  return success;
+}
+
+bool 
+octave_scalar_struct::save_binary (std::ostream& os, bool& save_as_floats)
+{
+  octave_map m = map_value ();
+
+  octave_idx_type nf = m.nfields ();
+
+  int32_t len = nf;
+  os.write (reinterpret_cast<char *> (&len), 4);
+
+  // Iterating over the list of keys will preserve the order of the
+  // fields.
+  string_vector keys = m.fieldnames ();
+
+  for (octave_idx_type i = 0; i < nf; i++)
+    {
+      std::string key = keys(i);
+
+      octave_value val = map.contents (key);
+
+      bool b = save_binary_data (os, val, key, "", 0, save_as_floats);
+      
+      if (! b)
+        return os;
+    }
+
+  return true;
+}
+
+bool 
+octave_scalar_struct::load_binary (std::istream& is, bool swap,
+                                   oct_mach_info::float_format fmt)
+{
+  bool success = true;
+  int32_t len;
+  if (! is.read (reinterpret_cast<char *> (&len), 4))
+    return false;
+  if (swap)
+    swap_bytes<4> (&len);
+
+  dim_vector dv (1, 1);
+
+  if (len > 0)
+    {
+      octave_scalar_map m;
+
+      for (octave_idx_type j = 0; j < len; j++)
+        {
+          octave_value t2;
+          bool dummy;
+          std::string doc;
+
+          // recurse to read cell elements
+          std::string nm = read_binary_data (is, swap, fmt, std::string (), 
+                                             dummy, t2, doc);
+
+          if (!is)
+            break;
+
+          if (error_state)
+            {
+              error ("load: internal error loading struct elements");
+              return false;
+            }
+
+          m.setfield (nm, t2);
+        }
+
+      if (is) 
+        map = m;
+      else
+        {
+          error ("load: failed to load structure");
+          success = false;
+        }
+    }
+  else if (len == 0)
+    map = octave_scalar_map ();
+  else
+    success = false;
+
+  return success;
+}
+
+#if defined (HAVE_HDF5)
+
+bool
+octave_scalar_struct::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats)
+{
+  hid_t data_hid = -1;
+
+#if HAVE_HDF5_18
+  data_hid = H5Gcreate (loc_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
+#else
+  data_hid = H5Gcreate (loc_id, name, 0);
+#endif
+  if (data_hid < 0) return false;
+
+  // recursively add each element of the structure to this group
+  octave_scalar_map m = scalar_map_value ();
+
+  octave_idx_type nf = m.nfields ();
+
+  // Iterating over the list of keys will preserve the order of the
+  // fields.
+  string_vector keys = m.fieldnames ();
+
+  for (octave_idx_type i = 0; i < nf; i++)
+    {
+      std::string key = keys(i);
+
+      octave_value val = map.contents (key);
+
+      bool retval2 = add_hdf5_data (data_hid, val, key, "", false, 
+                                    save_as_floats);
+
+      if (! retval2)
+        break;
+    }
+
+  H5Gclose (data_hid);
+
+  return true;
+}
+
+bool 
+octave_scalar_struct::load_hdf5 (hid_t loc_id, const char *name)
+{
+  bool retval = false;
+
+  hdf5_callback_data dsub;
+
+  herr_t retval2 = 0;
+  octave_scalar_map m;
+  int current_item = 0;
+  hsize_t num_obj = 0;
+#if HAVE_HDF5_18
+  hid_t group_id = H5Gopen (loc_id, name, H5P_DEFAULT);
+#else
+  hid_t group_id = H5Gopen (loc_id, name);
+#endif
+  H5Gget_num_objs (group_id, &num_obj);
+  H5Gclose (group_id);
+
+  // FIXME -- fields appear to be sorted alphabetically on loading.
+  // Why is that happening?
+
+  while (current_item < static_cast<int> (num_obj)
+         && (retval2 = H5Giterate (loc_id, name, &current_item,
+                                   hdf5_read_next_data, &dsub)) > 0)
+    {
+      octave_value t2 = dsub.tc;
+
+      if (error_state)
+        {
+          error ("load: internal error loading struct elements");
+          return false;
+        }
+
+      m.setfield (dsub.name, t2);
+
+    }
+
+  if (retval2 >= 0)
+    {
+      map = m;
+      retval = true;
+    }
+  
+  return retval;
+}
+
+#endif
+
+mxArray *
+octave_scalar_struct::as_mxArray (void) const
+{
+  int nf = nfields ();
+  string_vector kv = map_keys ();
+
+  OCTAVE_LOCAL_BUFFER (const char *, f, nf);
+
+  for (int i = 0; i < nf; i++)
+    f[i] = kv[i].c_str ();
+
+  mxArray *retval = new mxArray (dims (), nf, f);
+
+  mxArray **elts = static_cast<mxArray **> (retval->get_data ());
+
+  mwSize nel = numel ();
+
+  mwSize ntot = nf * nel;
+
+  for (int i = 0; i < nf; i++)
+    {
+      Cell c = map.contents (kv[i]);
+
+      const octave_value *p = c.data ();
+
+      mwIndex k = 0;
+      for (mwIndex j = i; j < ntot; j += nf)
+        elts[j] = new mxArray (p[k++]);
+    }
+
+  return retval;
+}
+
+
+octave_value
+octave_scalar_struct::to_array (void)
+{
+  return new octave_struct (octave_map (map));
+}
+
+/*
+%!shared x
+%! x(1).a=1; x(2).a=2; x(1).b=3; x(2).b=3;
+%!assert(struct('a',1,'b',3),x(1))
+%!assert(isempty(x([])))
+%!assert(isempty(struct('a',{},'b',{})))
+%!assert(struct('a',{1,2},'b',{3,3}),x)
+%!assert(struct('a',{1,2},'b',3),x)
+%!assert(struct('a',{1,2},'b',{3}),x)
+%!assert(struct('b',3,'a',{1,2}),x)
+%!assert(struct('b',{3},'a',{1,2}),x) 
+%!test x=struct([]);
+%!assert(size(x),[0,0]);
+%!assert(isstruct(x));
+%!assert(isempty(fieldnames(x)));
+%!fail("struct('a',{1,2},'b',{1,2,3})","dimensions of parameter 2 do not match those of parameter 4")
+%!fail("struct(1,2,3,4)","struct expects alternating \"field\", VALUE pairs");
+%!fail("struct('1',2,'3')","struct expects alternating \"field\", VALUE pairs");
+*/
+
 DEFUN (struct, args, ,
   "-*- texinfo -*-\n\
 @deftypefn {Built-in Function} {} struct (\"field\", @var{value}, \"field\", @var{value}, @dots{})\n\
@@ -722,7 +1726,7 @@
 
   if (nargin == 1 && args(0).is_object ())
     {
-      Octave_map m = args(0).map_value ();
+      octave_map m = args(0).map_value ();
       retval = octave_value (new octave_struct (m));
 
       return retval;
@@ -736,12 +1740,12 @@
       if (nargin == 2)
         {
           if (args(1).is_cellstr ())
-            retval = Octave_map (args(0).dims (), args(1).cell_value ());
+            retval = octave_map (args(0).dims (), args(1).cellstr_value ());
           else
             error ("struct: expecting cell array of field names as second argument");
         }
       else
-        retval = Octave_map (args(0).dims ());
+        retval = octave_map (args(0).dims ());
 
       return retval;
     }
@@ -788,7 +1792,7 @@
 
   // Create the return value.
 
-  Octave_map map (dims);
+  octave_map map (dims);
 
   for (int i = 0; i < nargin; i+= 2) 
     {
@@ -819,12 +1823,12 @@
             return retval;
 
           if (scalar (c.dims ())) 
-            map.assign (key, Cell (dims, c(0)));
+            map.setfield (key, Cell (dims, c(0)));
           else 
-            map.assign (key, c);
+            map.setfield (key, c);
         }
       else 
-        map.assign (key, Cell (dims, args(i+1)));
+        map.setfield (key, Cell (dims, args(i+1)));
 
       if (error_state)
         return retval;
@@ -868,14 +1872,14 @@
 
       if (arg.is_map () || arg.is_object ())
         {
-          Octave_map m = arg.map_value ();
-
-          string_vector keys = m.keys ();
+          octave_map m = arg.map_value ();
+
+          string_vector keys = m.fieldnames ();
 
           if (keys.length () == 0)
             retval = Cell (0, 1);
           else
-            retval = Cell (m.keys ());
+            retval = Cell (keys);
         }
       else
         gripe_wrong_type_arg ("fieldnames", args(0));
@@ -911,7 +1915,7 @@
 
       if (args(0).is_map ())
         {
-          Octave_map m = args(0).map_value ();
+          octave_map m = args(0).map_value ();
 
           // FIXME -- should this work for all types that can do
           // structure reference operations?
@@ -920,12 +1924,12 @@
             {
               std::string key = args(1).string_value ();
 
-              retval = m.contains (key) != 0;
+              retval = m.isfield (key);
             }
           else if (args(1).is_cell ())
             {
               Cell c = args(1).cell_value ();
-              boolMatrix bm (c.dims ());
+              boolNDArray bm (c.dims ());
               octave_idx_type n = bm.numel ();
 
               for (octave_idx_type i = 0; i < n; i++)
@@ -934,7 +1938,7 @@
                     {
                       std::string key = c(i).string_value ();
 
-                      bm(i) = m.contains (key) != 0;
+                      bm(i) = m.isfield (key);
                     }
                   else
                     bm(i) = false;
@@ -1133,7 +2137,7 @@
                       // All initializing is done, we can start moving
                       // values.
 
-                      Octave_map map;
+                      octave_map map;
 
                       // If field is a cell array then we use all
                       // elements in array, on the other hand when
@@ -1207,7 +2211,7 @@
 
                           map.reshape (value_dv);
 
-                          map.assign (field_str, c_value);
+                          map.setfield (field_str, c_value);
                         }
 
                       if (! error_state)
@@ -1260,7 +2264,7 @@
 
   if (nargin == 2)
     {
-      Octave_map m = args(0).map_value ();
+      octave_map m = args(0).map_value ();
 
       octave_value_list fval = Fcellstr (args(1), 1);
 
@@ -1272,8 +2276,8 @@
             {
               std::string key = fcell(i).string_value ();
 
-              if (m.contains (key))
-                m.del (key);
+              if (m.isfield (key))
+                m.rmfield (key);
               else
                 {
                   error ("rmfield: structure does not contain field %s",
@@ -1302,367 +2306,3 @@
 %!  assert (size (y), [1, 6]);
 */
 
-bool
-octave_struct::save_ascii (std::ostream& os)
-{
-  Octave_map m = map_value ();
-
-  octave_idx_type nf = m.nfields ();
-
-  const dim_vector dv = dims ();
-
-  os << "# ndims: " << dv.length () << "\n";
-
-  for (int i = 0; i < dv.length (); i++)
-    os << " " << dv (i);
-  os << "\n";
-
-  os << "# length: " << nf << "\n";
-
-  // Iterating over the list of keys will preserve the order of the
-  // fields.
-  string_vector keys = m.keys ();
-
-  for (octave_idx_type i = 0; i < nf; i++)
-    {
-      std::string key = keys(i);
-
-      octave_value val = map.contents (key);
-
-      bool b = save_ascii_data (os, val, key, false, 0);
-      
-      if (! b)
-        return os;
-    }
-
-  return true;
-}
-
-bool 
-octave_struct::load_ascii (std::istream& is)
-{
-  octave_idx_type len = 0;
-  dim_vector dv (1, 1);
-  bool success = true;
-
-  // KLUGE: earlier Octave versions did not save extra dimensions with struct,
-  // and as a result did not preserve dimensions for empty structs.
-  // The default dimensions were 1x1, which we want to preserve.
-  string_vector keywords(2);
-
-  keywords[0] = "ndims";
-  keywords[1] = "length";
-
-  std::string kw;
-
-  if (extract_keyword (is, keywords, kw, len, true))
-    {
-      if (kw == keywords[0])
-        {
-          int mdims = std::max (static_cast<int> (len), 2);
-          dv.resize (mdims);
-          for (int i = 0; i < mdims; i++)
-            is >> dv(i);
-
-          success = extract_keyword (is, keywords[1], len);
-        }
-    }
-  else
-    success = false;
-
-  if (success && len >= 0)
-    {
-      if (len > 0)
-        {
-          Octave_map m (dv);
-
-          for (octave_idx_type j = 0; j < len; j++)
-            {
-              octave_value t2;
-              bool dummy;
-
-              // recurse to read cell elements
-              std::string nm
-                = read_ascii_data (is, std::string (), dummy, t2, j);
-
-              if (!is)
-                break;
-
-              Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
-
-              if (error_state)
-                {
-                  error ("load: internal error loading struct elements");
-                  return false;
-                }
-
-              m.assign (nm, tcell);
-            }
-
-          if (is) 
-            map = m;
-          else
-            {
-              error ("load: failed to load structure");
-              success = false;
-            }
-        }
-      else if (len == 0 )
-        map = Octave_map (dv);
-      else
-        panic_impossible ();
-    }
-  else {
-    error ("load: failed to extract number of elements in structure");
-    success = false;
-  }
-
-  return success;
-}
-
-bool 
-octave_struct::save_binary (std::ostream& os, bool& save_as_floats)
-{
-  Octave_map m = map_value ();
-
-  octave_idx_type nf = m.nfields ();
-
-  dim_vector d = dims ();
-  if (d.length () < 1)
-    return false;
-
-  // Use negative value for ndims
-  int32_t di = - d.length();
-  os.write (reinterpret_cast<char *> (&di), 4);
-  for (int i = 0; i < d.length (); i++)
-    {
-      di = d(i);
-      os.write (reinterpret_cast<char *> (&di), 4);
-    }
-  
-  int32_t len = nf;
-  os.write (reinterpret_cast<char *> (&len), 4);
-
-  // Iterating over the list of keys will preserve the order of the
-  // fields.
-  string_vector keys = m.keys ();
-
-  for (octave_idx_type i = 0; i < nf; i++)
-    {
-      std::string key = keys(i);
-
-      octave_value val = map.contents (key);
-
-      bool b = save_binary_data (os, val, key, "", 0, save_as_floats);
-      
-      if (! b)
-        return os;
-    }
-
-  return true;
-}
-
-bool 
-octave_struct::load_binary (std::istream& is, bool swap,
-                            oct_mach_info::float_format fmt)
-{
-  bool success = true;
-  int32_t len;
-  if (! is.read (reinterpret_cast<char *> (&len), 4))
-    return false;
-  if (swap)
-    swap_bytes<4> (&len);
-
-  dim_vector dv (1, 1);
-
-  if (len < 0)
-    {
-      // We have explicit dimensions.
-      int mdims = -len;
-
-      int32_t di;
-      dv.resize (mdims);
-
-      for (int i = 0; i < mdims; i++)
-        {
-          if (! is.read (reinterpret_cast<char *> (&di), 4))
-            return false;
-          if (swap)
-            swap_bytes<4> (&di);
-          dv(i) = di;
-        }
-
-      if (! is.read (reinterpret_cast<char *> (&len), 4))
-        return false;
-      if (swap)
-        swap_bytes<4> (&len);
-    }
-
-  if (len > 0)
-    {
-      Octave_map m (dv);
-
-      for (octave_idx_type j = 0; j < len; j++)
-        {
-          octave_value t2;
-          bool dummy;
-          std::string doc;
-
-          // recurse to read cell elements
-          std::string nm = read_binary_data (is, swap, fmt, std::string (), 
-                                             dummy, t2, doc);
-
-          if (!is)
-            break;
-
-          Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
- 
-          if (error_state)
-            {
-              error ("load: internal error loading struct elements");
-              return false;
-            }
-
-          m.assign (nm, tcell);
-        }
-
-      if (is) 
-        map = m;
-      else
-        {
-          error ("load: failed to load structure");
-          success = false;
-        }
-    }
-  else if (len == 0)
-    map = Octave_map (dv);
-  else
-    success = false;
-
-  return success;
-}
-
-#if defined (HAVE_HDF5)
-
-bool
-octave_struct::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats)
-{
-  hid_t data_hid = -1;
-
-#if HAVE_HDF5_18
-  data_hid = H5Gcreate (loc_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
-#else
-  data_hid = H5Gcreate (loc_id, name, 0);
-#endif
-  if (data_hid < 0) return false;
-
-  // recursively add each element of the structure to this group
-  Octave_map m = map_value ();
-
-  octave_idx_type nf = m.nfields ();
-
-  // Iterating over the list of keys will preserve the order of the
-  // fields.
-  string_vector keys = m.keys ();
-
-  for (octave_idx_type i = 0; i < nf; i++)
-    {
-      std::string key = keys(i);
-
-      octave_value val = map.contents (key);
-
-      bool retval2 = add_hdf5_data (data_hid, val, key, "", false, 
-                                    save_as_floats);
-
-      if (! retval2)
-        break;
-    }
-
-  H5Gclose (data_hid);
-
-  return true;
-}
-
-bool 
-octave_struct::load_hdf5 (hid_t loc_id, const char *name)
-{
-  bool retval = false;
-
-  hdf5_callback_data dsub;
-
-  herr_t retval2 = 0;
-  Octave_map m (dim_vector (1, 1));
-  int current_item = 0;
-  hsize_t num_obj = 0;
-#if HAVE_HDF5_18
-  hid_t group_id = H5Gopen (loc_id, name, H5P_DEFAULT);
-#else
-  hid_t group_id = H5Gopen (loc_id, name);
-#endif
-  H5Gget_num_objs (group_id, &num_obj);
-  H5Gclose (group_id);
-
-  // FIXME -- fields appear to be sorted alphabetically on loading.
-  // Why is that happening?
-
-  while (current_item < static_cast<int> (num_obj)
-         && (retval2 = H5Giterate (loc_id, name, &current_item,
-                                   hdf5_read_next_data, &dsub)) > 0)
-    {
-      octave_value t2 = dsub.tc;
-
-      Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
- 
-      if (error_state)
-        {
-          error ("load: internal error loading struct elements");
-          return false;
-        }
-
-      m.assign (dsub.name, tcell);
-
-    }
-
-  if (retval2 >= 0)
-    {
-      map = m;
-      retval = true;
-    }
-  
-  return retval;
-}
-
-#endif
-
-mxArray *
-octave_struct::as_mxArray (void) const
-{
-  int nf = nfields ();
-  string_vector kv = map_keys ();
-
-  OCTAVE_LOCAL_BUFFER (const char *, f, nf);
-
-  for (int i = 0; i < nf; i++)
-    f[i] = kv[i].c_str ();
-
-  mxArray *retval = new mxArray (dims (), nf, f);
-
-  mxArray **elts = static_cast<mxArray **> (retval->get_data ());
-
-  mwSize nel = numel ();
-
-  mwSize ntot = nf * nel;
-
-  for (int i = 0; i < nf; i++)
-    {
-      Cell c = map.contents (kv[i]);
-
-      const octave_value *p = c.data ();
-
-      mwIndex k = 0;
-      for (mwIndex j = i; j < ntot; j += nf)
-        elts[j] = new mxArray (p[k++]);
-    }
-
-  return retval;
-}
--- a/src/ov-struct.h
+++ b/src/ov-struct.h
@@ -52,6 +52,9 @@
   octave_struct (void)
     : octave_base_value () { }
 
+  octave_struct (const octave_map& m)
+    : octave_base_value (), map (m) { }
+
   octave_struct (const Octave_map& m)
     : octave_base_value (), map (m) { }
 
@@ -63,6 +66,8 @@
   octave_base_value *clone (void) const { return new octave_struct (*this); }
   octave_base_value *empty_clone (void) const { return new octave_struct (); }
 
+  octave_base_value *try_narrowing_conversion (void);
+
   Cell dotref (const octave_value_list& idx, bool auto_add = false);
 
   octave_value subsref (const std::string& type,
@@ -102,8 +107,7 @@
   // of elements is numel () * nfields ().
   octave_idx_type numel (void) const
   {
-    dim_vector dv = dims ();
-    return dv.numel ();
+    return map.numel ();
   }
 
   octave_idx_type nfields (void) const { return map.nfields (); }
@@ -112,7 +116,7 @@
     { return map.reshape (new_dims); }
 
   octave_value resize (const dim_vector& dv, bool = false) const
-    { Octave_map tmap = map; tmap.resize (dv); return tmap; }
+    { octave_map tmap = map; tmap.resize (dv); return tmap; }
 
   bool is_defined (void) const { return true; }
 
@@ -122,9 +126,9 @@
 
   builtin_type_t builtin_type (void) const { return btyp_struct; }
 
-  Octave_map map_value (void) const { return map; }
+  octave_map map_value (void) const { return map; }
 
-  string_vector map_keys (void) const { return map.keys (); }
+  string_vector map_keys (void) const { return map.fieldnames (); }
 
   void print (std::ostream& os, bool pr_as_read_syntax = false) const;
 
@@ -152,7 +156,7 @@
 protected:
 
   // The associative array used to manage the structure data.
-  Octave_map map;
+  octave_map map;
 
 private:
 
@@ -161,4 +165,121 @@
   DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
 };
 
+class
+octave_scalar_struct : public octave_base_value
+{
+public:
+
+  octave_scalar_struct (void)
+    : octave_base_value () { }
+
+  octave_scalar_struct (const octave_scalar_map& m)
+    : octave_base_value (), map (m) { }
+
+  octave_scalar_struct (const octave_scalar_struct& s)
+    : octave_base_value (), map (s.map) { }
+
+  ~octave_scalar_struct (void) { }
+
+  octave_base_value *clone (void) const { return new octave_scalar_struct (*this); }
+  octave_base_value *empty_clone (void) const { return new octave_scalar_struct (); }
+
+  octave_value dotref (const octave_value_list& idx, bool auto_add = false);
+
+  octave_value subsref (const std::string& type,
+                        const std::list<octave_value_list>& idx);
+
+  octave_value_list subsref (const std::string& type,
+                             const std::list<octave_value_list>& idx, int);
+
+
+  octave_value subsref (const std::string& type,
+                        const std::list<octave_value_list>& idx,
+                        bool auto_add);
+
+  static octave_value numeric_conv (const octave_value& val,
+                                    const std::string& type);
+
+  octave_value subsasgn (const std::string& type,
+                         const std::list<octave_value_list>& idx,
+                         const octave_value& rhs);
+
+  octave_value squeeze (void) const { return map; }
+
+  octave_value permute (const Array<int>& vec, bool inv = false) const
+    { return octave_map (map).permute (vec, inv); }
+
+  octave_value do_index_op (const octave_value_list& idx,
+                            bool resize_ok = false);
+
+  dim_vector dims (void) const { static dim_vector dv (1, 1); return dv; }
+
+  size_t byte_size (void) const;
+
+  // This is the number of elements in each field.  The total number
+  // of elements is numel () * nfields ().
+  octave_idx_type numel (void) const
+  {
+    return 1;
+  }
+
+  octave_idx_type nfields (void) const { return map.nfields (); }
+
+  octave_value reshape (const dim_vector& new_dims) const
+    { return octave_map (map).reshape (new_dims); }
+
+  octave_value resize (const dim_vector& dv, bool = false) const
+    { octave_map tmap = map; tmap.resize (dv); return tmap; }
+
+  bool is_defined (void) const { return true; }
+
+  bool is_constant (void) const { return true; }
+
+  bool is_map (void) const { return true; }
+
+  builtin_type_t builtin_type (void) const { return btyp_struct; }
+
+  octave_map map_value (void) const { return map; }
+
+  octave_scalar_map scalar_map_value (void) const { return map; }
+
+  string_vector map_keys (void) const { return map.fieldnames (); }
+
+  void print (std::ostream& os, bool pr_as_read_syntax = false) const;
+
+  void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const;
+
+  bool print_name_tag (std::ostream& os, const std::string& name) const;
+
+  bool save_ascii (std::ostream& os);
+
+  bool load_ascii (std::istream& is);
+
+  bool save_binary (std::ostream& os, bool& save_as_floats);
+
+  bool load_binary (std::istream& is, bool swap, 
+                    oct_mach_info::float_format fmt);
+
+#if defined (HAVE_HDF5)
+  bool save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats);
+
+  bool load_hdf5 (hid_t loc_id, const char *name);
 #endif
+
+  mxArray *as_mxArray (void) const;
+
+protected:
+
+  // The associative array used to manage the structure data.
+  octave_scalar_map map;
+
+private:
+
+  octave_value to_array (void);
+
+  DECLARE_OCTAVE_ALLOCATOR
+
+  DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
+};
+
+#endif
--- a/src/ov.cc
+++ b/src/ov.cc
@@ -1116,9 +1116,21 @@
   maybe_mutate ();
 }
 
+octave_value::octave_value (const octave_map& m)
+  : rep (new octave_struct (m))
+{
+  maybe_mutate ();
+}
+
+octave_value::octave_value (const octave_scalar_map& m)
+  : rep (new octave_scalar_struct (m))
+{
+}
+
 octave_value::octave_value (const Octave_map& m)
   : rep (new octave_struct (m))
 {
+  maybe_mutate ();
 }
 
 octave_value::octave_value (const Octave_map& m, const std::string& id)
@@ -1431,12 +1443,24 @@
 #endif
 }
 
-Octave_map
+octave_map
 octave_value::map_value (void) const
 {
   return rep->map_value ();
 }
 
+octave_scalar_map
+octave_value::scalar_map_value (void) const
+{
+  return rep->scalar_map_value ();
+}
+
+Octave_map
+octave_value::old_map_value (void) const
+{
+  return rep->old_map_value ();
+}
+
 octave_function *
 octave_value::function_value (bool silent) const
 {
--- a/src/ov.h
+++ b/src/ov.h
@@ -45,6 +45,8 @@
 #include "oct-sort.h"
 
 class Cell;
+class octave_map;
+class octave_scalar_map;
 class Octave_map;
 class octave_stream;
 class octave_function;
@@ -275,6 +277,8 @@
   octave_value (const idx_vector& idx, bool lazy = true);
   octave_value (double base, double limit, double inc);
   octave_value (const Range& r);
+  octave_value (const octave_map& m);
+  octave_value (const octave_scalar_map& m);
   octave_value (const Octave_map& m);
   octave_value (const Octave_map& m, const std::string& id);
   octave_value (const octave_value_list& m, bool = false);
@@ -840,7 +844,11 @@
   Range range_value (void) const
     { return rep->range_value (); }
 
-  Octave_map map_value (void) const;
+  octave_map map_value (void) const;
+
+  octave_scalar_map scalar_map_value (void) const;
+
+  Octave_map old_map_value (void) const;
 
   string_vector map_keys (void) const
     { return rep->map_keys (); }