Mercurial > octave
changeset 30491:2be7ac9389cb
maint: Merge stable to default.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Wed, 15 Dec 2021 20:26:12 -0500 |
parents | 458b014d8829 (current diff) 34b4d993abb5 (diff) |
children | 6fc9847bd302 |
files | configure.ac libinterp/corefcn/__isprimelarge__.cc libinterp/corefcn/mex.cc |
diffstat | 29 files changed, 770 insertions(+), 449 deletions(-) [+] |
line wrap: on
line diff
--- a/build-aux/mk-octave-config-h.sh Thu Dec 09 21:21:37 2021 -0800 +++ b/build-aux/mk-octave-config-h.sh Wed Dec 15 20:26:12 2021 -0500 @@ -279,6 +279,7 @@ $SED -n 's/#\(\(undef\|define\) OCTAVE_ENABLE_OPENMP.*$\)/# \1/p' $config_h_file $SED -n 's/#\(\(undef\|define\) OCTAVE_HAVE_LONG_LONG_INT.*$\)/# \1/p' $config_h_file $SED -n 's/#\(\(undef\|define\) OCTAVE_HAVE_UNSIGNED_LONG_LONG_INT.*$\)/# \1/p' $config_h_file +$SED -n 's/#\(\(undef\|define\) OCTAVE_HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR.*$\)/# \1/p' $config_h_file $SED -n 's/#\(\(undef\|define\) OCTAVE_HAVE_OVERLOAD_CHAR_INT8_TYPES.*$\)/# \1/p' $config_h_file $SED -n 's/#\(\(undef\|define\) OCTAVE_SIZEOF_F77_INT_TYPE.*$\)/# \1/p' $config_h_file $SED -n 's/#\(\(undef\|define\) OCTAVE_SIZEOF_IDX_TYPE.*$\)/# \1/p' $config_h_file
--- a/configure.ac Thu Dec 09 21:21:37 2021 -0800 +++ b/configure.ac Wed Dec 15 20:26:12 2021 -0500 @@ -400,6 +400,8 @@ OCTAVE_CONFIGURE_WARNING([warn_stl_algo_h]) fi +OCTAVE_CHECK_STD_PMR_POLYMORPHIC_ALLOCATOR + ### Check version number when using gcc. dnl It might be different from the g++ version number.
--- a/libinterp/corefcn/__isprimelarge__.cc Thu Dec 09 21:21:37 2021 -0800 +++ b/libinterp/corefcn/__isprimelarge__.cc Wed Dec 15 20:26:12 2021 -0500 @@ -23,6 +23,10 @@ // //////////////////////////////////////////////////////////////////////// +#if defined (HAVE_CONFIG_H) +# include "config.h" +#endif + #include "defun.h" #include "error.h" #include "ovl.h"
--- a/libinterp/corefcn/mex.cc Thu Dec 09 21:21:37 2021 -0800 +++ b/libinterp/corefcn/mex.cc Wed Dec 15 20:26:12 2021 -0500 @@ -27,6 +27,12 @@ # include "config.h" #endif +#define DEBUG 1 + +#if defined (DEBUG) +# include <iostream> +#endif + #include <cstdarg> #include <cstdlib> #include <cstring> @@ -34,9 +40,12 @@ #include <limits> #include <map> +#include <memory_resource> #include <set> #include <string> +// Needed to instantiate Array objects with custom allocator. +#include "Array.cc" #include "f77-fcn.h" #include "lo-ieee.h" #include "oct-locbuf.h" @@ -253,18 +262,12 @@ extern OCTINTERP_API void mxSetImagData (mxArray *ptr, void *pi); } -// #define DEBUG 1 - -#if DEBUG -# include <iostream> -#endif - static void * xmalloc (size_t n) { void *ptr = std::malloc (n); -#if DEBUG +#if defined (DEBUG) std::cerr << "xmalloc (" << n << ") = " << ptr << std::endl; #endif @@ -276,7 +279,7 @@ { void *newptr = std::realloc (ptr, n); -#if DEBUG +#if defined (DEBUG) std::cerr << "xrealloc (" << ptr << ", " << n << ") = " << newptr << std::endl; #endif @@ -287,7 +290,7 @@ static void xfree (void *ptr) { -#if DEBUG +#if defined (DEBUG) std::cerr << "xfree (" << ptr << ")" << std::endl; #endif @@ -310,6 +313,63 @@ return max_len; } +// FIXME: Is there a better/standard way to do this job? + +template <typename T> +class fp_type_traits +{ +public: + static const bool is_complex = false; +}; + +template <> +class fp_type_traits<Complex> +{ +public: + static const bool is_complex = true; +}; + +template <> +class fp_type_traits <FloatComplex> +{ +public: + static const bool is_complex = true; +}; + +#if defined (HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR) +# include <memory_resource> + +class mx_memory_resource : public std::pmr::memory_resource +{ +private: + + void * do_allocate (std::size_t bytes, size_t /*alignment*/) + { + void *ptr = xmalloc (bytes); + + if (! ptr) + throw std::bad_alloc (); + + return ptr; + } + + void do_deallocate (void* ptr, std::size_t /*bytes*/, + std::size_t /*alignment*/) + { + xfree (ptr); + } + + bool do_is_equal (const std::pmr::memory_resource& other) const noexcept + { + return this == dynamic_cast<const mx_memory_resource *> (&other); + } +}; + +// FIXME: Is it OK for the memory resource object to be defined this +// way? +static mx_memory_resource the_mx_memory_resource; +#endif + // ------------------------------------------------------------------ mxArray_base::mxArray_base (bool interleaved) @@ -2079,13 +2139,46 @@ octave_value fp_to_ov (const dim_vector& dv) const { + octave_value retval; + ELT_T *ppr = static_cast<ELT_T *> (m_pr); - Array<ELT_T> val (ppr, dv); - - maybe_disown_ptr (m_pr); - - return octave_value (val); +#if defined (HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR) + + octave::unwind_action act ([=] () { maybe_disown_ptr (m_pr); }); + + return octave_value (Array<ELT_T> (ppr, dv, &the_mx_memory_resource)); + +#else + + if (fp_type_traits<ELT_T>::is_complex) + { + // Mixing malloc and delete[] for arrays of Complex and + // FloatComplex objects is not possible. + + Array<ELT_T> val (dv); + + ELT_T *ptr = val.fortran_vec (); + + mwSize nel = get_number_of_elements (); + + for (mwIndex i = 0; i < nel; i++) + ptr[i] = ppr[i]; + + return octave_value (val); + } + else + { + // Although behavior is not specified by the standard, it should + // work to mix malloc and delete[] for arrays of float and + // double. + + octave::unwind_action act ([=] () { maybe_disown_ptr (m_pr); }); + + return octave_value (Array<ELT_T> (ppr, dv)); + } + +#endif } template <typename ELT_T, typename ARRAY_T, typename ARRAY_ELT_T> @@ -2097,11 +2190,17 @@ ELT_T *ppr = static_cast<ELT_T *> (m_pr); -#if 0 - ARRAY_T val (ppr, dv); - - maybe_disown_ptr (m_pr); +#if 0 && defined (HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR) + + octave::unwind_action act ([=] () { maybe_disown_ptr (m_pr); }); + + return ARRAY_T (ppr, dv, &the_mx_memory_resource); + #else + + // All octave_int types are objects so we can't mix malloc and + // delete[] and we always have to copy. + ARRAY_T val (dv); ARRAY_ELT_T *ptr = val.fortran_vec (); @@ -2110,9 +2209,10 @@ for (mwIndex i = 0; i < nel; i++) ptr[i] = ppr[i]; -#endif return octave_value (val); + +#endif } protected: @@ -2363,6 +2463,9 @@ T *ppr = static_cast<T *> (m_pr); + // We allocate in the Array<T> constructor and copy here, so we + // don't need the custom allocator for this object. + Array<std::complex<T>> val (dv); std::complex<T> *ptr = val.fortran_vec ();
--- a/libinterp/corefcn/pr-output.h Thu Dec 09 21:21:37 2021 -0800 +++ b/libinterp/corefcn/pr-output.h Wed Dec 15 20:26:12 2021 -0500 @@ -31,8 +31,10 @@ #include <iosfwd> #include "Array-fwd.h" +#include "intNDArray-fwd.h" #include "oct-cmplx.h" #include "oct-inttypes-fwd.h" +#include "range-fwd.h" #include "pr-flt-fmt.h" @@ -56,13 +58,6 @@ class Cell; class octave_value; -namespace octave -{ - template <typename T> class range; -} - -template <typename T> class intNDArray; - template <typename T> float_display_format make_format (const std::complex<T>&)
--- a/libinterp/octave-value/ov-range.h Thu Dec 09 21:21:37 2021 -0800 +++ b/libinterp/octave-value/ov-range.h Wed Dec 15 20:26:12 2021 -0500 @@ -33,6 +33,7 @@ #include <iosfwd> #include <string> +#include "Array-fwd.h" #include "Range.h" #include "lo-mappers.h"
--- a/liboctave/array/Array-fwd.h Thu Dec 09 21:21:37 2021 -0800 +++ b/liboctave/array/Array-fwd.h Wed Dec 15 20:26:12 2021 -0500 @@ -28,6 +28,17 @@ #include "octave-config.h" -template <typename T> class OCTARRAY_API Array; +#if defined (HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR) +# include <memory_resource> + +template <typename T, typename Alloc = std::pmr::polymorphic_allocator<T>> +class OCTARRAY_API Array; + +#else + +template <typename T, typename Alloc = std::allocator<T>> +class OCTARRAY_API Array; #endif + +#endif
--- a/liboctave/array/Array.cc Thu Dec 09 21:21:37 2021 -0800 +++ b/liboctave/array/Array.cc Wed Dec 15 20:26:12 2021 -0500 @@ -37,9 +37,9 @@ // One dimensional array class. Handles the reference counting for // all the derived classes. -template <typename T> -typename Array<T>::ArrayRep * -Array<T>::nil_rep (void) +template <typename T, typename Alloc> +typename Array<T, Alloc>::ArrayRep * +Array<T, Alloc>::nil_rep (void) { static ArrayRep nr; return &nr; @@ -47,8 +47,8 @@ // 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 <typename T> -Array<T>::Array (const Array<T>& a, const dim_vector& dv) +template <typename T, typename Alloc> +Array<T, Alloc>::Array (const Array<T, Alloc>& 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 @@ m_dimensions.chop_trailing_singletons (); } -template <typename T> +template <typename T, typename Alloc> void -Array<T>::fill (const T& val) +Array<T, Alloc>::fill (const T& val) { if (m_rep->m_count > 1) { @@ -82,9 +82,9 @@ std::fill_n (m_slice_data, m_slice_len, val); } -template <typename T> +template <typename T, typename Alloc> void -Array<T>::clear (void) +Array<T, Alloc>::clear (void) { if (--m_rep->m_count == 0) delete m_rep; @@ -97,9 +97,9 @@ m_dimensions = dim_vector (); } -template <typename T> +template <typename T, typename Alloc> void -Array<T>::clear (const dim_vector& dv) +Array<T, Alloc>::clear (const dim_vector& dv) { if (--m_rep->m_count == 0) delete m_rep; @@ -112,11 +112,11 @@ m_dimensions.chop_trailing_singletons (); } -template <typename T> -Array<T> -Array<T>::squeeze (void) const +template <typename T, typename Alloc> +Array<T, Alloc> +Array<T, Alloc>::squeeze (void) const { - Array<T> retval = *this; + Array<T, Alloc> retval = *this; if (ndims () > 2) { @@ -159,37 +159,37 @@ } } - retval = Array<T> (*this, new_dimensions); + retval = Array<T, Alloc> (*this, new_dimensions); } return retval; } -template <typename T> +template <typename T, typename Alloc> octave_idx_type -Array<T>::compute_index (octave_idx_type i, octave_idx_type j) const +Array<T, Alloc>::compute_index (octave_idx_type i, octave_idx_type j) const { return ::compute_index (i, j, m_dimensions); } -template <typename T> +template <typename T, typename Alloc> octave_idx_type -Array<T>::compute_index (octave_idx_type i, octave_idx_type j, +Array<T, Alloc>::compute_index (octave_idx_type i, octave_idx_type j, octave_idx_type k) const { return ::compute_index (i, j, k, m_dimensions); } -template <typename T> +template <typename T, typename Alloc> octave_idx_type -Array<T>::compute_index (const Array<octave_idx_type>& ra_idx) const +Array<T, Alloc>::compute_index (const Array<octave_idx_type>& ra_idx) const { return ::compute_index (ra_idx, m_dimensions); } -template <typename T> +template <typename T, typename Alloc> T& -Array<T>::checkelem (octave_idx_type n) +Array<T, Alloc>::checkelem (octave_idx_type n) { // Do checks directly to avoid recomputing m_slice_len. if (n < 0) @@ -200,30 +200,30 @@ return elem (n); } -template <typename T> +template <typename T, typename Alloc> T& -Array<T>::checkelem (octave_idx_type i, octave_idx_type j) +Array<T, Alloc>::checkelem (octave_idx_type i, octave_idx_type j) { return elem (compute_index (i, j)); } -template <typename T> +template <typename T, typename Alloc> T& -Array<T>::checkelem (octave_idx_type i, octave_idx_type j, octave_idx_type k) +Array<T, Alloc>::checkelem (octave_idx_type i, octave_idx_type j, octave_idx_type k) { return elem (compute_index (i, j, k)); } -template <typename T> +template <typename T, typename Alloc> T& -Array<T>::checkelem (const Array<octave_idx_type>& ra_idx) +Array<T, Alloc>::checkelem (const Array<octave_idx_type>& ra_idx) { return elem (compute_index (ra_idx)); } -template <typename T> -typename Array<T>::crefT -Array<T>::checkelem (octave_idx_type n) const +template <typename T, typename Alloc> +typename Array<T, Alloc>::crefT +Array<T, Alloc>::checkelem (octave_idx_type n) const { // Do checks directly to avoid recomputing m_slice_len. if (n < 0) @@ -234,56 +234,56 @@ return elem (n); } -template <typename T> -typename Array<T>::crefT -Array<T>::checkelem (octave_idx_type i, octave_idx_type j) const +template <typename T, typename Alloc> +typename Array<T, Alloc>::crefT +Array<T, Alloc>::checkelem (octave_idx_type i, octave_idx_type j) const { return elem (compute_index (i, j)); } -template <typename T> -typename Array<T>::crefT -Array<T>::checkelem (octave_idx_type i, octave_idx_type j, +template <typename T, typename Alloc> +typename Array<T, Alloc>::crefT +Array<T, Alloc>::checkelem (octave_idx_type i, octave_idx_type j, octave_idx_type k) const { return elem (compute_index (i, j, k)); } -template <typename T> -typename Array<T>::crefT -Array<T>::checkelem (const Array<octave_idx_type>& ra_idx) const +template <typename T, typename Alloc> +typename Array<T, Alloc>::crefT +Array<T, Alloc>::checkelem (const Array<octave_idx_type>& ra_idx) const { return elem (compute_index (ra_idx)); } -template <typename T> -Array<T> -Array<T>::column (octave_idx_type k) const +template <typename T, typename Alloc> +Array<T, Alloc> +Array<T, Alloc>::column (octave_idx_type k) const { octave_idx_type r = m_dimensions(0); - return Array<T> (*this, dim_vector (r, 1), k*r, k*r + r); + return Array<T, Alloc> (*this, dim_vector (r, 1), k*r, k*r + r); } -template <typename T> -Array<T> -Array<T>::page (octave_idx_type k) const +template <typename T, typename Alloc> +Array<T, Alloc> +Array<T, Alloc>::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<T> (*this, dim_vector (r, c), k*p, k*p + p); + return Array<T, Alloc> (*this, dim_vector (r, c), k*p, k*p + p); } -template <typename T> -Array<T> -Array<T>::linear_slice (octave_idx_type lo, octave_idx_type up) const +template <typename T, typename Alloc> +Array<T, Alloc> +Array<T, Alloc>::linear_slice (octave_idx_type lo, octave_idx_type up) const { if (up < lo) up = lo; - return Array<T> (*this, dim_vector (up - lo, 1), lo, up); + return Array<T, Alloc> (*this, dim_vector (up - lo, 1), lo, up); } // Helper class for multi-d dimension permuting (generalized transpose). @@ -426,11 +426,11 @@ bool m_use_blk; }; -template <typename T> -Array<T> -Array<T>::permute (const Array<octave_idx_type>& perm_vec_arg, bool inv) const +template <typename T, typename Alloc> +Array<T, Alloc> +Array<T, Alloc>::permute (const Array<octave_idx_type>& perm_vec_arg, bool inv) const { - Array<T> retval; + Array<T, Alloc> retval; Array<octave_idx_type> perm_vec = perm_vec_arg; @@ -484,7 +484,7 @@ for (int i = 0; i < perm_vec_len; i++) dv_new(i) = dv(perm_vec(i)); - retval = Array<T> (dv_new); + retval = Array<T, Alloc> (dv_new); if (numel () > 0) { @@ -692,9 +692,9 @@ int m_n; }; -template <typename T> -Array<T> -Array<T>::index (const octave::idx_vector& i) const +template <typename T, typename Alloc> +Array<T, Alloc> +Array<T, Alloc>::index (const octave::idx_vector& i) const { // Colon: // @@ -715,12 +715,12 @@ // array | anything | same size as index octave_idx_type n = numel (); - Array<T> retval; + Array<T, Alloc> retval; if (i.is_colon ()) { // A(:) produces a shallow copy as a column vector. - retval = Array<T> (*this, dim_vector (n, 1)); + retval = Array<T, Alloc> (*this, dim_vector (n, 1)); } else { @@ -744,12 +744,12 @@ octave_idx_type l, u; if (idx_len != 0 && i.is_cont_range (n, l, u)) // If suitable, produce a shallow slice. - retval = Array<T> (*this, result_dims, l, u); + retval = Array<T, Alloc> (*this, result_dims, l, u); else { // Don't use resize here to avoid useless initialization for POD // types. - retval = Array<T> (result_dims); + retval = Array<T, Alloc> (result_dims); if (idx_len != 0) i.index (data (), n, retval.fortran_vec ()); @@ -759,20 +759,20 @@ return retval; } -template <typename T> -Array<T> -Array<T>::index (const octave::idx_vector& i, const octave::idx_vector& j) const +template <typename T, typename Alloc> +Array<T, Alloc> +Array<T, Alloc>::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<T> retval; + Array<T, Alloc> retval; if (i.is_colon () && j.is_colon ()) { // A(:,:) produces a shallow copy. - retval = Array<T> (*this, dv); + retval = Array<T, Alloc> (*this, dv); } else { @@ -792,11 +792,11 @@ octave_idx_type l, u; if (ii.length () > 0 && ii.is_cont_range (n, l, u)) // If suitable, produce a shallow slice. - retval = Array<T> (*this, dim_vector (il, jl), l, u); + retval = Array<T, Alloc> (*this, dim_vector (il, jl), l, u); else { // Don't use resize to avoid useless initialization for POD types. - retval = Array<T> (dim_vector (il, jl)); + retval = Array<T, Alloc> (dim_vector (il, jl)); ii.index (data (), n, retval.fortran_vec ()); } @@ -804,7 +804,7 @@ else { // Don't use resize to avoid useless initialization for POD types. - retval = Array<T> (dim_vector (il, jl)); + retval = Array<T, Alloc> (dim_vector (il, jl)); const T *src = data (); T *dest = retval.fortran_vec (); @@ -817,12 +817,12 @@ return retval; } -template <typename T> -Array<T> -Array<T>::index (const Array<octave::idx_vector>& ia) const +template <typename T, typename Alloc> +Array<T, Alloc> +Array<T, Alloc>::index (const Array<octave::idx_vector>& ia) const { int ial = ia.numel (); - Array<T> retval; + Array<T, Alloc> retval; // FIXME: is this dispatching necessary? if (ial == 1) @@ -849,7 +849,7 @@ { // A(:,:,...,:) produces a shallow copy. dv.chop_trailing_singletons (); - retval = Array<T> (*this, dv); + retval = Array<T, Alloc> (*this, dv); } else { @@ -864,11 +864,11 @@ octave_idx_type l, u; if (rh.is_cont_range (l, u)) // If suitable, produce a shallow slice. - retval = Array<T> (*this, rdv, l, u); + retval = Array<T, Alloc> (*this, rdv, l, u); else { // Don't use resize to avoid useless initialization for POD types. - retval = Array<T> (rdv); + retval = Array<T, Alloc> (rdv); // Do it. rh.index (data (), retval.fortran_vec ()); @@ -881,9 +881,9 @@ // The default fill value. Override if you want a different one. -template <typename T> +template <typename T, typename Alloc> T -Array<T>::resize_fill_value (void) const +Array<T, Alloc>::resize_fill_value (void) const { static T zero = T (); return zero; @@ -892,9 +892,9 @@ // Yes, we could do resize using index & assign. However, that would // possibly involve a lot more memory traffic than we actually need. -template <typename T> +template <typename T, typename Alloc> void -Array<T>::resize1 (octave_idx_type n, const T& rfv) +Array<T, Alloc>::resize1 (octave_idx_type n, const T& rfv) { if (n < 0 || ndims () != 2) octave::err_invalid_resize (); @@ -940,7 +940,7 @@ { static const octave_idx_type max_stack_chunk = 1024; octave_idx_type nn = n + std::min (nx, max_stack_chunk); - Array<T> tmp (Array<T> (dim_vector (nn, 1)), dv, 0, n); + Array<T, Alloc> tmp (Array<T, Alloc> (dim_vector (nn, 1)), dv, 0, n); T *dest = tmp.fortran_vec (); std::copy_n (data (), nx, dest); @@ -951,7 +951,7 @@ } else if (n != nx) { - Array<T> tmp = Array<T> (dv); + Array<T, Alloc> tmp = Array<T, Alloc> (dv); T *dest = tmp.fortran_vec (); octave_idx_type n0 = std::min (n, nx); @@ -963,9 +963,9 @@ } } -template <typename T> +template <typename T, typename Alloc> void -Array<T>::resize2 (octave_idx_type r, octave_idx_type c, const T& rfv) +Array<T, Alloc>::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 @@ octave_idx_type cx = columns (); if (r != rx || c != cx) { - Array<T> tmp = Array<T> (dim_vector (r, c)); + Array<T, Alloc> tmp = Array<T, Alloc> (dim_vector (r, c)); T *dest = tmp.fortran_vec (); octave_idx_type r0 = std::min (r, rx); @@ -1005,9 +1005,9 @@ } } -template <typename T> +template <typename T, typename Alloc> void -Array<T>::resize (const dim_vector& dv, const T& rfv) +Array<T, Alloc>::resize (const dim_vector& dv, const T& rfv) { int dvl = dv.ndims (); if (dvl == 2) @@ -1017,7 +1017,7 @@ if (m_dimensions.ndims () > dvl || dv.any_neg ()) octave::err_invalid_resize (); - Array<T> tmp (dv); + Array<T, Alloc> tmp (dv); // Prepare for recursive resizing. rec_resize_helper rh (dv, m_dimensions.redim (dvl)); @@ -1027,11 +1027,11 @@ } } -template <typename T> -Array<T> -Array<T>::index (const octave::idx_vector& i, bool resize_ok, const T& rfv) const +template <typename T, typename Alloc> +Array<T, Alloc> +Array<T, Alloc>::index (const octave::idx_vector& i, bool resize_ok, const T& rfv) const { - Array<T> tmp = *this; + Array<T, Alloc> tmp = *this; if (resize_ok) { octave_idx_type n = numel (); @@ -1039,24 +1039,24 @@ if (n != nx) { if (i.is_scalar ()) - return Array<T> (dim_vector (1, 1), rfv); + return Array<T, Alloc> (dim_vector (1, 1), rfv); else tmp.resize1 (nx, rfv); } if (tmp.numel () != nx) - return Array<T> (); + return Array<T, Alloc> (); } return tmp.index (i); } -template <typename T> -Array<T> -Array<T>::index (const octave::idx_vector& i, const octave::idx_vector& j, +template <typename T, typename Alloc> +Array<T, Alloc> +Array<T, Alloc>::index (const octave::idx_vector& i, const octave::idx_vector& j, bool resize_ok, const T& rfv) const { - Array<T> tmp = *this; + Array<T, Alloc> tmp = *this; if (resize_ok) { dim_vector dv = m_dimensions.redim (2); @@ -1067,24 +1067,24 @@ if (r != rx || c != cx) { if (i.is_scalar () && j.is_scalar ()) - return Array<T> (dim_vector (1, 1), rfv); + return Array<T, Alloc> (dim_vector (1, 1), rfv); else tmp.resize2 (rx, cx, rfv); } if (tmp.rows () != rx || tmp.columns () != cx) - return Array<T> (); + return Array<T, Alloc> (); } return tmp.index (i, j); } -template <typename T> -Array<T> -Array<T>::index (const Array<octave::idx_vector>& ia, +template <typename T, typename Alloc> +Array<T, Alloc> +Array<T, Alloc>::index (const Array<octave::idx_vector>& ia, bool resize_ok, const T& rfv) const { - Array<T> tmp = *this; + Array<T, Alloc> tmp = *this; if (resize_ok) { int ial = ia.numel (); @@ -1098,21 +1098,21 @@ for (int i = 0; i < ial; i++) all_scalars = all_scalars && ia(i).is_scalar (); if (all_scalars) - return Array<T> (dim_vector (1, 1), rfv); + return Array<T, Alloc> (dim_vector (1, 1), rfv); else tmp.resize (dvx, rfv); if (tmp.m_dimensions != dvx) - return Array<T> (); + return Array<T, Alloc> (); } } return tmp.index (ia); } -template <typename T> +template <typename T, typename Alloc> void -Array<T>::assign (const octave::idx_vector& i, const Array<T>& rhs, const T& rfv) +Array<T, Alloc>::assign (const octave::idx_vector& i, const Array<T, Alloc>& rhs, const T& rfv) { octave_idx_type n = numel (); octave_idx_type rhl = rhs.numel (); @@ -1129,9 +1129,9 @@ if (m_dimensions.zero_by_zero () && colon) { if (rhl == 1) - *this = Array<T> (dim_vector (1, nx), rhs(0)); + *this = Array<T, Alloc> (dim_vector (1, nx), rhs(0)); else - *this = Array<T> (rhs, dim_vector (1, nx)); + *this = Array<T, Alloc> (rhs, dim_vector (1, nx)); return; } @@ -1157,10 +1157,10 @@ } // Assignment to a 2-dimensional array -template <typename T> +template <typename T, typename Alloc> void -Array<T>::assign (const octave::idx_vector& i, const octave::idx_vector& j, - const Array<T>& rhs, const T& rfv) +Array<T, Alloc>::assign (const octave::idx_vector& i, const octave::idx_vector& j, + const Array<T, Alloc>& rhs, const T& rfv) { bool initial_dims_all_zero = m_dimensions.all_zero (); @@ -1203,9 +1203,9 @@ if (dv.zero_by_zero () && all_colons) { if (isfill) - *this = Array<T> (rdv, rhs(0)); + *this = Array<T, Alloc> (rdv, rhs(0)); else - *this = Array<T> (rhs, rdv); + *this = Array<T, Alloc> (rhs, rdv); return; } @@ -1261,10 +1261,10 @@ } // Assignment to a multi-dimensional array -template <typename T> +template <typename T, typename Alloc> void -Array<T>::assign (const Array<octave::idx_vector>& ia, - const Array<T>& rhs, const T& rfv) +Array<T, Alloc>::assign (const Array<octave::idx_vector>& ia, + const Array<T, Alloc>& rhs, const T& rfv) { int ial = ia.numel (); @@ -1327,9 +1327,9 @@ { rdv.chop_trailing_singletons (); if (isfill) - *this = Array<T> (rdv, rhs(0)); + *this = Array<T, Alloc> (rdv, rhs(0)); else - *this = Array<T> (rhs, rdv); + *this = Array<T, Alloc> (rhs, rdv); return; } @@ -1389,14 +1389,14 @@ %!error <op1 is 2x2, op2 is 2x1> a(1:2,2:3) = [1;2] */ -template <typename T> +template <typename T, typename Alloc> void -Array<T>::delete_elements (const octave::idx_vector& i) +Array<T, Alloc>::delete_elements (const octave::idx_vector& i) { octave_idx_type n = numel (); if (i.is_colon ()) { - *this = Array<T> (); + *this = Array<T, Alloc> (); } else if (i.length (n) != 0) { @@ -1414,7 +1414,7 @@ { // Special case deleting a contiguous range. octave_idx_type m = n + l - u; - Array<T> tmp (dim_vector (col_vec ? m : 1, ! col_vec ? m : 1)); + Array<T, Alloc> 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 @@ } } -template <typename T> +template <typename T, typename Alloc> void -Array<T>::delete_elements (int dim, const octave::idx_vector& i) +Array<T, Alloc>::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 @@ octave_idx_type n = m_dimensions(dim); if (i.is_colon ()) { - *this = Array<T> (); + *this = Array<T, Alloc> (); } else if (i.length (n) != 0) { @@ -1460,7 +1460,7 @@ for (int k = dim + 1; k < ndims (); k++) du *= m_dimensions(k); // Special case deleting a contiguous range. - Array<T> tmp = Array<T> (rdv); + Array<T, Alloc> tmp = Array<T, Alloc> (rdv); const T *src = data (); T *dest = tmp.fortran_vec (); l *= dl; u *= dl; n *= dl; @@ -1485,9 +1485,9 @@ } } -template <typename T> +template <typename T, typename Alloc> void -Array<T>::delete_elements (const Array<octave::idx_vector>& ia) +Array<T, Alloc>::delete_elements (const Array<octave::idx_vector>& ia) { int ial = ia.numel (); @@ -1510,7 +1510,7 @@ { dim_vector dv = m_dimensions; dv(0) = 0; - *this = Array<T> (dv); + *this = Array<T, Alloc> (dv); } else if (k == ial) { @@ -1562,9 +1562,9 @@ } -template <typename T> -Array<T>& -Array<T>::insert (const Array<T>& a, octave_idx_type r, octave_idx_type c) +template <typename T, typename Alloc> +Array<T, Alloc>& +Array<T, Alloc>::insert (const Array<T, Alloc>& 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 @@ return *this; } -template <typename T> -Array<T>& -Array<T>::insert (const Array<T>& a, const Array<octave_idx_type>& ra_idx) +template <typename T, typename Alloc> +Array<T, Alloc>& +Array<T, Alloc>::insert (const Array<T, Alloc>& a, const Array<octave_idx_type>& ra_idx) { octave_idx_type n = ra_idx.numel (); Array<octave::idx_vector> idx (dim_vector (n, 1)); @@ -1598,9 +1598,9 @@ return *this; } -template <typename T> -Array<T> -Array<T>::transpose (void) const +template <typename T, typename Alloc> +Array<T, Alloc> +Array<T, Alloc>::transpose (void) const { assert (ndims () == 2); @@ -1609,7 +1609,7 @@ if (nr >= 8 && nc >= 8) { - Array<T> result (dim_vector (nc, nr)); + Array<T, Alloc> result (dim_vector (nc, nr)); // Reuse the implementation used for permuting. @@ -1619,7 +1619,7 @@ } else if (nr > 1 && nc > 1) { - Array<T> result (dim_vector (nc, nr)); + Array<T, Alloc> 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 @@ else { // Fast transpose for vectors and empty matrices. - return Array<T> (*this, dim_vector (nc, nr)); + return Array<T, Alloc> (*this, dim_vector (nc, nr)); } } @@ -1641,9 +1641,9 @@ return x; } -template <typename T> -Array<T> -Array<T>::hermitian (T (*fcn) (const T&)) const +template <typename T, typename Alloc> +Array<T, Alloc> +Array<T, Alloc>::hermitian (T (*fcn) (const T&)) const { assert (ndims () == 2); @@ -1655,7 +1655,7 @@ if (nr >= 8 && nc >= 8) { - Array<T> result (dim_vector (nc, nr)); + Array<T, Alloc> result (dim_vector (nc, nr)); // Blocked transpose to attempt to avoid cache misses. @@ -1695,7 +1695,7 @@ } else { - Array<T> result (dim_vector (nc, nr)); + Array<T, Alloc> 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 @@ */ -template <typename T> +template <typename T, typename Alloc> T * -Array<T>::fortran_vec (void) +Array<T, Alloc>::fortran_vec (void) { make_unique (); @@ -1756,14 +1756,14 @@ return false; } -template <typename T> -Array<T> -Array<T>::sort (int dim, sortmode mode) const +template <typename T, typename Alloc> +Array<T, Alloc> +Array<T, Alloc>::sort (int dim, sortmode mode) const { if (dim < 0) (*current_liboctave_error_handler) ("sort: invalid dimension"); - Array<T> m (dims ()); + Array<T, Alloc> m (dims ()); dim_vector dv = m.dims (); @@ -1868,15 +1868,15 @@ return m; } -template <typename T> -Array<T> -Array<T>::sort (Array<octave_idx_type>& sidx, int dim, - sortmode mode) const +template <typename T, typename Alloc> +Array<T, Alloc> +Array<T, Alloc>::sort (Array<octave_idx_type>& sidx, int dim, + sortmode mode) const { if (dim < 0 || dim >= ndims ()) (*current_liboctave_error_handler) ("sort: invalid dimension"); - Array<T> m (dims ()); + Array<T, Alloc> m (dims ()); dim_vector dv = m.dims (); @@ -2009,9 +2009,9 @@ return m; } -template <typename T> -typename Array<T>::compare_fcn_type -safe_comparator (sortmode mode, const Array<T>& /* a */, +template <typename T, typename Alloc> +typename Array<T, Alloc>::compare_fcn_type +safe_comparator (sortmode mode, const Array<T, Alloc>& /* a */, bool /* allow_chk */) { if (mode == ASCENDING) @@ -2022,9 +2022,9 @@ return nullptr; } -template <typename T> +template <typename T, typename Alloc> sortmode -Array<T>::issorted (sortmode mode) const +Array<T, Alloc>::issorted (sortmode mode) const { octave_sort<T> lsort; @@ -2054,9 +2054,9 @@ } -template <typename T> +template <typename T, typename Alloc> Array<octave_idx_type> -Array<T>::sort_rows_idx (sortmode mode) const +Array<T, Alloc>::sort_rows_idx (sortmode mode) const { Array<octave_idx_type> idx; @@ -2072,9 +2072,9 @@ return idx; } -template <typename T> +template <typename T, typename Alloc> sortmode -Array<T>::is_sorted_rows (sortmode mode) const +Array<T, Alloc>::is_sorted_rows (sortmode mode) const { octave_sort<T> lsort; @@ -2133,9 +2133,9 @@ } // Do a binary lookup in a sorted array. -template <typename T> +template <typename T, typename Alloc> octave_idx_type -Array<T>::lookup (const T& value, sortmode mode) const +Array<T, Alloc>::lookup (const T& value, sortmode mode) const { octave_idx_type n = numel (); octave_sort<T> lsort; @@ -2154,9 +2154,9 @@ return lsort.lookup (data (), n, value); } -template <typename T> +template <typename T, typename Alloc> Array<octave_idx_type> -Array<T>::lookup (const Array<T>& values, sortmode mode) const +Array<T, Alloc>::lookup (const Array<T, Alloc>& values, sortmode mode) const { octave_idx_type n = numel (); octave_idx_type nval = values.numel (); @@ -2198,9 +2198,9 @@ return idx; } -template <typename T> +template <typename T, typename Alloc> octave_idx_type -Array<T>::nnz (void) const +Array<T, Alloc>::nnz (void) const { const T *src = data (); octave_idx_type nel = numel (); @@ -2213,9 +2213,9 @@ return retval; } -template <typename T> +template <typename T, typename Alloc> Array<octave_idx_type> -Array<T>::find (octave_idx_type n, bool backward) const +Array<T, Alloc>::find (octave_idx_type n, bool backward) const { Array<octave_idx_type> retval; const T *src = data (); @@ -2294,9 +2294,9 @@ return retval; } -template <typename T> -Array<T> -Array<T>::nth_element (const octave::idx_vector& n, int dim) const +template <typename T, typename Alloc> +Array<T, Alloc> +Array<T, Alloc>::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 @@ dv.chop_trailing_singletons (); dim = std::min (dv.ndims (), static_cast<octave_idx_type> (dim)); - Array<T> m (dv); + Array<T, Alloc> m (dv); if (m.isempty ()) return m; @@ -2464,7 +2464,7 @@ return *this; \ } \ template <> API Array<T> \ - Array<T>::sort (Array<octave_idx_type> &sidx, int, sortmode) const \ + Array<T>::sort (Array<octave_idx_type> &sidx, int, sortmode) const \ { \ sidx = Array<octave_idx_type> (); \ return *this; \ @@ -2516,13 +2516,13 @@ #define NO_INSTANTIATE_ARRAY_SORT(T) NO_INSTANTIATE_ARRAY_SORT_API (T,) -template <typename T> -Array<T> -Array<T>::diag (octave_idx_type k) const +template <typename T, typename Alloc> +Array<T, Alloc> +Array<T, Alloc>::diag (octave_idx_type k) const { dim_vector dv = dims (); octave_idx_type nd = dv.ndims (); - Array<T> d; + Array<T, Alloc> d; if (nd > 2) (*current_liboctave_error_handler) ("Matrix must be 2-dimensional"); @@ -2584,7 +2584,7 @@ if (nnr == 1) { octave_idx_type n = nnc + std::abs (k); - d = Array<T> (dim_vector (n, n), resize_fill_value ()); + d = Array<T, Alloc> (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 @@ else { octave_idx_type n = nnr + std::abs (k); - d = Array<T> (dim_vector (n, n), resize_fill_value ()); + d = Array<T, Alloc> (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 @@ return d; } -template <typename T> -Array<T> -Array<T>::diag (octave_idx_type m, octave_idx_type n) const +template <typename T, typename Alloc> +Array<T, Alloc> +Array<T, Alloc>::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<T> retval (dim_vector (m, n), resize_fill_value ()); + Array<T, Alloc> 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 @@ return retval; } -template <typename T> -Array<T> -Array<T>::cat (int dim, octave_idx_type n, const Array<T> *array_list) +template <typename T, typename Alloc> +Array<T, Alloc> +Array<T, Alloc>::cat (int dim, octave_idx_type n, const Array<T, Alloc> *array_list) { // Default concatenation. bool (dim_vector::*concat_rule) (const dim_vector&, int) = &dim_vector::concat; @@ -2636,7 +2636,7 @@ if (n == 1) return array_list[0]; else if (n == 0) - return Array<T> (); + return Array<T, Alloc> (); // Special case: // @@ -2684,7 +2684,7 @@ if (! (dv.*concat_rule) (array_list[i].dims (), dim)) (*current_liboctave_error_handler) ("cat: dimension mismatch"); - Array<T> retval (dv); + Array<T, Alloc> retval (dv); if (retval.isempty ()) return retval; @@ -2722,9 +2722,9 @@ return retval; } -template <typename T> +template <typename T, typename Alloc> void -Array<T>::print_info (std::ostream& os, const std::string& prefix) const +Array<T, Alloc>::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 @@ // << prefix << "cols: " << cols () << "\n"; } -template <typename T> -bool Array<T>::optimize_dimensions (const dim_vector& dv) +template <typename T, typename Alloc> +bool Array<T, Alloc>::optimize_dimensions (const dim_vector& dv) { bool retval = m_dimensions == dv; if (retval) @@ -2749,29 +2749,33 @@ return retval; } -template <typename T> -void Array<T>::instantiation_guard () +template <typename T, typename Alloc> +void Array<T, Alloc>::instantiation_guard () { // This guards against accidental implicit instantiations. - // Array<T> instances should always be explicit and use INSTANTIATE_ARRAY. + // Array<T, Alloc> instances should always be explicit and use INSTANTIATE_ARRAY. T::__xXxXx__ (); } #if defined (__clang__) -# define INSTANTIATE_ARRAY(T, API) \ - template <> API void Array<T>::instantiation_guard () { } \ - template class API Array<T> +# define INSTANTIATE_ARRAY(T, API) \ + template <> API void \ + Array<T>::instantiation_guard () { } \ + \ + template class API Array<T> #else -# define INSTANTIATE_ARRAY(T, API) \ - template <> API void Array<T>::instantiation_guard () { } \ - template class Array<T> +# define INSTANTIATE_ARRAY(T, API) \ + template <> API void \ + Array<T>::instantiation_guard () { } \ + \ + template class Array<T> #endif // FIXME: is this used? -template <typename T> +template <typename T, typename Alloc> std::ostream& -operator << (std::ostream& os, const Array<T>& a) +operator << (std::ostream& os, const Array<T, Alloc>& a) { dim_vector a_dims = a.dims ();
--- a/liboctave/array/Array.h Thu Dec 09 21:21:37 2021 -0800 +++ b/liboctave/array/Array.h Wed Dec 15 20:26:12 2021 -0500 @@ -123,65 +123,89 @@ //! - string_vector: Array<std::string> with 1 column //! - Cell: Array<octave_value>, equivalent to an Octave cell. -template <typename T> +template <typename T, typename Alloc> class Array { protected: //! The real representation of all arrays. - class ArrayRep + class ArrayRep : public Alloc { public: - T *m_data; + typedef std::allocator_traits<Alloc> Alloc_traits; + + typedef typename Alloc_traits::rebind_traits<T> T_Alloc_traits; + typedef typename T_Alloc_traits::pointer pointer; + + pointer m_data; octave_idx_type m_len; octave::refcount<octave_idx_type> 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 <typename U> - 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 @@ dim_vector m_dimensions; - typename Array<T>::ArrayRep *m_rep; + typename Array<T, Alloc>::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 @@ octave_idx_type m_slice_len; //! slice constructor - Array (const Array<T>& a, const dim_vector& dv, + Array (const Array<T, Alloc>& 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 @@ private: - static OCTARRAY_API typename Array<T>::ArrayRep *nil_rep (void); + static OCTARRAY_API typename Array<T, Alloc>::ArrayRep *nil_rep (void); public: @@ -257,7 +281,7 @@ //! nD uninitialized ctor. explicit Array (const dim_vector& dv) : m_dimensions (dv), - m_rep (new typename Array<T>::ArrayRep (dv.safe_numel ())), + m_rep (new typename Array<T, Alloc>::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 @@ //! nD initialized ctor. explicit Array (const dim_vector& dv, const T& val) : m_dimensions (dv), - m_rep (new typename Array<T>::ArrayRep (dv.safe_numel ())), + m_rep (new typename Array<T, Alloc>::ArrayRep (dv.safe_numel ())), m_slice_data (m_rep->m_data), m_slice_len (m_rep->m_len) { fill (val); @@ -279,38 +303,39 @@ // 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<T>::ArrayRep (ptr, dv)), + m_rep (new typename Array<T, Alloc>::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<T>& a, const dim_vector& dv); + OCTARRAY_API Array (const Array<T, Alloc>& a, const dim_vector& dv); //! Constructor from standard library sequence containers. template<template <typename...> class Container> Array (const Container<T>& a, const dim_vector& dv); //! Type conversion case. - template <typename U> - Array (const Array<U>& a) + template <typename U, typename A = Alloc> + Array (const Array<U, A>& a) : m_dimensions (a.dims ()), - m_rep (new typename Array<T>::ArrayRep (a.data (), a.numel ())), + m_rep (new typename Array<T, Alloc>::ArrayRep (a.data (), a.numel ())), m_slice_data (m_rep->m_data), m_slice_len (m_rep->m_len) { } //! No type conversion case. - Array (const Array<T>& a) + Array (const Array<T, Alloc>& a) : m_dimensions (a.m_dimensions), m_rep (a.m_rep), m_slice_data (a.m_slice_data), m_slice_len (a.m_slice_len) { m_rep->m_count++; } - Array (Array<T>&& a) + Array (Array<T, Alloc>&& a) : m_dimensions (std::move (a.m_dimensions)), m_rep (a.m_rep), m_slice_data (a.m_slice_data), m_slice_len (a.m_slice_len) { @@ -331,7 +356,7 @@ delete m_rep; } - Array<T>& operator = (const Array<T>& a) + Array<T, Alloc>& operator = (const Array<T, Alloc>& a) { if (this != &a) { @@ -349,7 +374,7 @@ return *this; } - Array<T>& operator = (Array<T>&& a) + Array<T, Alloc>& operator = (Array<T, Alloc>&& a) { if (this != &a) { @@ -387,9 +412,9 @@ //@} //! Return the array as a column vector. - Array<T> as_column (void) const + Array<T, Alloc> as_column (void) const { - Array<T> retval (*this); + Array<T, Alloc> retval (*this); if (m_dimensions.ndims () != 2 || m_dimensions(1) != 1) retval.m_dimensions = dim_vector (numel (), 1); @@ -397,9 +422,9 @@ } //! Return the array as a row vector. - Array<T> as_row (void) const + Array<T, Alloc> as_row (void) const { - Array<T> retval (*this); + Array<T, Alloc> retval (*this); if (m_dimensions.ndims () != 2 || m_dimensions(0) != 1) retval.m_dimensions = dim_vector (1, numel ()); @@ -407,9 +432,9 @@ } //! Return the array as a matrix. - Array<T> as_matrix (void) const + Array<T, Alloc> as_matrix (void) const { - Array<T> retval (*this); + Array<T, Alloc> retval (*this); if (m_dimensions.ndims () != 2) retval.m_dimensions = m_dimensions.redim (2); @@ -462,16 +487,17 @@ const dim_vector& dims (void) const { return m_dimensions; } //! Chop off leading singleton dimensions - OCTARRAY_API Array<T> squeeze (void) const; + OCTARRAY_API Array<T, Alloc> squeeze (void) const; OCTARRAY_API octave_idx_type compute_index (octave_idx_type i, octave_idx_type j) const; OCTARRAY_API octave_idx_type compute_index (octave_idx_type i, octave_idx_type j, octave_idx_type k) const; OCTARRAY_API octave_idx_type compute_index (const Array<octave_idx_type>& ra_idx) const; - octave_idx_type compute_index_unchecked (const Array<octave_idx_type>& ra_idx) - const - { return m_dimensions.compute_index (ra_idx.data (), ra_idx.numel ()); } + octave_idx_type compute_index_unchecked (const Array<octave_idx_type>& ra_idx) const + { + return m_dimensions.compute_index (ra_idx.data (), ra_idx.numel ()); + } // No checking, even for multiple references, ever. @@ -517,7 +543,7 @@ { return elem (i, dim2 ()*k+j); } T& elem (const Array<octave_idx_type>& ra_idx) - { return Array<T>::elem (compute_index_unchecked (ra_idx)); } + { return Array<T, Alloc>::elem (compute_index_unchecked (ra_idx)); } T& operator () (octave_idx_type n) { return elem (n); } T& operator () (octave_idx_type i, octave_idx_type j) { return elem (i, j); } @@ -544,7 +570,7 @@ { return xelem (i, j, k); } crefT elem (const Array<octave_idx_type>& ra_idx) const - { return Array<T>::xelem (compute_index_unchecked (ra_idx)); } + { return Array<T, Alloc>::xelem (compute_index_unchecked (ra_idx)); } crefT operator () (octave_idx_type n) const { return elem (n); } crefT operator () (octave_idx_type i, octave_idx_type j) const @@ -558,22 +584,22 @@ // Fast extractors. All of these produce shallow copies. //! Extract column: A(:,k+1). - OCTARRAY_API Array<T> column (octave_idx_type k) const; + OCTARRAY_API Array<T, Alloc> column (octave_idx_type k) const; //! Extract page: A(:,:,k+1). - OCTARRAY_API Array<T> page (octave_idx_type k) const; + OCTARRAY_API Array<T, Alloc> page (octave_idx_type k) const; //! Extract a slice from this array as a column vector: A(:)(lo+1:up). //! Must be 0 <= lo && up <= numel. May be up < lo. - OCTARRAY_API Array<T> linear_slice (octave_idx_type lo, octave_idx_type up) const; + OCTARRAY_API Array<T, Alloc> linear_slice (octave_idx_type lo, octave_idx_type up) const; - Array<T> reshape (octave_idx_type nr, octave_idx_type nc) const - { return Array<T> (*this, dim_vector (nr, nc)); } + Array<T, Alloc> reshape (octave_idx_type nr, octave_idx_type nc) const + { return Array<T, Alloc> (*this, dim_vector (nr, nc)); } - Array<T> reshape (const dim_vector& new_dims) const - { return Array<T> (*this, new_dims); } + Array<T, Alloc> reshape (const dim_vector& new_dims) const + { return Array<T, Alloc> (*this, new_dims); } - OCTARRAY_API Array<T> permute (const Array<octave_idx_type>& vec, bool inv = false) const; - Array<T> ipermute (const Array<octave_idx_type>& vec) const + OCTARRAY_API Array<T, Alloc> permute (const Array<octave_idx_type>& vec, bool inv = false) const; + Array<T, Alloc> ipermute (const Array<octave_idx_type>& vec) const { return permute (vec, true); } bool issquare (void) const { return (dim1 () == dim2 ()); } @@ -584,8 +610,8 @@ bool is_nd_vector (void) const { return m_dimensions.is_nd_vector (); } - OCTARRAY_API Array<T> transpose (void) const; - OCTARRAY_API Array<T> hermitian (T (*fcn) (const T&) = nullptr) const; + OCTARRAY_API Array<T, Alloc> transpose (void) const; + OCTARRAY_API Array<T, Alloc> hermitian (T (*fcn) (const T&) = nullptr) const; const T * data (void) const { return m_slice_data; } @@ -602,11 +628,11 @@ //@{ //! Indexing without resizing. - OCTARRAY_API Array<T> index (const octave::idx_vector& i) const; + OCTARRAY_API Array<T, Alloc> index (const octave::idx_vector& i) const; - OCTARRAY_API Array<T> index (const octave::idx_vector& i, const octave::idx_vector& j) const; + OCTARRAY_API Array<T, Alloc> index (const octave::idx_vector& i, const octave::idx_vector& j) const; - OCTARRAY_API Array<T> index (const Array<octave::idx_vector>& ia) const; + OCTARRAY_API Array<T, Alloc> index (const Array<octave::idx_vector>& ia) const; //@} virtual OCTARRAY_API T resize_fill_value (void) const; @@ -632,24 +658,24 @@ // FIXME: this is really a corner case, that should better be // handled directly in liboctinterp. - OCTARRAY_API Array<T> index (const octave::idx_vector& i, bool resize_ok, const T& rfv) const; - Array<T> index (const octave::idx_vector& i, bool resize_ok) const + OCTARRAY_API Array<T, Alloc> index (const octave::idx_vector& i, bool resize_ok, const T& rfv) const; + Array<T, Alloc> index (const octave::idx_vector& i, bool resize_ok) const { return index (i, resize_ok, resize_fill_value ()); } - OCTARRAY_API Array<T> index (const octave::idx_vector& i, const octave::idx_vector& j, + OCTARRAY_API Array<T, Alloc> index (const octave::idx_vector& i, const octave::idx_vector& j, bool resize_ok, const T& rfv) const; - Array<T> index (const octave::idx_vector& i, const octave::idx_vector& j, + Array<T, Alloc> index (const octave::idx_vector& i, const octave::idx_vector& j, bool resize_ok) const { return index (i, j, resize_ok, resize_fill_value ()); } - OCTARRAY_API Array<T> index (const Array<octave::idx_vector>& ia, bool resize_ok, + OCTARRAY_API Array<T, Alloc> index (const Array<octave::idx_vector>& ia, bool resize_ok, const T& rfv) const; - Array<T> index (const Array<octave::idx_vector>& ia, bool resize_ok) const + Array<T, Alloc> index (const Array<octave::idx_vector>& ia, bool resize_ok) const { return index (ia, resize_ok, resize_fill_value ()); } @@ -657,22 +683,22 @@ //@{ //! Indexed assignment (always with resize & fill). - OCTARRAY_API void assign (const octave::idx_vector& i, const Array<T>& rhs, const T& rfv); - void assign (const octave::idx_vector& i, const Array<T>& rhs) + OCTARRAY_API void assign (const octave::idx_vector& i, const Array<T, Alloc>& rhs, const T& rfv); + void assign (const octave::idx_vector& i, const Array<T, Alloc>& rhs) { assign (i, rhs, resize_fill_value ()); } OCTARRAY_API void assign (const octave::idx_vector& i, const octave::idx_vector& j, - const Array<T>& rhs, + const Array<T, Alloc>& rhs, const T& rfv); - void assign (const octave::idx_vector& i, const octave::idx_vector& j, const Array<T>& rhs) + void assign (const octave::idx_vector& i, const octave::idx_vector& j, const Array<T, Alloc>& rhs) { assign (i, j, rhs, resize_fill_value ()); } - OCTARRAY_API void assign (const Array<octave::idx_vector>& ia, const Array<T>& rhs, const T& rfv); - void assign (const Array<octave::idx_vector>& ia, const Array<T>& rhs) + OCTARRAY_API void assign (const Array<octave::idx_vector>& ia, const Array<T, Alloc>& rhs, const T& rfv); + void assign (const Array<octave::idx_vector>& ia, const Array<T, Alloc>& rhs) { assign (ia, rhs, resize_fill_value ()); } @@ -695,10 +721,10 @@ //! size (a) is [d1 d2 ... dN] and idx is [i1 i2 ... iN], this //! method is equivalent to x(i1:i1+d1-1, i2:i2+d2-1, ... , //! iN:iN+dN-1) = a. - OCTARRAY_API Array<T>& insert (const Array<T>& a, const Array<octave_idx_type>& idx); + OCTARRAY_API Array<T, Alloc>& insert (const Array<T, Alloc>& a, const Array<octave_idx_type>& idx); //! This is just a special case for idx = [r c 0 ...] - OCTARRAY_API Array<T>& insert (const Array<T>& a, octave_idx_type r, octave_idx_type c); + OCTARRAY_API Array<T, Alloc>& insert (const Array<T, Alloc>& a, octave_idx_type r, octave_idx_type c); void maybe_economize (void) { @@ -713,9 +739,9 @@ OCTARRAY_API void print_info (std::ostream& os, const std::string& prefix) const; - OCTARRAY_API Array<T> sort (int dim = 0, sortmode mode = ASCENDING) const; - OCTARRAY_API Array<T> sort (Array<octave_idx_type>& sidx, int dim = 0, - sortmode mode = ASCENDING) const; + OCTARRAY_API Array<T, Alloc> sort (int dim = 0, sortmode mode = ASCENDING) const; + OCTARRAY_API Array<T, Alloc> sort (Array<octave_idx_type>& sidx, int dim = 0, + sortmode mode = ASCENDING) const; //! Ordering is auto-detected or can be specified. OCTARRAY_API sortmode issorted (sortmode mode = UNSORTED) const; @@ -732,8 +758,8 @@ //! Ditto, but for an array of values, specializing on the case when values //! are sorted. NaNs get the value N. - OCTARRAY_API Array<octave_idx_type> lookup (const Array<T>& values, - sortmode mode = UNSORTED) const; + OCTARRAY_API Array<octave_idx_type> lookup (const Array<T, Alloc>& values, + sortmode mode = UNSORTED) const; //! Count nonzero elements. OCTARRAY_API octave_idx_type nnz (void) const; @@ -741,37 +767,42 @@ //! Find indices of (at most n) nonzero elements. If n is specified, //! backward specifies search from backward. OCTARRAY_API Array<octave_idx_type> find (octave_idx_type n = -1, - bool backward = false) const; + bool backward = false) const; //! Returns the n-th element in increasing order, using the same //! ordering as used for sort. n can either be a scalar index or a //! contiguous range. - OCTARRAY_API Array<T> nth_element (const octave::idx_vector& n, int dim = 0) const; + OCTARRAY_API Array<T, Alloc> nth_element (const octave::idx_vector& n, int dim = 0) const; //! Get the kth super or subdiagonal. The zeroth diagonal is the //! ordinary diagonal. - OCTARRAY_API Array<T> diag (octave_idx_type k = 0) const; + OCTARRAY_API Array<T, Alloc> diag (octave_idx_type k = 0) const; - OCTARRAY_API Array<T> diag (octave_idx_type m, octave_idx_type n) const; + OCTARRAY_API Array<T, Alloc> diag (octave_idx_type m, octave_idx_type n) const; //! Concatenation along a specified (0-based) dimension, equivalent //! to cat(). dim = -1 corresponds to dim = 0 and dim = -2 //! corresponds to dim = 1, but apply the looser matching rules of //! vertcat/horzcat. - static OCTARRAY_API Array<T> - cat (int dim, octave_idx_type n, const Array<T> *array_list); + static OCTARRAY_API Array<T, Alloc> + cat (int dim, octave_idx_type n, const Array<T, Alloc> *array_list); - //! Apply function fcn to each element of the Array<T>. This function + //! Apply function fcn to each element of the Array<T, Alloc>. This function //! is optimized with a manually unrolled loop. - template <typename U, typename F> - Array<U> +#if defined (HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR) + template <typename U, typename F, + typename A = std::pmr::polymorphic_allocator<U>> +#else + template <typename U, typename F, typename A = std::allocator<U>> +#endif + Array<U, A> map (F fcn) const { octave_idx_type len = numel (); const T *m = data (); - Array<U> result (dims ()); + Array<U, A> result (dims ()); U *p = result.fortran_vec (); octave_idx_type i; @@ -795,15 +826,23 @@ //@{ //! Overloads for function references. - template <typename U> - Array<U> +#if defined (HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR) + template <typename U, typename A = std::pmr::polymorphic_allocator<U>> +#else + template <typename U, typename A = std::allocator<U>> +#endif + Array<U, A> map (U (&fcn) (T)) const - { return map<U, U (&) (T)> (fcn); } + { return map<U, U (&) (T), A> (fcn); } - template <typename U> - Array<U> +#if defined (HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR) + template <typename U, typename A = std::pmr::polymorphic_allocator<U>> +#else + template <typename U, typename A = std::allocator<U>> +#endif + Array<U, A> map (U (&fcn) (const T&)) const - { return map<U, U (&) (const T&)> (fcn); } + { return map<U, U (&) (const T&), A> (fcn); } //@} //! Generic any/all test functionality with arbitrary predicate. @@ -839,7 +878,7 @@ { return test<bool (&) (const T&), true> (fcn); } //@} - template <typename U> friend class Array; + template <typename U, typename A> friend class Array; //! Returns true if this->dims () == dv, and if so, replaces this->m_dimensions //! by a shallow copy of dv. This is useful for maintaining several arrays @@ -853,10 +892,10 @@ // We use a variadic template for template template parameter so that // we don't have to specify all the template parameters and limit this // to Container<T>. http://stackoverflow.com/a/20499809/1609556 -template<typename T> +template<typename T, typename Alloc> template<template <typename...> class Container> -Array<T>::Array (const Container<T>& a, const dim_vector& dv) - : m_dimensions (dv), m_rep (new typename Array<T>::ArrayRep (dv.safe_numel ())), +Array<T, Alloc>::Array (const Container<T>& a, const dim_vector& dv) + : m_dimensions (dv), m_rep (new typename Array<T, Alloc>::ArrayRep (dv.safe_numel ())), m_slice_data (m_rep->m_data), m_slice_len (m_rep->m_len) { if (m_dimensions.safe_numel () != octave_idx_type (a.size ())) @@ -875,8 +914,8 @@ m_dimensions.chop_trailing_singletons (); } -template <typename T> +template <typename T, typename Alloc> OCTARRAY_API std::ostream& -operator << (std::ostream& os, const Array<T>& a); +operator << (std::ostream& os, const Array<T, Alloc>& a); #endif
--- a/liboctave/array/MArray-C.cc Thu Dec 09 21:21:37 2021 -0800 +++ b/liboctave/array/MArray-C.cc Wed Dec 15 20:26:12 2021 -0500 @@ -34,7 +34,7 @@ #include "MArray.h" #include "MArray.cc" -INSTANTIATE_MARRAY (Complex); +INSTANTIATE_MARRAY (Complex, OCTAVE_API); INSTANTIATE_MARRAY_FRIENDS (Complex, OCTAVE_API)
--- a/liboctave/array/MArray-d.cc Thu Dec 09 21:21:37 2021 -0800 +++ b/liboctave/array/MArray-d.cc Wed Dec 15 20:26:12 2021 -0500 @@ -32,7 +32,7 @@ #include "MArray.h" #include "MArray.cc" -INSTANTIATE_MARRAY (double); +INSTANTIATE_MARRAY (double, OCTAVE_API); INSTANTIATE_MARRAY_FRIENDS (double, OCTAVE_API)
--- a/liboctave/array/MArray-f.cc Thu Dec 09 21:21:37 2021 -0800 +++ b/liboctave/array/MArray-f.cc Wed Dec 15 20:26:12 2021 -0500 @@ -32,7 +32,7 @@ #include "MArray.h" #include "MArray.cc" -INSTANTIATE_MARRAY (float); +INSTANTIATE_MARRAY (float, OCTAVE_API); INSTANTIATE_MARRAY_FRIENDS (float, OCTAVE_API)
--- a/liboctave/array/MArray-fC.cc Thu Dec 09 21:21:37 2021 -0800 +++ b/liboctave/array/MArray-fC.cc Wed Dec 15 20:26:12 2021 -0500 @@ -34,7 +34,7 @@ #include "MArray.h" #include "MArray.cc" -INSTANTIATE_MARRAY (FloatComplex); +INSTANTIATE_MARRAY (FloatComplex, OCTAVE_API); INSTANTIATE_MARRAY_FRIENDS (FloatComplex, OCTAVE_API)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/liboctave/array/MArray-fwd.h Wed Dec 15 20:26:12 2021 -0500 @@ -0,0 +1,33 @@ +//////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2021 The Octave Project Developers +// +// See the file COPYRIGHT.md in the top-level directory of this +// distribution or <https://octave.org/copyright/>. +// +// This file is part of Octave. +// +// Octave is free software: you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Octave is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Octave; see the file COPYING. If not, see +// <https://www.gnu.org/licenses/>. +// +//////////////////////////////////////////////////////////////////////// + +#if ! defined (octave_MArray_fwd_h) +#define octave_MArray_fwd_h 1 + +#include "octave-config.h" + +template <typename T> class OCTARRAY_API MArray; + +#endif
--- a/liboctave/array/MArray-i.cc Thu Dec 09 21:21:37 2021 -0800 +++ b/liboctave/array/MArray-i.cc Wed Dec 15 20:26:12 2021 -0500 @@ -34,9 +34,9 @@ #include "MArray.h" #include "MArray.cc" -INSTANTIATE_MARRAY (int); +INSTANTIATE_MARRAY (int, OCTAVE_API); #if defined (OCTAVE_ENABLE_64) -INSTANTIATE_MARRAY (int64_t); +INSTANTIATE_MARRAY (int64_t, OCTAVE_API); #endif INSTANTIATE_MARRAY_FRIENDS (int, OCTAVE_API) @@ -44,20 +44,20 @@ INSTANTIATE_MARRAY_FRIENDS (int64_t, OCTAVE_API) #endif -INSTANTIATE_MARRAY (octave_int8); -INSTANTIATE_MARRAY (octave_int16); -INSTANTIATE_MARRAY (octave_int32); -INSTANTIATE_MARRAY (octave_int64); +INSTANTIATE_MARRAY (octave_int8, OCTAVE_API); +INSTANTIATE_MARRAY (octave_int16, OCTAVE_API); +INSTANTIATE_MARRAY (octave_int32, OCTAVE_API); +INSTANTIATE_MARRAY (octave_int64, OCTAVE_API); INSTANTIATE_MARRAY_FRIENDS (octave_int8, OCTAVE_API) INSTANTIATE_MARRAY_FRIENDS (octave_int16, OCTAVE_API) INSTANTIATE_MARRAY_FRIENDS (octave_int32, OCTAVE_API) INSTANTIATE_MARRAY_FRIENDS (octave_int64, OCTAVE_API) -INSTANTIATE_MARRAY (octave_uint8); -INSTANTIATE_MARRAY (octave_uint16); -INSTANTIATE_MARRAY (octave_uint32); -INSTANTIATE_MARRAY (octave_uint64); +INSTANTIATE_MARRAY (octave_uint8, OCTAVE_API); +INSTANTIATE_MARRAY (octave_uint16, OCTAVE_API); +INSTANTIATE_MARRAY (octave_uint32, OCTAVE_API); +INSTANTIATE_MARRAY (octave_uint64, OCTAVE_API); INSTANTIATE_MARRAY_FRIENDS (octave_uint8, OCTAVE_API) INSTANTIATE_MARRAY_FRIENDS (octave_uint16, OCTAVE_API)
--- a/liboctave/array/MArray-s.cc Thu Dec 09 21:21:37 2021 -0800 +++ b/liboctave/array/MArray-s.cc Wed Dec 15 20:26:12 2021 -0500 @@ -32,7 +32,7 @@ #include "MArray.h" #include "MArray.cc" -INSTANTIATE_MARRAY (short); +INSTANTIATE_MARRAY (short, OCTAVE_API); INSTANTIATE_MARRAY_FRIENDS (short, OCTAVE_API)
--- a/liboctave/array/MArray.cc Thu Dec 09 21:21:37 2021 -0800 +++ b/liboctave/array/MArray.cc Wed Dec 15 20:26:12 2021 -0500 @@ -372,8 +372,24 @@ return do_mx_unary_op<T, T> (a, mx_inline_uminus); } +template <typename T> +void MArray<T>::instantiation_guard () +{ + // This guards against accidental implicit instantiations. + // Array<T, Alloc> instances should always be explicit and use INSTANTIATE_ARRAY. + T::__xXxXx__ (); +} + #if defined (__clang__) -# define INSTANTIATE_MARRAY(T) template class OCTAVE_API MArray<T> +# define INSTANTIATE_MARRAY(T, API) \ + template <> API void \ + MArray<T>::instantiation_guard () { } \ + \ + template class API MArray<T> #else -# define INSTANTIATE_MARRAY(T) template class MArray<T> +# define INSTANTIATE_MARRAY(T, API) \ + template <> API void \ + MArray<T>::instantiation_guard () { } \ + \ + template class MArray<T> #endif
--- a/liboctave/array/MArray.h Thu Dec 09 21:21:37 2021 -0800 +++ b/liboctave/array/MArray.h Wed Dec 15 20:26:12 2021 -0500 @@ -29,38 +29,36 @@ #include "octave-config.h" #include "Array.h" +#include "MArray-fwd.h" #include "mx-inlines.cc" -// forward declare template with visibility attribute -template <typename T> class OCTAVE_API MArray; - -template <typename T> OCTAVE_API MArray<T>& operator += (MArray<T>&, const T&); -template <typename T> OCTAVE_API MArray<T>& operator -= (MArray<T>&, const T&); -template <typename T> OCTAVE_API MArray<T>& operator *= (MArray<T>&, const T&); -template <typename T> OCTAVE_API MArray<T>& operator /= (MArray<T>&, const T&); -template <typename T> OCTAVE_API MArray<T>& operator += (MArray<T>&, const MArray<T>&); -template <typename T> OCTAVE_API MArray<T>& operator -= (MArray<T>&, const MArray<T>&); -template <typename T> OCTAVE_API MArray<T>& product_eq (MArray<T>&, const MArray<T>&); -template <typename T> OCTAVE_API MArray<T>& quotient_eq (MArray<T>&, const MArray<T>&); -template <typename T> OCTAVE_API MArray<T> operator + (const MArray<T>&); -template <typename T> OCTAVE_API MArray<T> operator - (const MArray<T>&); -template <typename T> OCTAVE_API MArray<T> operator + (const MArray<T>&, const T&); -template <typename T> OCTAVE_API MArray<T> operator - (const MArray<T>&, const T&); -template <typename T> OCTAVE_API MArray<T> operator * (const MArray<T>&, const T&); -template <typename T> OCTAVE_API MArray<T> operator / (const MArray<T>&, const T&); -template <typename T> OCTAVE_API MArray<T> operator + (const T&, const MArray<T>&); -template <typename T> OCTAVE_API MArray<T> operator - (const T&, const MArray<T>&); -template <typename T> OCTAVE_API MArray<T> operator * (const T&, const MArray<T>&); -template <typename T> OCTAVE_API MArray<T> operator / (const T&, const MArray<T>&); -template <typename T> OCTAVE_API MArray<T> operator + (const MArray<T>&, const MArray<T>&); -template <typename T> OCTAVE_API MArray<T> operator - (const MArray<T>&, const MArray<T>&); -template <typename T> OCTAVE_API MArray<T> quotient (const MArray<T>&, const MArray<T>&); -template <typename T> OCTAVE_API MArray<T> product (const MArray<T>&, const MArray<T>&); +template <typename T> OCTARRAY_API MArray<T>& operator += (MArray<T>&, const T&); +template <typename T> OCTARRAY_API MArray<T>& operator -= (MArray<T>&, const T&); +template <typename T> OCTARRAY_API MArray<T>& operator *= (MArray<T>&, const T&); +template <typename T> OCTARRAY_API MArray<T>& operator /= (MArray<T>&, const T&); +template <typename T> OCTARRAY_API MArray<T>& operator += (MArray<T>&, const MArray<T>&); +template <typename T> OCTARRAY_API MArray<T>& operator -= (MArray<T>&, const MArray<T>&); +template <typename T> OCTARRAY_API MArray<T>& product_eq (MArray<T>&, const MArray<T>&); +template <typename T> OCTARRAY_API MArray<T>& quotient_eq (MArray<T>&, const MArray<T>&); +template <typename T> OCTARRAY_API MArray<T> operator + (const MArray<T>&); +template <typename T> OCTARRAY_API MArray<T> operator - (const MArray<T>&); +template <typename T> OCTARRAY_API MArray<T> operator + (const MArray<T>&, const T&); +template <typename T> OCTARRAY_API MArray<T> operator - (const MArray<T>&, const T&); +template <typename T> OCTARRAY_API MArray<T> operator * (const MArray<T>&, const T&); +template <typename T> OCTARRAY_API MArray<T> operator / (const MArray<T>&, const T&); +template <typename T> OCTARRAY_API MArray<T> operator + (const T&, const MArray<T>&); +template <typename T> OCTARRAY_API MArray<T> operator - (const T&, const MArray<T>&); +template <typename T> OCTARRAY_API MArray<T> operator * (const T&, const MArray<T>&); +template <typename T> OCTARRAY_API MArray<T> operator / (const T&, const MArray<T>&); +template <typename T> OCTARRAY_API MArray<T> operator + (const MArray<T>&, const MArray<T>&); +template <typename T> OCTARRAY_API MArray<T> operator - (const MArray<T>&, const MArray<T>&); +template <typename T> OCTARRAY_API MArray<T> quotient (const MArray<T>&, const MArray<T>&); +template <typename T> OCTARRAY_API MArray<T> product (const MArray<T>&, const MArray<T>&); //! Template for N-dimensional array classes with like-type math operators. template <typename T> class -OCTAVE_API +OCTARRAY_API MArray : public Array<T> { public: @@ -106,22 +104,25 @@ //! Performs indexed accumulative addition. //@{ - OCTAVE_API void idx_add (const octave::idx_vector& idx, T val); - OCTAVE_API void + OCTARRAY_API void idx_add (const octave::idx_vector& idx, T val); + OCTARRAY_API void idx_add (const octave::idx_vector& idx, const MArray<T>& vals); //@} - OCTAVE_API void + OCTARRAY_API void idx_min (const octave::idx_vector& idx, const MArray<T>& vals); - OCTAVE_API void + OCTARRAY_API void idx_max (const octave::idx_vector& idx, const MArray<T>& vals); - OCTAVE_API void + OCTARRAY_API void idx_add_nd (const octave::idx_vector& idx, const MArray<T>& vals, int dim = -1); - OCTAVE_API void changesign (void); + OCTARRAY_API void changesign (void); + +private: + OCTARRAY_API static void instantiation_guard (); }; // Define all the MArray forwarding functions for return type R and
--- a/liboctave/array/Range.h Thu Dec 09 21:21:37 2021 -0800 +++ b/liboctave/array/Range.h Wed Dec 15 20:26:12 2021 -0500 @@ -35,13 +35,12 @@ #include "dim-vector.h" #include "lo-error.h" #include "oct-sort.h" +#include "range-fwd.h" namespace octave { template <typename T> - class - OCTAVE_API - range + class range { public:
--- a/liboctave/array/dNDArray.h Thu Dec 09 21:21:37 2021 -0800 +++ b/liboctave/array/dNDArray.h Wed Dec 15 20:26:12 2021 -0500 @@ -28,13 +28,12 @@ #include "octave-config.h" +#include "intNDArray-fwd.h" #include "MArray.h" #include "bsxfun-decl.h" #include "mx-defs.h" #include "mx-op-decl.h" -template <typename T> class intNDArray; - class OCTAVE_API NDArray : public MArray<double>
--- a/liboctave/array/fNDArray.h Thu Dec 09 21:21:37 2021 -0800 +++ b/liboctave/array/fNDArray.h Wed Dec 15 20:26:12 2021 -0500 @@ -28,13 +28,12 @@ #include "octave-config.h" +#include "intNDArray-fwd.h" #include "MArray.h" #include "bsxfun-decl.h" #include "mx-defs.h" #include "mx-op-decl.h" -template <typename T> class intNDArray; - class OCTAVE_API FloatNDArray : public MArray<float>
--- a/liboctave/array/idx-vector.h Thu Dec 09 21:21:37 2021 -0800 +++ b/liboctave/array/idx-vector.h Wed Dec 15 20:26:12 2021 -0500 @@ -40,11 +40,10 @@ #include "oct-inttypes.h" #include "oct-refcount.h" #include "Sparse-fwd.h" +#include "range-fwd.h" namespace octave { - template <typename T> class range; - // Design rationale: // // idx_vector is a reference-counting, polymorphic pointer, that can
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/liboctave/array/intNDArray-fwd.h Wed Dec 15 20:26:12 2021 -0500 @@ -0,0 +1,33 @@ +//////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2021 The Octave Project Developers +// +// See the file COPYRIGHT.md in the top-level directory of this +// distribution or <https://octave.org/copyright/>. +// +// This file is part of Octave. +// +// Octave is free software: you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Octave is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Octave; see the file COPYING. If not, see +// <https://www.gnu.org/licenses/>. +// +//////////////////////////////////////////////////////////////////////// + +#if ! defined (octave_intNDArray_fwd_h) +#define octave_intNDArray_fwd_h 1 + +#include "octave-config.h" + +template <typename T> class OCTAVE_API intNDArray; + +#endif
--- a/liboctave/array/intNDArray.h Thu Dec 09 21:21:37 2021 -0800 +++ b/liboctave/array/intNDArray.h Wed Dec 15 20:26:12 2021 -0500 @@ -28,6 +28,7 @@ #include "octave-config.h" +#include "intNDArray-fwd.h" #include "MArray.h" #include "boolNDArray.h" @@ -35,7 +36,6 @@ template <typename T> class -OCTAVE_API intNDArray : public MArray<T> { public:
--- a/liboctave/array/module.mk Thu Dec 09 21:21:37 2021 -0800 +++ b/liboctave/array/module.mk Wed Dec 15 20:26:12 2021 -0500 @@ -2,31 +2,41 @@ %reldir%/Array-fwd.h \ %reldir%/Array-util.h \ %reldir%/Array.h \ - %reldir%/boolMatrix.h \ - %reldir%/boolNDArray.h \ - %reldir%/boolSparse.h \ %reldir%/CColVector.h \ %reldir%/CDiagMatrix.h \ - %reldir%/chMatrix.h \ - %reldir%/chNDArray.h \ %reldir%/CMatrix.h \ %reldir%/CNDArray.h \ %reldir%/CRowVector.h \ %reldir%/CSparse.h \ + %reldir%/DiagArray2.h \ + %reldir%/MArray-fwd.h \ + %reldir%/MArray.h \ + %reldir%/MDiagArray2.h \ + %reldir%/MSparse.h \ + %reldir%/Matrix.h \ + %reldir%/MatrixType.h \ + %reldir%/PermMatrix.h \ + %reldir%/Range.h \ + %reldir%/Sparse-fwd.h \ + %reldir%/Sparse.h \ + %reldir%/boolMatrix.h \ + %reldir%/boolNDArray.h \ + %reldir%/boolSparse.h \ + %reldir%/chMatrix.h \ + %reldir%/chNDArray.h \ %reldir%/dColVector.h \ %reldir%/dDiagMatrix.h \ - %reldir%/DiagArray2.h \ - %reldir%/dim-vector.h \ %reldir%/dMatrix.h \ %reldir%/dNDArray.h \ %reldir%/dRowVector.h \ %reldir%/dSparse.h \ + %reldir%/dim-vector.h \ %reldir%/fCColVector.h \ %reldir%/fCDiagMatrix.h \ %reldir%/fCMatrix.h \ %reldir%/fCNDArray.h \ + %reldir%/fCRowVector.h \ %reldir%/fColVector.h \ - %reldir%/fCRowVector.h \ %reldir%/fDiagMatrix.h \ %reldir%/fMatrix.h \ %reldir%/fNDArray.h \ @@ -36,24 +46,17 @@ %reldir%/int32NDArray.h \ %reldir%/int64NDArray.h \ %reldir%/int8NDArray.h \ + %reldir%/intNDArray-fwd.h \ %reldir%/intNDArray.h \ - %reldir%/MArray.h \ - %reldir%/Matrix.h \ - %reldir%/MatrixType.h \ - %reldir%/MDiagArray2.h \ - %reldir%/MSparse.h \ - %reldir%/PermMatrix.h \ - %reldir%/Range.h \ - %reldir%/Sparse-fwd.h \ - %reldir%/Sparse.h \ + %reldir%/range-fwd.h \ %reldir%/uint16NDArray.h \ %reldir%/uint32NDArray.h \ %reldir%/uint64NDArray.h \ %reldir%/uint8NDArray.h ARRAY_SRC = \ + %reldir%/Array-C.cc \ %reldir%/Array-b.cc \ - %reldir%/Array-C.cc \ %reldir%/Array-ch.cc \ %reldir%/Array-d.cc \ %reldir%/Array-f.cc \ @@ -64,30 +67,44 @@ %reldir%/Array-str.cc \ %reldir%/Array-util.cc \ %reldir%/Array-voidp.cc \ - %reldir%/boolMatrix.cc \ - %reldir%/boolNDArray.cc \ - %reldir%/boolSparse.cc \ %reldir%/CColVector.cc \ %reldir%/CDiagMatrix.cc \ - %reldir%/chMatrix.cc \ - %reldir%/chNDArray.cc \ %reldir%/CMatrix.cc \ %reldir%/CNDArray.cc \ %reldir%/CRowVector.cc \ %reldir%/CSparse.cc \ + %reldir%/MArray-C.cc \ + %reldir%/MArray-d.cc \ + %reldir%/MArray-f.cc \ + %reldir%/MArray-fC.cc \ + %reldir%/MArray-i.cc \ + %reldir%/MArray-s.cc \ + %reldir%/MSparse-C.cc \ + %reldir%/MSparse-d.cc \ + %reldir%/MatrixType.cc \ + %reldir%/PermMatrix.cc \ + %reldir%/Range.cc \ + %reldir%/Sparse-C.cc \ + %reldir%/Sparse-b.cc \ + %reldir%/Sparse-d.cc \ + %reldir%/boolMatrix.cc \ + %reldir%/boolNDArray.cc \ + %reldir%/boolSparse.cc \ + %reldir%/chMatrix.cc \ + %reldir%/chNDArray.cc \ %reldir%/dColVector.cc \ %reldir%/dDiagMatrix.cc \ - %reldir%/dim-vector.cc \ %reldir%/dMatrix.cc \ %reldir%/dNDArray.cc \ %reldir%/dRowVector.cc \ %reldir%/dSparse.cc \ + %reldir%/dim-vector.cc \ %reldir%/fCColVector.cc \ %reldir%/fCDiagMatrix.cc \ %reldir%/fCMatrix.cc \ %reldir%/fCNDArray.cc \ + %reldir%/fCRowVector.cc \ %reldir%/fColVector.cc \ - %reldir%/fCRowVector.cc \ %reldir%/fDiagMatrix.cc \ %reldir%/fMatrix.cc \ %reldir%/fNDArray.cc \ @@ -97,20 +114,6 @@ %reldir%/int32NDArray.cc \ %reldir%/int64NDArray.cc \ %reldir%/int8NDArray.cc \ - %reldir%/MArray-C.cc \ - %reldir%/MArray-d.cc \ - %reldir%/MArray-f.cc \ - %reldir%/MArray-fC.cc \ - %reldir%/MArray-i.cc \ - %reldir%/MArray-s.cc \ - %reldir%/MatrixType.cc \ - %reldir%/MSparse-C.cc \ - %reldir%/MSparse-d.cc \ - %reldir%/PermMatrix.cc \ - %reldir%/Range.cc \ - %reldir%/Sparse-b.cc \ - %reldir%/Sparse-C.cc \ - %reldir%/Sparse-d.cc \ %reldir%/uint16NDArray.cc \ %reldir%/uint32NDArray.cc \ %reldir%/uint64NDArray.cc \ @@ -119,11 +122,11 @@ LIBOCTAVE_TEMPLATE_SRC += \ %reldir%/Array.cc \ %reldir%/DiagArray2.cc \ - %reldir%/intNDArray.cc \ %reldir%/MArray.cc \ %reldir%/MDiagArray2.cc \ %reldir%/MSparse.cc \ - %reldir%/Sparse.cc + %reldir%/Sparse.cc \ + %reldir%/intNDArray.cc noinst_LTLIBRARIES += %reldir%/libarray.la
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/liboctave/array/range-fwd.h Wed Dec 15 20:26:12 2021 -0500 @@ -0,0 +1,36 @@ +//////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2021 The Octave Project Developers +// +// See the file COPYRIGHT.md in the top-level directory of this +// distribution or <https://octave.org/copyright/>. +// +// This file is part of Octave. +// +// Octave is free software: you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Octave is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Octave; see the file COPYING. If not, see +// <https://www.gnu.org/licenses/>. +// +//////////////////////////////////////////////////////////////////////// + +#if ! defined (octave_range_fwd_h) +#define octave_range_fwd_h 1 + +#include "octave-config.h" + +namespace octave +{ + template <typename T> class OCTAVE_API range; +} + +#endif
--- a/liboctave/numeric/sparse-qr.h Thu Dec 09 21:21:37 2021 -0800 +++ b/liboctave/numeric/sparse-qr.h Wed Dec 15 20:26:12 2021 -0500 @@ -31,13 +31,13 @@ #include <memory> #include "oct-cmplx.h" +#include "MArray-fwd.h" class Matrix; class ComplexMatrix; class SparseMatrix; class SparseComplexMatrix; class ColumnVector; -template <typename T> class MArray; namespace octave {
--- a/liboctave/util/oct-inttypes.h Thu Dec 09 21:21:37 2021 -0800 +++ b/liboctave/util/oct-inttypes.h Wed Dec 15 20:26:12 2021 -0500 @@ -779,9 +779,7 @@ { }; template <typename T> -class -OCTAVE_API -octave_int : public octave_int_base<T> +class octave_int : public octave_int_base<T> { public:
--- a/m4/acinclude.m4 Thu Dec 09 21:21:37 2021 -0800 +++ b/m4/acinclude.m4 Wed Dec 15 20:26:12 2021 -0500 @@ -255,6 +255,51 @@ fi ]) dnl +dnl Check whether std::pmr::polymorphic_allocator is available. +dnl +AC_DEFUN([OCTAVE_CHECK_STD_PMR_POLYMORPHIC_ALLOCATOR], [ + AC_CACHE_CHECK([whether std::pmr::polymorphic_allocator is avalable], + [octave_cv_std_pmr_polymorphic_allocator], + [AC_LANG_PUSH(C++) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include <cstdlib> + #include <memory_resource> + #include <vector> + class mx_memory_resource : public std::pmr::memory_resource + { + private: + void * do_allocate (std::size_t bytes, size_t /*alignment*/) + { + void *ptr = std::malloc (bytes); + if (! ptr) + throw std::bad_alloc (); + return ptr; + } + void do_deallocate (void* ptr, std::size_t /*bytes*/, + std::size_t /*alignment*/) + { + std::free (ptr); + } + bool do_is_equal (const std::pmr::memory_resource& other) const noexcept + { + return this == dynamic_cast<const mx_memory_resource *> (&other); + return true; + } + }; + mx_memory_resource the_mx_memory_resource; + ]], [[ + std::pmr::vector<int> my_int_vec { &the_mx_memory_resource }; + ]])], + octave_cv_std_pmr_polymorphic_allocator=yes, + octave_cv_std_pmr_polymorphic_allocator=no) + AC_LANG_POP(C++) + ]) + if test $octave_cv_std_pmr_polymorphic_allocator = yes; then + AC_DEFINE(HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR, 1, + [Define to 1 if std::pmr::polymorphic_allocator is available.]) + fi +]) +dnl dnl Check whether CXSparse is version 2.2 or later dnl FIXME: This test uses a version number. It potentially could dnl be re-written to actually call a function, but is it worth it?