diff liboctave/idx-vector.h @ 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 cddd5c3d5f04
line wrap: on
line diff
--- a/liboctave/idx-vector.h
+++ b/liboctave/idx-vector.h
@@ -59,7 +59,8 @@
       class_colon = 0,
       class_range,
       class_scalar,
-      class_vector
+      class_vector,
+      class_mask
     };
 
 private:
@@ -279,7 +280,7 @@
 
     idx_vector_rep (bool);
 
-    idx_vector_rep (const Array<bool>&);
+    idx_vector_rep (const Array<bool>&, octave_idx_type = -1);
 
     idx_vector_rep (const Sparse<bool>&);
 
@@ -328,6 +329,74 @@
     dim_vector orig_dims;
   };
 
+  // The logical mask index.
+  class OCTAVE_API idx_mask_rep : public idx_base_rep
+  {
+  public:
+    // Direct constructor.
+    idx_mask_rep (bool *_data, octave_idx_type _len, 
+                  octave_idx_type _ext, const dim_vector& od, direct)
+      : data (_data), len (_len), ext (_ext), aowner (0), orig_dims (od) { }
+
+    idx_mask_rep (void) 
+      : data (0), len (0), aowner (0)
+      { }
+
+    idx_mask_rep (bool);
+
+    idx_mask_rep (const Array<bool>&, octave_idx_type = -1);
+
+    ~idx_mask_rep (void);
+
+    octave_idx_type xelem (octave_idx_type i) const;
+
+    octave_idx_type checkelem (octave_idx_type i) const;
+
+    octave_idx_type length (octave_idx_type) const
+      { return len; }
+
+    octave_idx_type extent (octave_idx_type n) const
+      { return std::max (n, ext); }
+
+    idx_class_type idx_class (void) const { return class_mask; }
+
+    idx_base_rep *sort_uniq_clone (bool = false) 
+      { count++; return this; }
+
+    dim_vector orig_dimensions (void) const
+      { return orig_dims; }
+
+    bool is_colon_equiv (octave_idx_type n) const
+      { return count == n && ext == n; }
+
+    const bool *get_data (void) const { return data; }
+
+    std::ostream& print (std::ostream& os) const;
+
+  private:
+
+    DECLARE_OCTAVE_ALLOCATOR
+
+    // No copying!
+    idx_mask_rep (const idx_mask_rep& idx);
+
+    const bool *data;
+    octave_idx_type len, ext;
+
+    // FIXME: I'm not sure if this is a good design. Maybe it would be better to
+    // employ some sort of generalized iteration scheme.
+    mutable octave_idx_type lsti, lste;
+
+    // This is a trick to allow user-given mask arrays to be used as indices
+    // without copying. If the following pointer is nonzero, we do not own the data,
+    // but rather have an Array<bool> object that provides us the data.
+    // Note that we need a pointer because we deferred the Array<T> declaration and
+    // we do not want it yet to be defined.
+    
+    Array<bool> *aowner;
+
+    dim_vector orig_dims;
+  };
 
   idx_vector (idx_base_rep *r) : rep (r) { }
 
@@ -400,7 +469,7 @@
   idx_vector (float x) : rep (new idx_scalar_rep (x)) { chkerr (); }
 
   // A scalar bool does not necessarily map to scalar index.
-  idx_vector (bool x) : rep (new idx_vector_rep (x)) { chkerr (); }
+  idx_vector (bool x) : rep (new idx_mask_rep (x)) { chkerr (); }
 
   template <class T>
   idx_vector (const Array<octave_int<T> >& nda) : rep (new idx_vector_rep (nda))
@@ -412,8 +481,7 @@
   idx_vector (const Array<float>& nda) : rep (new idx_vector_rep (nda))
     { chkerr (); }
 
-  idx_vector (const Array<bool>& nda) : rep (new idx_vector_rep (nda))
-    { chkerr (); }
+  idx_vector (const Array<bool>& nda);
 
   idx_vector (const Range& r) 
     : rep (new idx_range_rep (r))
@@ -552,6 +620,15 @@
               dest[i] = src[data[i]];
           }
           break;
+        case 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);
+            for (octave_idx_type i = 0; i < ext; i++)
+              if (data[i]) *dest++ = src[i];
+          }
+          break;
         default:
           assert (false);
           break;
@@ -608,6 +685,15 @@
               dest[data[i]] = src[i];
           }
           break;
+        case 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);
+            for (octave_idx_type i = 0; i < ext; i++)
+              if (data[i]) dest[i] = *src++;
+          }
+          break;
         default:
           assert (false);
           break;
@@ -664,6 +750,15 @@
               dest[data[i]] = val;
           }
           break;
+        case 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);
+            for (octave_idx_type i = 0; i < ext; i++)
+              if (data[i]) dest[i] = val;
+          }
+          break;
         default:
           assert (false);
           break;
@@ -716,6 +811,15 @@
             for (octave_idx_type i = 0; i < len; i++) body (data[i]);
           }
           break;
+        case 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);
+            for (octave_idx_type i = 0, j = 0; i < ext; i++)
+              if (data[i]) body (j++);
+          }
+          break;
         default:
           assert (false);
           break;
@@ -776,6 +880,17 @@
             ret = i;
           }
           break;
+        case 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), j = 0;
+            for (octave_idx_type i = 0; i < ext; i++)
+              if (data[i] && body (j++))
+                break;
+            ret = j;
+          }
+          break;
         default:
           assert (false);
           break;
@@ -809,9 +924,13 @@
   // Copies all the indices to a given array. Not allowed for colons.
   void copy_data (octave_idx_type *data) const;
 
+  // If the index is a mask, convert it to index vector.
+  idx_vector unmask (void) const;
+
   // Unconverts the index to a scalar, Range or double array.
+  // Note that the index class can be changed, if it's a mask index.
   void unconvert (idx_class_type& iclass,
-                  double& scalar, Range& range, Array<double>& array) const;
+                  double& scalar, Range& range, Array<double>& array);
     
   // FIXME -- these are here for compatibility.  They should be removed
   // when no longer in use.