diff liboctave/idx-vector.cc @ 9879:034677ab6865

smarter treatment of mask indexing
author Jaroslav Hajek <highegg@gmail.com>
date Fri, 27 Nov 2009 14:42:07 +0100
parents 6dafc60dde31
children 83bd7f34f9da
line wrap: on
line diff
--- a/liboctave/idx-vector.cc	Fri Nov 27 09:10:21 2009 +0100
+++ b/liboctave/idx-vector.cc	Fri Nov 27 14:42:07 2009 +0100
@@ -288,11 +288,12 @@
     }
 }
 
-idx_vector::idx_vector_rep::idx_vector_rep (const Array<bool>& bnda)
-  : data (0), len (0), ext (0), aowner (0), orig_dims ()
+idx_vector::idx_vector_rep::idx_vector_rep (const Array<bool>& bnda,
+                                            octave_idx_type nnz)
+  : data (0), len (nnz), ext (0), aowner (0), orig_dims ()
 {
-  for (octave_idx_type i = 0, l = bnda.numel (); i < l; i++)
-    if (bnda.xelem (i)) len++;
+  if (nnz < 0)
+    len = bnda.nnz ();
 
   const dim_vector dv = bnda.dims ();
 
@@ -393,8 +394,107 @@
   return os;
 }
 
+DEFINE_OCTAVE_ALLOCATOR(idx_vector::idx_mask_rep);
+
+idx_vector::idx_mask_rep::idx_mask_rep (bool b)
+  : data (0), len (b ? 1 : 0), ext (0), lsti (-1), lste (-1),
+    aowner (0), orig_dims (len, len)
+{
+  if (len != 0)
+    {
+      bool *d = new bool [1];
+      d[0] = true;
+      data = d;
+      ext = 1;
+    }
+}
+
+idx_vector::idx_mask_rep::idx_mask_rep (const Array<bool>& bnda,
+                                        octave_idx_type nnz)
+  : data (0), len (nnz), ext (bnda.numel ()), lsti (-1), lste (-1),
+    aowner (0), orig_dims ()
+{
+  if (nnz < 0)
+    len = bnda.nnz ();
+
+  // We truncate the extent as much as possible. For Matlab
+  // compatibility, but maybe it's not a bad idea anyway.
+  while (ext > 0 && ! bnda(ext-1))
+    ext--;
+
+  const dim_vector dv = bnda.dims ();
+
+  if (! dv.all_zero ())
+    orig_dims = ((dv.length () == 2 && dv(0) == 1) 
+                 ? dim_vector (1, len) : dim_vector (len, 1));
+
+  aowner = new Array<bool> (bnda);
+  data = bnda.data ();
+}
+
+idx_vector::idx_mask_rep::~idx_mask_rep (void)
+{ 
+  if (aowner) 
+    delete aowner;
+  else
+    delete [] data; 
+}
+
+octave_idx_type
+idx_vector::idx_mask_rep::xelem (octave_idx_type n) const
+{
+  if (n == lsti + 1)
+    {
+      lsti = n;
+      while (! data[++lste]) ;
+    }
+  else
+    {
+      lsti = n++;
+      lste = -1;
+      while (n > 0)
+        if (data[++lste]) --n;
+    }
+  return lste;
+}
+
+octave_idx_type
+idx_vector::idx_mask_rep::checkelem (octave_idx_type n) const
+{
+  if (n < 0 || n >= len)
+    {
+      gripe_invalid_index ();
+      return 0;
+    }
+
+  return xelem (n);
+}
+
+std::ostream& 
+idx_vector::idx_mask_rep::print (std::ostream& os) const
+{
+  os << '[';
+  for (octave_idx_type ii = 0; ii < ext - 1; ii++)
+    os << data[ii] << ',' << ' ';
+  if (ext > 0) os << data[ext-1]; os << ']';
+
+  return os;
+}
+
 const idx_vector idx_vector::colon (new idx_vector::idx_colon_rep ());
 
+idx_vector::idx_vector (const Array<bool>& bnda)
+  : rep (0)
+{
+  // Convert only if it means saving at least half the memory.
+  static const int factor = (2 * sizeof (octave_idx_type));
+  octave_idx_type nnz = bnda.nnz ();
+  if (nnz <= bnda.numel () / factor)
+    rep = new idx_vector_rep (bnda, nnz);
+  else
+    rep = new idx_mask_rep (bnda, nnz);
+}
+
 bool idx_vector::maybe_reduce (octave_idx_type n, const idx_vector& j,
                                octave_idx_type nj)
 {
@@ -574,6 +674,17 @@
         res = true;
       }
       break;
+    case class_mask:
+      {
+        idx_mask_rep * r = dynamic_cast<idx_mask_rep *> (rep);
+        octave_idx_type ext = r->extent (0), len = r->length (0);
+        if (ext == len)
+          {
+            l = 0;
+            u = len;
+            res = true;
+          }
+      }
     default:
       break;
     }
@@ -702,8 +813,27 @@
   return retval;
 }
 
+idx_vector
+idx_vector::unmask (void) const
+{
+  if (idx_class () == class_mask)
+    {
+      idx_mask_rep * r = dynamic_cast<idx_mask_rep *> (rep);
+      const bool *data = r->get_data ();
+      octave_idx_type ext = r->extent (0), len = r->length (0);
+      octave_idx_type *idata = new octave_idx_type [len];
+      for (octave_idx_type i = 0, j = 0; i < ext; i++)
+        if (data[i]) 
+          idata[j++] = i;
+      ext = len > 0 ? idata[len - 1] : 0;
+      return new idx_vector_rep (idata, len, ext, r->orig_dimensions (), DIRECT);
+    }
+  else
+    return *this;
+}
+
 void idx_vector::unconvert (idx_class_type& iclass,
-                            double& scalar, Range& range, Array<double>& array) const
+                            double& scalar, Range& range, Array<double>& array)
 {
   iclass = idx_class ();
   switch (iclass)
@@ -733,6 +863,14 @@
             array.xelem (i) = data[i] + 1;
         }
       break;
+    case class_mask:
+        {
+          // This is done because we don't want a logical index be cached for a
+          // numeric array.
+          *this = unmask ();
+          unconvert (iclass, scalar, range, array);
+        }
+      break;
     default:
       assert (false);
       break;