diff src/ov-struct.cc @ 10742:604e13a89c7f

initial code for structs rewrite
author Jaroslav Hajek <highegg@gmail.com>
date Tue, 22 Jun 2010 15:22:36 +0200
parents e0ba186b242b
children 58c1b5402588
line wrap: on
line diff
--- a/src/ov-struct.cc	Mon Jun 21 22:35:11 2010 -0700
+++ b/src/ov-struct.cc	Tue Jun 22 15:22:36 2010 +0200
@@ -51,6 +51,17 @@
 
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(octave_struct, "struct", "struct");
 
+octave_base_value *
+octave_struct::try_narrowing_conversion (void)
+{
+  octave_base_value *retval = 0;
+
+  if (numel () == 1)
+    retval = new octave_scalar_struct (map.checkelem (0));
+
+  return retval;
+}
+
 Cell
 octave_struct::dotref (const octave_value_list& idx, bool auto_add)
 {
@@ -60,7 +71,7 @@
 
   std::string nm = idx(0).string_value ();
 
-  Octave_map::const_iterator p = map.seek (nm);
+  octave_map::const_iterator p = map.seek (nm);
 
   if (p != map.end ())
     retval = map.contents (p);
@@ -131,7 +142,7 @@
               }
           }
         else
-          retval(0) = map.index (idx.front ());
+          retval(0) = do_index_op (idx.front ());
       }
       break;
 
@@ -197,7 +208,7 @@
               }
           }
         else
-          retval = map.index (idx.front (), auto_add);
+          retval = do_index_op (idx.front (), auto_add);
       }
       break;
 
@@ -245,7 +256,7 @@
   octave_value retval;
 
   if (type.length () > 0 && type[0] == '.' && ! val.is_map ())
-    retval = Octave_map ();
+    retval = octave_map ();
   else
     retval = val;
 
@@ -297,11 +308,11 @@
                 std::string next_type = type.substr (2);
 
                 Cell tmpc (1, 1);
-                Octave_map::iterator pkey = map.seek (key);
+                octave_map::iterator pkey = map.seek (key);
                 if (pkey != map.end ())
                   {
-                    pkey->second.make_unique ();
-                    tmpc = pkey->second.index (idx.front (), true);
+                    map.contents (pkey).make_unique ();
+                    tmpc = map.contents (pkey).index (idx.front (), true);
                   }
 
                 // FIXME: better code reuse? cf. octave_cell::subsasgn and the case below.
@@ -347,11 +358,11 @@
             std::string next_type = type.substr (1);
 
             Cell tmpc (1, 1);
-            Octave_map::iterator pkey = map.seek (key);
+            octave_map::iterator pkey = map.seek (key);
             if (pkey != map.end ())
               {
-                pkey->second.make_unique ();
-                tmpc = pkey->second;
+                map.contents (pkey).make_unique ();
+                tmpc = map.contents (pkey);
               }
 
             // FIXME: better code reuse?
@@ -420,7 +431,7 @@
                           tmp_cell = tmp_cell.reshape (didx);
 
 
-                        map.assign (idxf, key, tmp_cell);
+                        map.contents (key).assign (idxf, tmp_cell);
 
                         if (! error_state)
                           {
@@ -432,12 +443,12 @@
                       }
                     else 
                       {
-                        const Octave_map& cmap = const_cast<const Octave_map &> (map);
+                        const octave_map& cmap = const_cast<const octave_map &> (map);
                         // cast map to const reference to avoid forced key insertion.
                         if (idxf.all_scalars () 
                             || cmap.contents (key).index (idxf, true).numel () == 1)
                           {
-                            map.assign (idxf, key, t_rhs.storable_value ());
+                            map.contents (key).assign (idxf, Cell (t_rhs.storable_value ()));
                             if (! error_state)
                               {
                                 count++;
@@ -457,7 +468,7 @@
               {
                 if (t_rhs.is_map())
                   {
-                    Octave_map rhs_map = t_rhs.map_value ();
+                    octave_map rhs_map = t_rhs.map_value ();
 
                     if (! error_state)
                       {
@@ -478,7 +489,7 @@
                   {
                     if (t_rhs.is_null_value()) 
                       {
-                        map.maybe_delete_elements (idx.front());
+                        map.delete_elements (idx.front());
 
                         if (! error_state)
                           {
@@ -514,11 +525,14 @@
                 if (numel () == tmp_cell.numel ())
                   tmp_cell = tmp_cell.reshape (dims ());
 
-                map.assign (key, tmp_cell);
+                map.setfield (key, tmp_cell);
               }
             else
-              // Regularize a null matrix if stored into a struct component.
-              map.assign (key, t_rhs.storable_value ());
+              {
+                Cell tmp_cell(1, 1);
+                tmp_cell(0) = t_rhs.storable_value ();
+                map.setfield (key, tmp_cell);
+              }
 
             if (! error_state)
               {
@@ -547,7 +561,7 @@
 octave_value
 octave_struct::do_index_op (const octave_value_list& idx, bool resize_ok)
 {
-  // Octave_map handles indexing itself.
+  // octave_map handles indexing itself.
   return map.index (idx, resize_ok);
 }
 
@@ -558,7 +572,7 @@
 
   size_t retval = 0;
 
-  for (Octave_map::const_iterator p = map.begin (); p != map.end (); p++)
+  for (octave_map::const_iterator p = map.begin (); p != map.end (); p++)
     {
       std::string key = map.key (p);
 
@@ -606,7 +620,7 @@
           increment_indent_level ();
         }
 
-      string_vector key_list = map.keys ();
+      string_vector key_list = map.fieldnames ();
 
       for (octave_idx_type i = 0; i < key_list.length (); i++)
         {
@@ -693,6 +707,996 @@
 %!fail("struct('1',2,'3')","struct expects alternating \"field\", VALUE pairs");
 */
 
+bool
+octave_struct::save_ascii (std::ostream& os)
+{
+  octave_map m = map_value ();
+
+  octave_idx_type nf = m.nfields ();
+
+  const dim_vector dv = dims ();
+
+  os << "# ndims: " << dv.length () << "\n";
+
+  for (int i = 0; i < dv.length (); i++)
+    os << " " << dv (i);
+  os << "\n";
+
+  os << "# length: " << nf << "\n";
+
+  // Iterating over the list of keys will preserve the order of the
+  // fields.
+  string_vector keys = m.fieldnames ();
+
+  for (octave_idx_type i = 0; i < nf; i++)
+    {
+      std::string key = keys(i);
+
+      octave_value val = map.contents (key);
+
+      bool b = save_ascii_data (os, val, key, false, 0);
+      
+      if (! b)
+        return os;
+    }
+
+  return true;
+}
+
+bool 
+octave_struct::load_ascii (std::istream& is)
+{
+  octave_idx_type len = 0;
+  dim_vector dv (1, 1);
+  bool success = true;
+
+  // KLUGE: earlier Octave versions did not save extra dimensions with struct,
+  // and as a result did not preserve dimensions for empty structs.
+  // The default dimensions were 1x1, which we want to preserve.
+  string_vector keywords(2);
+
+  keywords[0] = "ndims";
+  keywords[1] = "length";
+
+  std::string kw;
+
+  if (extract_keyword (is, keywords, kw, len, true))
+    {
+      if (kw == keywords[0])
+        {
+          int mdims = std::max (static_cast<int> (len), 2);
+          dv.resize (mdims);
+          for (int i = 0; i < mdims; i++)
+            is >> dv(i);
+
+          success = extract_keyword (is, keywords[1], len);
+        }
+    }
+  else
+    success = false;
+
+  if (success && len >= 0)
+    {
+      if (len > 0)
+        {
+          octave_map m (dv);
+
+          for (octave_idx_type j = 0; j < len; j++)
+            {
+              octave_value t2;
+              bool dummy;
+
+              // recurse to read cell elements
+              std::string nm
+                = read_ascii_data (is, std::string (), dummy, t2, j);
+
+              if (!is)
+                break;
+
+              Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
+
+              if (error_state)
+                {
+                  error ("load: internal error loading struct elements");
+                  return false;
+                }
+
+              m.setfield (nm, tcell);
+            }
+
+          if (is) 
+            map = m;
+          else
+            {
+              error ("load: failed to load structure");
+              success = false;
+            }
+        }
+      else if (len == 0 )
+        map = octave_map (dv);
+      else
+        panic_impossible ();
+    }
+  else {
+    error ("load: failed to extract number of elements in structure");
+    success = false;
+  }
+
+  return success;
+}
+
+bool 
+octave_struct::save_binary (std::ostream& os, bool& save_as_floats)
+{
+  octave_map m = map_value ();
+
+  octave_idx_type nf = m.nfields ();
+
+  dim_vector d = dims ();
+  if (d.length () < 1)
+    return false;
+
+  // Use negative value for ndims
+  int32_t di = - d.length();
+  os.write (reinterpret_cast<char *> (&di), 4);
+  for (int i = 0; i < d.length (); i++)
+    {
+      di = d(i);
+      os.write (reinterpret_cast<char *> (&di), 4);
+    }
+  
+  int32_t len = nf;
+  os.write (reinterpret_cast<char *> (&len), 4);
+
+  // Iterating over the list of keys will preserve the order of the
+  // fields.
+  string_vector keys = m.fieldnames ();
+
+  for (octave_idx_type i = 0; i < nf; i++)
+    {
+      std::string key = keys(i);
+
+      octave_value val = map.contents (key);
+
+      bool b = save_binary_data (os, val, key, "", 0, save_as_floats);
+      
+      if (! b)
+        return os;
+    }
+
+  return true;
+}
+
+bool 
+octave_struct::load_binary (std::istream& is, bool swap,
+                            oct_mach_info::float_format fmt)
+{
+  bool success = true;
+  int32_t len;
+  if (! is.read (reinterpret_cast<char *> (&len), 4))
+    return false;
+  if (swap)
+    swap_bytes<4> (&len);
+
+  dim_vector dv (1, 1);
+
+  if (len < 0)
+    {
+      // We have explicit dimensions.
+      int mdims = -len;
+
+      int32_t di;
+      dv.resize (mdims);
+
+      for (int i = 0; i < mdims; i++)
+        {
+          if (! is.read (reinterpret_cast<char *> (&di), 4))
+            return false;
+          if (swap)
+            swap_bytes<4> (&di);
+          dv(i) = di;
+        }
+
+      if (! is.read (reinterpret_cast<char *> (&len), 4))
+        return false;
+      if (swap)
+        swap_bytes<4> (&len);
+    }
+
+  if (len > 0)
+    {
+      octave_map m (dv);
+
+      for (octave_idx_type j = 0; j < len; j++)
+        {
+          octave_value t2;
+          bool dummy;
+          std::string doc;
+
+          // recurse to read cell elements
+          std::string nm = read_binary_data (is, swap, fmt, std::string (), 
+                                             dummy, t2, doc);
+
+          if (!is)
+            break;
+
+          Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
+ 
+          if (error_state)
+            {
+              error ("load: internal error loading struct elements");
+              return false;
+            }
+
+          m.setfield (nm, tcell);
+        }
+
+      if (is) 
+        map = m;
+      else
+        {
+          error ("load: failed to load structure");
+          success = false;
+        }
+    }
+  else if (len == 0)
+    map = octave_map (dv);
+  else
+    success = false;
+
+  return success;
+}
+
+#if defined (HAVE_HDF5)
+
+bool
+octave_struct::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats)
+{
+  hid_t data_hid = -1;
+
+#if HAVE_HDF5_18
+  data_hid = H5Gcreate (loc_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
+#else
+  data_hid = H5Gcreate (loc_id, name, 0);
+#endif
+  if (data_hid < 0) return false;
+
+  // recursively add each element of the structure to this group
+  octave_map m = map_value ();
+
+  octave_idx_type nf = m.nfields ();
+
+  // Iterating over the list of keys will preserve the order of the
+  // fields.
+  string_vector keys = m.fieldnames ();
+
+  for (octave_idx_type i = 0; i < nf; i++)
+    {
+      std::string key = keys(i);
+
+      octave_value val = map.contents (key);
+
+      bool retval2 = add_hdf5_data (data_hid, val, key, "", false, 
+                                    save_as_floats);
+
+      if (! retval2)
+        break;
+    }
+
+  H5Gclose (data_hid);
+
+  return true;
+}
+
+bool 
+octave_struct::load_hdf5 (hid_t loc_id, const char *name)
+{
+  bool retval = false;
+
+  hdf5_callback_data dsub;
+
+  herr_t retval2 = 0;
+  octave_map m (dim_vector (1, 1));
+  int current_item = 0;
+  hsize_t num_obj = 0;
+#if HAVE_HDF5_18
+  hid_t group_id = H5Gopen (loc_id, name, H5P_DEFAULT);
+#else
+  hid_t group_id = H5Gopen (loc_id, name);
+#endif
+  H5Gget_num_objs (group_id, &num_obj);
+  H5Gclose (group_id);
+
+  // FIXME -- fields appear to be sorted alphabetically on loading.
+  // Why is that happening?
+
+  while (current_item < static_cast<int> (num_obj)
+         && (retval2 = H5Giterate (loc_id, name, &current_item,
+                                   hdf5_read_next_data, &dsub)) > 0)
+    {
+      octave_value t2 = dsub.tc;
+
+      Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
+ 
+      if (error_state)
+        {
+          error ("load: internal error loading struct elements");
+          return false;
+        }
+
+      m.setfield (dsub.name, tcell);
+
+    }
+
+  if (retval2 >= 0)
+    {
+      map = m;
+      retval = true;
+    }
+  
+  return retval;
+}
+
+#endif
+
+mxArray *
+octave_struct::as_mxArray (void) const
+{
+  int nf = nfields ();
+  string_vector kv = map_keys ();
+
+  OCTAVE_LOCAL_BUFFER (const char *, f, nf);
+
+  for (int i = 0; i < nf; i++)
+    f[i] = kv[i].c_str ();
+
+  mxArray *retval = new mxArray (dims (), nf, f);
+
+  mxArray **elts = static_cast<mxArray **> (retval->get_data ());
+
+  mwSize nel = numel ();
+
+  mwSize ntot = nf * nel;
+
+  for (int i = 0; i < nf; i++)
+    {
+      Cell c = map.contents (kv[i]);
+
+      const octave_value *p = c.data ();
+
+      mwIndex k = 0;
+      for (mwIndex j = i; j < ntot; j += nf)
+        elts[j] = new mxArray (p[k++]);
+    }
+
+  return retval;
+}
+
+DEFINE_OCTAVE_ALLOCATOR(octave_scalar_struct);
+
+DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(octave_scalar_struct, "scalar struct", "struct");
+
+octave_value
+octave_scalar_struct::dotref (const octave_value_list& idx, bool auto_add)
+{
+  assert (idx.length () == 1);
+
+  std::string nm = idx(0).string_value ();
+
+  octave_value retval = map.getfield (nm);
+
+  if (! auto_add && retval.is_undefined ())
+    error ("structure has no member `%s'", nm.c_str ());
+
+  return retval;
+}
+
+octave_value
+octave_scalar_struct::subsref (const std::string& type,
+                               const std::list<octave_value_list>& idx)
+{
+  octave_value retval;
+
+  if (type[0] == '.')
+    {
+      int skip = 1;
+
+      retval = dotref (idx.front ());
+
+      if (idx.size () > 1)
+        retval = retval.next_subsref (type, idx, skip);
+    }
+  else
+    retval = to_array ().subsref (type, idx);
+
+  return retval;
+}
+
+octave_value_list
+octave_scalar_struct::subsref (const std::string& type,
+                               const std::list<octave_value_list>& idx,
+                               int nargout)
+{
+  octave_value_list retval;
+
+  if (type[0] == '.')
+    {
+      int skip = 1;
+
+      retval(0) = dotref (idx.front ());
+
+      if (idx.size () > 1)
+        retval = retval(0).next_subsref (nargout, type, idx, skip);
+    }
+  else
+    retval = to_array ().subsref (type, idx, nargout);
+
+  return retval;
+}
+
+octave_value
+octave_scalar_struct::subsref (const std::string& type,
+                               const std::list<octave_value_list>& idx,
+                               bool auto_add)
+{
+  octave_value retval;
+
+  if (type[0] == '.')
+    {
+      int skip = 1;
+
+      retval = dotref (idx.front (), auto_add);
+
+      if (idx.size () > 1)
+        retval = retval.next_subsref (auto_add, type, idx, skip);
+    }
+  else
+    retval = to_array ().subsref (type, idx, auto_add);
+
+  return retval;
+}
+
+/*
+%!test
+%! x(1).a.a = 1; x(2).a.a = 2;
+%! assert (size (x), [1, 2]);
+%! assert (x(1).a.a, 1);
+%! assert (x(2).a.a, 2);
+*/
+
+octave_value
+octave_scalar_struct::numeric_conv (const octave_value& val,
+                                    const std::string& type)
+{
+  octave_value retval;
+
+  if (type.length () > 0 && type[0] == '.' && ! val.is_map ())
+    retval = octave_map ();
+  else
+    retval = val;
+
+  return retval;
+}
+
+octave_value
+octave_scalar_struct::subsasgn (const std::string& type,
+                                const std::list<octave_value_list>& idx,
+                                const octave_value& rhs)
+{
+  octave_value retval;
+
+  if (idx.front ().empty ())
+    {
+      error ("missing index in indexed assignment");
+      return retval;
+    }
+
+  if (type[0] == '.')
+    {
+      int n = type.length ();
+
+      octave_value t_rhs = rhs;
+
+      octave_value_list key_idx = idx.front ();
+
+      assert (key_idx.length () == 1);
+
+      std::string key = key_idx(0).string_value ();
+
+      if (n > 1)
+        {
+          std::list<octave_value_list> next_idx (idx);
+
+          next_idx.erase (next_idx.begin ());
+
+          std::string next_type = type.substr (1);
+
+          octave_value tmp;
+          octave_map::iterator pkey = map.seek (key);
+          if (pkey != map.end ())
+            {
+              map.contents (pkey).make_unique ();
+              tmp = map.contents (pkey);
+            }
+
+          if (! error_state)
+            {
+              if (! tmp.is_defined () || tmp.is_zero_by_zero ())
+                {
+                  tmp = octave_value::empty_conv (next_type, rhs);
+                  tmp.make_unique (); // probably a no-op.
+                }
+              else
+                // optimization: ignore the copy still stored inside our map.
+                tmp.make_unique (1);
+
+              if (! error_state)
+                t_rhs = tmp.subsasgn (next_type, next_idx, rhs);
+            }
+        }
+
+      if (! error_state)
+        map.setfield (key, t_rhs.storable_value ());
+      else
+        gripe_failed_assignment ();
+    }
+  else
+    {
+      // Forward this case to octave_struct.
+      octave_value tmp (new octave_struct (octave_map (map)));
+      retval = tmp.subsasgn (type, idx, rhs);
+    }
+
+  return retval;
+}
+
+octave_value
+octave_scalar_struct::do_index_op (const octave_value_list& idx, bool resize_ok)
+{
+  // octave_map handles indexing itself.
+  return octave_map (map).index (idx, resize_ok);
+}
+
+size_t
+octave_scalar_struct::byte_size (void) const
+{
+  // Neglect the size of the fieldnames.
+
+  size_t retval = 0;
+
+  for (octave_map::const_iterator p = map.begin (); p != map.end (); p++)
+    {
+      std::string key = map.key (p);
+
+      octave_value val = octave_value (map.contents (p));
+
+      retval += val.byte_size ();
+    }
+
+  return retval;
+}
+
+void
+octave_scalar_struct::print (std::ostream& os, bool) const
+{
+  print_raw (os);
+}
+
+void
+octave_scalar_struct::print_raw (std::ostream& os, bool) const
+{
+  unwind_protect frame;
+
+  frame.protect_var (Vstruct_levels_to_print);
+
+  if (Vstruct_levels_to_print >= 0)
+    {
+      bool print_keys_only = Vstruct_levels_to_print-- == 0;
+
+      indent (os);
+      os << "{";
+      newline (os);
+
+      increment_indent_level ();
+
+      octave_idx_type n = 1;
+
+      if (n != 1 || print_keys_only)
+        {
+          indent (os);
+          dim_vector dv = dims ();
+          os << dv.str () << " struct array containing the fields:";
+          newline (os);
+          newline (os);
+
+          increment_indent_level ();
+        }
+
+      string_vector key_list = map.fieldnames ();
+
+      for (octave_idx_type i = 0; i < key_list.length (); i++)
+        {
+          std::string key = key_list[i];
+
+          Cell val = map.contents (key);
+
+          octave_value tmp = (n == 1) ? val(0) : octave_value (val, true);
+
+          if (n != 1 || print_keys_only)
+            {
+              indent (os);
+              os << key;
+              if (n == 1)
+                {
+                  dim_vector dv = tmp.dims ();
+                  os << ": " << dv.str () << " " << tmp.type_name ();
+                }
+              newline (os);
+            }
+          else
+            tmp.print_with_name (os, key);
+        }
+
+      if (n != 1 || print_keys_only)
+        decrement_indent_level ();
+
+      decrement_indent_level ();
+
+      indent (os);
+      os << "}";
+      newline (os);
+    }
+  else
+    {
+      indent (os);
+      os << "<structure>";
+      newline (os);
+    }
+}
+
+bool
+octave_scalar_struct::print_name_tag (std::ostream& os, const std::string& name) const
+{
+  bool retval = false;
+
+  indent (os);
+
+  if (Vstruct_levels_to_print < 0)
+    os << name << " = ";
+  else
+    {
+      os << name << " =";
+      newline (os);
+      retval = true;
+    }
+
+  return retval;
+}
+
+bool
+octave_scalar_struct::save_ascii (std::ostream& os)
+{
+  octave_map m = map_value ();
+
+  octave_idx_type nf = m.nfields ();
+
+  const dim_vector dv = dims ();
+
+  os << "# ndims: " << dv.length () << "\n";
+
+  for (int i = 0; i < dv.length (); i++)
+    os << " " << dv (i);
+  os << "\n";
+
+  os << "# length: " << nf << "\n";
+
+  // Iterating over the list of keys will preserve the order of the
+  // fields.
+  string_vector keys = m.fieldnames ();
+
+  for (octave_idx_type i = 0; i < nf; i++)
+    {
+      std::string key = keys(i);
+
+      octave_value val = map.contents (key);
+
+      bool b = save_ascii_data (os, val, key, false, 0);
+      
+      if (! b)
+        return os;
+    }
+
+  return true;
+}
+
+bool
+octave_scalar_struct::load_ascii (std::istream& is)
+{
+  bool success = true;
+  octave_idx_type len = 0;
+
+  if (extract_keyword (is, "length", len, true) && len >= 0)
+    {
+      if (len > 0)
+        {
+          octave_scalar_map m;
+
+          for (octave_idx_type j = 0; j < len; j++)
+            {
+              octave_value t2;
+              bool dummy;
+
+              // recurse to read cell elements
+              std::string nm
+                = read_ascii_data (is, std::string (), dummy, t2, j);
+
+              if (!is)
+                break;
+
+              if (error_state)
+                {
+                  error ("load: internal error loading struct elements");
+                  return false;
+                }
+
+              m.setfield (nm, t2);
+            }
+
+          if (is) 
+            map = m;
+          else
+            {
+              error ("load: failed to load structure");
+              success = false;
+            }
+        }
+      else if (len == 0)
+        map = octave_scalar_map ();
+      else
+        panic_impossible ();
+    }
+  else {
+    error ("load: failed to extract number of elements in structure");
+    success = false;
+  }
+
+  return success;
+}
+
+bool 
+octave_scalar_struct::save_binary (std::ostream& os, bool& save_as_floats)
+{
+  octave_map m = map_value ();
+
+  octave_idx_type nf = m.nfields ();
+
+  int32_t len = nf;
+  os.write (reinterpret_cast<char *> (&len), 4);
+
+  // Iterating over the list of keys will preserve the order of the
+  // fields.
+  string_vector keys = m.fieldnames ();
+
+  for (octave_idx_type i = 0; i < nf; i++)
+    {
+      std::string key = keys(i);
+
+      octave_value val = map.contents (key);
+
+      bool b = save_binary_data (os, val, key, "", 0, save_as_floats);
+      
+      if (! b)
+        return os;
+    }
+
+  return true;
+}
+
+bool 
+octave_scalar_struct::load_binary (std::istream& is, bool swap,
+                                   oct_mach_info::float_format fmt)
+{
+  bool success = true;
+  int32_t len;
+  if (! is.read (reinterpret_cast<char *> (&len), 4))
+    return false;
+  if (swap)
+    swap_bytes<4> (&len);
+
+  dim_vector dv (1, 1);
+
+  if (len > 0)
+    {
+      octave_scalar_map m;
+
+      for (octave_idx_type j = 0; j < len; j++)
+        {
+          octave_value t2;
+          bool dummy;
+          std::string doc;
+
+          // recurse to read cell elements
+          std::string nm = read_binary_data (is, swap, fmt, std::string (), 
+                                             dummy, t2, doc);
+
+          if (!is)
+            break;
+
+          if (error_state)
+            {
+              error ("load: internal error loading struct elements");
+              return false;
+            }
+
+          m.setfield (nm, t2);
+        }
+
+      if (is) 
+        map = m;
+      else
+        {
+          error ("load: failed to load structure");
+          success = false;
+        }
+    }
+  else if (len == 0)
+    map = octave_scalar_map ();
+  else
+    success = false;
+
+  return success;
+}
+
+#if defined (HAVE_HDF5)
+
+bool
+octave_scalar_struct::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats)
+{
+  hid_t data_hid = -1;
+
+#if HAVE_HDF5_18
+  data_hid = H5Gcreate (loc_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
+#else
+  data_hid = H5Gcreate (loc_id, name, 0);
+#endif
+  if (data_hid < 0) return false;
+
+  // recursively add each element of the structure to this group
+  octave_scalar_map m = scalar_map_value ();
+
+  octave_idx_type nf = m.nfields ();
+
+  // Iterating over the list of keys will preserve the order of the
+  // fields.
+  string_vector keys = m.fieldnames ();
+
+  for (octave_idx_type i = 0; i < nf; i++)
+    {
+      std::string key = keys(i);
+
+      octave_value val = map.contents (key);
+
+      bool retval2 = add_hdf5_data (data_hid, val, key, "", false, 
+                                    save_as_floats);
+
+      if (! retval2)
+        break;
+    }
+
+  H5Gclose (data_hid);
+
+  return true;
+}
+
+bool 
+octave_scalar_struct::load_hdf5 (hid_t loc_id, const char *name)
+{
+  bool retval = false;
+
+  hdf5_callback_data dsub;
+
+  herr_t retval2 = 0;
+  octave_scalar_map m;
+  int current_item = 0;
+  hsize_t num_obj = 0;
+#if HAVE_HDF5_18
+  hid_t group_id = H5Gopen (loc_id, name, H5P_DEFAULT);
+#else
+  hid_t group_id = H5Gopen (loc_id, name);
+#endif
+  H5Gget_num_objs (group_id, &num_obj);
+  H5Gclose (group_id);
+
+  // FIXME -- fields appear to be sorted alphabetically on loading.
+  // Why is that happening?
+
+  while (current_item < static_cast<int> (num_obj)
+         && (retval2 = H5Giterate (loc_id, name, &current_item,
+                                   hdf5_read_next_data, &dsub)) > 0)
+    {
+      octave_value t2 = dsub.tc;
+
+      if (error_state)
+        {
+          error ("load: internal error loading struct elements");
+          return false;
+        }
+
+      m.setfield (dsub.name, t2);
+
+    }
+
+  if (retval2 >= 0)
+    {
+      map = m;
+      retval = true;
+    }
+  
+  return retval;
+}
+
+#endif
+
+mxArray *
+octave_scalar_struct::as_mxArray (void) const
+{
+  int nf = nfields ();
+  string_vector kv = map_keys ();
+
+  OCTAVE_LOCAL_BUFFER (const char *, f, nf);
+
+  for (int i = 0; i < nf; i++)
+    f[i] = kv[i].c_str ();
+
+  mxArray *retval = new mxArray (dims (), nf, f);
+
+  mxArray **elts = static_cast<mxArray **> (retval->get_data ());
+
+  mwSize nel = numel ();
+
+  mwSize ntot = nf * nel;
+
+  for (int i = 0; i < nf; i++)
+    {
+      Cell c = map.contents (kv[i]);
+
+      const octave_value *p = c.data ();
+
+      mwIndex k = 0;
+      for (mwIndex j = i; j < ntot; j += nf)
+        elts[j] = new mxArray (p[k++]);
+    }
+
+  return retval;
+}
+
+
+octave_value
+octave_scalar_struct::to_array (void)
+{
+  return new octave_struct (octave_map (map));
+}
+
+/*
+%!shared x
+%! x(1).a=1; x(2).a=2; x(1).b=3; x(2).b=3;
+%!assert(struct('a',1,'b',3),x(1))
+%!assert(isempty(x([])))
+%!assert(isempty(struct('a',{},'b',{})))
+%!assert(struct('a',{1,2},'b',{3,3}),x)
+%!assert(struct('a',{1,2},'b',3),x)
+%!assert(struct('a',{1,2},'b',{3}),x)
+%!assert(struct('b',3,'a',{1,2}),x)
+%!assert(struct('b',{3},'a',{1,2}),x) 
+%!test x=struct([]);
+%!assert(size(x),[0,0]);
+%!assert(isstruct(x));
+%!assert(isempty(fieldnames(x)));
+%!fail("struct('a',{1,2},'b',{1,2,3})","dimensions of parameter 2 do not match those of parameter 4")
+%!fail("struct(1,2,3,4)","struct expects alternating \"field\", VALUE pairs");
+%!fail("struct('1',2,'3')","struct expects alternating \"field\", VALUE pairs");
+*/
+
 DEFUN (struct, args, ,
   "-*- texinfo -*-\n\
 @deftypefn {Built-in Function} {} struct (\"field\", @var{value}, \"field\", @var{value}, @dots{})\n\
@@ -722,7 +1726,7 @@
 
   if (nargin == 1 && args(0).is_object ())
     {
-      Octave_map m = args(0).map_value ();
+      octave_map m = args(0).map_value ();
       retval = octave_value (new octave_struct (m));
 
       return retval;
@@ -736,12 +1740,12 @@
       if (nargin == 2)
         {
           if (args(1).is_cellstr ())
-            retval = Octave_map (args(0).dims (), args(1).cell_value ());
+            retval = octave_map (args(0).dims (), args(1).cellstr_value ());
           else
             error ("struct: expecting cell array of field names as second argument");
         }
       else
-        retval = Octave_map (args(0).dims ());
+        retval = octave_map (args(0).dims ());
 
       return retval;
     }
@@ -788,7 +1792,7 @@
 
   // Create the return value.
 
-  Octave_map map (dims);
+  octave_map map (dims);
 
   for (int i = 0; i < nargin; i+= 2) 
     {
@@ -819,12 +1823,12 @@
             return retval;
 
           if (scalar (c.dims ())) 
-            map.assign (key, Cell (dims, c(0)));
+            map.setfield (key, Cell (dims, c(0)));
           else 
-            map.assign (key, c);
+            map.setfield (key, c);
         }
       else 
-        map.assign (key, Cell (dims, args(i+1)));
+        map.setfield (key, Cell (dims, args(i+1)));
 
       if (error_state)
         return retval;
@@ -868,14 +1872,14 @@
 
       if (arg.is_map () || arg.is_object ())
         {
-          Octave_map m = arg.map_value ();
-
-          string_vector keys = m.keys ();
+          octave_map m = arg.map_value ();
+
+          string_vector keys = m.fieldnames ();
 
           if (keys.length () == 0)
             retval = Cell (0, 1);
           else
-            retval = Cell (m.keys ());
+            retval = Cell (keys);
         }
       else
         gripe_wrong_type_arg ("fieldnames", args(0));
@@ -911,7 +1915,7 @@
 
       if (args(0).is_map ())
         {
-          Octave_map m = args(0).map_value ();
+          octave_map m = args(0).map_value ();
 
           // FIXME -- should this work for all types that can do
           // structure reference operations?
@@ -920,12 +1924,12 @@
             {
               std::string key = args(1).string_value ();
 
-              retval = m.contains (key) != 0;
+              retval = m.isfield (key);
             }
           else if (args(1).is_cell ())
             {
               Cell c = args(1).cell_value ();
-              boolMatrix bm (c.dims ());
+              boolNDArray bm (c.dims ());
               octave_idx_type n = bm.numel ();
 
               for (octave_idx_type i = 0; i < n; i++)
@@ -934,7 +1938,7 @@
                     {
                       std::string key = c(i).string_value ();
 
-                      bm(i) = m.contains (key) != 0;
+                      bm(i) = m.isfield (key);
                     }
                   else
                     bm(i) = false;
@@ -1133,7 +2137,7 @@
                       // All initializing is done, we can start moving
                       // values.
 
-                      Octave_map map;
+                      octave_map map;
 
                       // If field is a cell array then we use all
                       // elements in array, on the other hand when
@@ -1207,7 +2211,7 @@
 
                           map.reshape (value_dv);
 
-                          map.assign (field_str, c_value);
+                          map.setfield (field_str, c_value);
                         }
 
                       if (! error_state)
@@ -1260,7 +2264,7 @@
 
   if (nargin == 2)
     {
-      Octave_map m = args(0).map_value ();
+      octave_map m = args(0).map_value ();
 
       octave_value_list fval = Fcellstr (args(1), 1);
 
@@ -1272,8 +2276,8 @@
             {
               std::string key = fcell(i).string_value ();
 
-              if (m.contains (key))
-                m.del (key);
+              if (m.isfield (key))
+                m.rmfield (key);
               else
                 {
                   error ("rmfield: structure does not contain field %s",
@@ -1302,367 +2306,3 @@
 %!  assert (size (y), [1, 6]);
 */
 
-bool
-octave_struct::save_ascii (std::ostream& os)
-{
-  Octave_map m = map_value ();
-
-  octave_idx_type nf = m.nfields ();
-
-  const dim_vector dv = dims ();
-
-  os << "# ndims: " << dv.length () << "\n";
-
-  for (int i = 0; i < dv.length (); i++)
-    os << " " << dv (i);
-  os << "\n";
-
-  os << "# length: " << nf << "\n";
-
-  // Iterating over the list of keys will preserve the order of the
-  // fields.
-  string_vector keys = m.keys ();
-
-  for (octave_idx_type i = 0; i < nf; i++)
-    {
-      std::string key = keys(i);
-
-      octave_value val = map.contents (key);
-
-      bool b = save_ascii_data (os, val, key, false, 0);
-      
-      if (! b)
-        return os;
-    }
-
-  return true;
-}
-
-bool 
-octave_struct::load_ascii (std::istream& is)
-{
-  octave_idx_type len = 0;
-  dim_vector dv (1, 1);
-  bool success = true;
-
-  // KLUGE: earlier Octave versions did not save extra dimensions with struct,
-  // and as a result did not preserve dimensions for empty structs.
-  // The default dimensions were 1x1, which we want to preserve.
-  string_vector keywords(2);
-
-  keywords[0] = "ndims";
-  keywords[1] = "length";
-
-  std::string kw;
-
-  if (extract_keyword (is, keywords, kw, len, true))
-    {
-      if (kw == keywords[0])
-        {
-          int mdims = std::max (static_cast<int> (len), 2);
-          dv.resize (mdims);
-          for (int i = 0; i < mdims; i++)
-            is >> dv(i);
-
-          success = extract_keyword (is, keywords[1], len);
-        }
-    }
-  else
-    success = false;
-
-  if (success && len >= 0)
-    {
-      if (len > 0)
-        {
-          Octave_map m (dv);
-
-          for (octave_idx_type j = 0; j < len; j++)
-            {
-              octave_value t2;
-              bool dummy;
-
-              // recurse to read cell elements
-              std::string nm
-                = read_ascii_data (is, std::string (), dummy, t2, j);
-
-              if (!is)
-                break;
-
-              Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
-
-              if (error_state)
-                {
-                  error ("load: internal error loading struct elements");
-                  return false;
-                }
-
-              m.assign (nm, tcell);
-            }
-
-          if (is) 
-            map = m;
-          else
-            {
-              error ("load: failed to load structure");
-              success = false;
-            }
-        }
-      else if (len == 0 )
-        map = Octave_map (dv);
-      else
-        panic_impossible ();
-    }
-  else {
-    error ("load: failed to extract number of elements in structure");
-    success = false;
-  }
-
-  return success;
-}
-
-bool 
-octave_struct::save_binary (std::ostream& os, bool& save_as_floats)
-{
-  Octave_map m = map_value ();
-
-  octave_idx_type nf = m.nfields ();
-
-  dim_vector d = dims ();
-  if (d.length () < 1)
-    return false;
-
-  // Use negative value for ndims
-  int32_t di = - d.length();
-  os.write (reinterpret_cast<char *> (&di), 4);
-  for (int i = 0; i < d.length (); i++)
-    {
-      di = d(i);
-      os.write (reinterpret_cast<char *> (&di), 4);
-    }
-  
-  int32_t len = nf;
-  os.write (reinterpret_cast<char *> (&len), 4);
-
-  // Iterating over the list of keys will preserve the order of the
-  // fields.
-  string_vector keys = m.keys ();
-
-  for (octave_idx_type i = 0; i < nf; i++)
-    {
-      std::string key = keys(i);
-
-      octave_value val = map.contents (key);
-
-      bool b = save_binary_data (os, val, key, "", 0, save_as_floats);
-      
-      if (! b)
-        return os;
-    }
-
-  return true;
-}
-
-bool 
-octave_struct::load_binary (std::istream& is, bool swap,
-                            oct_mach_info::float_format fmt)
-{
-  bool success = true;
-  int32_t len;
-  if (! is.read (reinterpret_cast<char *> (&len), 4))
-    return false;
-  if (swap)
-    swap_bytes<4> (&len);
-
-  dim_vector dv (1, 1);
-
-  if (len < 0)
-    {
-      // We have explicit dimensions.
-      int mdims = -len;
-
-      int32_t di;
-      dv.resize (mdims);
-
-      for (int i = 0; i < mdims; i++)
-        {
-          if (! is.read (reinterpret_cast<char *> (&di), 4))
-            return false;
-          if (swap)
-            swap_bytes<4> (&di);
-          dv(i) = di;
-        }
-
-      if (! is.read (reinterpret_cast<char *> (&len), 4))
-        return false;
-      if (swap)
-        swap_bytes<4> (&len);
-    }
-
-  if (len > 0)
-    {
-      Octave_map m (dv);
-
-      for (octave_idx_type j = 0; j < len; j++)
-        {
-          octave_value t2;
-          bool dummy;
-          std::string doc;
-
-          // recurse to read cell elements
-          std::string nm = read_binary_data (is, swap, fmt, std::string (), 
-                                             dummy, t2, doc);
-
-          if (!is)
-            break;
-
-          Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
- 
-          if (error_state)
-            {
-              error ("load: internal error loading struct elements");
-              return false;
-            }
-
-          m.assign (nm, tcell);
-        }
-
-      if (is) 
-        map = m;
-      else
-        {
-          error ("load: failed to load structure");
-          success = false;
-        }
-    }
-  else if (len == 0)
-    map = Octave_map (dv);
-  else
-    success = false;
-
-  return success;
-}
-
-#if defined (HAVE_HDF5)
-
-bool
-octave_struct::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats)
-{
-  hid_t data_hid = -1;
-
-#if HAVE_HDF5_18
-  data_hid = H5Gcreate (loc_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
-#else
-  data_hid = H5Gcreate (loc_id, name, 0);
-#endif
-  if (data_hid < 0) return false;
-
-  // recursively add each element of the structure to this group
-  Octave_map m = map_value ();
-
-  octave_idx_type nf = m.nfields ();
-
-  // Iterating over the list of keys will preserve the order of the
-  // fields.
-  string_vector keys = m.keys ();
-
-  for (octave_idx_type i = 0; i < nf; i++)
-    {
-      std::string key = keys(i);
-
-      octave_value val = map.contents (key);
-
-      bool retval2 = add_hdf5_data (data_hid, val, key, "", false, 
-                                    save_as_floats);
-
-      if (! retval2)
-        break;
-    }
-
-  H5Gclose (data_hid);
-
-  return true;
-}
-
-bool 
-octave_struct::load_hdf5 (hid_t loc_id, const char *name)
-{
-  bool retval = false;
-
-  hdf5_callback_data dsub;
-
-  herr_t retval2 = 0;
-  Octave_map m (dim_vector (1, 1));
-  int current_item = 0;
-  hsize_t num_obj = 0;
-#if HAVE_HDF5_18
-  hid_t group_id = H5Gopen (loc_id, name, H5P_DEFAULT);
-#else
-  hid_t group_id = H5Gopen (loc_id, name);
-#endif
-  H5Gget_num_objs (group_id, &num_obj);
-  H5Gclose (group_id);
-
-  // FIXME -- fields appear to be sorted alphabetically on loading.
-  // Why is that happening?
-
-  while (current_item < static_cast<int> (num_obj)
-         && (retval2 = H5Giterate (loc_id, name, &current_item,
-                                   hdf5_read_next_data, &dsub)) > 0)
-    {
-      octave_value t2 = dsub.tc;
-
-      Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
- 
-      if (error_state)
-        {
-          error ("load: internal error loading struct elements");
-          return false;
-        }
-
-      m.assign (dsub.name, tcell);
-
-    }
-
-  if (retval2 >= 0)
-    {
-      map = m;
-      retval = true;
-    }
-  
-  return retval;
-}
-
-#endif
-
-mxArray *
-octave_struct::as_mxArray (void) const
-{
-  int nf = nfields ();
-  string_vector kv = map_keys ();
-
-  OCTAVE_LOCAL_BUFFER (const char *, f, nf);
-
-  for (int i = 0; i < nf; i++)
-    f[i] = kv[i].c_str ();
-
-  mxArray *retval = new mxArray (dims (), nf, f);
-
-  mxArray **elts = static_cast<mxArray **> (retval->get_data ());
-
-  mwSize nel = numel ();
-
-  mwSize ntot = nf * nel;
-
-  for (int i = 0; i < nf; i++)
-    {
-      Cell c = map.contents (kv[i]);
-
-      const octave_value *p = c.data ();
-
-      mwIndex k = 0;
-      for (mwIndex j = i; j < ntot; j += nf)
-        elts[j] = new mxArray (p[k++]);
-    }
-
-  return retval;
-}