changeset 9986:672e1b49e01e

optimize indexing of ranges by single subscripts
author Jaroslav Hajek <highegg@gmail.com>
date Tue, 15 Dec 2009 10:04:34 +0100
parents 43a29eeda994
children bb30843c4929
files liboctave/ChangeLog liboctave/Range.cc liboctave/Range.h src/ChangeLog src/ov-range.cc
diffstat 5 files changed, 96 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/liboctave/ChangeLog
+++ b/liboctave/ChangeLog
@@ -1,3 +1,9 @@
+2009-12-15  Jaroslav Hajek  <highegg@gmail.com>
+
+	* Range.cc (Range::elem, Range::checkelem, Range::index):
+	New methods.
+	* Range.h: Declare them.
+
 2009-12-15  Jaroslav Hajek  <highegg@gmail.com>
 
 	* idx-vector.h (idx_vector::loop, idx_vector::bloop): Fix behavior for
--- a/liboctave/Range.cc
+++ b/liboctave/Range.cc
@@ -81,6 +81,57 @@
   return cache;
 }
 
+double
+Range::checkelem (octave_idx_type i) const
+{
+  if (i < 0 || i >= rng_nelem)
+    (*current_liboctave_error_handler) ("Range::elem (%d): range error", i);
+
+  return rng_base + rng_inc * i;
+}
+
+struct _rangeidx_helper
+{
+  double *array, base, inc;
+  _rangeidx_helper (double *a, double b, double i) 
+    : array (a), base (b), inc (i) { }
+  void operator () (octave_idx_type i)
+    { *array++ = base + i * inc; }
+};
+
+Array<double> 
+Range::index (const idx_vector& i) const
+{
+  Array<double> retval;
+
+  octave_idx_type n = rng_nelem;
+
+  if (i.is_colon ())
+    {
+      retval = matrix_value ().reshape (dim_vector (rng_nelem, 1));
+    }
+  else if (i.extent (n) != n)
+    {
+      (*current_liboctave_error_handler)
+        ("A(I): Index exceeds matrix dimension.");
+    }
+  else
+    {
+      dim_vector rd = i.orig_dimensions ();
+      octave_idx_type il = i.length (n);
+
+      // taken from Array.cc.
+
+      if (n != 1 && rd.is_vector ())
+        rd = dim_vector (1, il);
+
+      retval.clear (rd);
+
+      i.loop (n, _rangeidx_helper (retval.fortran_vec (), rng_base, rng_inc));
+    }
+
+  return retval;
+}
 
 // NOTE: max and min only return useful values if nelem > 0.
 
--- a/liboctave/Range.h
+++ b/liboctave/Range.h
@@ -77,6 +77,21 @@
 
   sortmode is_sorted (sortmode mode = ASCENDING) const;
 
+  // Support for single-index subscripting, without generating matrix cache.
+
+  double checkelem (octave_idx_type i) const;
+
+  double elem (octave_idx_type i) const
+    {
+#if defined (BOUNDS_CHECKING)
+      return checkelem (i);
+#else
+      return rng_base + rng_inc * i;
+#endif
+    }
+
+  Array<double> index (const idx_vector& i) const;
+
   void set_base (double b)
   {
     if (rng_base != b)
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,8 @@
+2009-12-14  Jaroslav Hajek  <highegg@gmail.com>
+
+	* ov-range.cc (octave_range::do_index_op): Defer single subscript to
+	new Range methods.
+
 2009-12-14  Jaroslav Hajek  <highegg@gmail.com>
 
 	* symtab.cc (symbol_table::cleanup): New static method.
--- a/src/ov-range.cc
+++ b/src/ov-range.cc
@@ -118,19 +118,28 @@
 octave_value
 octave_range::do_index_op (const octave_value_list& idx, bool resize_ok)
 {
-  // FIXME -- this doesn't solve the problem of
-  //
-  //   a = 1:5; a(1, 1, 1)
-  //
-  // and similar constructions.  Hmm...
+  if (idx.length () == 1 && ! resize_ok)
+    {
+      octave_value retval;
 
-  // FIXME -- using this constructor avoids possibly narrowing
-  // the range to a scalar value.  Need a better solution to this
-  // problem.
+      // The range can handle a single subscript.
+      idx_vector i = idx(0).index_vector ();
+      if (! error_state)
+        {
+          if (i.is_scalar () && i(0) < range.nelem ())
+            retval = range.elem (i(0));
+          else
+            retval = range.index (i);
+        }
 
-  octave_value tmp (new octave_matrix (range.matrix_value ()));
+      return retval;
+    }
+  else
+    {
+      octave_value tmp (new octave_matrix (range.matrix_value ()));
 
-  return tmp.do_index_op (idx, resize_ok);
+      return tmp.do_index_op (idx, resize_ok);
+    }
 }
 
 double