changeset 10769:569823598028

merge rewrite of structs (highegg)
author Jaroslav Hajek <highegg@gmail.com>
date Wed, 07 Jul 2010 11:03:30 +0200
parents 38bdcbb58df7 (current diff) 8a868004a437 (diff)
children 84c35a483d1f
files src/ChangeLog
diffstat 44 files changed, 3377 insertions(+), 860 deletions(-) [+]
line wrap: on
line diff
--- a/liboctave/ChangeLog
+++ b/liboctave/ChangeLog
@@ -1,3 +1,8 @@
+2010-06-28  Jaroslav Hajek  <highegg@gmail.com>
+
+	* dim-vector.h (dim_vector::scalar_1x1): New method.
+	* lo-traits.h (equal_types): Fix.
+
 2010-06-21  Jaroslav Hajek  <highegg@gmail.com>
 
 	* Array.cc (Array<T>::cat): Implement the loose horzcat/vertcat rules
--- a/liboctave/lo-traits.h
+++ b/liboctave/lo-traits.h
@@ -62,7 +62,7 @@
 {
 public:
 
-  static const bool value = false;
+  static const bool value = true;
 };
 
 // Determine whether a type is an instance of a template.
--- a/src/Cell.h
+++ b/src/Cell.h
@@ -136,4 +136,8 @@
   Cell map (ctype_mapper) const;
 };
 
+template<>
+inline Cell octave_value_extract<Cell> (const octave_value& v)
+  { return v.cell_value (); }
+
 #endif
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,10 @@
+2010-07-07  Jaroslav Hajek  <highegg@gmail.com>
+
+	* ov-class.h (octave_class::map): Turn to octave_map.
+	* ov-class.cc (octave_class): Update methods.
+	* ov-base.h, ov-base.cc (octave_base_value::old_map_value) : Remove.
+	* ov.h, ov.cc (octave_value::old_map_value) : Remove.
+
 2010-07-06  David Bateman  <dbateman@free.fr>
 
 	* pr-output.cc (static bool print_eng): Flag engineering format,
@@ -28,6 +35,88 @@
 	* DLD_FUNCTIONS/__magick_read__.cc: restore locale after
 	GraphicsMagick initialisation.
 
+2010-07-02  Jaroslav Hajek  <highegg@gmail.com>
+
+	* toplev.cc (octave_call_stack::do_backtrace): Use static
+	octave_fields struct.
+	(octave_call_stack::empty_backtrace): New static method.
+	* toplev.h: Declare it.
+	* error.cc (Vlast_error_stack, initialize_last_error_stack,
+	Frethrow): Use octave_map or octave_scalar_map where applicable.
+
+2010-07-02  Jaroslav Hajek  <highegg@gmail.com>
+
+	* pt-mat.cc (tm_row_const::tm_row_const_rep::all_1x1,
+	tm_cont::all_1x1): New member fields.
+	(tm_row_const::tm_row_const_rep::init, tm_const::init):
+	Handle them here.
+	(tm_row_const::all_1x1_p, tm_const::all_1x1_p): New methods.
+	(single_type_concat<MAP> (octave_map&, ...)): New template
+	overload.
+	(do_single_type_concat<octave_map>): New template specialization.
+	(tree_matrix::rvalue1): Specialize for cell and struct classes.
+	* oct-map.cc (octave_map::do_cat (..., const octave_map *, ...)): 
+	Assign result dimensions.
+
+2010-07-02  Jaroslav Hajek  <highegg@gmail.com>
+
+	* oct-map.cc (octave_map::cat (..., const octave_scalar_map *)):
+	Handle special dims (-1, -2). 
+	* data.cc (do_single_type_concat_map): Don't handle them here.
+
+2010-07-01  Jaroslav Hajek  <highegg@gmail.com>
+
+	* syscalls.cc (mk_stat_map, Funame): Use octave_scalar_map.
+
+2010-07-01  Jaroslav Hajek  <highegg@gmail.com>
+
+	* oct-map.h (octave_scalar_map::assign (const std::string&, const
+	octave_value&), octave_map::assign (const std::string&, const Cell&)):
+	Backward-compatible aliases for setfield.
+
+2010-07-01  Jaroslav Hajek  <highegg@gmail.com>
+
+	* oct-map.cc (octave_fields::equal_up_to_order (const octave_fields&,
+	octave_idx_type *)): New overload.
+	(octave_fields::equal_up_to_order (const octave_fields&,
+	Array<octave_idx_type>&)): Use it here.
+	(octave_map::fast_elem_insert,
+	octave_map::fast_elem_extract): New methods.
+	* oct-map.h: Update decls.
+	* ov-struct.cc (octave_struct::fast_elem_extract,
+	octave_struct::fast_elem_insert,
+	octave_scalar_struct::fast_elem_insert_self): New methods.
+	* ov-struct.h: Update decls.
+
+2010-06-28  Jaroslav Hajek  <highegg@gmail.com>
+
+	* data.cc (single_type_concat): Optimize all scalars case where
+	applicable.
+	(single_type_concat_map, do_single_type_concat_map): New funcs.
+	* pt-mat.cc (get_concat_class): Handle cell and struct concats.
+
+
+2010-06-25  Jaroslav Hajek  <highegg@gmail.com>
+
+	* DLD-FUNCTIONS/cellfun.cc (Fnum2cell, do_num2cell): Optimize cells
+	and structs.
+
+2010-06-25  Jaroslav Hajek  <highegg@gmail.com>
+
+	* ov-struct.h (octave_scalar_struct::resize, octave_struct::resize):
+	Don't ignore fill argument.
+
+2010-06-25  Jaroslav Hajek  <highegg@gmail.com>
+
+	* oct-map.h (octave_map::octave_map (const dim_vector&, const
+	octave_fields&)): New internal ctor.
+
+	* oct-map.cc (octave_map::assign): Handle no fields case.
+
+2010-06-25  Jaroslav Hajek  <highegg@gmail.com>
+
+	* ov-struct.cc (Fcell2struct): Rewrite.
+
 2010-06-30  Jaroslav Hajek  <highegg@gmail.com>
 
 	* ov-range.cc (octave_range::save_ascii): Save length rather than
@@ -49,6 +138,23 @@
 
         * octave.cc: Add [FILE] to octave usage string (bug #30258).
 
+2010-06-24  Jaroslav Hajek  <highegg@gmail.com>
+
+	* oct-map.h (octave_map, octave_scalar_map): New classes.
+	* oct-map.cc (octave_map, octave_scalar_map): Implement them.
+	(Octave_map::Octave_map (const octave_map&)): New ctor.
+	* ov-struct.h (octave_struct): Use octave_map for storage.
+	(octave_scalar_struct): New class.
+	* ov-struct.cc: Update implementations.
+	* ov-base.h (octave_base_value::old_map_value): New method.
+	(octave_base_value::map_value): Return octave_map.
+	(octave_base_value::scalar_map_value): New method.
+	* ov-base.cc (octave_base_value::old_map_value,
+	octave_base_value::map_value, octave_base_value::scalar_map_value): 
+	Add default implementations.
+	* ov-class.h (octave_class::old_map_value): New override.
+	* ov-class.cc: Use old_map_value for efficiency.
+
 2010-06-23  David Bateman  <dbateman@free.fr>
 
 	* graphics.cc (void root_figure::reset_default_properties (void),
--- a/src/DLD-FUNCTIONS/cellfun.cc
+++ b/src/DLD-FUNCTIONS/cellfun.cc
@@ -906,6 +906,16 @@
 }
 
 template<class NDA>
+static inline typename NDA::element_type
+do_num2cell_elem (const NDA& array, octave_idx_type i)
+{ return array(i); }
+
+static inline Cell
+do_num2cell_elem (const Cell& array, octave_idx_type i)
+{ return Cell (array(i)); }
+
+
+template<class NDA>
 static Cell
 do_num2cell (const NDA& array, const Array<int>& dimv)
 {
@@ -914,7 +924,7 @@
       Cell retval (array.dims ());
       octave_idx_type nel = array.numel ();
       for (octave_idx_type i = 0; i < nel; i++)
-        retval.xelem (i) = array(i);
+        retval.xelem (i) = do_num2cell_elem (array, i);
 
       return retval;
     }
@@ -1030,34 +1040,10 @@
                 retval = do_num2cell (array.array_value (), dimv);
             }
         }
-      else if (array.is_cell () || array.is_map ())
-        {
-          dim_vector celldv, arraydv;
-          Array<int> perm;
-          do_num2cell_helper (array.dims (), dimv, celldv, arraydv, perm);
-
-          if (! error_state)
-            {
-              // FIXME: this operation may be rather inefficient.
-              octave_value parray = array.permute (perm);
-
-              octave_idx_type nela = arraydv.numel (), nelc = celldv.numel ();
-              parray = parray.reshape (dim_vector (nela, nelc));
-
-              Cell retcell (celldv);
-              octave_value_list idx (2);
-              idx(0) = octave_value::magic_colon_t;
-
-              for (octave_idx_type i = 0; i < nelc; i++)
-                {
-                  idx(1) = i + 1;
-                  octave_value tmp = parray.do_index_op (idx);
-                  retcell(i) = tmp.reshape (arraydv);
-                }
-
-              retval = retcell;
-            }
-        }
+      else if (array.is_map ())
+        retval = do_num2cell (array.map_value (), dimv);
+      else if (array.is_cell ())
+        retval = do_num2cell (array.cell_value (), dimv);
       else
         gripe_wrong_type_arg ("num2cell", array);
     }
--- 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/data.cc
+++ b/src/data.cc
@@ -1369,6 +1369,17 @@
 
  */
 
+static bool
+all_scalar_1x1 (const octave_value_list& args)
+{
+  int n_args = args.length ();
+  for (int i = 0; i < n_args; i++)
+    if (args(i).numel () != 1)
+      return false;
+
+  return true;
+}
+
 template <class TYPE, class T>
 static void 
 single_type_concat (Array<T>& result,
@@ -1376,17 +1387,41 @@
                     int dim)
 {
   int n_args = args.length ();
-  OCTAVE_LOCAL_BUFFER (Array<T>, array_list, n_args);
-
-  for (int j = 0; j < n_args && ! error_state; j++)
+  if (! (equal_types<T, char>::value
+         || equal_types<T, octave_value>::value)
+      && all_scalar_1x1 (args))
     {
-      octave_quit ();
-
-      array_list[j] = octave_value_extract<TYPE> (args(j));
+      // Optimize all scalars case.
+      dim_vector dv (1, 1);
+      if (dim == -1 || dim == -2)
+        dim = -dim - 1;
+      else if (dim >= 2)
+        dv.resize (dim+1, 1);
+      dv(dim) = n_args;
+
+      result.clear (dv);
+
+      for (int j = 0; j < n_args && ! error_state; j++)
+        {
+          octave_quit ();
+
+          result(j) = octave_value_extract<T> (args(j));
+        }
     }
-
-  if (! error_state)
-    result = Array<T>::cat (dim, n_args, array_list);
+  else
+    {
+      OCTAVE_LOCAL_BUFFER (Array<T>, array_list, n_args);
+
+      for (int j = 0; j < n_args && ! error_state; j++)
+        {
+          octave_quit ();
+
+          array_list[j] = octave_value_extract<TYPE> (args(j));
+        }
+
+      if (! error_state)
+        result = Array<T>::cat (dim, n_args, array_list);
+    }
 }
 
 template <class TYPE, class T>
@@ -1421,6 +1456,39 @@
   return result;
 }
 
+template<class MAP>
+static void 
+single_type_concat_map (octave_map& result,
+                        const octave_value_list& args,
+                        int dim)
+{
+  int n_args = args.length ();
+  OCTAVE_LOCAL_BUFFER (MAP, map_list, n_args);
+
+  for (int j = 0; j < n_args && ! error_state; j++)
+    {
+      octave_quit ();
+
+      map_list[j] = octave_value_extract<MAP> (args(j));
+    }
+
+  if (! error_state)
+    result = octave_map::cat (dim, n_args, map_list);
+}
+
+static octave_map
+do_single_type_concat_map (const octave_value_list& args,
+                           int dim)
+{
+  octave_map result;
+  if (all_scalar_1x1 (args)) // optimize all scalars case.
+    single_type_concat_map<octave_scalar_map> (result, args, dim);
+  else
+    single_type_concat_map<octave_map> (result, args, dim);
+
+  return result;
+}
+
 static octave_value
 do_cat (const octave_value_list& args, int dim, std::string fname)
 {
@@ -1514,6 +1582,10 @@
         retval = do_single_type_concat<uint32NDArray> (args, dim);
       else if (result_type == "uint64")
         retval = do_single_type_concat<uint64NDArray> (args, dim);
+      else if (result_type == "cell")
+        retval = do_single_type_concat<Cell> (args, dim);
+      else if (result_type == "struct")
+        retval = do_single_type_concat_map (args, dim);
       else
         {
           dim_vector  dv = args(0).dims ();
--- a/src/error.cc
+++ b/src/error.cc
@@ -87,7 +87,7 @@
 static std::string Vlast_error_id;
 
 // The last file in which an error occured
-static Octave_map Vlast_error_stack;
+static octave_map Vlast_error_stack;
 
 // Current error state.
 //
@@ -141,24 +141,10 @@
   warning_options.assign ("state", state);
 }
 
-static Octave_map
+static octave_map
 initialize_last_error_stack (void)
 {
-  static bool initialized = false;
-
-  static string_vector sv (4);
-
-  if (! initialized)
-    {
-      sv[0] = "file";
-      sv[1] = "name";
-      sv[2] = "line";
-      sv[3] = "column";
-
-      initialized = true;
-    }
-
-  return Octave_map (dim_vector (0, 1), sv);
+  return octave_call_stack::empty_backtrace ();
 }
 
 // Warning messages are never buffered.
@@ -867,14 +853,14 @@
     print_usage ();
   else
     {
-      Octave_map err = args(0).map_value ();
+      const octave_scalar_map err = args(0).scalar_map_value ();
 
       if (! error_state)
         {
           if (err.contains ("message") && err.contains ("identifier"))
             {
-              std::string msg = err.contents("message")(0).string_value ();
-              std::string id = err.contents("identifier")(0).string_value ();
+              std::string msg = err.contents("message").string_value ();
+              std::string id = err.contents("identifier").string_value ();
               int len = msg.length();
 
               std::string file;
@@ -882,11 +868,11 @@
               int l = -1;
               int c = -1;
 
-              Octave_map err_stack = initialize_last_error_stack ();
+              octave_map err_stack = initialize_last_error_stack ();
 
               if (err.contains ("stack"))
                 {
-                  err_stack = err.contents("stack")(0).map_value ();
+                  err_stack = err.contents("stack").map_value ();
 
                   if (err_stack.numel () > 0)
                     {
--- 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,1202 @@
 #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;
+}
+
+octave_fields::octave_fields (const char * const *fields)
+  : rep (new fields_rep)
+{
+  octave_idx_type n = 0;
+  while (*fields)
+    (*rep)[std::string (*fields++)] = n++;
+}
+
+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,
+                                  octave_idx_type* perm) const
+{
+  bool retval = true;
+
+  iterator p = begin (), q = other.begin ();
+  for (; p != end () && q != other.end (); p++, q++)
+    {
+      if (p->first == q->first)
+        perm[p->second] = q->second;
+      else
+        {
+          retval = false;
+          break;
+        }
+    }
+
+  retval = (p == end () && q == other.end ());
+
+  return retval;
+}
+
+bool 
+octave_fields::equal_up_to_order (const octave_fields& other,
+                                  Array<octave_idx_type>& perm) const
+{
+  octave_idx_type n = nfields ();
+  if (perm.length () != n)
+    perm.clear (1, n);
+
+  return equal_up_to_order (other, perm.fortran_vec ());
+}
+
+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 = xkeys.getfield (k);
+  return (idx >= 0) ? xvals[idx] : octave_value ();
+}
+
+void
+octave_scalar_map::setfield (const std::string& k, const octave_value& val)
+{
+  octave_idx_type idx = xkeys.getfield (k);
+  if (idx < static_cast<octave_idx_type> (xvals.size ()))
+    xvals[idx] = val;
+  else
+    xvals.push_back (val);
+}
+
+void
+octave_scalar_map::rmfield (const std::string& k)
+{
+  octave_idx_type idx = xkeys.rmfield (k);
+  if (idx >= 0)
+    xvals.erase (xvals.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 (xkeys);
+  retval.xkeys.orderfields (perm);
+
+  octave_idx_type nf = nfields ();
+  for (octave_idx_type i = 0; i < nf; i++)
+    retval.xvals[i] = xvals[perm.xelem(i)];
+
+  return retval;
+}
+
+octave_scalar_map
+octave_scalar_map::orderfields (const octave_scalar_map& other,
+                                Array<octave_idx_type>& perm) const
+{
+  if (xkeys.is_same (other.xkeys))
+    return *this;
+  else
+    {
+      octave_scalar_map retval (other.xkeys);
+      if (other.xkeys.equal_up_to_order (xkeys, perm))
+        {
+          octave_idx_type nf = nfields ();
+          for (octave_idx_type i = 0; i < nf; i++)
+            retval.xvals[i] = xvals[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 = xkeys.getfield (k);
+  if (idx >= static_cast<octave_idx_type> (xvals.size ()))
+    xvals.resize (idx);
+  return xvals[idx];
+}
+
+octave_map::octave_map (const octave_scalar_map& m)
+  : xkeys (m.xkeys), xvals (), dimensions (1, 1)
+{
+  octave_idx_type nf = m.nfields ();
+  xvals.reserve (nf);
+  for (octave_idx_type i = 0; i < nf; i++)
+    {
+      xvals.push_back (Cell (dimensions));
+      xvals[i].xelem(0) = m.xvals[i];
+    }
+}
+
+octave_map::octave_map (const Octave_map& m)
+  : xkeys (m.keys ()), xvals (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 = xkeys.getfield (k);
+  return (idx >= 0) ? xvals[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 = xkeys.getfield (k);
+      if (idx < static_cast<octave_idx_type> (xvals.size ()))
+        xvals[idx] = val;
+      else
+        xvals.push_back (val);
+    }
+  else
+    error ("octave_map::setfield: internal error");
+}
+
+void
+octave_map::rmfield (const std::string& k)
+{
+  octave_idx_type idx = xkeys.rmfield (k);
+  if (idx >= 0)
+    xvals.erase (xvals.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 (xkeys);
+  retval.xkeys.orderfields (perm);
+
+  octave_idx_type nf = nfields ();
+  for (octave_idx_type i = 0; i < nf; i++)
+    retval.xvals[i] = xvals[perm.xelem(i)];
+
+  return retval;
+}
+
+octave_map
+octave_map::orderfields (const octave_map& other,
+                         Array<octave_idx_type>& perm) const
+{
+  if (xkeys.is_same (other.xkeys))
+    return *this;
+  else
+    {
+      octave_map retval (other.xkeys);
+      if (other.xkeys.equal_up_to_order (xkeys, perm))
+        {
+          octave_idx_type nf = nfields ();
+          for (octave_idx_type i = 0; i < nf; i++)
+            retval.xvals[i] = xvals[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 = xkeys.getfield (k);
+  if (idx >= static_cast<octave_idx_type> (xvals.size ()))
+    xvals.push_back (Cell (dimensions)); // auto-set correct dims.
+  return xvals[idx];
+}
+
+void 
+octave_map::extract_scalar (octave_scalar_map& dest, 
+                            octave_idx_type idx) const
+{
+  octave_idx_type nf = nfields ();
+  for (octave_idx_type i = 0; i < nf; i++)
+    dest.xvals[i] = xvals[i](idx);
+}
+
+octave_scalar_map
+octave_map::checkelem (octave_idx_type n) const
+{
+  octave_scalar_map retval (xkeys);
+
+  // 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 (xkeys);
+
+  // 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 (xkeys);
+
+  // Optimize this so that there is just one check.
+  extract_scalar (retval, compute_index (ra_idx, dimensions));
+
+  return retval;
+}
+
+octave_scalar_map
+octave_map::fast_elem_extract (octave_idx_type n) const
+{
+  octave_scalar_map retval (xkeys);
+
+  extract_scalar (retval, n);
+
+  return retval;
+}
+
+bool
+octave_map::fast_elem_insert (octave_idx_type n, 
+                              const octave_scalar_map& rhs)
+{
+  bool retval = false;
+
+  octave_idx_type nf = nfields ();
+  if (rhs.xkeys.is_same (xkeys))
+    {
+      for (octave_idx_type i = 0; i < nf; i++)
+        xvals[i](n) = rhs.xvals[i];
+
+      retval = true;
+    }
+  else
+    {
+      OCTAVE_LOCAL_BUFFER (octave_idx_type, perm, nf);
+      if (xkeys.equal_up_to_order (rhs.xkeys, perm))
+        {
+          for (octave_idx_type i = 0; i < nf; i++)
+            xvals[i](n) = rhs.xvals[perm[i]];
+
+          retval = true;
+        }
+    }
+
+  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.xvals[i] = xvals[i].squeeze ();
+
+  retval.optimize_dimensions ();
+
+  return retval;
+}
+
+/*
+%!# test preservation of xkeys 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 (xkeys);
+  octave_idx_type nf = nfields ();
+
+  for (octave_idx_type i = 0; i < nf; i++)
+    retval.xvals[i] = xvals[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.xvals[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 (xkeys);
+
+  retval.dimensions = dim_vector (dimensions (1), dimensions (0));
+
+  octave_idx_type nf = nfields ();
+  for (octave_idx_type i = 0; i < nf; i++)
+    retval.xvals[i] = xvals[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 (xkeys);
+  retval.dimensions = dv;
+
+  octave_idx_type nf = nfields ();
+  if (nf > 0)
+    {
+      retval.xvals.reserve (nf);
+      for (octave_idx_type i = 0; i < nf; i++)
+        retval.xvals[i] = xvals[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, bool fill)
+{
+  octave_idx_type nf = nfields ();
+  if (nf > 0)
+    {
+      for (octave_idx_type i = 0; i < nf; i++)
+        {
+          if (fill)
+            xvals[i].resize (dv, Cell::resize_fill_value ());
+          else
+            xvals[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.xvals.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.xvals.push_back (Cell (rd));
+      assert (retval.xvals[j].numel () == n);
+      for (octave_idx_type i = 0; i < n; i++)
+        retval.xvals[j].xelem(i) = map_list[i].xvals[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.xvals.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].xvals[j];
+
+      retval.xvals.push_back (Array<octave_value>::cat (dim, n, field_list));
+      if (j == 0)
+        retval.dimensions = retval.xvals[j].dims ();
+    }
+}
+
+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;
+  // Allow dim = -1, -2 for compatibility, though it makes no difference here.
+  if (dim == -1 || dim == -2)
+    dim = -dim - 1;
+  else if (dim < 0)
+    (*current_liboctave_error_handler)
+      ("cat: invalid dimension");
+
+  if (n > 0)
+    {
+      retval.xkeys = map_list[0].xkeys;
+      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].xkeys.is_same (map_list[i].xkeys);
+              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.xkeys = map_list[0].xkeys;
+      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].xkeys.is_same (map_list[i].xkeys);
+          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 (xkeys);
+  octave_idx_type nf = nfields ();
+
+  for (octave_idx_type k = 0; k < nf; k++)
+    retval.xvals[k] = xvals[k].index (i, resize_ok);
+
+  if (nf > 0)
+    retval.dimensions = retval.xvals[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 (xkeys);
+  octave_idx_type nf = nfields ();
+
+  for (octave_idx_type k = 0; k < nf; k++)
+    retval.xvals[k] = xvals[k].index (i, j, resize_ok);
+
+  if (nf > 0)
+    retval.dimensions = retval.xvals[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 (xkeys);
+  octave_idx_type nf = nfields ();
+
+  for (octave_idx_type k = 0; k < nf; k++)
+    retval.xvals[k] = xvals[k].index (ia, resize_ok);
+
+  if (nf > 0)
+    retval.dimensions = retval.xvals[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;
+}
+
+// Perhaps one day these will be optimized. Right now, they just call index.
+octave_map 
+octave_map::column (octave_idx_type k) const
+{
+  return index (idx_vector::colon, k);
+}
+
+octave_map 
+octave_map::page (octave_idx_type k) const
+{
+  static Array<idx_vector> ia (3, 1, idx_vector::colon);
+
+  ia(2) = k;
+  return index (ia);
+}
+
+void
+octave_map::assign (const idx_vector& i, const octave_map& rhs)
+{
+  if (rhs.xkeys.is_same (xkeys))
+    {
+      octave_idx_type nf = nfields ();
+
+      for (octave_idx_type k = 0; k < nf; k++)
+        xvals[k].assign (i, rhs.xvals[k]);
+
+      if (nf > 0)
+        dimensions = xvals[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 if (nfields () == 0)
+    {
+      octave_map tmp (dimensions, rhs.xkeys);
+      tmp.assign (i, rhs);
+      *this = tmp;
+    }
+  else
+    {
+      Array<octave_idx_type> perm;
+      octave_map rhs1 = rhs.orderfields (*this, perm);
+      if (! error_state)
+        {
+          assert (rhs1.xkeys.is_same (xkeys));
+          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.xkeys.is_same (xkeys))
+    {
+      octave_idx_type nf = nfields ();
+
+      for (octave_idx_type k = 0; k < nf; k++)
+        xvals[k].assign (i, j, rhs.xvals[k]);
+
+      if (nf > 0)
+        dimensions = xvals[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 if (nfields () == 0)
+    {
+      octave_map tmp (dimensions, rhs.xkeys);
+      tmp.assign (i, j, rhs);
+      *this = tmp;
+    }
+  else
+    {
+      Array<octave_idx_type> perm;
+      octave_map rhs1 = rhs.orderfields (*this, perm);
+      if (! error_state)
+        {
+          assert (rhs1.xkeys.is_same (xkeys));
+          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.xkeys.is_same (xkeys))
+    {
+      octave_idx_type nf = nfields ();
+
+      for (octave_idx_type k = 0; k < nf; k++)
+        xvals[k].assign (ia, rhs.xvals[k]);
+
+      if (nf > 0)
+        dimensions = xvals[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 if (nfields () == 0)
+    {
+      octave_map tmp (dimensions, rhs.xkeys);
+      tmp.assign (ia, rhs);
+      *this = tmp;
+    }
+  else
+    {
+      Array<octave_idx_type> perm;
+      octave_map rhs1 = rhs.orderfields (*this, perm);
+      if (! error_state)
+        {
+          assert (rhs1.xkeys.is_same (xkeys));
+          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::assign (const octave_value_list& idx, const std::string& k,
+                    const Cell& rhs)
+{
+  Cell tmp;
+  iterator p = seek (k);
+  Cell& ref = p != end () ? contents (p) : tmp;
+
+  if (&ref == &tmp)
+    ref = Cell (dimensions);
+
+  ref.assign (idx, rhs);
+    
+  if (! error_state && ref.dims () != dimensions)
+    {
+      dimensions = ref.dims ();
+
+      octave_idx_type nf = nfields ();
+      for (octave_idx_type i = 0; i < nf; i++)
+        {
+          if (&xvals[i] != &ref)
+            xvals[i].resize (dimensions, Cell::resize_fill_value ());
+        }
+
+      optimize_dimensions ();
+    }
+
+  if (! error_state && &ref == &tmp)
+    setfield (k, tmp);
+}
+
+void
+octave_map::delete_elements (const idx_vector& i)
+{
+  octave_idx_type nf = nfields ();
+  for (octave_idx_type k = 0; k < nf; k++)
+    xvals[k].delete_elements (i);
+
+  if (nf > 0)
+    dimensions = xvals[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++)
+    xvals[k].delete_elements (dim, i);
+
+  if (nf > 0)
+    dimensions = xvals[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++)
+    xvals[k].delete_elements (ia);
+
+  if (nf > 0)
+    dimensions = xvals[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 (! xvals[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 +1246,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 +1277,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 +1298,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 +1372,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 +1393,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 +1463,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 +1695,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,442 @@
 
 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 (const char * const *);
+
+  ~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 == 0)
+        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,
+                          octave_idx_type* perm) const;
+
+  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
+{
+public:
+
+  octave_scalar_map (const octave_fields& k)
+    : xkeys (k), xvals (k.nfields ()) { }
+
+  octave_scalar_map (void) : xkeys (), xvals () { }
+
+  octave_scalar_map (const string_vector& k)
+    : xkeys (k), xvals (k.length ()) { }
+
+  octave_scalar_map (const octave_scalar_map& m)
+    : xkeys (m.xkeys), xvals(m.xvals) { }
+
+  octave_scalar_map& operator = (const octave_scalar_map& m)
+    {
+      xkeys = m.xkeys;
+      xvals = m.xvals;
+
+      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 xkeys.begin (); }
+  const_iterator end (void) const { return xkeys.end (); }
+
+  const_iterator seek (const std::string& k) const { return xkeys.seek (k); }
+
+  std::string key (const_iterator p) const 
+    { return xkeys.key (p); }
+  octave_idx_type index (const_iterator p) const
+    { return xkeys.index (p); }
+
+  const octave_value& contents (const_iterator p) const 
+    { return xvals[xkeys.index (p)]; }
+
+  octave_value& contents (iterator p)
+    { return xvals[xkeys.index (p)]; }
+
+  const octave_value& contents (octave_idx_type i) const
+    { return xvals[i]; }
+
+  octave_value& contents (octave_idx_type i)
+    { return xvals[i]; }
+
+  // number of fields.
+  octave_idx_type nfields (void) const { return xkeys.nfields (); }
+
+  // check whether a field exists.
+  bool isfield (const std::string& name) const 
+    { return xkeys.isfield (name); }
+
+  bool contains (const std::string& name) const 
+    { return isfield (name); }
+
+  string_vector fieldnames (void) const
+    { return xkeys.fieldnames (); }
+
+  string_vector keys (void) const
+    { return 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);
+  void assign (const std::string& k, const octave_value& val)
+    { setfield (k, val); } 
+
+  // remove a given field. do nothing if not exist.
+  void rmfield (const std::string& key);
+  void del (const std::string& k) { rmfield (k); }
+
+  // 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)
+    {
+      xkeys.clear ();
+      xvals.clear ();
+    }
+
+  friend class octave_map;
+
+private:
+
+  octave_fields xkeys;
+  std::vector<octave_value> xvals;
+
+};
+
+template<>
+inline octave_scalar_map octave_value_extract<octave_scalar_map> (const octave_value& v)
+  { return v.scalar_map_value (); }
+
+class OCTINTERP_API
+octave_map
+{
+public:
+
+  octave_map (const octave_fields& k)
+    : xkeys (k), xvals (k.nfields ()), dimensions () { }
+
+  octave_map (const dim_vector& dv, const octave_fields& k)
+    : xkeys (k), xvals (k.nfields (), Cell (dv)), dimensions (dv) { }
+
+  typedef octave_scalar_map element_type;
+
+  octave_map (void) : xkeys (), xvals (), dimensions () { }
+
+  octave_map (const dim_vector& dv) : xkeys (), xvals (), dimensions (dv) { }
+
+  octave_map (const string_vector& k)
+    : xkeys (k), xvals (k.length ()), dimensions (1, 1) { }
+
+  octave_map (const dim_vector& dv, const string_vector& k)
+    : xkeys (k), xvals (k.length (), Cell (dv)), dimensions (dv) { }
+
+  octave_map (const octave_map& m)
+    : xkeys (m.xkeys), xvals (m.xvals), dimensions (m.dimensions) { }
+
+  octave_map (const octave_scalar_map& m);
+
+  octave_map (const Octave_map& m);
+
+  octave_map& operator = (const octave_map& m)
+    {
+      xkeys = m.xkeys;
+      xvals = m.xvals;
+      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 xkeys.begin (); }
+  const_iterator end (void) const { return xkeys.end (); }
+
+  const_iterator seek (const std::string& k) const { return xkeys.seek (k); }
+
+  std::string key (const_iterator p) const 
+    { return xkeys.key (p); }
+  octave_idx_type index (const_iterator p) const
+    { return xkeys.index (p); }
+
+  const Cell& contents (const_iterator p) const 
+    { return xvals[xkeys.index (p)]; }
+
+  Cell& contents (iterator p)
+    { return xvals[xkeys.index (p)]; }
+
+  const Cell& contents (octave_idx_type i) const
+    { return xvals[i]; }
+
+  Cell& contents (octave_idx_type i)
+    { return xvals[i]; }
+
+  // number of fields.
+  octave_idx_type nfields (void) const { return xkeys.nfields (); }
+
+  // check whether a field exists.
+  bool isfield (const std::string& name) const 
+    { return xkeys.isfield (name); }
+
+  bool contains (const std::string& name) const 
+    { return isfield (name); }
+
+  string_vector fieldnames (void) const
+    { return xkeys.fieldnames (); }
+
+  string_vector keys (void) const
+    { return 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);
+  void assign (const std::string& k, const Cell& val)
+    { setfield (k, val); } 
+
+  // remove a given field. do nothing if not exist.
+  void rmfield (const std::string& key);
+  void del (const std::string& k) { rmfield (k); }
+
+  // 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)
+    {
+      xkeys.clear ();
+      xvals.clear ();
+    }
+
+  // The Array-like methods.
+  octave_idx_type numel (void) const { return dimensions.numel (); }
+  octave_idx_type length (void) const { return numel (); }
+  bool is_empty (void) const { return dimensions.any_zero (); }
+
+  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_scalar_map operator () (octave_idx_type n) const
+    { return checkelem (n); }
+  octave_scalar_map operator () (octave_idx_type i, octave_idx_type j) const
+    { return checkelem (i, j); }
+
+  octave_scalar_map
+  operator () (const Array<octave_idx_type>& ra_idx) const
+    { return checkelem (ra_idx); }
+
+  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, bool fill = false);
+
+  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 = false) const;
+
+  octave_map index (const idx_vector& i, const idx_vector& j,
+                    bool resize_ok = false) const;
+
+  octave_map index (const Array<idx_vector>& ia,
+                    bool resize_ok = false) const;
+
+  octave_map index (const octave_value_list&, bool resize_ok = false) const;
+  
+  octave_map column (octave_idx_type k) const;
+  octave_map page (octave_idx_type k) 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 assign (const octave_value_list& idx, const std::string& k,
+               const Cell& 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);
+
+  // like checkelem, but no check.
+  octave_scalar_map fast_elem_extract (octave_idx_type n) const;
+
+  // element assignment, no bounds check
+  bool fast_elem_insert (octave_idx_type n, const octave_scalar_map& rhs);
+
+private:
+
+  octave_fields xkeys;
+  std::vector<Cell> xvals;
+  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);
+};
+
+template<>
+inline octave_map octave_value_extract<octave_map> (const octave_value& v)
+  { return v.map_value (); }
+
+// The original Octave_map object. Octave_map and octave_map are convertible to
+// each other.
+
 class
 OCTINTERP_API
 Octave_map
@@ -85,6 +522,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-mat.h
+++ b/src/ov-base-mat.h
@@ -39,8 +39,6 @@
 #include "ov-base.h"
 #include "ov-typeinfo.h"
 
-class Octave_map;
-
 class tree_walker;
 
 // Real matrix values.
--- a/src/ov-base-sparse.h
+++ b/src/ov-base-sparse.h
@@ -39,8 +39,6 @@
 #include "boolSparse.h"
 #include "MatrixType.h"
 
-class Octave_map;
-
 class tree_walker;
 
 class octave_sparse_bool_matrix;
--- a/src/ov-base.cc
+++ b/src/ov-base.cc
@@ -885,14 +885,30 @@
   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 ();
+    }
+}
+
 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,9 @@
 
   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 string_vector map_keys (void) const;
 
--- a/src/ov-bool-mat.h
+++ b/src/ov-bool-mat.h
@@ -42,7 +42,6 @@
 
 #include "MatrixType.h"
 
-class Octave_map;
 class octave_value_list;
 
 class tree_walker;
--- a/src/ov-bool-sparse.h
+++ b/src/ov-bool-sparse.h
@@ -42,7 +42,6 @@
 #include "ov-base-sparse.h"
 #include "ov-re-sparse.h"
 
-class Octave_map;
 class octave_value_list;
 
 class tree_walker;
--- a/src/ov-bool.h
+++ b/src/ov-bool.h
@@ -41,7 +41,6 @@
 #include "ov-scalar.h"
 #include "ov-typeinfo.h"
 
-class Octave_map;
 class octave_value_list;
 
 class tree_walker;
--- 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-ch-mat.h
+++ b/src/ov-ch-mat.h
@@ -41,7 +41,6 @@
 #include "ov-re-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
@@ -66,7 +66,7 @@
     (octave_class::t_name, "<unknown>", octave_value (new octave_class ()));
 }
 
-octave_class::octave_class (const Octave_map& m, const std::string& id, 
+octave_class::octave_class (const octave_map& m, const std::string& id, 
                             const octave_value_list& parents)
   : octave_base_value (), map (m), c_name (id), obsolete_copies (0)
 {
@@ -231,7 +231,7 @@
             }
         }
 
-      Octave_map m;
+      octave_map m;
 
       m.assign ("type", type_field);
       m.assign ("subs", subs_field);
@@ -259,7 +259,7 @@
   octave_base_value *obvp
     = method_class.empty () ? 0 : find_parent_class (method_class);
 
-  Octave_map my_map;
+  octave_map my_map;
 
   my_map = obvp ? obvp->map_value () : map;
 
@@ -267,7 +267,7 @@
 
   if (! error_state)
     {
-      Octave_map::const_iterator p = my_map.seek (nm);
+      octave_map::const_iterator p = my_map.seek (nm);
 
       if (p != my_map.end ())
         retval = my_map.contents (p);
@@ -486,7 +486,7 @@
       retval = val(0);
 
       if (type.length () > 0 && type[0] == '.' && ! retval.is_map ())
-        retval = Octave_map ();
+        retval = octave_map ();
     }
   else
     gripe_invalid_index_for_assignment ();
@@ -646,11 +646,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?
@@ -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.map_value ();
 
                     if (! error_state)
                       {
@@ -742,7 +742,7 @@
                   {
                     if (t_rhs.is_empty ())
                       {
-                        map.maybe_delete_elements (idx.front());
+                        map.delete_elements (idx.front());
 
                         if (! error_state)
                           {
@@ -851,7 +851,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);
 
@@ -884,9 +884,9 @@
            pit != parent_list.end ();
            pit++)
         {
-          Octave_map::const_iterator smap = map.seek (*pit);
+          octave_map::const_iterator smap = map.seek (*pit);
 
-          const Cell& tmp = smap->second;
+          const Cell& tmp = map.contents (smap);
 
           octave_value vtmp = tmp(0);
 
@@ -915,9 +915,9 @@
            pit != parent_list.end ();
            pit++)
         {
-          Octave_map::iterator smap = map.seek (*pit);
+          octave_map::iterator smap = map.seek (*pit);
 
-          Cell& tmp = smap->second;
+          Cell& tmp = map.contents (smap);
 
           octave_value& vtmp = tmp(0);
 
@@ -1053,7 +1053,7 @@
   std::string dbgstr = "dork";
 
   // First, check to see if there might be an issue with inheritance.
-  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);
       Cell         val = map.contents (p);
@@ -1102,7 +1102,7 @@
 octave_class::save_ascii (std::ostream& os)
 {
   os << "# classname: " << class_name () << "\n";
-  Octave_map m;
+  octave_map m;
   if (load_path::find_method (class_name (), "saveobj") != std::string ())
     {
       octave_value in = new octave_class (*this);
@@ -1117,7 +1117,7 @@
 
   os << "# length: " << m.nfields () << "\n";
 
-  Octave_map::iterator i = m.begin ();
+  octave_map::iterator i = m.begin ();
   while (i != m.end ())
     {
       octave_value val = map.contents (i);
@@ -1146,7 +1146,7 @@
         {
           if (len > 0)
             {
-              Octave_map m (map);
+              octave_map m (map);
 
               for (octave_idx_type j = 0; j < len; j++)
                 {
@@ -1203,7 +1203,7 @@
             }
           else if (len == 0 )
             {
-              map = Octave_map (dim_vector (1, 1));
+              map = octave_map (dim_vector (1, 1));
               c_name = classname;
             }
           else
@@ -1232,7 +1232,7 @@
   os.write (reinterpret_cast<char *> (&classname_len), 4);
   os << class_name ();
 
-  Octave_map m;
+  octave_map m;
   if (load_path::find_method (class_name (), "saveobj") != std::string ())
     {
       octave_value in = new octave_class (*this);
@@ -1248,7 +1248,7 @@
   int32_t len = m.nfields();
   os.write (reinterpret_cast<char *> (&len), 4);
   
-  Octave_map::iterator i = m.begin ();
+  octave_map::iterator i = m.begin ();
   while (i != m.end ())
     {
       octave_value val = map.contents (i);
@@ -1295,7 +1295,7 @@
 
   if (len > 0)
     {
-      Octave_map m (map);
+      octave_map m (map);
 
       for (octave_idx_type j = 0; j < len; j++)
         {
@@ -1348,7 +1348,7 @@
         }
     }
   else if (len == 0 )
-    map = Octave_map (dim_vector (1, 1));
+    map = octave_map (dim_vector (1, 1));
   else
     panic_impossible ();
 
@@ -1366,8 +1366,8 @@
   hid_t space_hid = -1;
   hid_t class_hid = -1;
   hid_t data_hid = -1;
-  Octave_map m;
-  Octave_map::iterator i;
+  octave_map m;
+  octave_map::iterator i;
 
 #if HAVE_HDF5_18
   group_hid = H5Gcreate (loc_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
@@ -1468,7 +1468,7 @@
   hdf5_callback_data dsub;
 
   herr_t retval2 = 0;
-  Octave_map m (dim_vector (1, 1));
+  octave_map m (dim_vector (1, 1));
   int current_item = 0;
   hsize_t num_obj = 0;
   int slen = 0;
@@ -1624,7 +1624,7 @@
 {
   if (obj.is_object ())
     {
-      Octave_map m = obj.map_value ();
+      octave_map m = obj.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.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).map_value ();
 
           if (! error_state)
             {
--- a/src/ov-class.h
+++ b/src/ov-class.h
@@ -52,14 +52,14 @@
   octave_class (void)
     : octave_base_value (), obsolete_copies (0)  { }
 
-  octave_class (const Octave_map& m, const std::string& id)
+  octave_class (const octave_map& m, const std::string& id)
     : octave_base_value (), map (m), c_name (id), obsolete_copies (0) { }
 
   octave_class (const octave_class& s)
     : octave_base_value (s), map (s.map), c_name (s.c_name),
       parent_list (s.parent_list), obsolete_copies (0)  { }
 
-  octave_class (const Octave_map& m, const std::string& id, 
+  octave_class (const octave_map& m, const std::string& id, 
                 const octave_value_list& parents);
 
   ~octave_class (void) { }
@@ -70,7 +70,7 @@
 
   octave_base_value *empty_clone (void) const
   {
-    return new octave_class (Octave_map (map.keys ()), class_name ());
+    return new octave_class (octave_map (map.keys ()), class_name ());
   }
 
   Cell dotref (const octave_value_list& idx);
@@ -122,7 +122,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; }
 
@@ -130,7 +130,7 @@
 
   bool is_object (void) const { return true; }
 
-  Octave_map map_value (void) const { return map; }
+  octave_map map_value (void) const { return map; }
 
   string_vector map_keys (void) const;
 
@@ -178,7 +178,7 @@
 
 private:
 
-  Octave_map map;
+  octave_map map;
 
   DECLARE_OCTAVE_ALLOCATOR
 
--- a/src/ov-colon.h
+++ b/src/ov-colon.h
@@ -36,7 +36,6 @@
 #include "ov-base.h"
 #include "ov-typeinfo.h"
 
-class Octave_map;
 class octave_value_list;
 
 class tree_walker;
--- a/src/ov-complex.h
+++ b/src/ov-complex.h
@@ -41,7 +41,6 @@
 #include "ov-base-scalar.h"
 #include "ov-typeinfo.h"
 
-class Octave_map;
 class octave_value_list;
 
 class tree_walker;
--- a/src/ov-cx-mat.h
+++ b/src/ov-cx-mat.h
@@ -42,7 +42,6 @@
 
 #include "MatrixType.h"
 
-class Octave_map;
 class octave_value_list;
 
 class tree_walker;
--- a/src/ov-cx-sparse.h
+++ b/src/ov-cx-sparse.h
@@ -42,7 +42,6 @@
 #include "ov-base-sparse.h"
 #include "ov-re-sparse.h"
 
-class Octave_map;
 class octave_value_list;
 
 class tree_walker;
--- 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-float.h
+++ b/src/ov-float.h
@@ -43,7 +43,6 @@
 #include "ov-base-scalar.h"
 #include "ov-typeinfo.h"
 
-class Octave_map;
 class octave_value_list;
 
 class tree_walker;
--- a/src/ov-flt-complex.h
+++ b/src/ov-flt-complex.h
@@ -41,7 +41,6 @@
 #include "ov-base-scalar.h"
 #include "ov-typeinfo.h"
 
-class Octave_map;
 class octave_value_list;
 
 class tree_walker;
--- a/src/ov-flt-cx-mat.h
+++ b/src/ov-flt-cx-mat.h
@@ -42,7 +42,6 @@
 
 #include "MatrixType.h"
 
-class Octave_map;
 class octave_value_list;
 
 class tree_walker;
--- a/src/ov-flt-re-mat.h
+++ b/src/ov-flt-re-mat.h
@@ -42,7 +42,6 @@
 
 #include "MatrixType.h"
 
-class Octave_map;
 class octave_value_list;
 
 class tree_walker;
--- a/src/ov-range.h
+++ b/src/ov-range.h
@@ -43,7 +43,6 @@
 #include "ov-re-mat.h"
 #include "ov-typeinfo.h"
 
-class Octave_map;
 class octave_value_list;
 
 class tree_walker;
--- a/src/ov-re-mat.h
+++ b/src/ov-re-mat.h
@@ -42,7 +42,6 @@
 
 #include "MatrixType.h"
 
-class Octave_map;
 class octave_value_list;
 
 class tree_walker;
--- a/src/ov-re-sparse.h
+++ b/src/ov-re-sparse.h
@@ -43,7 +43,6 @@
 #include "ov-base-sparse.h"
 #include "ov-cx-sparse.h"
 
-class Octave_map;
 class octave_value_list;
 
 class tree_walker;
--- a/src/ov-scalar.h
+++ b/src/ov-scalar.h
@@ -42,7 +42,6 @@
 #include "ov-base-scalar.h"
 #include "ov-typeinfo.h"
 
-class Octave_map;
 class octave_value_list;
 
 class tree_walker;
--- a/src/ov-str-mat.h
+++ b/src/ov-str-mat.h
@@ -40,7 +40,6 @@
 #include "ov-re-mat.h"
 #include "ov-typeinfo.h"
 
-class Octave_map;
 class octave_value_list;
 
 class tree_walker;
--- 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?
@@ -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.assign (idxf, key, 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)
               {
@@ -541,13 +555,15 @@
   else
     gripe_failed_assignment ();
 
+  retval.maybe_mutate ();
+
   return retval;
 }
 
 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 +574,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 +622,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,619 +709,10 @@
 %!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\
-\n\
-Create a structure and initialize its value.\n\
-\n\
-If the values are cell arrays, create a structure array and initialize\n\
-its values.  The dimensions of each cell array of values must match.\n\
-Singleton cells and non-cell values are repeated so that they fill\n\
-the entire array.  If the cells are empty, create an empty structure\n\
-array with the specified field names.\n\
-\n\
-If the argument is an object, return the underlying struct.\n\
-@end deftypefn")
-{
-  octave_value retval;
-
-  int nargin = args.length ();
-
-  // struct ([]) returns an empty struct.
-
-  // struct (empty_matrix) returns an empty struct with the same
-  // dimensions as the empty matrix.
-
-  // Note that struct () creates a 1x1 struct with no fields for
-  // compatibility with Matlab.
-
-  if (nargin == 1 && args(0).is_object ())
-    {
-      Octave_map m = args(0).map_value ();
-      retval = octave_value (new octave_struct (m));
-
-      return retval;
-    }
-
-  if ((nargin == 1 || nargin == 2)
-      && args(0).is_empty () && args(0).is_real_matrix ())
-    {
-      Cell fields;
-
-      if (nargin == 2)
-        {
-          if (args(1).is_cellstr ())
-            retval = Octave_map (args(0).dims (), args(1).cell_value ());
-          else
-            error ("struct: expecting cell array of field names as second argument");
-        }
-      else
-        retval = Octave_map (args(0).dims ());
-
-      return retval;
-    }
-    
-  // Check for "field", VALUE pairs.
-
-  for (int i = 0; i < nargin; i += 2) 
-    {
-      if (! args(i).is_string () || i + 1 >= nargin)
-        {
-          error ("struct expects alternating \"field\", VALUE pairs");
-          return retval;
-        }
-    }
-
-  // Check that the dimensions of the values correspond.
-
-  dim_vector dims (1, 1);
-
-  int first_dimensioned_value = 0;
-
-  for (int i = 1; i < nargin; i += 2) 
-    {
-      if (args(i).is_cell ()) 
-        {
-          dim_vector argdims (args(i).dims ());
-
-          if (! scalar (argdims))
-            {
-              if (! first_dimensioned_value)
-                {
-                  dims = argdims;
-                  first_dimensioned_value = i + 1;
-                }
-              else if (dims != argdims)
-                {
-                  error ("struct: dimensions of parameter %d do not match those of parameter %d",
-                         first_dimensioned_value, i+1);
-                  return retval;
-                }
-            }
-        }
-    }
-
-  // Create the return value.
-
-  Octave_map map (dims);
-
-  for (int i = 0; i < nargin; i+= 2) 
-    {
-      // Get key.
-
-      std::string key (args(i).string_value ());
-
-      if (error_state)
-        return retval;
-
-      if (! valid_identifier (key))
-        {
-          error ("struct: invalid structure field name `%s'", key.c_str ());
-          return retval;
-        }
-
-      // Value may be v, { v }, or { v1, v2, ... }
-      // In the first two cases, we need to create a cell array of
-      // the appropriate dimensions filled with v.  In the last case, 
-      // the cell array has already been determined to be of the
-      // correct dimensions.
-
-      if (args(i+1).is_cell ()) 
-        {
-          const Cell c (args(i+1).cell_value ());
-
-          if (error_state)
-            return retval;
-
-          if (scalar (c.dims ())) 
-            map.assign (key, Cell (dims, c(0)));
-          else 
-            map.assign (key, c);
-        }
-      else 
-        map.assign (key, Cell (dims, args(i+1)));
-
-      if (error_state)
-        return retval;
-    }
-
-  return octave_value (map);
-}
-
-DEFUN (isstruct, args, ,
-  "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {} isstruct (@var{expr})\n\
-Return 1 if the value of the expression @var{expr} is a structure\n\
-(or a structure array).\n\
-@end deftypefn")
-{
-  octave_value retval;
-
-  if (args.length () == 1)
-    retval = args(0).is_map ();
-  else
-    print_usage ();
-
-  return retval;
-}
-
-DEFUN (fieldnames, args, ,
-  "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {} fieldnames (@var{struct})\n\
-Return a cell array of strings naming the elements of the structure\n\
-@var{struct}.  It is an error to call @code{fieldnames} with an\n\
-argument that is not a structure.\n\
-@end deftypefn")
-{
-  octave_value retval;
-
-  int nargin = args.length ();
-
-  if (nargin == 1)
-    {
-      octave_value arg = args(0);
-
-      if (arg.is_map () || arg.is_object ())
-        {
-          Octave_map m = arg.map_value ();
-
-          string_vector keys = m.keys ();
-
-          if (keys.length () == 0)
-            retval = Cell (0, 1);
-          else
-            retval = Cell (m.keys ());
-        }
-      else
-        gripe_wrong_type_arg ("fieldnames", args(0));
-    }
-  else
-    print_usage ();
-
-  return retval;
-}
-
-/*
-%!# test preservation of fieldname order
-%!test
-%!  x(3).d=1; x(2).a=2; x(1).b=3; x(2).c=3;
-%!  assert(fieldnames(x), {"d"; "a"; "b"; "c"});
-*/
-
-DEFUN (isfield, args, ,
-  "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {} isfield (@var{expr}, @var{name})\n\
-Return true if the expression @var{expr} is a structure and it\n\
-includes an element named @var{name}.  If @var{name} is a cell\n\
-array, a logical array of equal dimension is returned.\n\
-@end deftypefn")
-{
-  octave_value retval;
-
-  int nargin = args.length ();
-
-  if (nargin == 2)
-    {
-      retval = false;
-
-      if (args(0).is_map ())
-        {
-          Octave_map m = args(0).map_value ();
-
-          // FIXME -- should this work for all types that can do
-          // structure reference operations?
-
-          if (args(1).is_string ())
-            {
-              std::string key = args(1).string_value ();
-
-              retval = m.contains (key) != 0;
-            }
-          else if (args(1).is_cell ())
-            {
-              Cell c = args(1).cell_value ();
-              boolMatrix bm (c.dims ());
-              octave_idx_type n = bm.numel ();
-
-              for (octave_idx_type i = 0; i < n; i++)
-                {
-                  if (c(i).is_string ())
-                    {
-                      std::string key = c(i).string_value ();
-
-                      bm(i) = m.contains (key) != 0;
-                    }
-                  else
-                    bm(i) = false;
-                }
-
-              retval = bm;
-            }
-        }
-    }
-  else
-    print_usage ();
-
-  return retval;
-}
-
-DEFUN (nfields, args, ,
-  "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {} nfields (@var{s})\n\
-Return the number of fields of the structure @var{s}.\n\
-@end deftypefn")
-{
-  octave_value retval;
-
-  int nargin = args.length ();
-
-  if (nargin == 1 && args(0).is_map ())
-    {
-      retval = static_cast<double> (args(0).nfields ());
-    }
-  else
-    print_usage ();
-
-  return retval;
-}
-
-/*
-%!# test isfield
-%!test
-%!  x(3).d=1; x(2).a=2; x(1).b=3; x(2).c=3;
-%!  assert (isfield (x, "b"));
-%!assert( isfield( struct("a", "1"), "a"));
-%!assert( isfield( {1}, "c"), logical (0));
-%!assert( isfield( struct("a", "1"), 10), logical (0));
-%!assert( isfield( struct("a", "b"), "a "), logical (0));
-
-*/
-
-// Check that the dimensions of the input arguments are correct.
-
-static bool
-cell2struct_check_args (const dim_vector& c_dv, const dim_vector& f_dv,
-                        bool is_cell, int dim)
-{
-  bool retval = true;
-
-  if (dim >= 0 && dim < c_dv.length ())
-    {
-      if (is_cell)
-        {
-          if (f_dv.numel () != c_dv(dim))
-            {
-              error ("cell2struct: numel (FIELD) != size (CELL, DIM)");
-
-              retval = false;
-            }
-        }
-      else
-        {
-          if (f_dv.length () > 2)
-            {
-              error ("cell2struct: field array must be a 2-d matrix");
-
-              retval = false;
-            }
-          else if (f_dv(0) != c_dv(dim))
-            {
-              error ("cell2struct: size (FIELD, 1) != length (C, DIM)");
-
-              retval = false;
-            }
-        }
-    }
-  else
-    {
-      error ("cell2struct: DIM out of range");
-
-      retval = false;
-    }
-
-  return retval;
-}
-
-static void
-cell2struct_construct_idx (Array<octave_idx_type>& ra_idx1,
-                           const Array<octave_idx_type>& ra_idx2,
-                           octave_idx_type dim, octave_idx_type fill_value)
-{
-  octave_idx_type iidx = 0;
-
-  for (octave_idx_type idx = 0; idx < ra_idx1.length (); idx++)
-    {
-      if (idx == dim)
-        ra_idx1.elem (idx) = fill_value;
-      else
-        ra_idx1.elem (idx) = ra_idx2(iidx++);
-    }
-}
-
-DEFUN (cell2struct, args, ,
-       "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {} cell2struct (@var{cell}, @var{fields}, @var{dim})\n\
-Convert @var{cell} to a structure.  The number of fields in @var{fields}\n\
-must match the number of elements in @var{cell} along dimension @var{dim},\n\
-that is @code{numel (@var{fields}) == size (@var{cell}, @var{dim})}.\n\
-\n\
-@example\n\
-@group\n\
-A = cell2struct (@{'Peter', 'Hannah', 'Robert';\n\
-                   185, 170, 168@},\n\
-                 @{'Name','Height'@}, 1);\n\
-A(1)\n\
-     @result{} ans =\n\
-        @{\n\
-          Name   = Peter\n\
-          Height = 185\n\
-        @}\n\
-\n\
-@end group\n\
-@end example\n\
-@end deftypefn")
-{
-  octave_value retval;
-
-  if (args.length () == 3)
-    {
-      Cell c = args(0).cell_value ();
-
-      if (! error_state)
-        {
-          octave_value field = args(1);
-
-          // Field is either cell or character matrix.
-
-          // FIXME -- this could be simplified if we had
-          // cellstr and iscellstr functions available.
-
-          bool field_is_cell = field.is_cell ();
-
-          Cell field_cell;
-          charMatrix field_char;
-
-          if (field_is_cell)
-            field_cell = field.cell_value ();
-          else
-            field_char = field.char_matrix_value ();
-
-          if (! error_state)
-            {
-              // Retrieve the dimension value.
-
-              // FIXME --  int_value () should print out the
-              // conversions it does to be Matlab compatible.
-
-              octave_idx_type dim = args(2).int_value () - 1;
-
-              if (! error_state)
-                {
-                  dim_vector c_dv = c.dims ();
-                  dim_vector field_dv = field.dims ();
-
-                  if (cell2struct_check_args (c_dv, field_dv, field_is_cell,
-                                              dim))
-                    {
-                      octave_idx_type c_dv_length = c_dv.length ();
-
-                      // Dimension vector for the Cell arrays to be
-                      // put into the structure.
-
-                      dim_vector value_dv;
-
-                      // Initialize c_value_dv.
-
-                      if (c_dv_length == 2)
-                        value_dv = dim_vector (1, 1);
-                      else
-                        value_dv.resize (c_dv_length - 1);
-
-                      octave_idx_type idx_tmp = 0;
-
-                      for (octave_idx_type i = 0; i < c_dv_length; i++)
-                        {
-                          if (i != dim)
-                            value_dv.elem (idx_tmp++) = c_dv.elem (i);
-                        }
-
-                      // All initializing is done, we can start moving
-                      // values.
-
-                      Octave_map map;
-
-                      // If field is a cell array then we use all
-                      // elements in array, on the other hand when
-                      // field is a character array the number of
-                      // elements is equals the number of rows.
-
-                      octave_idx_type field_numel
-                        = field_is_cell ? field_dv.numel (): field_dv(0);
-
-                      // For matlab compatibility.
-
-                      if (field_numel == 0)
-                        map.reshape (dim_vector (0, 1));
-
-                      for (octave_idx_type i = 0; i < field_numel; i++)
-                        {
-                          // Construct cell array which goes into the
-                          // structure together with the appropriate
-                          // field name.
-
-                          Cell c_value (value_dv);
-
-                          Array<octave_idx_type> value_idx (value_dv.length (), 1, 0);
-                          Array<octave_idx_type> c_idx (c_dv_length, 1, 0);
-
-                          for (octave_idx_type j = 0; j < value_dv.numel (); j++)
-                            {
-                              // Need to do this to construct the
-                              // appropriate idx for getting elements
-                              // from the original cell array.
-
-                              cell2struct_construct_idx (c_idx, value_idx,
-                                                         dim, i);
-
-                              c_value.elem (value_idx) = c.elem (c_idx);
-
-                              increment_index (value_idx, value_dv);
-                            }
-
-                          std::string field_str;
-
-                          if (field_is_cell)
-                            {
-                              // Matlab retrieves the field values
-                              // column by column.
-
-                              octave_value field_tmp = field_cell.elem (i);
-
-                              field_str = field_tmp.string_value ();
-
-                              if (error_state)
-                                {
-                                  error ("cell2struct: fields have to be of type string");
-                                  break;
-                                }
-                            }
-                          else
-                            {
-                              field_str = field_char.row_as_string (i);
-
-                              if (error_state)
-                                return retval;
-                            }
-
-                          if (! valid_identifier (field_str))
-                            {
-                              error ("cell2struct: invalid field name `%s'",
-                                     field_str.c_str ());
-                              break;
-                            }
-
-                          map.reshape (value_dv);
-
-                          map.assign (field_str, c_value);
-                        }
-
-                      if (! error_state)
-                        retval = map;
-                    }
-                }
-              else
-                error ("cell2struct: expecting third argument to be an integer");
-            }
-          else
-            error ("cell2struct: expecting second argument to be a cell or character array");
-        }
-      else
-        error ("cell2struct: expecting first argument to be a cell array");
-    }
-  else
-    print_usage ();
-
-  return retval;
-}
-
-/*
-%!# test cell2struct versus struct2cell
-%!test
-%!  keys = cellstr (char (floor (rand (100,10)*24+65)))';
-%!  vals = mat2cell(rand (100,1), ones (100,1), 1)';
-%!  s = struct ([keys; vals]{:});
-%!  t = cell2struct (vals, keys, 2);
-%!  assert (s, t);
-%!  assert (struct2cell (s), vals');
-%!  assert (fieldnames (s), keys');
-*/
-
-
-// So we can call Fcellstr directly.
-extern octave_value_list Fcellstr (const octave_value_list& args, int);
-
-DEFUN (rmfield, args, ,
-       "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {} rmfield (@var{s}, @var{f})\n\
-Return a copy of the structure (array) @var{s} with the field @var{f} removed.\n\
-If @var{f} is a cell array of strings or a character array, remove the\n\
-named fields.\n\
-@seealso{cellstr, iscellstr, setfield}\n\
-@end deftypefn")
-{
-  octave_value retval;
-
-  int nargin = args.length ();
-
-  if (nargin == 2)
-    {
-      Octave_map m = args(0).map_value ();
-
-      octave_value_list fval = Fcellstr (args(1), 1);
-
-      if (! error_state)
-        {
-          Cell fcell = fval(0).cell_value ();
-
-          for (int i = 0; i < fcell.numel (); i++)
-            {
-              std::string key = fcell(i).string_value ();
-
-              if (m.contains (key))
-                m.del (key);
-              else
-                {
-                  error ("rmfield: structure does not contain field %s",
-                         key.c_str ());
-
-                  break;
-                }
-            }
-
-          if (! error_state)
-            retval = m;
-        }
-    }
-  else
-    print_usage ();
-
-  return retval;
-}
-
-/*
-%!# test rmfield
-%!test
-%!  x(3).d=1; x(2).a=2; x(1).b=3; x(2).c=3; x(6).f="abc123";
-%!  y = rmfield (x, {"a", "f"});
-%!  assert (fieldnames (y), {"d"; "b"; "c"});
-%!  assert (size (y), [1, 6]);
-*/
-
 bool
 octave_struct::save_ascii (std::ostream& os)
 {
-  Octave_map m = map_value ();
+  octave_map m = map_value ();
 
   octave_idx_type nf = m.nfields ();
 
@@ -1321,7 +728,7 @@
 
   // Iterating over the list of keys will preserve the order of the
   // fields.
-  string_vector keys = m.keys ();
+  string_vector keys = m.fieldnames ();
 
   for (octave_idx_type i = 0; i < nf; i++)
     {
@@ -1374,7 +781,7 @@
     {
       if (len > 0)
         {
-          Octave_map m (dv);
+          octave_map m (dv);
 
           for (octave_idx_type j = 0; j < len; j++)
             {
@@ -1396,7 +803,7 @@
                   return false;
                 }
 
-              m.assign (nm, tcell);
+              m.setfield (nm, tcell);
             }
 
           if (is) 
@@ -1408,7 +815,7 @@
             }
         }
       else if (len == 0 )
-        map = Octave_map (dv);
+        map = octave_map (dv);
       else
         panic_impossible ();
     }
@@ -1423,7 +830,7 @@
 bool 
 octave_struct::save_binary (std::ostream& os, bool& save_as_floats)
 {
-  Octave_map m = map_value ();
+  octave_map m = map_value ();
 
   octave_idx_type nf = m.nfields ();
 
@@ -1445,7 +852,7 @@
 
   // Iterating over the list of keys will preserve the order of the
   // fields.
-  string_vector keys = m.keys ();
+  string_vector keys = m.fieldnames ();
 
   for (octave_idx_type i = 0; i < nf; i++)
     {
@@ -1500,7 +907,7 @@
 
   if (len > 0)
     {
-      Octave_map m (dv);
+      octave_map m (dv);
 
       for (octave_idx_type j = 0; j < len; j++)
         {
@@ -1523,7 +930,7 @@
               return false;
             }
 
-          m.assign (nm, tcell);
+          m.setfield (nm, tcell);
         }
 
       if (is) 
@@ -1535,7 +942,7 @@
         }
     }
   else if (len == 0)
-    map = Octave_map (dv);
+    map = octave_map (dv);
   else
     success = false;
 
@@ -1557,13 +964,13 @@
   if (data_hid < 0) return false;
 
   // recursively add each element of the structure to this group
-  Octave_map m = map_value ();
+  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 ();
+  string_vector keys = m.fieldnames ();
 
   for (octave_idx_type i = 0; i < nf; i++)
     {
@@ -1591,7 +998,7 @@
   hdf5_callback_data dsub;
 
   herr_t retval2 = 0;
-  Octave_map m (dim_vector (1, 1));
+  octave_map m (dim_vector (1, 1));
   int current_item = 0;
   hsize_t num_obj = 0;
 #if HAVE_HDF5_18
@@ -1619,7 +1026,7 @@
           return false;
         }
 
-      m.assign (dsub.name, tcell);
+      m.setfield (dsub.name, tcell);
 
     }
 
@@ -1666,3 +1073,1124 @@
 
   return retval;
 }
+
+octave_value
+octave_struct::fast_elem_extract (octave_idx_type n) const
+{
+  if (n < map.numel ())
+    return map.checkelem (n);
+  else
+    return octave_value ();
+}
+
+bool
+octave_struct::fast_elem_insert (octave_idx_type n, 
+                                 const octave_value& x)
+{
+  bool retval = false;
+
+  if (n < map.numel ())
+    {
+      // To avoid copying the scalar struct, it just stores a pointer to
+      // itself.
+      const octave_scalar_map *sm_ptr;
+      void *here = reinterpret_cast<void *>(&sm_ptr);
+      return (x.get_rep().fast_elem_insert_self (here, btyp_struct)
+              && map.fast_elem_insert (n, *sm_ptr));
+    }
+
+  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 ();
+
+      count++;
+      retval = this;
+    }
+  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) && 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));
+}
+
+bool
+octave_scalar_struct::fast_elem_insert_self (void *where, builtin_type_t btyp) const
+{
+
+  if (btyp == btyp_struct)
+    {
+      *(reinterpret_cast<const octave_scalar_map **>(where)) = &map;
+      return true;
+    }
+  else
+    return false;
+}
+/*
+%!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\
+\n\
+Create a structure and initialize its value.\n\
+\n\
+If the values are cell arrays, create a structure array and initialize\n\
+its values.  The dimensions of each cell array of values must match.\n\
+Singleton cells and non-cell values are repeated so that they fill\n\
+the entire array.  If the cells are empty, create an empty structure\n\
+array with the specified field names.\n\
+\n\
+If the argument is an object, return the underlying struct.\n\
+@end deftypefn")
+{
+  octave_value retval;
+
+  int nargin = args.length ();
+
+  // struct ([]) returns an empty struct.
+
+  // struct (empty_matrix) returns an empty struct with the same
+  // dimensions as the empty matrix.
+
+  // Note that struct () creates a 1x1 struct with no fields for
+  // compatibility with Matlab.
+
+  if (nargin == 1 && args(0).is_map ())
+    return args(0);
+
+  if (nargin == 1 && args(0).is_object ())
+    {
+      retval = args(0).map_value ();
+
+      return retval;
+    }
+
+  if ((nargin == 1 || nargin == 2)
+      && args(0).is_empty () && args(0).is_real_matrix ())
+    {
+      Cell fields;
+
+      if (nargin == 2)
+        {
+          if (args(1).is_cellstr ())
+            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 ());
+
+      return retval;
+    }
+    
+  // Check for "field", VALUE pairs.
+
+  for (int i = 0; i < nargin; i += 2) 
+    {
+      if (! args(i).is_string () || i + 1 >= nargin)
+        {
+          error ("struct expects alternating \"field\", VALUE pairs");
+          return retval;
+        }
+    }
+
+  // Check that the dimensions of the values correspond.
+
+  dim_vector dims (1, 1);
+
+  int first_dimensioned_value = 0;
+
+  for (int i = 1; i < nargin; i += 2) 
+    {
+      if (args(i).is_cell ()) 
+        {
+          dim_vector argdims (args(i).dims ());
+
+          if (! scalar (argdims))
+            {
+              if (! first_dimensioned_value)
+                {
+                  dims = argdims;
+                  first_dimensioned_value = i + 1;
+                }
+              else if (dims != argdims)
+                {
+                  error ("struct: dimensions of parameter %d do not match those of parameter %d",
+                         first_dimensioned_value, i+1);
+                  return retval;
+                }
+            }
+        }
+    }
+
+  // Create the return value.
+
+  octave_map map (dims);
+
+  for (int i = 0; i < nargin; i+= 2) 
+    {
+      // Get key.
+
+      std::string key (args(i).string_value ());
+
+      if (error_state)
+        return retval;
+
+      if (! valid_identifier (key))
+        {
+          error ("struct: invalid structure field name `%s'", key.c_str ());
+          return retval;
+        }
+
+      // Value may be v, { v }, or { v1, v2, ... }
+      // In the first two cases, we need to create a cell array of
+      // the appropriate dimensions filled with v.  In the last case, 
+      // the cell array has already been determined to be of the
+      // correct dimensions.
+
+      if (args(i+1).is_cell ()) 
+        {
+          const Cell c (args(i+1).cell_value ());
+
+          if (error_state)
+            return retval;
+
+          if (scalar (c.dims ())) 
+            map.setfield (key, Cell (dims, c(0)));
+          else 
+            map.setfield (key, c);
+        }
+      else 
+        map.setfield (key, Cell (dims, args(i+1)));
+
+      if (error_state)
+        return retval;
+    }
+
+  return octave_value (map);
+}
+
+DEFUN (isstruct, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {} isstruct (@var{expr})\n\
+Return 1 if the value of the expression @var{expr} is a structure\n\
+(or a structure array).\n\
+@end deftypefn")
+{
+  octave_value retval;
+
+  if (args.length () == 1)
+    retval = args(0).is_map ();
+  else
+    print_usage ();
+
+  return retval;
+}
+
+DEFUN (fieldnames, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {} fieldnames (@var{struct})\n\
+Return a cell array of strings naming the elements of the structure\n\
+@var{struct}.  It is an error to call @code{fieldnames} with an\n\
+argument that is not a structure.\n\
+@end deftypefn")
+{
+  octave_value retval;
+
+  int nargin = args.length ();
+
+  if (nargin == 1)
+    {
+      octave_value arg = args(0);
+
+      if (arg.is_map () || arg.is_object ())
+        {
+          octave_map m = arg.map_value ();
+
+          string_vector keys = m.fieldnames ();
+
+          if (keys.length () == 0)
+            retval = Cell (0, 1);
+          else
+            retval = Cell (keys);
+        }
+      else
+        gripe_wrong_type_arg ("fieldnames", args(0));
+    }
+  else
+    print_usage ();
+
+  return retval;
+}
+
+/*
+%!# test preservation of fieldname order
+%!test
+%!  x(3).d=1; x(2).a=2; x(1).b=3; x(2).c=3;
+%!  assert(fieldnames(x), {"d"; "a"; "b"; "c"});
+*/
+
+DEFUN (isfield, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {} isfield (@var{expr}, @var{name})\n\
+Return true if the expression @var{expr} is a structure and it\n\
+includes an element named @var{name}.  If @var{name} is a cell\n\
+array, a logical array of equal dimension is returned.\n\
+@end deftypefn")
+{
+  octave_value retval;
+
+  int nargin = args.length ();
+
+  if (nargin == 2)
+    {
+      retval = false;
+
+      if (args(0).is_map ())
+        {
+          octave_map m = args(0).map_value ();
+
+          // FIXME -- should this work for all types that can do
+          // structure reference operations?
+
+          if (args(1).is_string ())
+            {
+              std::string key = args(1).string_value ();
+
+              retval = m.isfield (key);
+            }
+          else if (args(1).is_cell ())
+            {
+              Cell c = args(1).cell_value ();
+              boolNDArray bm (c.dims ());
+              octave_idx_type n = bm.numel ();
+
+              for (octave_idx_type i = 0; i < n; i++)
+                {
+                  if (c(i).is_string ())
+                    {
+                      std::string key = c(i).string_value ();
+
+                      bm(i) = m.isfield (key);
+                    }
+                  else
+                    bm(i) = false;
+                }
+
+              retval = bm;
+            }
+        }
+    }
+  else
+    print_usage ();
+
+  return retval;
+}
+
+DEFUN (nfields, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {} nfields (@var{s})\n\
+Return the number of fields of the structure @var{s}.\n\
+@end deftypefn")
+{
+  octave_value retval;
+
+  int nargin = args.length ();
+
+  if (nargin == 1 && args(0).is_map ())
+    {
+      retval = static_cast<double> (args(0).nfields ());
+    }
+  else
+    print_usage ();
+
+  return retval;
+}
+
+/*
+%!# test isfield
+%!test
+%!  x(3).d=1; x(2).a=2; x(1).b=3; x(2).c=3;
+%!  assert (isfield (x, "b"));
+%!assert( isfield( struct("a", "1"), "a"));
+%!assert( isfield( {1}, "c"), logical (0));
+%!assert( isfield( struct("a", "1"), 10), logical (0));
+%!assert( isfield( struct("a", "b"), "a "), logical (0));
+
+*/
+
+DEFUN (cell2struct, args, ,
+       "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {} cell2struct (@var{cell}, @var{fields}, @var{dim})\n\
+Convert @var{cell} to a structure.  The number of fields in @var{fields}\n\
+must match the number of elements in @var{cell} along dimension @var{dim},\n\
+that is @code{numel (@var{fields}) == size (@var{cell}, @var{dim})}.\n\
+\n\
+@example\n\
+@group\n\
+A = cell2struct (@{'Peter', 'Hannah', 'Robert';\n\
+                   185, 170, 168@},\n\
+                 @{'Name','Height'@}, 1);\n\
+A(1)\n\
+     @result{} ans =\n\
+        @{\n\
+          Name   = Peter\n\
+          Height = 185\n\
+        @}\n\
+\n\
+@end group\n\
+@end example\n\
+@end deftypefn")
+{
+  octave_value retval;
+
+  if (args.length () == 3)
+    {
+      if (! args(0).is_cell ()) 
+        error ("cell2struct: first argument must be a cell");
+      else if (! (args(1).is_cellstr () || args(1).is_char_matrix ()))
+        error ("cell2struct: second argument must be a cell array of strings or a character matrix");
+      else if (! args(2).is_real_scalar ())
+        error ("cell2struct: third argument must be a real scalar");
+      else
+        {
+          const Cell vals = args(0).cell_value ();
+          const Array<std::string> fields = args(1).cellstr_value ();
+          int dim = args(2).int_value () - 1;
+          octave_idx_type ext = 0;
+          
+          if (dim < 0)
+            error ("cell2struct: dim must be a valid dimension");
+          else
+            {
+              ext = vals.ndims () > dim ? vals.dims ()(dim) : 1;
+              if (ext != fields.numel ())
+                error ("cell2struct: number of fields doesn't match dimension");
+            }
+
+
+          if (! error_state)
+            {
+              int nd = std::max (dim+1, vals.ndims ());
+              // result dimensions.
+              dim_vector rdv = vals.dims ().redim (nd);
+
+              assert (ext == rdv(dim));
+              if (nd == 2)
+                {
+                  rdv(0) = rdv(1-dim);
+                  rdv(1) = 1;
+                }
+              else
+                {
+                  for (int i =  dim + 1; i < nd; i++)
+                    rdv(i-1) = rdv(i);
+
+                  rdv.resize (nd-1);
+                }
+
+              octave_map map (rdv);
+              Array<idx_vector> ia (nd, 1, idx_vector::colon);
+
+              for (octave_idx_type i = 0; i < ext; i++)
+                {
+                  ia(dim) = i;
+                  map.setfield (fields(i), vals.index (ia).reshape (rdv));
+                }
+
+              retval = map;
+            }
+        }
+    }
+  else
+    print_usage ();
+
+  return retval;
+}
+
+/*
+%!# test cell2struct versus struct2cell
+%!test
+%!  keys = cellstr (char (floor (rand (100,10)*24+65)))';
+%!  vals = mat2cell(rand (100,1), ones (100,1), 1)';
+%!  s = struct ([keys; vals]{:});
+%!  t = cell2struct (vals, keys, 2);
+%!  assert (s, t);
+%!  assert (struct2cell (s), vals');
+%!  assert (fieldnames (s), keys');
+*/
+
+
+// So we can call Fcellstr directly.
+extern octave_value_list Fcellstr (const octave_value_list& args, int);
+
+DEFUN (rmfield, args, ,
+       "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {} rmfield (@var{s}, @var{f})\n\
+Return a copy of the structure (array) @var{s} with the field @var{f} removed.\n\
+If @var{f} is a cell array of strings or a character array, remove the\n\
+named fields.\n\
+@seealso{cellstr, iscellstr, setfield}\n\
+@end deftypefn")
+{
+  octave_value retval;
+
+  int nargin = args.length ();
+
+  if (nargin == 2)
+    {
+      octave_map m = args(0).map_value ();
+
+      octave_value_list fval = Fcellstr (args(1), 1);
+
+      if (! error_state)
+        {
+          Cell fcell = fval(0).cell_value ();
+
+          for (int i = 0; i < fcell.numel (); i++)
+            {
+              std::string key = fcell(i).string_value ();
+
+              if (m.isfield (key))
+                m.rmfield (key);
+              else
+                {
+                  error ("rmfield: structure does not contain field %s",
+                         key.c_str ());
+
+                  break;
+                }
+            }
+
+          if (! error_state)
+            retval = m;
+        }
+    }
+  else
+    print_usage ();
+
+  return retval;
+}
+
+/*
+%!# test rmfield
+%!test
+%!  x(3).d=1; x(2).a=2; x(1).b=3; x(2).c=3; x(6).f="abc123";
+%!  y = rmfield (x, {"a", "f"});
+%!  assert (fieldnames (y), {"d"; "b"; "c"});
+%!  assert (size (y), [1, 6]);
+*/
+
--- 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 (); }
@@ -111,8 +115,8 @@
   octave_value reshape (const dim_vector& new_dims) const
     { 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_value resize (const dim_vector& dv, bool fill = false) const
+    { octave_map tmap = map; tmap.resize (dv, fill); 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;
 
@@ -149,10 +153,16 @@
 
   mxArray *as_mxArray (void) const;
 
+  octave_value
+  fast_elem_extract (octave_idx_type n) const;
+
+  bool
+  fast_elem_insert (octave_idx_type n, const octave_value& x);
+
 protected:
 
   // The associative array used to manage the structure data.
-  Octave_map map;
+  octave_map map;
 
 private:
 
@@ -161,4 +171,123 @@
   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 fill = false) const
+    { octave_map tmap = map; tmap.resize (dv, fill); 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;
+
+  bool fast_elem_insert_self (void *where, builtin_type_t btyp) 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,18 @@
 #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_function *
 octave_value::function_value (bool silent) const
 {
@@ -2569,7 +2587,7 @@
         case '(':
           {
             if (type.length () > 1 && type[1] == '.')
-              retval = Octave_map ();
+              retval = octave_map ();
             else
               retval = octave_value (rhs.empty_clone ());
           }
@@ -2580,7 +2598,7 @@
           break;
 
         case '.':
-          retval = Octave_map ();
+          retval = octave_scalar_map ();
           break;
 
         default:
@@ -2629,6 +2647,7 @@
   octave_sparse_matrix::register_type ();
   octave_sparse_complex_matrix::register_type ();
   octave_struct::register_type ();
+  octave_scalar_struct::register_type ();
   octave_class::register_type ();
   octave_cs_list::register_type ();
   octave_magic_colon::register_type ();
--- 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,9 @@
   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;
 
   string_vector map_keys (void) const
     { return rep->map_keys (); }
--- a/src/pt-mat.cc
+++ b/src/pt-mat.cc
@@ -70,14 +70,14 @@
         all_sq_str (false), all_dq_str (false),
         some_str (false), all_real (false), all_cmplx (false),
         all_mt (true), any_sparse (false), any_class (false),
-        class_nm (), ok (false)
+        all_1x1 (false), class_nm (), ok (false)
     { }
 
     tm_row_const_rep (const tree_argument_list& row)
       : count (1), dv (0, 0), all_str (false), all_sq_str (false),
         some_str (false), all_real (false), all_cmplx (false),
         all_mt (true), any_sparse (false), any_class (false),
-        class_nm (), ok (false)
+        all_1x1 (! row.empty ()), class_nm (), ok (false)
     { init (row); }
 
     ~tm_row_const_rep (void) { }
@@ -95,6 +95,7 @@
     bool all_mt;
     bool any_sparse;
     bool any_class;
+    bool all_1x1;
 
     std::string class_nm;
 
@@ -171,6 +172,7 @@
   bool all_empty_p (void) const { return rep->all_mt; }
   bool any_sparse_p (void) const { return rep->any_sparse; }
   bool any_class_p (void) const { return rep->any_class; }
+  bool all_1x1_p (void) const { return rep->all_1x1; }
 
   std::string class_name (void) const { return rep->class_nm; }
 
@@ -249,6 +251,10 @@
         retval = c2;
       else if (c1_is_logical && c2_is_logical)
         retval = c1;
+      else if (c1 == "struct" && c2 == c1)
+        retval = c1;
+      else if (c1 == "cell" && c2 == c1)
+        retval = c1;
     }
 
   return retval;    
@@ -322,6 +328,8 @@
   if (!any_class && val.is_object ())
     any_class = true;
 
+  all_1x1 = all_1x1 && val.numel () == 1;
+
   return true;
 }
 
@@ -416,6 +424,7 @@
   bool all_empty_p (void) const { return all_mt; }
   bool any_sparse_p (void) const { return any_sparse; }
   bool any_class_p (void) const { return any_class; }
+  bool all_1x1_p (void) const { return all_1x1; }
 
   std::string class_name (void) const { return class_nm; }
 
@@ -434,6 +443,7 @@
   bool all_mt;
   bool any_sparse;
   bool any_class;
+  bool all_1x1;
 
   std::string class_nm;
 
@@ -458,6 +468,7 @@
   all_cmplx = true;
   any_sparse = false;
   any_class = false;
+  all_1x1 = ! empty ();
 
   bool first_elem = true;
 
@@ -503,6 +514,8 @@
           if (!any_class && tmp.any_class_p ())
             any_class = true;
 
+          all_1x1 = all_1x1 && tmp.all_1x1_p ();
+
           append (tmp);
         }
       else
@@ -677,6 +690,7 @@
     {
       // If possible, forward the operation to liboctave.
       // Single row.
+      // FIXME: optimize all scalars case.
       tm_row_const& row = tmp.front ();
       octave_idx_type ncols = row.length (), i = 0;
       OCTAVE_LOCAL_BUFFER (Array<T>, array_list, ncols);
@@ -748,6 +762,49 @@
   result = Sparse<T>::cat (0, nrows, sparse_row_list);
 }
 
+template<class MAP>
+static void 
+single_type_concat (octave_map& result,
+                    const dim_vector& dv,
+                    tm_const& tmp)
+{
+  if (dv.any_zero ())
+    {
+      result = octave_map (dv);
+      return;
+    }
+
+  octave_idx_type nrows = tmp.length (), j = 0;
+  OCTAVE_LOCAL_BUFFER (octave_map, map_row_list, nrows);
+  for (tm_const::iterator p = tmp.begin (); p != tmp.end (); p++)
+    {
+      tm_row_const row = *p;
+      octave_idx_type ncols = row.length (), i = 0;
+      OCTAVE_LOCAL_BUFFER (MAP, map_list, ncols);
+
+      for (tm_row_const::iterator q = row.begin ();
+           q != row.end () && ! error_state;
+           q++)
+        {
+          octave_quit ();
+
+          // Use 0x0 in place of all empty arrays to allow looser rules.
+          // If MAP is octave_scalar_map, the condition is vacuously true.
+          if (! q->is_empty ())
+            map_list[i] = octave_value_extract<MAP> (*q);
+          i++;
+        }
+
+      octave_map mtmp = octave_map::cat (1, ncols, map_list);
+      // Use 0x0 in place of all empty arrays to allow looser rules.
+      if (! mtmp.is_empty ())
+        map_row_list[j] = mtmp;
+      j++;
+    }
+
+  result = octave_map::cat (0, nrows, map_row_list);
+}
+
 template<class TYPE>
 static octave_value 
 do_single_type_concat (const dim_vector& dv,
@@ -760,6 +817,21 @@
   return result;
 }
 
+template<>
+octave_value 
+do_single_type_concat<octave_map> (const dim_vector& dv,
+                                   tm_const& tmp)
+{
+  octave_map result;
+
+  if (tmp.all_1x1_p ())
+    single_type_concat<octave_scalar_map> (result, dv, tmp);
+  else
+    single_type_concat<octave_map> (result, dv, tmp);
+
+  return result;
+}
+
 template<class TYPE, class OV_TYPE>
 static octave_value 
 do_single_type_concat_no_mutate (const dim_vector& dv,
@@ -929,6 +1001,10 @@
         retval = do_single_type_concat<uint32NDArray> (dv, tmp);
       else if (result_type == "uint64")
         retval = do_single_type_concat<uint64NDArray> (dv, tmp);
+      else if (result_type == "cell")
+        retval = do_single_type_concat<Cell> (dv, tmp);
+      else if (result_type == "struct")
+        retval = do_single_type_concat<octave_map> (dv, tmp);
       else
         {
           // The line below might seem crazy, since we take a copy of
--- a/src/syscalls.cc
+++ b/src/syscalls.cc
@@ -57,10 +57,10 @@
 #include "variables.h"
 #include "input.h"
 
-static Octave_map
+static octave_scalar_map
 mk_stat_map (const base_file_stat& fs)
 {
-  Octave_map m;
+  octave_scalar_map m;
 
   m.assign ("dev", static_cast<double> (fs.dev ()));
   m.assign ("ino", fs.ino ());
@@ -1202,7 +1202,7 @@
     {
       octave_uname sysinfo;
 
-      Octave_map m;
+      octave_scalar_map m;
 
       m.assign ("sysname", sysinfo.sysname ());
       m.assign ("nodename", sysinfo.nodename ());
--- a/src/toplev.cc
+++ b/src/toplev.cc
@@ -234,12 +234,22 @@
   return retval;
 }
 
-Octave_map
+// Use static fields for the best efficiency.
+// NOTE: C++0x will allow these two to be merged into one.
+static const char *bt_fieldnames[] = { "file", "name", "line",
+    "column", "scope", "context", 0 };
+static const octave_fields bt_fields (bt_fieldnames);
+
+octave_map
+octave_call_stack::empty_backtrace (void)
+{
+  return octave_map (dim_vector (0, 1), bt_fields);
+}
+
+octave_map
 octave_call_stack::do_backtrace (size_t nskip,
                                  octave_idx_type& curr_user_frame) const
 {
-  Octave_map retval;
-
   size_t user_code_frames = do_num_user_code_frames (curr_user_frame);
 
   size_t nframes = nskip <= user_code_frames ? user_code_frames - nskip : 0;
@@ -247,21 +257,14 @@
   // Our list is reversed.
   curr_user_frame = nframes - curr_user_frame - 1;
 
-  Cell keys (6, 1);
+  octave_map retval (dim_vector (nframes, 1), bt_fields);
 
-  keys(0) = "file";
-  keys(1) = "name";
-  keys(2) = "line";
-  keys(3) = "column";
-  keys(4) = "scope";
-  keys(5) = "context";
-
-  Cell file (nframes, 1);
-  Cell name (nframes, 1);
-  Cell line (nframes, 1);
-  Cell column (nframes, 1);
-  Cell scope (nframes, 1);
-  Cell context (nframes, 1);
+  Cell& file = retval.contents (0);
+  Cell& name = retval.contents (1);
+  Cell& line = retval.contents (2);
+  Cell& column = retval.contents (3);
+  Cell& scope = retval.contents (4);
+  Cell& context = retval.contents (5);
 
   if (nframes > 0)
     {
@@ -306,13 +309,6 @@
                 }
             }
         }
-
-      retval.assign ("file", file);
-      retval.assign ("name", name);
-      retval.assign ("line", line);
-      retval.assign ("column", column);
-      retval.assign ("scope", scope);
-      retval.assign ("context", context);
     }
 
   return retval;
--- a/src/toplev.h
+++ b/src/toplev.h
@@ -266,12 +266,14 @@
       instance->do_goto_base_frame ();
   }
 
-  static Octave_map backtrace (size_t nskip, octave_idx_type& curr_user_frame)
+  static octave_map backtrace (size_t nskip, octave_idx_type& curr_user_frame)
   {
     return instance_ok ()
-      ? instance->do_backtrace (nskip, curr_user_frame) : Octave_map ();
+      ? instance->do_backtrace (nskip, curr_user_frame) : octave_map ();
   }
 
+  static octave_map empty_backtrace (void);
+
   static void pop (void)
   {
     if (instance_ok ())
@@ -389,7 +391,7 @@
       }
   }
 
-  Octave_map do_backtrace (size_t nskip,
+  octave_map do_backtrace (size_t nskip,
                            octave_idx_type& curr_user_frame) const;
 
   bool do_goto_frame (size_t n, bool verbose);