# HG changeset patch # User Michael Goffioul # Date 1369359711 14400 # Node ID 665fa0f621cc2d5c20a4f9617ed5fa119fce8c87 # Parent 2823f8e3da771d159b5c2921ff2ebfc076f4577e Support combination of object array extension and multi-level indexing. * libinterp/octave-value/ov-classdef.h (octave_classdef::subsref(string, list& idx, + bool auto_add) +{ + size_t skip = 0; + octave_value_list retval; + + // FIXME: should check "subsref" method first + // ? not sure this still applied with auto_add version of subsref + + retval = object.subsref (type, idx, 1, skip, cdef_class (), auto_add); + + if (! error_state) + { + if (type.length () > skip && idx.size () > skip) + retval = retval(0).next_subsref (1, type, idx, skip); + } + + return retval.length () > 0 ? retval(0) : octave_value (); +} + +octave_value octave_classdef::subsasgn (const std::string& type, const std::list& idx, const octave_value& rhs) @@ -1028,7 +1050,7 @@ cdef_object_scalar::subsref (const std::string& type, const std::list& idx, int nargout, size_t& skip, - const cdef_class& context) + const cdef_class& context, bool auto_add) { skip = 0; @@ -1096,6 +1118,23 @@ } break; } + + case '(': + { + refcount++; + + cdef_object this_obj (this); + + Array arr (dim_vector (1, 1), this_obj); + + cdef_object new_obj = cdef_object (new cdef_object_array (arr)); + + new_obj.set_class (get_class ()); + + retval = new_obj.subsref (type, idx, nargout, skip, cls, auto_add); + } + break; + default: error ("object cannot be indexed with `%c'", type[0]); break; @@ -1221,7 +1260,7 @@ cdef_object_array::subsref (const std::string& type, const std::list& idx, int /* nargout */, size_t& skip, - const cdef_class& /* context */) + const cdef_class& /* context */, bool auto_add) { octave_value_list retval; @@ -1244,10 +1283,17 @@ if (! error_state) { - Array ires = array.index (iv); + Array ires = array.index (iv, auto_add); if (! error_state) { + // If resizing is enabled (auto_add = true), it's possible + // indexing was out-of-bound and the result array contains + // invalid cdef_objects. + + if (auto_add) + fill_empty_values (ires); + if (is_scalar) retval(0) = to_ov (ires(0)); else @@ -1406,18 +1452,26 @@ { cdef_object obj = a(0); + int ignore_copies = 0; + // If the object in 'a' is not valid, this means the index // was out-of-bound and we need to create a new object. if (! obj.ok ()) obj = get_class ().construct_object (octave_value_list ()); + else + // Optimize the subsasgn call to come. There are 2 copies + // that we can safely ignore: + // - 1 in "array" + // - 1 in "a" + ignore_copies = 2; std::list next_idx (idx); next_idx.erase (next_idx.begin ()); octave_value tmp = obj.subsasgn (type.substr (1), next_idx, - rhs); + rhs, ignore_copies); if (! error_state) { @@ -1467,7 +1521,7 @@ } void -cdef_object_array::fill_empty_values (void) +cdef_object_array::fill_empty_values (Array& arr) { cdef_class cls = get_class (); @@ -1475,21 +1529,21 @@ { cdef_object obj; - int n = array.numel (); + int n = arr.numel (); for (int i = 0; ! error_state && i < n; i++) { - if (! array.xelem (i).ok ()) + if (! arr.xelem (i).ok ()) { if (! obj.ok ()) { obj = cls.construct_object (octave_value_list ()); if (! error_state) - array.xelem (i) = obj; + arr.xelem (i) = obj; } else - array.xelem (i) = obj.copy (); + arr.xelem (i) = obj.copy (); } } } diff -r 2823f8e3da77 -r 665fa0f621cc libinterp/octave-value/ov-classdef.h --- a/libinterp/octave-value/ov-classdef.h Thu May 23 14:12:33 2013 -0400 +++ b/libinterp/octave-value/ov-classdef.h Thu May 23 21:41:51 2013 -0400 @@ -108,7 +108,7 @@ virtual octave_value_list subsref (const std::string&, const std::list&, - int, size_t&, const cdef_class&) + int, size_t&, const cdef_class&, bool) { gripe_invalid_object ("subsref"); return octave_value_list (); @@ -256,14 +256,15 @@ octave_value_list subsref (const std::string& type, const std::list& idx, - int nargout, size_t& skip, const cdef_class& context) - { return rep->subsref (type, idx, nargout, skip, context); } + int nargout, size_t& skip, const cdef_class& context, + bool auto_add = false) + { return rep->subsref (type, idx, nargout, skip, context, auto_add); } octave_value subsasgn (const std::string& type, const std::list& idx, - const octave_value& rhs) + const octave_value& rhs, int ignore_copies = 0) { - make_unique (); + make_unique (ignore_copies); return rep->subsasgn (type, idx, rhs); } @@ -294,9 +295,9 @@ protected: cdef_object_rep* get_rep (void) { return rep; } - void make_unique (void) + void make_unique (int ignore_copies) { - if (rep->refcount > 1) + if (rep->refcount > ignore_copies + 1) *this = clone (); } @@ -369,7 +370,8 @@ octave_value_list subsref (const std::string& type, const std::list& idx, - int nargout, size_t& skip, const cdef_class& context); + int nargout, size_t& skip, const cdef_class& context, + bool auto_add); octave_value subsasgn (const std::string& type, const std::list& idx, @@ -379,7 +381,9 @@ Array array; private: - void fill_empty_values (void); + void fill_empty_values (void) { fill_empty_values (array); } + + void fill_empty_values (Array& arr); // Private copying! cdef_object_array (const cdef_object_array& obj) @@ -417,7 +421,8 @@ octave_value_list subsref (const std::string& type, const std::list& idx, - int nargout, size_t& skip, const cdef_class& context); + int nargout, size_t& skip, const cdef_class& context, + bool auto_add); octave_value subsasgn (const std::string& type, const std::list& idx, @@ -1415,6 +1420,10 @@ return (retval.length () > 0 ? retval(0) : octave_value ()); } + octave_value subsref (const std::string& type, + const std::list& idx, + bool auto_add); + octave_value subsasgn (const std::string& type, const std::list& idx, const octave_value& rhs);