comparison libinterp/octave-value/ov-classdef.cc @ 16696:665fa0f621cc classdef

Support combination of object array extension and multi-level indexing. * libinterp/octave-value/ov-classdef.h (octave_classdef::subsref(string, list<octave_value_list, bool)): New method. (cdef_object_array:subsref, cdef_object_scalar::subsref, cdef_object_rep): Add boolean argument "auto_add". (cdef_object_array::fill_empty_values(Array&)): New method. (cdef_object_array::fill_empty_values()): Rewrite using the overload. (cdef_object::subsasgn, cdef_object::make_unique): New boolean argument "ignore_copies" for assignment optimization. * libinterp/octave-value/ov-classdef.cc (octave_classdef::subsref(string, list<octave_value_list, bool)): New method. (cdef_object_array::fill_empty_values()): Move implementation to the overload version. (cdef_object_array::subsasgn): Optimize assignment to avoir unnecessary copies of value objects. (cdef_object_array::subsref): New auto_add argument for automatic extension of the array. (cdef_object_scalar::subsref): New auto_add argument. Implement (-indexing by delegating to a new array object.
author Michael Goffioul <michael.goffioul@gmail.com>
date Thu, 23 May 2013 21:41:51 -0400
parents 2823f8e3da77
children 13b3b92ea99c
comparison
equal deleted inserted replaced
16695:2823f8e3da77 16696:665fa0f621cc
770 if (type.length () > skip && idx.size () > skip) 770 if (type.length () > skip && idx.size () > skip)
771 retval = retval(0).next_subsref (nargout, type, idx, skip); 771 retval = retval(0).next_subsref (nargout, type, idx, skip);
772 } 772 }
773 773
774 return retval; 774 return retval;
775 }
776
777 octave_value
778 octave_classdef::subsref (const std::string& type,
779 const std::list<octave_value_list>& idx,
780 bool auto_add)
781 {
782 size_t skip = 0;
783 octave_value_list retval;
784
785 // FIXME: should check "subsref" method first
786 // ? not sure this still applied with auto_add version of subsref
787
788 retval = object.subsref (type, idx, 1, skip, cdef_class (), auto_add);
789
790 if (! error_state)
791 {
792 if (type.length () > skip && idx.size () > skip)
793 retval = retval(0).next_subsref (1, type, idx, skip);
794 }
795
796 return retval.length () > 0 ? retval(0) : octave_value ();
775 } 797 }
776 798
777 octave_value 799 octave_value
778 octave_classdef::subsasgn (const std::string& type, 800 octave_classdef::subsasgn (const std::string& type,
779 const std::list<octave_value_list>& idx, 801 const std::list<octave_value_list>& idx,
1026 1048
1027 octave_value_list 1049 octave_value_list
1028 cdef_object_scalar::subsref (const std::string& type, 1050 cdef_object_scalar::subsref (const std::string& type,
1029 const std::list<octave_value_list>& idx, 1051 const std::list<octave_value_list>& idx,
1030 int nargout, size_t& skip, 1052 int nargout, size_t& skip,
1031 const cdef_class& context) 1053 const cdef_class& context, bool auto_add)
1032 { 1054 {
1033 skip = 0; 1055 skip = 0;
1034 1056
1035 cdef_class cls = (context.ok () ? context : get_class ()); 1057 cdef_class cls = (context.ok () ? context : get_class ());
1036 1058
1094 else 1116 else
1095 error ("subsref: unknown method or property: %s", name.c_str ()); 1117 error ("subsref: unknown method or property: %s", name.c_str ());
1096 } 1118 }
1097 break; 1119 break;
1098 } 1120 }
1121
1122 case '(':
1123 {
1124 refcount++;
1125
1126 cdef_object this_obj (this);
1127
1128 Array<cdef_object> arr (dim_vector (1, 1), this_obj);
1129
1130 cdef_object new_obj = cdef_object (new cdef_object_array (arr));
1131
1132 new_obj.set_class (get_class ());
1133
1134 retval = new_obj.subsref (type, idx, nargout, skip, cls, auto_add);
1135 }
1136 break;
1137
1099 default: 1138 default:
1100 error ("object cannot be indexed with `%c'", type[0]); 1139 error ("object cannot be indexed with `%c'", type[0]);
1101 break; 1140 break;
1102 } 1141 }
1103 1142
1219 1258
1220 octave_value_list 1259 octave_value_list
1221 cdef_object_array::subsref (const std::string& type, 1260 cdef_object_array::subsref (const std::string& type,
1222 const std::list<octave_value_list>& idx, 1261 const std::list<octave_value_list>& idx,
1223 int /* nargout */, size_t& skip, 1262 int /* nargout */, size_t& skip,
1224 const cdef_class& /* context */) 1263 const cdef_class& /* context */, bool auto_add)
1225 { 1264 {
1226 octave_value_list retval; 1265 octave_value_list retval;
1227 1266
1228 skip = 1; 1267 skip = 1;
1229 1268
1242 is_scalar = is_scalar && iv(i).is_scalar (); 1281 is_scalar = is_scalar && iv(i).is_scalar ();
1243 } 1282 }
1244 1283
1245 if (! error_state) 1284 if (! error_state)
1246 { 1285 {
1247 Array<cdef_object> ires = array.index (iv); 1286 Array<cdef_object> ires = array.index (iv, auto_add);
1248 1287
1249 if (! error_state) 1288 if (! error_state)
1250 { 1289 {
1290 // If resizing is enabled (auto_add = true), it's possible
1291 // indexing was out-of-bound and the result array contains
1292 // invalid cdef_objects.
1293
1294 if (auto_add)
1295 fill_empty_values (ires);
1296
1251 if (is_scalar) 1297 if (is_scalar)
1252 retval(0) = to_ov (ires(0)); 1298 retval(0) = to_ov (ires(0));
1253 else 1299 else
1254 { 1300 {
1255 cdef_object array_obj (new cdef_object_array (ires)); 1301 cdef_object array_obj (new cdef_object_array (ires));
1404 1450
1405 if (! error_state) 1451 if (! error_state)
1406 { 1452 {
1407 cdef_object obj = a(0); 1453 cdef_object obj = a(0);
1408 1454
1455 int ignore_copies = 0;
1456
1409 // If the object in 'a' is not valid, this means the index 1457 // If the object in 'a' is not valid, this means the index
1410 // was out-of-bound and we need to create a new object. 1458 // was out-of-bound and we need to create a new object.
1411 1459
1412 if (! obj.ok ()) 1460 if (! obj.ok ())
1413 obj = get_class ().construct_object (octave_value_list ()); 1461 obj = get_class ().construct_object (octave_value_list ());
1462 else
1463 // Optimize the subsasgn call to come. There are 2 copies
1464 // that we can safely ignore:
1465 // - 1 in "array"
1466 // - 1 in "a"
1467 ignore_copies = 2;
1414 1468
1415 std::list<octave_value_list> next_idx (idx); 1469 std::list<octave_value_list> next_idx (idx);
1416 1470
1417 next_idx.erase (next_idx.begin ()); 1471 next_idx.erase (next_idx.begin ());
1418 1472
1419 octave_value tmp = obj.subsasgn (type.substr (1), next_idx, 1473 octave_value tmp = obj.subsasgn (type.substr (1), next_idx,
1420 rhs); 1474 rhs, ignore_copies);
1421 1475
1422 if (! error_state) 1476 if (! error_state)
1423 { 1477 {
1424 cdef_object robj = to_cdef (tmp); 1478 cdef_object robj = to_cdef (tmp);
1425 1479
1465 1519
1466 return retval; 1520 return retval;
1467 } 1521 }
1468 1522
1469 void 1523 void
1470 cdef_object_array::fill_empty_values (void) 1524 cdef_object_array::fill_empty_values (Array<cdef_object>& arr)
1471 { 1525 {
1472 cdef_class cls = get_class (); 1526 cdef_class cls = get_class ();
1473 1527
1474 if (! error_state) 1528 if (! error_state)
1475 { 1529 {
1476 cdef_object obj; 1530 cdef_object obj;
1477 1531
1478 int n = array.numel (); 1532 int n = arr.numel ();
1479 1533
1480 for (int i = 0; ! error_state && i < n; i++) 1534 for (int i = 0; ! error_state && i < n; i++)
1481 { 1535 {
1482 if (! array.xelem (i).ok ()) 1536 if (! arr.xelem (i).ok ())
1483 { 1537 {
1484 if (! obj.ok ()) 1538 if (! obj.ok ())
1485 { 1539 {
1486 obj = cls.construct_object (octave_value_list ()); 1540 obj = cls.construct_object (octave_value_list ());
1487 1541
1488 if (! error_state) 1542 if (! error_state)
1489 array.xelem (i) = obj; 1543 arr.xelem (i) = obj;
1490 } 1544 }
1491 else 1545 else
1492 array.xelem (i) = obj.copy (); 1546 arr.xelem (i) = obj.copy ();
1493 } 1547 }
1494 } 1548 }
1495 } 1549 }
1496 } 1550 }
1497 1551