diff liboctave/Array.cc @ 4513:508238e65af7

[project @ 2003-09-19 21:40:57 by jwe]
author jwe
date Fri, 19 Sep 2003 21:41:21 +0000
parents 5719210fff4c
children b4449b1193ac
line wrap: on
line diff
--- a/liboctave/Array.cc
+++ b/liboctave/Array.cc
@@ -34,140 +34,220 @@
 #include <iostream>
 
 #include "Array.h"
-
-#if defined (HEAVYWEIGHT_INDEXING)
+#include "Array-idx.h"
 #include "idx-vector.h"
-#include "Array-idx.h"
-#endif
-
 #include "lo-error.h"
 
 // One dimensional array class.  Handles the reference counting for
 // all the derived classes.
 
 template <class T>
-Array<T>::Array (int n, const T& val)
-{
-  rep = new typename Array<T>::ArrayRep (n);
-
-  for (int i = 0; i < n; i++)
-    rep->data[i] = val;
-
-#ifdef HEAVYWEIGHT_INDEXING
-  max_indices = 1;
-  idx_count = 0;
-  idx = 0;
-#endif
-}
-
-template <class T>
 Array<T>::~Array (void)
 {
   if (--rep->count <= 0)
     delete rep;
 
-#ifdef HEAVYWEIGHT_INDEXING
   delete [] idx;
-#endif
+}
+
+// A guess (should be quite conservative).
+#define MALLOC_OVERHEAD 1024
+
+template <class T>
+int
+Array<T>::get_size (int r, int c)
+{
+  // XXX KLUGE XXX
+
+  // If an allocation of an array with r * c elements of type T
+  // would cause an overflow in the allocator when computing the
+  // size of the allocation, then return a value which, although
+  // not equivalent to the actual request, should be too large for
+  // most current hardware, but not so large to cause the
+  // allocator to barf on computing retval * sizeof (T).
+
+  static int nl;
+  static double dl
+    = frexp (static_cast<double>
+	     (INT_MAX - MALLOC_OVERHEAD) / sizeof (T), &nl);
+
+  // This value should be an integer.  If we return this value and
+  // things work the way we expect, we should be paying a visit to
+  // new_handler in no time flat.
+  static int max_items = static_cast<int> (ldexp (dl, nl));
+
+  int nr, nc;
+  double dr = frexp (static_cast<double> (r), &nr);
+  double dc = frexp (static_cast<double> (c), &nc);
+
+  int nt = nr + nc;
+  double dt = dr * dc;
+
+  if (dt <= 0.5)
+    {
+      nt--;
+      dt *= 2;
+
+      if (dt <= 0.5)
+	nt--;
+    }
+
+  return (nt < nl || (nt == nl && dt < dl)) ? r * c : max_items;
 }
 
 template <class T>
-Array<T>&
-Array<T>::operator = (const Array<T>& a)
+int
+Array<T>::get_size (int r, int c, int p)
 {
-  if (this != &a && rep != a.rep)
+  // XXX KLUGE XXX
+
+  // If an allocation of an array with r * c * p elements of type T
+  // would cause an overflow in the allocator when computing the
+  // size of the allocation, then return a value which, although
+  // not equivalent to the actual request, should be too large for
+  // most current hardware, but not so large to cause the
+  // allocator to barf on computing retval * sizeof (T).
+
+  static int nl;
+  static double dl
+    = frexp (static_cast<double>
+	     (INT_MAX - MALLOC_OVERHEAD) / sizeof (T), &nl);
+
+  // This value should be an integer.  If we return this value and
+  // things work the way we expect, we should be paying a visit to
+  // new_handler in no time flat.
+  static int max_items = static_cast<int> (ldexp (dl, nl));
+
+  int nr, nc, np;
+  double dr = frexp (static_cast<double> (r), &nr);
+  double dc = frexp (static_cast<double> (c), &nc);
+  double dp = frexp (static_cast<double> (p), &np);
+
+  int nt = nr + nc + np;
+  double dt = dr * dc * dp;
+
+  if (dt <= 0.5)
     {
-      if (--rep->count <= 0)
-	delete rep;
+      nt--;
+      dt *= 2;
 
-      rep = a.rep;
-      rep->count++;
+      if (dt <= 0.5)
+	nt--;
     }
 
-#ifdef HEAVYWEIGHT_INDEXING
-  idx_count = 0;
-  idx = 0;
-#endif
-
-  return *this;
+  return (nt < nl || (nt == nl && dt < dl)) ? r * c * p : max_items;
 }
 
 template <class T>
-void
-Array<T>::resize (int n)
+int
+Array<T>::get_size (const dim_vector& ra_idx)
 {
-  if (n < 0)
+  // XXX KLUGE XXX
+
+  // If an allocation of an array with r * c elements of type T
+  // would cause an overflow in the allocator when computing the
+  // size of the allocation, then return a value which, although
+  // not equivalent to the actual request, should be too large for
+  // most current hardware, but not so large to cause the
+  // allocator to barf on computing retval * sizeof (T).
+
+  static int nl;
+  static double dl
+    = frexp (static_cast<double>
+	     (INT_MAX - MALLOC_OVERHEAD) / sizeof (T), &nl);
+
+  // This value should be an integer.  If we return this value and
+  // things work the way we expect, we should be paying a visit to
+  // new_handler in no time flat.
+
+  static int max_items = static_cast<int> (ldexp (dl, nl));
+
+  int retval = max_items;
+
+  int n = ra_idx.length ();
+
+  int nt = 0;
+  double dt = 1;
+
+  for (int i = 0; i < n; i++)
     {
-      (*current_liboctave_error_handler) ("can't resize to negative dimension");
-      return;
+      int nra_idx;
+      double dra_idx = frexp (static_cast<double> (ra_idx(i)), &nra_idx);
+
+      nt += nra_idx;
+      dt *= dra_idx;
     }
 
-  if (n == length ())
-    return;
-
-  typename Array<T>::ArrayRep *old_rep = rep;
-  const T *old_data = data ();
-  int old_len = length ();
+  if (dt <= 0.5)
+    {
+      nt--;
+      dt *= 2;
 
-  rep = new typename Array<T>::ArrayRep (n);
-
-  if (old_data && old_len > 0)
-    {
-      int min_len = old_len < n ? old_len : n;
-
-      for (int i = 0; i < min_len; i++)
-	xelem (i) = old_data[i];
+      if (dt <= 0.5)
+	nt--;
     }
 
-  if (--old_rep->count <= 0)
-    delete old_rep;
+  if (nt < nl || (nt == nl && dt < dl))
+    {
+      retval = 1;
+
+      for (int i = 0; i < n; i++)
+	retval *= ra_idx(i);
+    }
+
+  return retval;
 }
 
+#undef MALLOC_OVERHEAD
+
 template <class T>
-void
-Array<T>::resize (int n, const T& val)
+int
+Array<T>::compute_index (const Array<int>& ra_idx) const
 {
-  if (n < 0)
+  int retval = -1;
+
+  int n = dimensions.length ();
+
+  if (n > 0 && n == ra_idx.length ())
     {
-      (*current_liboctave_error_handler) ("can't resize to negative dimension");
-      return;
-    }
-
-  if (n == length ())
-    return;
-
-  typename Array<T>::ArrayRep *old_rep = rep;
-  const T *old_data = data ();
-  int old_len = length ();
+      retval = ra_idx(--n);
 
-  rep = new typename Array<T>::ArrayRep (n);
-
-  int min_len = old_len < n ? old_len : n;
+      while (--n >= 0)
+	{
+	  retval *= dimensions(n);
+	  retval += ra_idx(n);
+	}
+    }
+  else
+    (*current_liboctave_error_handler)
+      ("Array<T>::compute_index: invalid ra_idxing operation");
 
-  if (old_data && old_len > 0)
-    {
-      for (int i = 0; i < min_len; i++)
-	xelem (i) = old_data[i];
-    }
-
-  for (int i = old_len; i < n; i++)
-    xelem (i) = val;
-
-  if (--old_rep->count <= 0)
-    delete old_rep;
+  return retval;
 }
 
+#if 0
+
 template <class T>
-T *
-Array<T>::fortran_vec (void)
+int
+Array<T>::compute_index (int i, int j) const
 {
-  if (rep->count > 1)
-    {
-      --rep->count;
-      rep = new typename Array<T>::ArrayRep (*rep);
-    }
-  return rep->data;
+  int retval = -1;
+
+  int n = dimensions.length ();
+
+  if (n == 2)
+    retval = j*dimensions(0)+i;
+  else if (n == 1 && j == 0)
+    retval = i;
+  else
+    (*current_liboctave_error_handler)
+      ("Array<T>::compute_index: invalid ra_idxing operation");
+
+  return retval;
 }
+
+#endif
+
 template <class T>
 T
 Array<T>::range_error (const char *fcn, int n) const
@@ -186,6 +266,572 @@
 }
 
 template <class T>
+T
+Array<T>::range_error (const char *fcn, int i, int j) const
+{
+  (*current_liboctave_error_handler)
+    ("%s (%d, %d): range error", fcn, i, j);
+  return T ();
+}
+
+template <class T>
+T&
+Array<T>::range_error (const char *fcn, int i, int j)
+{
+  (*current_liboctave_error_handler)
+    ("%s (%d, %d): range error", fcn, i, j);
+  static T foo;
+  return foo;
+}
+
+template <class T>
+T
+Array<T>::range_error (const char *fcn, int i, int j, int k) const
+{
+  (*current_liboctave_error_handler)
+    ("%s (%d, %d, %d): range error", fcn, i, j, k);
+  return T ();
+}
+
+template <class T>
+T&
+Array<T>::range_error (const char *fcn, int i, int j, int k)
+{
+  (*current_liboctave_error_handler)
+    ("%s (%d, %d, %d): range error", fcn, i, j, k);
+  static T foo;
+  return foo;
+}
+
+template <class T>
+T
+Array<T>::range_error (const char *fcn, const Array<int>& ra_idx) const
+{
+  // XXX FIXME XXX -- report index values too!
+
+  (*current_liboctave_error_handler) ("range error in Array");
+
+  return T ();
+}
+
+template <class T>
+T&
+Array<T>::range_error (const char *fcn, const Array<int>& ra_idx)
+{
+  // XXX FIXME XXX -- report index values too!
+
+  (*current_liboctave_error_handler) ("range error in Array");
+
+  static T foo;
+  return foo;
+}
+
+template <class T>
+void
+Array<T>::resize_no_fill (int n)
+{
+  if (n < 0)
+    {
+      (*current_liboctave_error_handler)
+	("can't resize to negative dimension");
+      return;
+    }
+
+  if (n == length ())
+    return;
+
+  typename Array<T>::ArrayRep *old_rep = rep;
+  const T *old_data = data ();
+  int old_len = length ();
+
+  rep = new typename Array<T>::ArrayRep (n);
+
+  dimensions = dim_vector (n);
+
+  if (old_data && old_len > 0)
+    {
+      int min_len = old_len < n ? old_len : n;
+
+      for (int i = 0; i < min_len; i++)
+	xelem (i) = old_data[i];
+    }
+
+  if (--old_rep->count <= 0)
+    delete old_rep;
+}
+
+template <class T>
+void
+Array<T>::resize_no_fill (const dim_vector& dims)
+{
+  int n = dims.length ();
+
+  for (int i = 0; i < n; i++)
+    {
+      if (dims(i) < 0)
+	{
+	  (*current_liboctave_error_handler)
+	    ("can't resize to negative dimension");
+	  return;
+	}
+    }
+
+  bool no_change = true;
+
+  for (int i = 0; i < n; i++)
+    {
+      if (dims(i) != dimensions(i))
+	{
+	  no_change = false;
+	  break;
+	}
+    }
+
+  if (no_change)
+    return;
+
+  int old_len = length ();
+
+  typename Array<T>::ArrayRep *old_rep = rep;
+  const T *old_data = data ();
+
+  rep = new typename Array<T>::ArrayRep (get_size (dims));
+
+  dim_vector old_dimensions = dimensions;
+
+  dimensions = dims;
+
+  Array<int> ra_idx (dimensions.length (), 0);
+
+  for (int i = 0; i < old_len; i++)
+    {
+      if (index_in_bounds (ra_idx, dimensions))
+	xelem (ra_idx) = old_data[i];
+
+      increment_index (ra_idx, dimensions);
+    }
+
+  if (--old_rep->count <= 0)
+    delete old_rep;
+}
+
+template <class T>
+void
+Array<T>::resize_no_fill (int r, int c)
+{
+  if (r < 0 || c < 0)
+    {
+      (*current_liboctave_error_handler)
+	("can't resize to negative dimension");
+      return;
+    }
+
+  if (r == dim1 () && c == dim2 ())
+    return;
+
+  typename Array<T>::ArrayRep *old_rep = Array<T>::rep;
+  const T *old_data = data ();
+
+  int old_d1 = dim1 ();
+  int old_d2 = dim2 ();
+  int old_len = length ();
+
+  rep = new typename Array<T>::ArrayRep (get_size (r, c));
+
+  dimensions = dim_vector (r, c);
+
+  if (old_data && old_len > 0)
+    {
+      int min_r = old_d1 < r ? old_d1 : r;
+      int min_c = old_d2 < c ? old_d2 : c;
+
+      for (int j = 0; j < min_c; j++)
+	for (int i = 0; i < min_r; i++)
+	  xelem (i, j) = old_data[old_d1*j+i];
+    }
+
+  if (--old_rep->count <= 0)
+    delete old_rep;
+}
+
+template <class T>
+void
+Array<T>::resize_no_fill (int r, int c, int p)
+{
+  if (r < 0 || c < 0 || p < 0)
+    {
+      (*current_liboctave_error_handler)
+	("can't resize to negative dimension");
+      return;
+    }
+
+  if (r == dim1 () && c == dim2 () && p == dim3 ())
+    return;
+
+  typename Array<T>::ArrayRep *old_rep = rep;
+  const T *old_data = data ();
+
+  int old_d1 = dim1 ();
+  int old_d2 = dim2 ();
+  int old_d3 = dim3 ();
+  int old_len = length ();
+
+  int ts = get_size (get_size (r, c), p);
+
+  rep = new typename Array<T>::ArrayRep (ts);
+
+  dimensions = dim_vector (r, c, p);
+
+  if (old_data && old_len > 0)
+    {
+      int min_r = old_d1 < r ? old_d1 : r;
+      int min_c = old_d2 < c ? old_d2 : c;
+      int min_p = old_d3 < p ? old_d3 : p;
+
+      for (int k = 0; k < min_p; k++)
+	for (int j = 0; j < min_c; j++)
+	  for (int i = 0; i < min_r; i++)
+	    xelem (i, j, k) = old_data[old_d1*(old_d2*k+j)+i];
+    }
+
+  if (--old_rep->count <= 0)
+    delete old_rep;
+}
+
+template <class T>
+void
+Array<T>::resize_and_fill (int n, const T& val)
+{
+  if (n < 0)
+    {
+      (*current_liboctave_error_handler)
+	("can't resize to negative dimension");
+      return;
+    }
+
+  if (n == length ())
+    return;
+
+  typename Array<T>::ArrayRep *old_rep = rep;
+  const T *old_data = data ();
+  int old_len = length ();
+
+  rep = new typename Array<T>::ArrayRep (n);
+
+  dimensions = dim_vector (n);
+
+  int min_len = old_len < n ? old_len : n;
+
+  if (old_data && old_len > 0)
+    {
+      for (int i = 0; i < min_len; i++)
+	xelem (i) = old_data[i];
+    }
+
+  for (int i = old_len; i < n; i++)
+    xelem (i) = val;
+
+  if (--old_rep->count <= 0)
+    delete old_rep;
+}
+
+template <class T>
+void
+Array<T>::resize_and_fill (int r, int c, const T& val)
+{
+  if (r < 0 || c < 0)
+    {
+      (*current_liboctave_error_handler)
+	("can't resize to negative dimension");
+      return;
+    }
+
+  if (r == dim1 () && c == dim2 ())
+    return;
+
+  typename Array<T>::ArrayRep *old_rep = Array<T>::rep;
+  const T *old_data = data ();
+
+  int old_d1 = dim1 ();
+  int old_d2 = dim2 ();
+  int old_len = length ();
+
+  rep = new typename Array<T>::ArrayRep (get_size (r, c));
+
+  dimensions = dim_vector (r, c);
+
+  int min_r = old_d1 < r ? old_d1 : r;
+  int min_c = old_d2 < c ? old_d2 : c;
+
+  if (old_data && old_len > 0)
+    {
+      for (int j = 0; j < min_c; j++)
+	for (int i = 0; i < min_r; i++)
+	  xelem (i, j) = old_data[old_d1*j+i];
+    }
+
+  for (int j = 0; j < min_c; j++)
+    for (int i = min_r; i < r; i++)
+      xelem (i, j) = val;
+
+  for (int j = min_c; j < c; j++)
+    for (int i = 0; i < r; i++)
+      xelem (i, j) = val;
+
+  if (--old_rep->count <= 0)
+    delete old_rep;
+}
+
+template <class T>
+void
+Array<T>::resize_and_fill (int r, int c, int p, const T& val)
+{
+  if (r < 0 || c < 0 || p < 0)
+    {
+      (*current_liboctave_error_handler)
+	("can't resize to negative dimension");
+      return;
+    }
+
+  if (r == dim1 () && c == dim2 () && p == dim3 ())
+    return;
+
+  typename Array<T>::ArrayRep *old_rep = rep;
+  const T *old_data = data ();
+
+  int old_d1 = dim1 ();
+  int old_d2 = dim2 ();
+  int old_d3 = dim3 ();
+
+  int old_len = length ();
+
+  int ts = get_size (get_size (r, c), p);
+
+  rep = new typename Array<T>::ArrayRep (ts);
+
+  dimensions = dim_vector (r, c, p);
+
+  int min_r = old_d1 < r ? old_d1 : r;
+  int min_c = old_d2 < c ? old_d2 : c;
+  int min_p = old_d3 < p ? old_d3 : p;
+
+  if (old_data && old_len > 0)
+    for (int k = 0; k < min_p; k++)
+      for (int j = 0; j < min_c; j++)
+	for (int i = 0; i < min_r; i++)
+	  xelem (i, j, k) = old_data[old_d1*(old_d2*k+j)+i];
+
+  // XXX FIXME XXX -- if the copy constructor is expensive, this may
+  // win.  Otherwise, it may make more sense to just copy the value
+  // everywhere when making the new ArrayRep.
+
+  for (int k = 0; k < min_p; k++)
+    for (int j = min_c; j < c; j++)
+      for (int i = 0; i < min_r; i++)
+	xelem (i, j, k) = val;
+
+  for (int k = 0; k < min_p; k++)
+    for (int j = 0; j < c; j++)
+      for (int i = min_r; i < r; i++)
+	xelem (i, j, k) = val;
+
+  for (int k = min_p; k < p; k++)
+    for (int j = 0; j < c; j++)
+      for (int i = 0; i < r; i++)
+	xelem (i, j, k) = val;
+
+  if (--old_rep->count <= 0)
+    delete old_rep;
+}
+
+template <class T>
+void
+Array<T>::resize_and_fill (const dim_vector& dims, const T& val)
+{
+  int n = dims.length ();
+
+  for (int i = 0; i < n; i++)
+    {
+      if (dims(i) < 0)
+	{
+	  (*current_liboctave_error_handler)
+	    ("can't resize to negative dimension");
+	  return;
+	}
+    }
+
+  bool no_change = true;
+
+  for (int i = 0; i < n; i++)
+    {
+      if (dims(i) != dimensions(i))
+	{
+	  no_change = false;
+	  break;
+	}
+    }
+
+  if (no_change)
+    return;
+
+  typename Array<T>::ArrayRep *old_rep = rep;
+  const T *old_data = data ();
+
+  int old_len = length ();
+
+  int len = get_size (dims);
+
+  rep = new typename Array<T>::ArrayRep (len);
+
+  dim_vector old_dimensions = dimensions;
+
+  dimensions = dims;
+
+  Array<int> ra_idx (dimensions.length (), 0);
+
+  // XXX FIXME XXX -- it is much simpler to fill the whole array
+  // first, but probably slower for large arrays, or if the assignment
+  // operator for the type T is expensive.  OTOH, the logic for
+  // deciding whether an element needs the copied value or the filled
+  // value might be more expensive.
+
+  for (int i = 0; i < len; i++)
+    rep->elem (i) = val;
+
+  for (int i = 0; i < old_len; i++)
+    {
+      if (index_in_bounds (ra_idx, dimensions))
+	xelem (ra_idx) = old_data[i];
+
+      increment_index (ra_idx, dimensions);
+    }
+
+  if (--old_rep->count <= 0)
+    delete old_rep;
+}
+
+template <class T>
+Array<T>&
+Array<T>::insert (const Array<T>& a, int r, int c)
+{
+  int a_rows = a.rows ();
+  int a_cols = a.cols ();
+
+  if (r < 0 || r + a_rows > rows () || c < 0 || c + a_cols > cols ())
+    {
+      (*current_liboctave_error_handler) ("range error for insert");
+      return *this;
+    }
+
+  for (int j = 0; j < a_cols; j++)
+    for (int i = 0; i < a_rows; i++)
+      elem (r+i, c+j) = a.elem (i, j);
+
+  return *this;
+}
+
+template <class T>
+Array<T>&
+Array<T>::insert (const Array<T>& a, const Array<int>& ra_idx)
+{
+  int n = ra_idx.length ();
+
+  if (n == dimensions.length ())
+    {
+      dim_vector a_dims = a.dims ();
+
+      for (int i = 0; i < n; i++)
+	{
+	  if (ra_idx(i) < 0 || ra_idx(i) + a_dims(i) > dimensions(i))
+	    {
+	      (*current_liboctave_error_handler)
+		("Array<T>::insert: range error for insert");
+	      return *this;
+	    }
+	}
+
+#if 0
+      // XXX FIXME XXX -- need to copy elements
+
+      for (int j = 0; j < a_cols; j++)
+	for (int i = 0; i < a_rows; i++)
+	  elem (r+i, c+j) = a.elem (i, j);
+#endif
+
+    }
+  else
+    (*current_liboctave_error_handler)
+      ("Array<T>::insert: invalid indexing operation");
+
+  return *this;
+}
+
+template <class T>
+void
+Array<T>::maybe_delete_dims (void)
+{
+  int ndims = dimensions.length ();
+
+  dim_vector new_dims (1, 1);
+
+  bool delete_dims = true;
+
+  for (int i = ndims - 1; i >= 0; i--)
+    {
+      if (delete_dims)
+        {
+          if (dimensions(i) != 1)
+	    {
+	      delete_dims = false;
+
+	      new_dims = dim_vector (i + 1, dimensions(i));
+	    }
+        }
+      else
+	new_dims(i) = dimensions(i);
+    }
+    
+  if (ndims != new_dims.length ())
+    dimensions = new_dims;
+}
+
+template <class T>
+Array<T>
+Array<T>::transpose (void) const
+{
+  int nr = dim1 ();
+  int nc = dim2 ();
+
+  if (nr > 1 && nc > 1)
+    {
+      Array<T> result (dim_vector (nc, nr));
+
+      for (int j = 0; j < nc; j++)
+	for (int i = 0; i < nr; i++)
+	  result.xelem (j, i) = xelem (i, j);
+
+      return result;
+    }
+  else
+    {
+      // Fast transpose for vectors and empty matrices
+      return Array<T> (*this, dim_vector (nc, nr));
+    }
+}
+
+template <class T>
+T *
+Array<T>::fortran_vec (void)
+{
+  if (rep->count > 1)
+    {
+      --rep->count;
+      rep = new typename Array<T>::ArrayRep (*rep);
+    }
+  return rep->data;
+}
+
+template <class T>
 void
 Array<T>::print_info (std::ostream& os, const std::string& prefix) const
 {
@@ -193,6 +839,11 @@
      << prefix << "rep->len:    " << rep->len << "\n"
      << prefix << "rep->data:   " << static_cast<void *> (rep->data) << "\n"
      << prefix << "rep->count:  " << rep->count << "\n";
+
+  // 2D info:
+  //
+  //     << prefix << "rows: " << rows () << "\n"
+  //     << prefix << "cols: " << cols () << "\n";
 }
 
 /*