Mercurial > hg > octave-lyh
diff src/ov-class.cc @ 9529:8e5009334661
partially revert e79470be3ecb
author | Jaroslav Hajek <highegg@gmail.com> |
---|---|
date | Mon, 17 Aug 2009 13:09:12 +0200 |
parents | e79470be3ecb |
children | 8bf27324a9d0 |
line wrap: on
line diff
--- 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<octave_value_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<octave_value_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<octave_value_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<octave_value_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<octave_value_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<octave_value_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<octave_value_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 {