# HG changeset patch # User Jaroslav Hajek # Date 1250507352 -7200 # Node ID 8e50093346616d2c220db44639d4c86d0eac6fd4 # Parent ec066ba012c845b0a0ea6ca021ab14078618df83 partially revert e79470be3ecb diff --git a/src/ChangeLog b/src/ChangeLog --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,11 @@ +2009-08-17 Jaroslav Hajek + + * ov-struct.h, ov-struct.cc: Revert to e08d72bb988e. + * ov-class.h, ov-class.cc: Partially revert to e08d72bb988e. + (octave_class::subsasgn): Cut&paste code from octave_struct::subsasgn + for the nested dot indexing. + * ov-usr-fcn.cc (Voptimize_subasgn_calls): Default to true. + 2009-08-13 John W. Eaton * DLD-FUNCTIONS/fft.cc, DLD-FUNCTIONS/fft2.cc, diff --git a/src/ov-class.cc b/src/ov-class.cc --- a/src/ov-class.cc +++ b/src/ov-class.cc @@ -68,7 +68,7 @@ octave_class::octave_class (const Octave_map& m, const std::string& id, const octave_value_list& parents) - : octave_struct (m), c_name (id), obsolete_copies (0) + : octave_base_value (), map (m), c_name (id), obsolete_copies (0) { octave_idx_type n = parents.length (); @@ -138,6 +138,24 @@ error ("invalid index for class"); } +static void +gripe_invalid_index_for_assignment (void) +{ + error ("invalid index for class assignment"); +} + +static void +gripe_invalid_index_type (const std::string& nm, char t) +{ + error ("%s cannot be indexed with %c", nm.c_str (), t); +} + +static void +gripe_failed_assignment (void) +{ + error ("assignment to class element failed"); +} + static inline octave_value_list sanitize (const octave_value_list& ovl) { @@ -371,7 +389,68 @@ octave_value_list retval; if (in_class_method () || called_from_builtin ()) - retval = octave_struct::subsref (type, idx, nargout); + { + // FIXME -- this block of code is the same as the body of + // octave_struct::subsref. Maybe it could be shared instead of + // duplicated. + + int skip = 1; + + switch (type[0]) + { + case '(': + { + if (type.length () > 1 && type[1] == '.') + { + std::list::const_iterator p = idx.begin (); + octave_value_list key_idx = *++p; + + Cell tmp = dotref (key_idx); + + if (! error_state) + { + Cell t = tmp.index (idx.front ()); + + retval(0) = (t.length () == 1) ? t(0) : octave_value (t, true); + + // We handled two index elements, so tell + // next_subsref to skip both of them. + + skip++; + } + } + else + retval(0) = octave_value (map.index (idx.front ()), + class_name ()); + } + break; + + case '.': + { + if (map.numel() > 0) + { + Cell t = dotref (idx.front ()); + + retval(0) = (t.length () == 1) ? t(0) : octave_value (t, true); + } + } + break; + + case '{': + gripe_invalid_index_type (type_name (), type[0]); + break; + + default: + panic_impossible (); + } + + // FIXME -- perhaps there should be an + // octave_value_list::next_subsref member function? See also + // octave_user_function::subsref. + + if (idx.size () > 1) + retval = retval(0).next_subsref (nargout, type, idx, skip); + } else { octave_value meth = symbol_table::find_method ("subsref", class_name ()); @@ -422,59 +501,20 @@ return retval; } -octave_value -octave_class::subsref (const std::string& type, - const std::list& idx, - bool auto_add) -{ - if (in_class_method () || called_from_builtin ()) - return octave_struct::subsref (type, idx, auto_add); - else - return subsref (type, idx); - -} - -void -octave_class::gripe_failed_assignment (void) -{ - error ("assignment to class element failed"); -} - -octave_value -octave_class::dotasgn (const octave_value_list& idx, const octave_value& rhs) +octave_value +octave_class::numeric_conv (const Cell& val, const std::string& type) { octave_value retval; - // Find the class in which this method resides before - // attempting to access the requested field. - - std::string method_class = get_current_method_class (); - - octave_base_value *obvp = find_parent_class (method_class); - - if (obvp) + if (val.length () == 1) { - assert (idx.length () == 1); - - std::string key = idx(0).string_value (); + retval = val(0); - if (! error_state) - { - obvp->assign (key, rhs); - - if (! error_state) - { - count++; - retval = octave_value (this); - } - else - gripe_failed_assignment (); - } - else - gripe_failed_assignment (); + if (type.length () > 0 && type[0] == '.' && ! retval.is_map ()) + retval = Octave_map (); } else - error ("malformed class"); + gripe_invalid_index_for_assignment (); return retval; } @@ -484,14 +524,14 @@ const std::list& idx, const octave_value& rhs) { + octave_value retval; + if (! (in_class_method () || called_from_builtin ())) { octave_value meth = symbol_table::find_method ("subsasgn", class_name ()); if (meth.is_defined ()) { - octave_value retval; - octave_value_list args; if (rhs.is_cs_list ()) @@ -554,7 +594,246 @@ } } - return octave_struct::subsasgn (type, idx, rhs); + // FIXME -- this block of code is the same as the body of + // octave_struct::subsasgn. Maybe it could be shared instead of + // duplicated. + + int n = type.length (); + + octave_value t_rhs = rhs; + + if (n > 1 && ! (type.length () == 2 && type[0] == '(' && type[1] == '.')) + { + switch (type[0]) + { + case '(': + { + if (type.length () > 1 && type[1] == '.') + { + std::list::const_iterator p = idx.begin (); + octave_value_list t_idx = *p; + + octave_value_list key_idx = *++p; + + assert (key_idx.length () == 1); + + std::string key = key_idx(0).string_value (); + + if (! error_state) + { + octave_value u; + + if (! map.contains (key)) + u = octave_value::empty_conv (type.substr (2), rhs); + else + { + Cell map_val = map.contents (key); + + Cell map_elt = map_val.index (idx.front (), true); + + u = numeric_conv (map_elt, type.substr (2)); + } + + if (! error_state) + { + std::list next_idx (idx); + + // We handled two index elements, so subsasgn to + // needs to skip both of them. + + next_idx.erase (next_idx.begin ()); + next_idx.erase (next_idx.begin ()); + + u.make_unique (); + + t_rhs = u.subsasgn (type.substr (2), next_idx, rhs); + } + } + else + gripe_invalid_index_for_assignment (); + } + else + gripe_invalid_index_for_assignment (); + } + break; + + case '.': + { + octave_value_list key_idx = idx.front (); + + assert (key_idx.length () == 1); + + std::string key = key_idx(0).string_value (); + + std::list next_idx (idx); + + next_idx.erase (next_idx.begin ()); + + std::string next_type = type.substr (1); + + Cell tmpc (1, 1); + Octave_map::iterator pkey = map.seek (key); + if (pkey != map.end ()) + { + pkey->second.make_unique (); + tmpc = pkey->second; + } + + // FIXME: better code reuse? + if (! error_state) + { + if (tmpc.numel () == 1) + { + octave_value& tmp = tmpc(0); + + 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); + } + else + gripe_indexed_cs_list (); + } + } + break; + + case '{': + gripe_invalid_index_type (type_name (), type[0]); + break; + + default: + panic_impossible (); + } + } + + if (! error_state) + { + switch (type[0]) + { + case '(': + { + if (n > 1 && type[1] == '.') + { + std::list::const_iterator p = idx.begin (); + octave_value_list key_idx = *++p; + + assert (key_idx.length () == 1); + + std::string key = key_idx(0).string_value (); + + if (! error_state) + { + map.assign (idx.front (), key, t_rhs); + + if (! error_state) + { + count++; + retval = octave_value (this); + } + else + gripe_failed_assignment (); + } + else + gripe_failed_assignment (); + } + else + { + if (t_rhs.is_object () || t_rhs.is_map ()) + { + Octave_map rhs_map = t_rhs.map_value (); + + if (! error_state) + { + map.assign (idx.front (), rhs_map); + + if (! error_state) + { + count++; + retval = octave_value (this); + } + else + gripe_failed_assignment (); + } + else + error ("invalid class assignment"); + } + else + { + if (t_rhs.is_empty ()) + { + map.maybe_delete_elements (idx.front()); + + if (! error_state) + { + count++; + retval = octave_value (this); + } + else + gripe_failed_assignment (); + } + else + error ("invalid class assignment"); + } + } + } + break; + + case '.': + { + // Find the class in which this method resides before + // attempting to access the requested field. + + std::string method_class = get_current_method_class (); + + octave_base_value *obvp = find_parent_class (method_class); + + if (obvp) + { + octave_value_list key_idx = idx.front (); + + assert (key_idx.length () == 1); + + std::string key = key_idx(0).string_value (); + + if (! error_state) + { + obvp->assign (key, t_rhs); + + if (! error_state) + { + count++; + retval = octave_value (this); + } + else + gripe_failed_assignment (); + } + else + gripe_failed_assignment (); + } + else + error ("malformed class"); + } + break; + + case '{': + gripe_invalid_index_type (type_name (), type[0]); + break; + + default: + panic_impossible (); + } + } + else + gripe_failed_assignment (); + + return retval; } idx_vector @@ -591,6 +870,25 @@ return retval; } +size_t +octave_class::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; +} + string_vector octave_class::map_keys (void) const { diff --git a/src/ov-class.h b/src/ov-class.h --- a/src/ov-class.h +++ b/src/ov-class.h @@ -1,7 +1,6 @@ /* Copyright (C) 2007, 2008, 2009 John W. Eaton -Copyright (C) 2009 VZLU Prague This file is part of Octave. @@ -36,7 +35,6 @@ #include "oct-alloc.h" #include "oct-map.h" #include "ov-base.h" -#include "ov-struct.h" #include "ov-typeinfo.h" class octave_value_list; @@ -46,19 +44,19 @@ // Data structures. class -octave_class : public octave_struct +octave_class : public octave_base_value { public: octave_class (void) - : octave_struct (), obsolete_copies (0) { } + : octave_base_value (), obsolete_copies (0) { } octave_class (const Octave_map& m, const std::string& id) - : octave_struct (m), c_name (id), obsolete_copies (0) { } + : octave_base_value (), map (m), c_name (id), obsolete_copies (0) { } octave_class (const octave_class& s) - : octave_struct (s), c_name (s.c_name), - parent_list (s.parent_list), obsolete_copies (0) { } + : 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, const octave_value_list& parents); @@ -76,8 +74,6 @@ Cell dotref (const octave_value_list& idx); - octave_value dotasgn (const octave_value_list& idx, const octave_value& rhs); - Matrix size (void); octave_idx_type numel (const octave_value_list&); @@ -89,14 +85,13 @@ return tmp.length () > 0 ? tmp(0) : octave_value (); } - octave_value subsref (const std::string& type, - const std::list& idx, - bool auto_add); - octave_value_list subsref (const std::string& type, const std::list& idx, int nargout); + static octave_value numeric_conv (const Cell& val, + const std::string& type); + void assign(const std::string& k, const octave_value& rhs) { map.assign (k, rhs); }; @@ -108,12 +103,34 @@ dim_vector dims (void) const { return map.dims (); } + 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 + { + dim_vector dv = dims (); + return dv.numel (); + } + + octave_idx_type nfields (void) const { return map.nfields (); } + size_t nparents (void) const { return parent_list.size (); } + 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; } + + bool is_defined (void) const { return true; } + bool is_map (void) const { return false; } bool is_object (void) const { return true; } + Octave_map map_value (void) const { return map; } + string_vector map_keys (void) const; std::list parent_class_name_list (void) const @@ -156,11 +173,9 @@ mxArray *as_mxArray (void) const; -protected: +private: - void gripe_failed_assignment (void); - -private: + Octave_map map; DECLARE_OCTAVE_ALLOCATOR diff --git a/src/ov-struct.cc b/src/ov-struct.cc --- a/src/ov-struct.cc +++ b/src/ov-struct.cc @@ -93,8 +93,8 @@ error ("%s cannot be indexed with %c", nm.c_str (), t); } -void -octave_struct::gripe_failed_assignment (void) +static void +gripe_failed_assignment (void) { error ("assignment to structure element failed"); } @@ -254,43 +254,6 @@ } octave_value -octave_struct::dotasgn (const octave_value_list& idx, const octave_value& rhs) -{ - octave_value retval; - - assert (idx.length () == 1); - - std::string key = idx(0).string_value (); - - if (rhs.is_cs_list ()) - { - Cell tmp_cell = Cell (rhs.list_value ()); - - // The shape of the RHS is irrelevant, we just want - // the number of elements to agree and to preserve the - // shape of the left hand side of the assignment. - - if (numel () == tmp_cell.numel ()) - tmp_cell = tmp_cell.reshape (dims ()); - - map.assign (key, tmp_cell); - } - else - // Regularize a null matrix if stored into a struct component. - map.assign (key, rhs.storable_value ()); - - if (! error_state) - { - count++; - retval = octave_value (this); - } - else - gripe_failed_assignment (); - - return retval; -} - -octave_value octave_struct::subsasgn (const std::string& type, const std::list& idx, const octave_value& rhs) @@ -493,8 +456,7 @@ } else { - if (t_rhs.is_map() - || (is_object () && t_rhs.is_object ())) + if (t_rhs.is_map()) { Octave_map rhs_map = t_rhs.map_value (); @@ -536,7 +498,36 @@ case '.': { - retval = dotasgn (idx.front (), t_rhs); + octave_value_list key_idx = idx.front (); + + assert (key_idx.length () == 1); + + std::string key = key_idx(0).string_value (); + + if (t_rhs.is_cs_list ()) + { + Cell tmp_cell = Cell (t_rhs.list_value ()); + + // The shape of the RHS is irrelevant, we just want + // the number of elements to agree and to preserve the + // shape of the left hand side of the assignment. + + if (numel () == tmp_cell.numel ()) + tmp_cell = tmp_cell.reshape (dims ()); + + map.assign (key, tmp_cell); + } + else + // Regularize a null matrix if stored into a struct component. + map.assign (key, t_rhs.storable_value ()); + + if (! error_state) + { + count++; + retval = octave_value (this); + } + else + gripe_failed_assignment (); } break; diff --git a/src/ov-struct.h b/src/ov-struct.h --- a/src/ov-struct.h +++ b/src/ov-struct.h @@ -63,13 +63,7 @@ octave_base_value *clone (void) const { return new octave_struct (*this); } octave_base_value *empty_clone (void) const { return new octave_struct (); } - virtual Cell dotref (const octave_value_list& idx) - { return dotref (idx, false); } - - Cell dotref (const octave_value_list& idx, bool auto_add); - - virtual octave_value dotasgn (const octave_value_list& idx, - const octave_value& rhs); + Cell dotref (const octave_value_list& idx, bool auto_add = false); octave_value subsref (const std::string& type, const std::list& idx) @@ -155,8 +149,6 @@ protected: - virtual void gripe_failed_assignment (void); - // The associative array used to manage the structure data. Octave_map map; diff --git a/src/ov-usr-fcn.cc b/src/ov-usr-fcn.cc --- a/src/ov-usr-fcn.cc +++ b/src/ov-usr-fcn.cc @@ -53,7 +53,7 @@ static int Vmax_recursion_depth = 256; // Whether to optimize subsasgn method calls. -static bool Voptimize_subsasgn_calls = false; +static bool Voptimize_subsasgn_calls = true; // User defined scripts.