# HG changeset patch # User John W. Eaton # Date 1638625758 18000 # Sat Dec 04 08:49:18 2021 -0500 # Branch stable # Node ID dad899b0e3285d674c17f9390eb1efbdd9dc52dd # Parent e38202d3628d1c732e341d1e57d514f6b1f2c7cf allow custom allocators for the Array class * Array.h, Array.cc (class Array): New template parameter, Alloc, with default value of std::allocator. Update function declarations and definitions as needed. (class Array::ArrayRep): Derive from Alloc. Use std::allocator_traits to manage memory allocation. (Array::ArrayRep::allocate, Array::ArrayRep::deallocate): New functions to localize allocation and construction of ArrayRep data. Use them to replace calls to new and delete. * Array-fwd.h: Update declaration. diff --git a/liboctave/array/Array-fwd.h b/liboctave/array/Array-fwd.h --- a/liboctave/array/Array-fwd.h +++ b/liboctave/array/Array-fwd.h @@ -28,6 +28,7 @@ #include "octave-config.h" -template class OCTARRAY_API Array; +template > +class OCTARRAY_API Array; #endif diff --git a/liboctave/array/Array.cc b/liboctave/array/Array.cc --- a/liboctave/array/Array.cc +++ b/liboctave/array/Array.cc @@ -37,9 +37,9 @@ // One dimensional array class. Handles the reference counting for // all the derived classes. -template -typename Array::ArrayRep * -Array::nil_rep (void) +template +typename Array::ArrayRep * +Array::nil_rep (void) { static ArrayRep nr; return &nr; @@ -47,8 +47,8 @@ Array::nil_rep (void) // This is similar to the template for containers but specialized for Array. // Note we can't specialize a member without also specializing the class. -template -Array::Array (const Array& a, const dim_vector& dv) +template +Array::Array (const Array& a, const dim_vector& dv) : m_dimensions (dv), m_rep (a.m_rep), m_slice_data (a.m_slice_data), m_slice_len (a.m_slice_len) { @@ -68,9 +68,9 @@ Array::Array (const Array& a, cons m_dimensions.chop_trailing_singletons (); } -template +template void -Array::fill (const T& val) +Array::fill (const T& val) { if (m_rep->m_count > 1) { @@ -82,9 +82,9 @@ Array::fill (const T& val) std::fill_n (m_slice_data, m_slice_len, val); } -template +template void -Array::clear (void) +Array::clear (void) { if (--m_rep->m_count == 0) delete m_rep; @@ -97,9 +97,9 @@ Array::clear (void) m_dimensions = dim_vector (); } -template +template void -Array::clear (const dim_vector& dv) +Array::clear (const dim_vector& dv) { if (--m_rep->m_count == 0) delete m_rep; @@ -112,11 +112,11 @@ Array::clear (const dim_vector& dv) m_dimensions.chop_trailing_singletons (); } -template -Array -Array::squeeze (void) const +template +Array +Array::squeeze (void) const { - Array retval = *this; + Array retval = *this; if (ndims () > 2) { @@ -159,37 +159,37 @@ Array::squeeze (void) const } } - retval = Array (*this, new_dimensions); + retval = Array (*this, new_dimensions); } return retval; } -template +template octave_idx_type -Array::compute_index (octave_idx_type i, octave_idx_type j) const +Array::compute_index (octave_idx_type i, octave_idx_type j) const { return ::compute_index (i, j, m_dimensions); } -template +template octave_idx_type -Array::compute_index (octave_idx_type i, octave_idx_type j, +Array::compute_index (octave_idx_type i, octave_idx_type j, octave_idx_type k) const { return ::compute_index (i, j, k, m_dimensions); } -template +template octave_idx_type -Array::compute_index (const Array& ra_idx) const +Array::compute_index (const Array& ra_idx) const { return ::compute_index (ra_idx, m_dimensions); } -template +template T& -Array::checkelem (octave_idx_type n) +Array::checkelem (octave_idx_type n) { // Do checks directly to avoid recomputing m_slice_len. if (n < 0) @@ -200,30 +200,30 @@ Array::checkelem (octave_idx_type n) return elem (n); } -template +template T& -Array::checkelem (octave_idx_type i, octave_idx_type j) +Array::checkelem (octave_idx_type i, octave_idx_type j) { return elem (compute_index (i, j)); } -template +template T& -Array::checkelem (octave_idx_type i, octave_idx_type j, octave_idx_type k) +Array::checkelem (octave_idx_type i, octave_idx_type j, octave_idx_type k) { return elem (compute_index (i, j, k)); } -template +template T& -Array::checkelem (const Array& ra_idx) +Array::checkelem (const Array& ra_idx) { return elem (compute_index (ra_idx)); } -template -typename Array::crefT -Array::checkelem (octave_idx_type n) const +template +typename Array::crefT +Array::checkelem (octave_idx_type n) const { // Do checks directly to avoid recomputing m_slice_len. if (n < 0) @@ -234,56 +234,56 @@ Array::checkelem (octave_idx_type n) return elem (n); } -template -typename Array::crefT -Array::checkelem (octave_idx_type i, octave_idx_type j) const +template +typename Array::crefT +Array::checkelem (octave_idx_type i, octave_idx_type j) const { return elem (compute_index (i, j)); } -template -typename Array::crefT -Array::checkelem (octave_idx_type i, octave_idx_type j, +template +typename Array::crefT +Array::checkelem (octave_idx_type i, octave_idx_type j, octave_idx_type k) const { return elem (compute_index (i, j, k)); } -template -typename Array::crefT -Array::checkelem (const Array& ra_idx) const +template +typename Array::crefT +Array::checkelem (const Array& ra_idx) const { return elem (compute_index (ra_idx)); } -template -Array -Array::column (octave_idx_type k) const +template +Array +Array::column (octave_idx_type k) const { octave_idx_type r = m_dimensions(0); - return Array (*this, dim_vector (r, 1), k*r, k*r + r); + return Array (*this, dim_vector (r, 1), k*r, k*r + r); } -template -Array -Array::page (octave_idx_type k) const +template +Array +Array::page (octave_idx_type k) const { octave_idx_type r = m_dimensions(0); octave_idx_type c = m_dimensions(1); octave_idx_type p = r*c; - return Array (*this, dim_vector (r, c), k*p, k*p + p); + return Array (*this, dim_vector (r, c), k*p, k*p + p); } -template -Array -Array::linear_slice (octave_idx_type lo, octave_idx_type up) const +template +Array +Array::linear_slice (octave_idx_type lo, octave_idx_type up) const { if (up < lo) up = lo; - return Array (*this, dim_vector (up - lo, 1), lo, up); + return Array (*this, dim_vector (up - lo, 1), lo, up); } // Helper class for multi-d dimension permuting (generalized transpose). @@ -426,11 +426,11 @@ private: bool m_use_blk; }; -template -Array -Array::permute (const Array& perm_vec_arg, bool inv) const +template +Array +Array::permute (const Array& perm_vec_arg, bool inv) const { - Array retval; + Array retval; Array perm_vec = perm_vec_arg; @@ -484,7 +484,7 @@ Array::permute (const Array (dv_new); + retval = Array (dv_new); if (numel () > 0) { @@ -692,9 +692,9 @@ private: int m_n; }; -template -Array -Array::index (const octave::idx_vector& i) const +template +Array +Array::index (const octave::idx_vector& i) const { // Colon: // @@ -715,12 +715,12 @@ Array::index (const octave::idx_vecto // array | anything | same size as index octave_idx_type n = numel (); - Array retval; + Array retval; if (i.is_colon ()) { // A(:) produces a shallow copy as a column vector. - retval = Array (*this, dim_vector (n, 1)); + retval = Array (*this, dim_vector (n, 1)); } else { @@ -744,12 +744,12 @@ Array::index (const octave::idx_vecto octave_idx_type l, u; if (idx_len != 0 && i.is_cont_range (n, l, u)) // If suitable, produce a shallow slice. - retval = Array (*this, result_dims, l, u); + retval = Array (*this, result_dims, l, u); else { // Don't use resize here to avoid useless initialization for POD // types. - retval = Array (result_dims); + retval = Array (result_dims); if (idx_len != 0) i.index (data (), n, retval.fortran_vec ()); @@ -759,20 +759,20 @@ Array::index (const octave::idx_vecto return retval; } -template -Array -Array::index (const octave::idx_vector& i, const octave::idx_vector& j) const +template +Array +Array::index (const octave::idx_vector& i, const octave::idx_vector& j) const { // Get dimensions, allowing Fortran indexing in the 2nd dim. dim_vector dv = m_dimensions.redim (2); octave_idx_type r = dv(0); octave_idx_type c = dv(1); - Array retval; + Array retval; if (i.is_colon () && j.is_colon ()) { // A(:,:) produces a shallow copy. - retval = Array (*this, dv); + retval = Array (*this, dv); } else { @@ -792,11 +792,11 @@ Array::index (const octave::idx_vecto 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); + retval = Array (*this, dim_vector (il, jl), l, u); else { // Don't use resize to avoid useless initialization for POD types. - retval = Array (dim_vector (il, jl)); + retval = Array (dim_vector (il, jl)); ii.index (data (), n, retval.fortran_vec ()); } @@ -804,7 +804,7 @@ Array::index (const octave::idx_vecto else { // Don't use resize to avoid useless initialization for POD types. - retval = Array (dim_vector (il, jl)); + retval = Array (dim_vector (il, jl)); const T *src = data (); T *dest = retval.fortran_vec (); @@ -817,12 +817,12 @@ Array::index (const octave::idx_vecto return retval; } -template -Array -Array::index (const Array& ia) const +template +Array +Array::index (const Array& ia) const { int ial = ia.numel (); - Array retval; + Array retval; // FIXME: is this dispatching necessary? if (ial == 1) @@ -849,7 +849,7 @@ Array::index (const Array (*this, dv); + retval = Array (*this, dv); } else { @@ -864,11 +864,11 @@ Array::index (const Array (*this, rdv, l, u); + retval = Array (*this, rdv, l, u); else { // Don't use resize to avoid useless initialization for POD types. - retval = Array (rdv); + retval = Array (rdv); // Do it. rh.index (data (), retval.fortran_vec ()); @@ -881,9 +881,9 @@ Array::index (const Array +template T -Array::resize_fill_value (void) const +Array::resize_fill_value (void) const { static T zero = T (); return zero; @@ -892,9 +892,9 @@ Array::resize_fill_value (void) const // Yes, we could do resize using index & assign. However, that would // possibly involve a lot more memory traffic than we actually need. -template +template void -Array::resize1 (octave_idx_type n, const T& rfv) +Array::resize1 (octave_idx_type n, const T& rfv) { if (n < 0 || ndims () != 2) octave::err_invalid_resize (); @@ -940,7 +940,7 @@ Array::resize1 (octave_idx_type n, co { static const octave_idx_type max_stack_chunk = 1024; octave_idx_type nn = n + std::min (nx, max_stack_chunk); - Array tmp (Array (dim_vector (nn, 1)), dv, 0, n); + Array tmp (Array (dim_vector (nn, 1)), dv, 0, n); T *dest = tmp.fortran_vec (); std::copy_n (data (), nx, dest); @@ -951,7 +951,7 @@ Array::resize1 (octave_idx_type n, co } else if (n != nx) { - Array tmp = Array (dv); + Array tmp = Array (dv); T *dest = tmp.fortran_vec (); octave_idx_type n0 = std::min (n, nx); @@ -963,9 +963,9 @@ Array::resize1 (octave_idx_type n, co } } -template +template void -Array::resize2 (octave_idx_type r, octave_idx_type c, const T& rfv) +Array::resize2 (octave_idx_type r, octave_idx_type c, const T& rfv) { if (r < 0 || c < 0 || ndims () != 2) octave::err_invalid_resize (); @@ -974,7 +974,7 @@ Array::resize2 (octave_idx_type r, oc octave_idx_type cx = columns (); if (r != rx || c != cx) { - Array tmp = Array (dim_vector (r, c)); + Array tmp = Array (dim_vector (r, c)); T *dest = tmp.fortran_vec (); octave_idx_type r0 = std::min (r, rx); @@ -1005,9 +1005,9 @@ Array::resize2 (octave_idx_type r, oc } } -template +template void -Array::resize (const dim_vector& dv, const T& rfv) +Array::resize (const dim_vector& dv, const T& rfv) { int dvl = dv.ndims (); if (dvl == 2) @@ -1017,7 +1017,7 @@ Array::resize (const dim_vector& dv, if (m_dimensions.ndims () > dvl || dv.any_neg ()) octave::err_invalid_resize (); - Array tmp (dv); + Array tmp (dv); // Prepare for recursive resizing. rec_resize_helper rh (dv, m_dimensions.redim (dvl)); @@ -1027,11 +1027,11 @@ Array::resize (const dim_vector& dv, } } -template -Array -Array::index (const octave::idx_vector& i, bool resize_ok, const T& rfv) const +template +Array +Array::index (const octave::idx_vector& i, bool resize_ok, const T& rfv) const { - Array tmp = *this; + Array tmp = *this; if (resize_ok) { octave_idx_type n = numel (); @@ -1039,24 +1039,24 @@ Array::index (const octave::idx_vecto if (n != nx) { if (i.is_scalar ()) - return Array (dim_vector (1, 1), rfv); + return Array (dim_vector (1, 1), rfv); else tmp.resize1 (nx, rfv); } if (tmp.numel () != nx) - return Array (); + return Array (); } return tmp.index (i); } -template -Array -Array::index (const octave::idx_vector& i, const octave::idx_vector& j, +template +Array +Array::index (const octave::idx_vector& i, const octave::idx_vector& j, bool resize_ok, const T& rfv) const { - Array tmp = *this; + Array tmp = *this; if (resize_ok) { dim_vector dv = m_dimensions.redim (2); @@ -1067,24 +1067,24 @@ Array::index (const octave::idx_vecto if (r != rx || c != cx) { if (i.is_scalar () && j.is_scalar ()) - return Array (dim_vector (1, 1), rfv); + return Array (dim_vector (1, 1), rfv); else tmp.resize2 (rx, cx, rfv); } if (tmp.rows () != rx || tmp.columns () != cx) - return Array (); + return Array (); } return tmp.index (i, j); } -template -Array -Array::index (const Array& ia, +template +Array +Array::index (const Array& ia, bool resize_ok, const T& rfv) const { - Array tmp = *this; + Array tmp = *this; if (resize_ok) { int ial = ia.numel (); @@ -1098,21 +1098,21 @@ Array::index (const Array (dim_vector (1, 1), rfv); + return Array (dim_vector (1, 1), rfv); else tmp.resize (dvx, rfv); if (tmp.m_dimensions != dvx) - return Array (); + return Array (); } } return tmp.index (ia); } -template +template void -Array::assign (const octave::idx_vector& i, const Array& rhs, const T& rfv) +Array::assign (const octave::idx_vector& i, const Array& rhs, const T& rfv) { octave_idx_type n = numel (); octave_idx_type rhl = rhs.numel (); @@ -1129,9 +1129,9 @@ Array::assign (const octave::idx_vect if (m_dimensions.zero_by_zero () && colon) { if (rhl == 1) - *this = Array (dim_vector (1, nx), rhs(0)); + *this = Array (dim_vector (1, nx), rhs(0)); else - *this = Array (rhs, dim_vector (1, nx)); + *this = Array (rhs, dim_vector (1, nx)); return; } @@ -1157,10 +1157,10 @@ Array::assign (const octave::idx_vect } // Assignment to a 2-dimensional array -template +template void -Array::assign (const octave::idx_vector& i, const octave::idx_vector& j, - const Array& rhs, const T& rfv) +Array::assign (const octave::idx_vector& i, const octave::idx_vector& j, + const Array& rhs, const T& rfv) { bool initial_dims_all_zero = m_dimensions.all_zero (); @@ -1203,9 +1203,9 @@ Array::assign (const octave::idx_vect if (dv.zero_by_zero () && all_colons) { if (isfill) - *this = Array (rdv, rhs(0)); + *this = Array (rdv, rhs(0)); else - *this = Array (rhs, rdv); + *this = Array (rhs, rdv); return; } @@ -1261,10 +1261,10 @@ Array::assign (const octave::idx_vect } // Assignment to a multi-dimensional array -template +template void -Array::assign (const Array& ia, - const Array& rhs, const T& rfv) +Array::assign (const Array& ia, + const Array& rhs, const T& rfv) { int ial = ia.numel (); @@ -1327,9 +1327,9 @@ Array::assign (const Array (rdv, rhs(0)); + *this = Array (rdv, rhs(0)); else - *this = Array (rhs, rdv); + *this = Array (rhs, rdv); return; } @@ -1389,14 +1389,14 @@ Array::assign (const Array a(1:2,2:3) = [1;2] */ -template +template void -Array::delete_elements (const octave::idx_vector& i) +Array::delete_elements (const octave::idx_vector& i) { octave_idx_type n = numel (); if (i.is_colon ()) { - *this = Array (); + *this = Array (); } else if (i.length (n) != 0) { @@ -1414,7 +1414,7 @@ Array::delete_elements (const octave: { // Special case deleting a contiguous range. octave_idx_type m = n + l - u; - Array tmp (dim_vector (col_vec ? m : 1, ! col_vec ? m : 1)); + Array tmp (dim_vector (col_vec ? m : 1, ! col_vec ? m : 1)); const T *src = data (); T *dest = tmp.fortran_vec (); std::copy_n (src, l, dest); @@ -1429,9 +1429,9 @@ Array::delete_elements (const octave: } } -template +template void -Array::delete_elements (int dim, const octave::idx_vector& i) +Array::delete_elements (int dim, const octave::idx_vector& i) { if (dim < 0 || dim >= ndims ()) (*current_liboctave_error_handler) ("invalid dimension in delete_elements"); @@ -1439,7 +1439,7 @@ Array::delete_elements (int dim, cons octave_idx_type n = m_dimensions(dim); if (i.is_colon ()) { - *this = Array (); + *this = Array (); } else if (i.length (n) != 0) { @@ -1460,7 +1460,7 @@ Array::delete_elements (int dim, cons for (int k = dim + 1; k < ndims (); k++) du *= m_dimensions(k); // Special case deleting a contiguous range. - Array tmp = Array (rdv); + Array tmp = Array (rdv); const T *src = data (); T *dest = tmp.fortran_vec (); l *= dl; u *= dl; n *= dl; @@ -1485,9 +1485,9 @@ Array::delete_elements (int dim, cons } } -template +template void -Array::delete_elements (const Array& ia) +Array::delete_elements (const Array& ia) { int ial = ia.numel (); @@ -1510,7 +1510,7 @@ Array::delete_elements (const Array (dv); + *this = Array (dv); } else if (k == ial) { @@ -1562,9 +1562,9 @@ Array::delete_elements (const Array -Array& -Array::insert (const Array& a, octave_idx_type r, octave_idx_type c) +template +Array& +Array::insert (const Array& a, octave_idx_type r, octave_idx_type c) { octave::idx_vector i (r, r + a.rows ()); octave::idx_vector j (c, c + a.columns ()); @@ -1583,9 +1583,9 @@ Array::insert (const Array& a, oct return *this; } -template -Array& -Array::insert (const Array& a, const Array& ra_idx) +template +Array& +Array::insert (const Array& a, const Array& ra_idx) { octave_idx_type n = ra_idx.numel (); Array idx (dim_vector (n, 1)); @@ -1598,9 +1598,9 @@ Array::insert (const Array& a, con return *this; } -template -Array -Array::transpose (void) const +template +Array +Array::transpose (void) const { assert (ndims () == 2); @@ -1609,7 +1609,7 @@ Array::transpose (void) const if (nr >= 8 && nc >= 8) { - Array result (dim_vector (nc, nr)); + Array result (dim_vector (nc, nr)); // Reuse the implementation used for permuting. @@ -1619,7 +1619,7 @@ Array::transpose (void) const } else if (nr > 1 && nc > 1) { - Array result (dim_vector (nc, nr)); + Array result (dim_vector (nc, nr)); for (octave_idx_type j = 0; j < nc; j++) for (octave_idx_type i = 0; i < nr; i++) @@ -1630,7 +1630,7 @@ Array::transpose (void) const else { // Fast transpose for vectors and empty matrices. - return Array (*this, dim_vector (nc, nr)); + return Array (*this, dim_vector (nc, nr)); } } @@ -1641,9 +1641,9 @@ no_op_fcn (const T& x) return x; } -template -Array -Array::hermitian (T (*fcn) (const T&)) const +template +Array +Array::hermitian (T (*fcn) (const T&)) const { assert (ndims () == 2); @@ -1655,7 +1655,7 @@ Array::hermitian (T (*fcn) (const T&) if (nr >= 8 && nc >= 8) { - Array result (dim_vector (nc, nr)); + Array result (dim_vector (nc, nr)); // Blocked transpose to attempt to avoid cache misses. @@ -1695,7 +1695,7 @@ Array::hermitian (T (*fcn) (const T&) } else { - Array result (dim_vector (nc, nr)); + Array result (dim_vector (nc, nr)); for (octave_idx_type j = 0; j < nc; j++) for (octave_idx_type i = 0; i < nr; i++) @@ -1739,9 +1739,9 @@ Array::hermitian (T (*fcn) (const T&) */ -template +template T * -Array::fortran_vec (void) +Array::fortran_vec (void) { make_unique (); @@ -1756,14 +1756,14 @@ sort_isnan (typename ref_param::type) return false; } -template -Array -Array::sort (int dim, sortmode mode) const +template +Array +Array::sort (int dim, sortmode mode) const { if (dim < 0) (*current_liboctave_error_handler) ("sort: invalid dimension"); - Array m (dims ()); + Array m (dims ()); dim_vector dv = m.dims (); @@ -1868,15 +1868,15 @@ Array::sort (int dim, sortmode mode) return m; } -template -Array -Array::sort (Array& sidx, int dim, - sortmode mode) const +template +Array +Array::sort (Array& sidx, int dim, + sortmode mode) const { if (dim < 0 || dim >= ndims ()) (*current_liboctave_error_handler) ("sort: invalid dimension"); - Array m (dims ()); + Array m (dims ()); dim_vector dv = m.dims (); @@ -2009,9 +2009,9 @@ Array::sort (Array& return m; } -template -typename Array::compare_fcn_type -safe_comparator (sortmode mode, const Array& /* a */, +template +typename Array::compare_fcn_type +safe_comparator (sortmode mode, const Array& /* a */, bool /* allow_chk */) { if (mode == ASCENDING) @@ -2022,9 +2022,9 @@ safe_comparator (sortmode mode, const Ar return nullptr; } -template +template sortmode -Array::issorted (sortmode mode) const +Array::issorted (sortmode mode) const { octave_sort lsort; @@ -2054,9 +2054,9 @@ Array::issorted (sortmode mode) const } -template +template Array -Array::sort_rows_idx (sortmode mode) const +Array::sort_rows_idx (sortmode mode) const { Array idx; @@ -2072,9 +2072,9 @@ Array::sort_rows_idx (sortmode mode) return idx; } -template +template sortmode -Array::is_sorted_rows (sortmode mode) const +Array::is_sorted_rows (sortmode mode) const { octave_sort lsort; @@ -2133,9 +2133,9 @@ Array::is_sorted_rows (sortmode mode) } // Do a binary lookup in a sorted array. -template +template octave_idx_type -Array::lookup (const T& value, sortmode mode) const +Array::lookup (const T& value, sortmode mode) const { octave_idx_type n = numel (); octave_sort lsort; @@ -2154,9 +2154,9 @@ Array::lookup (const T& value, sortmo return lsort.lookup (data (), n, value); } -template +template Array -Array::lookup (const Array& values, sortmode mode) const +Array::lookup (const Array& values, sortmode mode) const { octave_idx_type n = numel (); octave_idx_type nval = values.numel (); @@ -2198,9 +2198,9 @@ Array::lookup (const Array& values return idx; } -template +template octave_idx_type -Array::nnz (void) const +Array::nnz (void) const { const T *src = data (); octave_idx_type nel = numel (); @@ -2213,9 +2213,9 @@ Array::nnz (void) const return retval; } -template +template Array -Array::find (octave_idx_type n, bool backward) const +Array::find (octave_idx_type n, bool backward) const { Array retval; const T *src = data (); @@ -2294,9 +2294,9 @@ Array::find (octave_idx_type n, bool return retval; } -template -Array -Array::nth_element (const octave::idx_vector& n, int dim) const +template +Array +Array::nth_element (const octave::idx_vector& n, int dim) const { if (dim < 0) (*current_liboctave_error_handler) ("nth_element: invalid dimension"); @@ -2313,7 +2313,7 @@ Array::nth_element (const octave::idx dv.chop_trailing_singletons (); dim = std::min (dv.ndims (), static_cast (dim)); - Array m (dv); + Array m (dv); if (m.isempty ()) return m; @@ -2464,7 +2464,7 @@ Array::nth_element (const octave::idx return *this; \ } \ template <> API Array \ - Array::sort (Array &sidx, int, sortmode) const \ + Array::sort (Array &sidx, int, sortmode) const \ { \ sidx = Array (); \ return *this; \ @@ -2516,13 +2516,13 @@ Array::nth_element (const octave::idx #define NO_INSTANTIATE_ARRAY_SORT(T) NO_INSTANTIATE_ARRAY_SORT_API (T,) -template -Array -Array::diag (octave_idx_type k) const +template +Array +Array::diag (octave_idx_type k) const { dim_vector dv = dims (); octave_idx_type nd = dv.ndims (); - Array d; + Array d; if (nd > 2) (*current_liboctave_error_handler) ("Matrix must be 2-dimensional"); @@ -2584,7 +2584,7 @@ Array::diag (octave_idx_type k) const if (nnr == 1) { octave_idx_type n = nnc + std::abs (k); - d = Array (dim_vector (n, n), resize_fill_value ()); + d = Array (dim_vector (n, n), resize_fill_value ()); for (octave_idx_type i = 0; i < nnc; i++) d.xelem (i+roff, i+coff) = elem (0, i); @@ -2592,7 +2592,7 @@ Array::diag (octave_idx_type k) const else { octave_idx_type n = nnr + std::abs (k); - d = Array (dim_vector (n, n), resize_fill_value ()); + d = Array (dim_vector (n, n), resize_fill_value ()); for (octave_idx_type i = 0; i < nnr; i++) d.xelem (i+roff, i+coff) = elem (i, 0); @@ -2602,14 +2602,14 @@ Array::diag (octave_idx_type k) const return d; } -template -Array -Array::diag (octave_idx_type m, octave_idx_type n) const +template +Array +Array::diag (octave_idx_type m, octave_idx_type n) const { if (ndims () != 2 || (rows () != 1 && cols () != 1)) (*current_liboctave_error_handler) ("cat: invalid dimension"); - Array retval (dim_vector (m, n), resize_fill_value ()); + Array retval (dim_vector (m, n), resize_fill_value ()); octave_idx_type nel = std::min (numel (), std::min (m, n)); for (octave_idx_type i = 0; i < nel; i++) @@ -2618,9 +2618,9 @@ Array::diag (octave_idx_type m, octav return retval; } -template -Array -Array::cat (int dim, octave_idx_type n, const Array *array_list) +template +Array +Array::cat (int dim, octave_idx_type n, const Array *array_list) { // Default concatenation. bool (dim_vector::*concat_rule) (const dim_vector&, int) = &dim_vector::concat; @@ -2636,7 +2636,7 @@ Array::cat (int dim, octave_idx_type if (n == 1) return array_list[0]; else if (n == 0) - return Array (); + return Array (); // Special case: // @@ -2684,7 +2684,7 @@ Array::cat (int dim, octave_idx_type if (! (dv.*concat_rule) (array_list[i].dims (), dim)) (*current_liboctave_error_handler) ("cat: dimension mismatch"); - Array retval (dv); + Array retval (dv); if (retval.isempty ()) return retval; @@ -2722,9 +2722,9 @@ Array::cat (int dim, octave_idx_type return retval; } -template +template void -Array::print_info (std::ostream& os, const std::string& prefix) const +Array::print_info (std::ostream& os, const std::string& prefix) const { os << prefix << "m_rep address: " << m_rep << '\n' << prefix << "m_rep->m_len: " << m_rep->m_len << '\n' @@ -2739,8 +2739,8 @@ Array::print_info (std::ostream& os, // << prefix << "cols: " << cols () << "\n"; } -template -bool Array::optimize_dimensions (const dim_vector& dv) +template +bool Array::optimize_dimensions (const dim_vector& dv) { bool retval = m_dimensions == dv; if (retval) @@ -2749,29 +2749,33 @@ bool Array::optimize_dimensions (cons return retval; } -template -void Array::instantiation_guard () +template +void Array::instantiation_guard () { // This guards against accidental implicit instantiations. - // Array instances should always be explicit and use INSTANTIATE_ARRAY. + // Array instances should always be explicit and use INSTANTIATE_ARRAY. T::__xXxXx__ (); } #if defined (__clang__) -# define INSTANTIATE_ARRAY(T, API) \ - template <> API void Array::instantiation_guard () { } \ - template class API Array +# define INSTANTIATE_ARRAY_WITH_ALLOCATOR(T, API) \ + template <> API void \ + Array::instantiation_guard () { } \ + \ + template class API Array #else -# define INSTANTIATE_ARRAY(T, API) \ - template <> API void Array::instantiation_guard () { } \ - template class Array +# define INSTANTIATE_ARRAY(T, API) \ + template <> API void \ + Array::instantiation_guard () { } \ + \ + template class Array #endif // FIXME: is this used? -template +template std::ostream& -operator << (std::ostream& os, const Array& a) +operator << (std::ostream& os, const Array& a) { dim_vector a_dims = a.dims (); diff --git a/liboctave/array/Array.h b/liboctave/array/Array.h --- a/liboctave/array/Array.h +++ b/liboctave/array/Array.h @@ -123,65 +123,89 @@ //! - string_vector: Array with 1 column //! - Cell: Array, equivalent to an Octave cell. -template +template class Array { protected: //! The real representation of all arrays. - class ArrayRep + class ArrayRep : public Alloc { public: - T *m_data; + typedef std::allocator_traits Alloc_traits; + + typedef typename Alloc_traits::rebind_traits T_Alloc_traits; + typedef typename T_Alloc_traits::pointer pointer; + + pointer m_data; octave_idx_type m_len; octave::refcount m_count; - ArrayRep (T *d, octave_idx_type l) - : m_data (new T [l]), m_len (l), m_count (1) + ArrayRep (pointer d, octave_idx_type len) + : Alloc (), m_data (allocate (len)), m_len (len), m_count (1) { - std::copy_n (d, l, m_data); + std::copy_n (d, len, m_data); } template - ArrayRep (U *d, octave_idx_type l) - : m_data (new T [l]), m_len (l), m_count (1) + ArrayRep (U *d, octave_idx_type len) + : Alloc (), m_data (allocate (len)), m_len (len), m_count (1) { - std::copy_n (d, l, m_data); + std::copy_n (d, len, m_data); } // Use new instead of setting data to 0 so that fortran_vec and // data always return valid addresses, even for zero-size arrays. - ArrayRep (void) : m_data (new T [0]), m_len (0), m_count (1) { } - - explicit ArrayRep (octave_idx_type n) - : m_data (new T [n]), m_len (n), m_count (1) { } + ArrayRep (void) + : Alloc (), m_data (allocate (0)), m_len (0), m_count (1) { } - explicit ArrayRep (octave_idx_type n, const T& val) - : m_data (new T [n]), m_len (n), m_count (1) + explicit ArrayRep (octave_idx_type len) + : Alloc (), m_data (allocate (len)), m_len (len), m_count (1) { } + + explicit ArrayRep (octave_idx_type len, const T& val) + : Alloc (), m_data (allocate (len)), m_len (len), m_count (1) { - std::fill_n (m_data, n, val); + std::fill_n (m_data, len, val); } - explicit ArrayRep (T *ptr, const dim_vector& dv) - : m_data (ptr), m_len (dv.safe_numel ()), m_count (1) + explicit ArrayRep (pointer ptr, const dim_vector& dv, + const Alloc& xallocator = Alloc ()) + : Alloc (xallocator), m_data (ptr), m_len (dv.safe_numel ()), m_count (1) { } + // FIXME: Should the allocator be copied or created with the default? ArrayRep (const ArrayRep& a) - : m_data (new T [a.m_len]), m_len (a.m_len), m_count (1) + : Alloc (), m_data (allocate (a.m_len)), m_len (a.m_len), + m_count (1) { std::copy_n (a.m_data, a.m_len, m_data); } - ~ArrayRep (void) { delete [] m_data; } + ~ArrayRep (void) { deallocate (m_data, m_len); } octave_idx_type numel (void) const { return m_len; } // No assignment! ArrayRep& operator = (const ArrayRep&) = delete; + + pointer allocate (size_t len) + { + pointer data = Alloc_traits::allocate (*this, len); + for (size_t i = 0; i < len; i++) + T_Alloc_traits::construct (*this, data+i); + return data; + } + + void deallocate (pointer data, size_t len) + { + for (size_t i = 0; i < len; i++) + T_Alloc_traits::destroy (*this, data+i); + Alloc_traits::deallocate (*this, data, len); + } }; //-------------------------------------------------------------------- @@ -219,7 +243,7 @@ protected: dim_vector m_dimensions; - typename Array::ArrayRep *m_rep; + typename Array::ArrayRep *m_rep; // Rationale: // m_slice_data is a pointer to m_rep->m_data, denoting together with m_slice_len the @@ -232,7 +256,7 @@ protected: octave_idx_type m_slice_len; //! slice constructor - Array (const Array& a, const dim_vector& dv, + Array (const Array& a, const dim_vector& dv, octave_idx_type l, octave_idx_type u) : m_dimensions (dv), m_rep(a.m_rep), m_slice_data (a.m_slice_data+l), m_slice_len (u-l) { @@ -242,7 +266,7 @@ protected: private: - static OCTARRAY_API typename Array::ArrayRep *nil_rep (void); + static OCTARRAY_API typename Array::ArrayRep *nil_rep (void); public: @@ -257,7 +281,7 @@ public: //! nD uninitialized ctor. explicit Array (const dim_vector& dv) : m_dimensions (dv), - m_rep (new typename Array::ArrayRep (dv.safe_numel ())), + m_rep (new typename Array::ArrayRep (dv.safe_numel ())), m_slice_data (m_rep->m_data), m_slice_len (m_rep->m_len) { m_dimensions.chop_trailing_singletons (); @@ -266,7 +290,7 @@ public: //! nD initialized ctor. explicit Array (const dim_vector& dv, const T& val) : m_dimensions (dv), - m_rep (new typename Array::ArrayRep (dv.safe_numel ())), + m_rep (new typename Array::ArrayRep (dv.safe_numel ())), m_slice_data (m_rep->m_data), m_slice_len (m_rep->m_len) { fill (val); @@ -279,38 +303,39 @@ public: // object is deleted. The dimension vector DV must be consistent with // the size of the allocated PTR array. - explicit Array (T *ptr, const dim_vector& dv) + explicit Array (T *ptr, const dim_vector& dv, + const Alloc& xallocator = Alloc ()) : m_dimensions (dv), - m_rep (new typename Array::ArrayRep (ptr, dv)), + m_rep (new typename Array::ArrayRep (ptr, dv, xallocator)), m_slice_data (m_rep->m_data), m_slice_len (m_rep->m_len) { m_dimensions.chop_trailing_singletons (); } //! Reshape constructor. - OCTARRAY_API Array (const Array& a, const dim_vector& dv); + OCTARRAY_API Array (const Array& a, const dim_vector& dv); //! Constructor from standard library sequence containers. template