diff liboctave/Array.h @ 8523:ad3afaaa19c1

implement non-copying contiguous range indexing
author Jaroslav Hajek <highegg@gmail.com>
date Thu, 15 Jan 2009 07:22:24 +0100
parents 8ba2ee57c594
children 937921654627
line wrap: on
line diff
--- a/liboctave/Array.h	Thu Jan 15 01:06:06 2009 -0500
+++ b/liboctave/Array.h	Thu Jan 15 07:22:24 2009 +0100
@@ -3,7 +3,7 @@
 
 Copyright (C) 1993, 1994, 1995, 1996, 1997, 2000, 2001, 2002, 2003,
               2004, 2005, 2006, 2007 John W. Eaton
-Copyright (C) 2008 Jaroslav Hajek <highegg@gmail.com>
+Copyright (C) 2008, 2009 Jaroslav Hajek <highegg@gmail.com>
 
 This file is part of Octave.
 
@@ -30,6 +30,7 @@
 #include <cstddef>
 
 #include <iostream>
+#include <algorithm>
 
 #include "dim-vector.h"
 #include "idx-vector.h"
@@ -58,7 +59,12 @@
     octave_idx_type len;
     int count;
 
-    ArrayRep (T *d, octave_idx_type l) : data (d), len (l), count (1) { }
+    ArrayRep (T *d, octave_idx_type l, bool copy = false) 
+      : data (copy ? new T [l] : d), len (l), count (1) 
+        { 
+          if (copy)
+            std::copy (d, d + l, data);
+        }
 
     ArrayRep (void) : data (0), len (0), count (1) { }
 
@@ -67,30 +73,19 @@
     explicit ArrayRep (octave_idx_type n, const T& val)
       : data (new T [n]), len (n), count (1)
       {
-	fill (val);
+        std::fill (data, data + n, val);
       }
 
     ArrayRep (const ArrayRep& a)
       : data (new T [a.len]), len (a.len), count (1)
       {
-        for (octave_idx_type i = 0; i < len; i++)
-	  data[i] = a.data[i];
+        std::copy (a.data, a.data + a.len, data);
       }
  
     ~ArrayRep (void) { delete [] data; }
 
     octave_idx_type length (void) const { return len; }
 
-    void fill (const T& val)
-      {
-	for (octave_idx_type i = 0; i < len; i++)
-	  data[i] = val;
-      }
-
-    T& elem (octave_idx_type n) { return data[n]; }
-
-    T elem (octave_idx_type n) const { return data[n]; }
-
   private:
 
     // No assignment!
@@ -110,19 +105,29 @@
       if (rep->count > 1)
 	{
 	  --rep->count;
-	  rep = new ArrayRep (*rep);
+	  rep = new ArrayRep (slice_data, slice_len, true);
+          slice_data = rep->data;
 	}
-    }
+      else if (slice_len != rep->len)
+        {
+          // Possibly economize here.
+          ArrayRep *new_rep = new ArrayRep (slice_data, slice_len, true);
+          delete rep;
+          rep = new_rep;
+          slice_data = rep->data;
+        }
+      }
 
   void make_unique (const T& val)
     {
       if (rep->count > 1)
 	{
 	  --rep->count;
-	  rep = new ArrayRep (rep->length (), val);
+	  rep = new ArrayRep (slice_len, val);
+          slice_data = rep->data;
 	}
       else
-	rep->fill (val);
+        std::fill (slice_data, slice_data + slice_len, val);
     }
 
   typedef T element_type;
@@ -136,12 +141,33 @@
 
 protected:
 
+  T* slice_data;
+  octave_idx_type slice_len;
+
   Array (T *d, octave_idx_type n)
-    : rep (new typename Array<T>::ArrayRep (d, n)), dimensions (n) { }
+    : rep (new typename Array<T>::ArrayRep (d, n)), dimensions (n) 
+    { 
+      slice_data = rep->data;
+      slice_len = rep->len;
+    }
 
   Array (T *d, const dim_vector& dv)
     : rep (new typename Array<T>::ArrayRep (d, get_size (dv))),
-      dimensions (dv) { }
+      dimensions (dv) 
+    { 
+      slice_data = rep->data;
+      slice_len = rep->len;
+    }
+
+  // slice constructor
+  Array (const Array<T>& a, const dim_vector& dv,
+         octave_idx_type l, octave_idx_type u)
+    : rep(a.rep), dimensions (dv)
+    {
+      rep->count++;
+      slice_data = a.slice_data + l;
+      slice_len = std::min (u, a.slice_len) - l;
+    }
 
 private:
 
@@ -168,14 +194,25 @@
 public:
 
   Array (void)
-    : rep (nil_rep ()), dimensions () { rep->count++; }
+    : rep (nil_rep ()), dimensions () 
+    { 
+      rep->count++; 
+      slice_data = rep->data;
+      slice_len = rep->len;
+    }
 
   explicit Array (octave_idx_type n)
-    : rep (new typename Array<T>::ArrayRep (n)), dimensions (n) { }
+    : rep (new typename Array<T>::ArrayRep (n)), dimensions (n) 
+    { 
+      slice_data = rep->data;
+      slice_len = rep->len;
+    }
 
   explicit Array (octave_idx_type n, const T& val)
     : rep (new typename Array<T>::ArrayRep (n)), dimensions (n)
     {
+      slice_data = rep->data;
+      slice_len = rep->len;
       fill (val);
     }
 
@@ -185,6 +222,8 @@
     : rep (new typename Array<T>::ArrayRep (coerce (a.data (), a.length ()), a.length ())),
       dimensions (a.dimensions)
     {
+      slice_data = rep->data;
+      slice_len = rep->len;
     }
 
   // No type conversion case.
@@ -192,18 +231,26 @@
     : rep (a.rep), dimensions (a.dimensions)
     {
       rep->count++;
+      slice_data = a.slice_data;
+      slice_len = a.slice_len;
     }
 
 public:
 
   Array (const dim_vector& dv)
     : rep (new typename Array<T>::ArrayRep (get_size (dv))),
-      dimensions (dv) { }
+      dimensions (dv) 
+    { 
+      slice_data = rep->data;
+      slice_len = rep->len;
+    }
 
   Array (const dim_vector& dv, const T& val)
     : rep (new typename Array<T>::ArrayRep (get_size (dv))),
       dimensions (dv)
     {
+      slice_data = rep->data;
+      slice_len = rep->len;
       fill (val);
     }
 
@@ -215,7 +262,7 @@
 
   void fill (const T& val) { make_unique (val); }
 
-  octave_idx_type capacity (void) const { return rep->length (); }
+  octave_idx_type capacity (void) const { return slice_len; }
   octave_idx_type length (void) const { return capacity (); }
   octave_idx_type nelem (void) const { return capacity (); }
   octave_idx_type numel (void) const { return nelem (); }
@@ -258,8 +305,8 @@
 
   // No checking, even for multiple references, ever.
 
-  T& xelem (octave_idx_type n) { return rep->elem (n); }
-  T xelem (octave_idx_type n) const { return rep->elem (n); }
+  T& xelem (octave_idx_type n) { return slice_data [n]; }
+  T xelem (octave_idx_type n) const { return slice_data [n]; }
 
   T& xelem (octave_idx_type i, octave_idx_type j) { return xelem (dim1()*j+i); }
   T xelem (octave_idx_type i, octave_idx_type j) const { return xelem (dim1()*j+i); }
@@ -279,7 +326,7 @@
 
   T& checkelem (octave_idx_type n)
     {
-      if (n < 0 || n >= rep->length ())
+      if (n < 0 || n >= slice_len)
 	return range_error ("T& Array<T>::checkelem", n);
       else
 	{
@@ -341,7 +388,7 @@
 
   T checkelem (octave_idx_type n) const
     {
-      if (n < 0 || n >= rep->length ())
+      if (n < 0 || n >= slice_len)
 	return range_error ("T Array<T>::checkelem", n);
       else
 	return xelem (n);
@@ -407,7 +454,7 @@
   Array<T> transpose (void) const;
   Array<T> hermitian (T (*fcn) (const T&) = 0) const;
 
-  const T *data (void) const { return rep->data; }
+  const T *data (void) const { return slice_data; }
 
   const T *fortran_vec (void) const { return data (); }
 
@@ -513,6 +560,17 @@
 
   Array<T>& insert (const Array<T>& a, const Array<octave_idx_type>& idx);
 
+  void maybe_economize (void)
+    {
+      if (rep->count == 1 && slice_len != rep->len)
+        {
+          ArrayRep *new_rep = new ArrayRep (slice_data, slice_len, true);
+          delete rep;
+          rep = new_rep;
+          slice_data = rep->data;
+        }
+    }
+
   void print_info (std::ostream& os, const std::string& prefix) const;
 
   // Unsafe.  This function exists to support the MEX interface.