# HG changeset patch
# User Jaroslav Hajek
# Date 1231945605 -3600
# Node ID f3a54bae02c8e81cd79a8ceac45065f8af07f7fc
# Parent 0e0bd07e6ae2df29a519e2c26a5561a5f5d4a0be
implement non-copying contiguous range indexing
diff --git a/liboctave/Array.cc b/liboctave/Array.cc
--- a/liboctave/Array.cc
+++ b/liboctave/Array.cc
@@ -3,7 +3,7 @@
Copyright (C) 1993, 1994, 1995, 1996, 1997, 2000, 2002, 2003, 2004,
2005, 2006, 2007 John W. Eaton
-Copyright (C) 2008 Jaroslav Hajek
+Copyright (C) 2008, 2009 Jaroslav Hajek
This file is part of Octave.
@@ -47,7 +47,8 @@
template
Array::Array (const Array& a, const dim_vector& dv)
- : rep (a.rep), dimensions (dv)
+ : rep (a.rep), dimensions (dv),
+ slice_data (a.slice_data), slice_len (a.slice_len)
{
rep->count++;
@@ -76,6 +77,8 @@
rep->count++;
dimensions = a.dimensions;
+ slice_data = a.slice_data;
+ slice_len = a.slice_len;
}
return *this;
@@ -680,6 +683,11 @@
template
void fill (const T& val, T *dest) const { do_fill (val, dest, top); }
+ bool is_cont_range (octave_idx_type& l,
+ octave_idx_type& u) const
+ {
+ return top == 0 && idx[0].is_cont_range (dim[0], l, u);
+ }
};
// Helper class for multi-d recursive resizing
@@ -758,9 +766,7 @@
if (i.is_colon ())
{
// A(:) produces a shallow copy as a column vector.
- retval.dimensions = dim_vector (n, 1);
- rep->count++;
- retval.rep = rep;
+ retval = Array (*this, dim_vector (n, 1));
}
else if (i.extent (n) != n)
{
@@ -797,12 +803,19 @@
rd = dim_vector (1, il);
}
- // Don't use resize here to avoid useless initialization for POD
- // types.
- retval = Array (rd);
+ octave_idx_type l, u;
+ if (il != 0 && i.is_cont_range (n, l, u))
+ // If suitable, produce a shallow slice.
+ retval = Array (*this, rd, l, u);
+ else
+ {
+ // Don't use resize here to avoid useless initialization for POD
+ // types.
+ retval = Array (rd);
- if (il != 0)
- i.index (data (), n, retval.fortran_vec ());
+ if (il != 0)
+ i.index (data (), n, retval.fortran_vec ());
+ }
}
return retval;
@@ -830,18 +843,30 @@
{
octave_idx_type n = numel (), il = i.length (r), jl = j.length (c);
- // Don't use resize here to avoid useless initialization for POD types.
- retval = Array (dim_vector (il, jl));
-
idx_vector ii (i);
- const T* src = data ();
- T *dest = retval.fortran_vec ();
+ if (ii.maybe_reduce (r, j, c))
+ {
+ octave_idx_type l, u;
+ if (ii.length () > 0 && ii.is_cont_range (n, l, u))
+ // If suitable, produce a shallow slice.
+ retval = Array (*this, dim_vector (il, jl), l, u);
+ else
+ {
+ // Don't use resize here to avoid useless initialization for POD types.
+ retval = Array (dim_vector (il, jl));
- if (ii.maybe_reduce (r, j, c))
- ii.index (src, n, dest);
+ ii.index (data (), n, retval.fortran_vec ());
+ }
+ }
else
{
+ // Don't use resize here to avoid useless initialization for POD types.
+ retval = Array (dim_vector (il, jl));
+
+ const T* src = data ();
+ T *dest = retval.fortran_vec ();
+
for (octave_idx_type k = 0; k < jl; k++)
dest += i.index (src + r * j.xelem (k), r, dest);
}
@@ -898,14 +923,21 @@
for (int i = 0; i < ial; i++) rdv(i) = ia(i).length (dv(i));
rdv.chop_trailing_singletons ();
- // Don't use resize here to avoid useless initialization for POD types.
- retval = Array (rdv);
-
// Prepare for recursive indexing
rec_index_helper rh (dv, ia);
- // Do it.
- rh.index (data (), retval.fortran_vec ());
+ octave_idx_type l, u;
+ if (rh.is_cont_range (l, u))
+ // If suitable, produce a shallow slice.
+ retval = Array (*this, rdv, l, u);
+ else
+ {
+ // Don't use resize here to avoid useless initialization for POD types.
+ retval = Array (rdv);
+
+ // Do it.
+ rh.index (data (), retval.fortran_vec ());
+ }
}
}
@@ -1842,7 +1874,7 @@
{
make_unique ();
- return rep->data;
+ return slice_data;
}
template
@@ -2168,10 +2200,12 @@
void
Array::print_info (std::ostream& os, const std::string& prefix) const
{
- os << prefix << "rep address: " << rep << "\n"
- << prefix << "rep->len: " << rep->len << "\n"
- << prefix << "rep->data: " << static_cast (rep->data) << "\n"
- << prefix << "rep->count: " << rep->count << "\n";
+ os << prefix << "rep address: " << rep << '\n'
+ << prefix << "rep->len: " << rep->len << '\n'
+ << prefix << "rep->data: " << static_cast (rep->data) << '\n'
+ << prefix << "rep->count: " << rep->count << '\n'
+ << prefix << "slice_data: " << static_cast (slice_data) << '\n'
+ << prefix << "slice_len: " << slice_len << '\n';
// 2D info:
//
diff --git a/liboctave/Array.h b/liboctave/Array.h
--- a/liboctave/Array.h
+++ b/liboctave/Array.h
@@ -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
+Copyright (C) 2008, 2009 Jaroslav Hajek
This file is part of Octave.
@@ -30,6 +30,7 @@
#include
#include
+#include
#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,29 +73,18 @@
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:
@@ -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::ArrayRep (d, n)), dimensions (n) { }
+ : rep (new typename Array::ArrayRep (d, n)), dimensions (n)
+ {
+ slice_data = rep->data;
+ slice_len = rep->len;
+ }
Array (T *d, const dim_vector& dv)
: rep (new typename Array::ArrayRep (d, get_size (dv))),
- dimensions (dv) { }
+ dimensions (dv)
+ {
+ slice_data = rep->data;
+ slice_len = rep->len;
+ }
+
+ // slice constructor
+ Array (const Array& 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::ArrayRep (n)), dimensions (n) { }
+ : rep (new typename Array::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::ArrayRep (n)), dimensions (n)
{
+ slice_data = rep->data;
+ slice_len = rep->len;
fill (val);
}
@@ -185,6 +222,8 @@
: rep (new typename Array::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::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::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::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::checkelem", n);
else
return xelem (n);
@@ -407,7 +454,7 @@
Array transpose (void) const;
Array 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& insert (const Array& a, const Array& 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.
diff --git a/liboctave/ChangeLog b/liboctave/ChangeLog
--- a/liboctave/ChangeLog
+++ b/liboctave/ChangeLog
@@ -0,0 +1,14 @@
+2009-01-14 Jaroslav Hajek
+
+ * Array.cc, Array.h (all Array constructors): Handle slice_data and
+ slice_len.
+ (Array::Array (const Array&, const dim_vector&,
+ octave_idx_type, octave_idx_type)): New constructor.
+ (Array::index): Use shallow copy when index reduces to a contiguous
+ range.
+ (Array::make_unique): Rewrite.
+ (Array::ArrayRep): Delete redundant methods.
+ (rec_index_helper::is_cont_range): New method.
+ (Array::maybe_economize): New method.
+ * DiagArray2.cc (DiagArray2::resize): Fix the mess.
+
diff --git a/liboctave/DiagArray2.cc b/liboctave/DiagArray2.cc
--- a/liboctave/DiagArray2.cc
+++ b/liboctave/DiagArray2.cc
@@ -107,6 +107,7 @@
if (r == dim1 () && c == dim2 ())
return;
+ // FIXME: this is a mess. DiagArray2 really needs a rewrite.
typename Array::ArrayRep *old_rep = Array::rep;
const T *old_data = this->data ();
octave_idx_type old_len = this->length ();
@@ -114,6 +115,8 @@
octave_idx_type new_len = r < c ? r : c;
Array::rep = new typename Array::ArrayRep (new_len);
+ Array::slice_data = Array::rep->data;
+ Array::slice_len = Array::rep->len;
this->dimensions = dim_vector (r, c);
diff --git a/src/ChangeLog b/src/ChangeLog
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -0,0 +1,15 @@
+2009-01-14 Jaroslav Hajek
+
+ * ov.cc (octave_value::maybe_economize): New method.
+ (octave_value::non_null_value): rename to storable_value.
+ (octave_value::make_non_null_value): rename to make_storable_value.
+ * ov-base.h (octave_base_value::maybe_economize): New method.
+ * ov-base-mat.h (octave_base_mat::maybe_economize): New override.
+ * oct-obj.cc (octave_value_list::normalize_null_values):
+ Rename to make_storable_values, use make_storable_value.
+ * oct-obj.h: Dtto.
+ * ov-builtin.cc: non_null_value -> storable_value.
+ * ov-cell.cc: Dtto.
+ * ov-struct.cc: Dtto.
+ * pt-decl.h: Dtto.
+
diff --git a/src/oct-obj.cc b/src/oct-obj.cc
--- a/src/oct-obj.cc
+++ b/src/oct-obj.cc
@@ -236,11 +236,11 @@
}
void
-octave_value_list::normalize_null_values (void)
+octave_value_list::make_storable_values (void)
{
octave_idx_type len = length ();
for (octave_idx_type i = 0; i < len; i++)
- data[i].make_non_null_value ();
+ data[i].make_storable_value ();
}
/*
diff --git a/src/oct-obj.h b/src/oct-obj.h
--- a/src/oct-obj.h
+++ b/src/oct-obj.h
@@ -121,7 +121,7 @@
string_vector name_tags (void) const { return names; }
- void normalize_null_values (void);
+ void make_storable_values (void);
private:
diff --git a/src/ov-base-mat.h b/src/ov-base-mat.h
--- a/src/ov-base-mat.h
+++ b/src/ov-base-mat.h
@@ -73,6 +73,8 @@
octave_value squeeze (void) const { return MT (matrix.squeeze ()); }
octave_value full_value (void) const { return matrix; }
+
+ void maybe_economize (void) { matrix.maybe_economize (); }
octave_value subsref (const std::string& type,
const std::list& idx);
diff --git a/src/ov-base.h b/src/ov-base.h
--- a/src/ov-base.h
+++ b/src/ov-base.h
@@ -151,6 +151,8 @@
virtual octave_value full_value (void) const;
virtual octave_base_value *try_narrowing_conversion (void) { return 0; }
+
+ virtual void maybe_economize (void) { }
virtual octave_value
subsref (const std::string& type,
diff --git a/src/ov-builtin.cc b/src/ov-builtin.cc
--- a/src/ov-builtin.cc
+++ b/src/ov-builtin.cc
@@ -107,7 +107,7 @@
retval = (*f) (args, nargout);
// Do not allow null values to be returned from functions.
// FIXME -- perhaps true builtins should be allowed?
- retval.normalize_null_values ();
+ retval.make_storable_values ();
}
catch (octave_execution_exception)
{
diff --git a/src/ov-cell.cc b/src/ov-cell.cc
--- a/src/ov-cell.cc
+++ b/src/ov-cell.cc
@@ -270,7 +270,7 @@
}
else if (i.all_scalars () || do_index_op (i, true).numel () == 1)
// Regularize a null matrix if stored into a cell.
- octave_base_matrix::assign (i, Cell (t_rhs.non_null_value ()));
+ octave_base_matrix::assign (i, Cell (t_rhs.storable_value ()));
else if (! error_state)
error ("scalar indices required for {} in assignment.");
diff --git a/src/ov-struct.cc b/src/ov-struct.cc
--- a/src/ov-struct.cc
+++ b/src/ov-struct.cc
@@ -412,7 +412,7 @@
}
else
// Regularize a null matrix if stored into a struct component.
- map.assign (key, t_rhs.non_null_value ());
+ map.assign (key, t_rhs.storable_value ());
if (! error_state)
{
diff --git a/src/ov.cc b/src/ov.cc
--- a/src/ov.cc
+++ b/src/ov.cc
@@ -1170,7 +1170,7 @@
{
if (op == op_asn_eq)
// Regularize a null matrix if stored into a variable.
- operator = (rhs.non_null_value ());
+ operator = (rhs.storable_value ());
else
{
// FIXME -- only do the following stuff if we can't find
@@ -1552,18 +1552,23 @@
type_name (), "complex vector"));
}
+// FIXME: This is a good place for pre-storage hooks, but the functions should
+// probably be named differently. These functions will be called
octave_value
-octave_value::non_null_value (void) const
+octave_value::storable_value (void) const
{
+ octave_value retval = *this;
if (is_null_value ())
- return octave_value (rep->empty_clone ());
+ retval = octave_value (rep->empty_clone ());
else
- return *this;
+ retval.maybe_economize ();
+
+ return retval;
}
void
-octave_value::make_non_null_value (void)
+octave_value::make_storable_value (void)
{
if (is_null_value ())
{
@@ -1572,6 +1577,8 @@
delete rep;
rep = rc;
}
+ else
+ maybe_economize ();
}
int
diff --git a/src/ov.h b/src/ov.h
--- a/src/ov.h
+++ b/src/ov.h
@@ -847,13 +847,18 @@
Array float_complex_vector_value (bool frc_str_conv = false,
bool frc_vec_conv = false) const;
- // Make a copy that is not a special null matrix
+ // Possibly economize a lazy-indexed value.
- octave_value non_null_value (void) const;
+ void maybe_economize (void)
+ { rep->maybe_economize (); }
+
+ // Make a copy suitable for storing.
+
+ octave_value storable_value (void) const;
// Ditto, but in place.
- void make_non_null_value (void);
+ void make_storable_value (void);
// Conversions. These should probably be private. If a user of this
// class wants a certain kind of constant, he should simply ask for
diff --git a/src/pt-decl.h b/src/pt-decl.h
--- a/src/pt-decl.h
+++ b/src/pt-decl.h
@@ -66,7 +66,7 @@
bool lvalue_ok (void) { return id ? id->lvalue_ok () : false; }
// Do not allow functions return null values
- octave_value rvalue (void) { return id ? id->rvalue ().non_null_value () : octave_value (); }
+ octave_value rvalue (void) { return id ? id->rvalue ().storable_value () : octave_value (); }
octave_value_list rvalue (int nargout)
{
| |