# HG changeset patch # User John W. Eaton # Date 1633116351 14400 # Node ID b00ff462e0f291bca599b4c8607080a001075dc9 # Parent f3ffb4596bd86d583358129735bff443b9b4b6d8 improve efficiency of mxArray -> octave_value conversion * Array.h (Array::ArrayRep, Array::Array): New constructor that accepts externally allocated data array. * Sparse.h (Sparse::SparseRep, Sparse::Sparse): New constructor that accepts externally allocated data and index arrays. * mex.cc (maybe_disown_ptr): New function. (mxArray_interleaved_full::fp_to_ov): Use new Array constructor to pass allocated data from mxArray object to Array object without copying data. Call maybe_disown_ptr on data pointer to give up ownership. (mxArray_interleaved_sparse::to_ov): Use new Array constructor to pass allocated data from mxArray object to Array object without copying data. Call maybe_disown_ptr on data pointer to give up ownership. (mxArray_separate_full::to_ov): New template. (mxArray_separate_flll::as_octave_value): Use it. diff -r f3ffb4596bd8 -r b00ff462e0f2 libinterp/corefcn/mex.cc --- a/libinterp/corefcn/mex.cc Wed Sep 29 16:43:08 2021 -0400 +++ b/libinterp/corefcn/mex.cc Fri Oct 01 15:25:51 2021 -0400 @@ -352,6 +352,8 @@ static inline void * maybe_mark_foreign (void *ptr); +static inline void maybe_disown_ptr (void *ptr); + #define VOID_MUTATION_METHOD(FCN_NAME, ARG_LIST) \ void FCN_NAME ARG_LIST { request_mutation (); } @@ -1995,10 +1997,12 @@ switch (get_class_id ()) { case mxDOUBLE_CLASS: - return fp_to_ov (dv); + return (is_complex () + ? fp_to_ov (dv) : fp_to_ov (dv)); case mxSINGLE_CLASS: - return fp_to_ov (dv); + return (is_complex () + ? fp_to_ov (dv) : fp_to_ov (dv)); case mxCHAR_CLASS: return int_to_ov (dv); @@ -2051,36 +2055,13 @@ octave_value fp_to_ov (const dim_vector& dv) const { - if (is_complex ()) - { - std::complex *ppr = static_cast *> (m_pr); - - Array> val (dv); - - std::complex *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 - { - ELT_T *ppr = static_cast (m_pr); - - Array 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); - } + ELT_T *ppr = static_cast (m_pr); + + Array val (ppr, dv); + + maybe_disown_ptr (m_pr); + + return octave_value (val); } template @@ -2092,6 +2073,11 @@ ELT_T *ppr = static_cast (m_pr); +#if 0 + ARRAY_T val (ppr, dv); + + maybe_disown_ptr (m_pr); +#else ARRAY_T val (dv); ARRAY_ELT_T *ptr = val.fortran_vec (); @@ -2100,6 +2086,7 @@ for (mwIndex i = 0; i < nel; i++) ptr[i] = ppr[i]; +#endif return octave_value (val); } @@ -2307,42 +2294,10 @@ switch (get_class_id ()) { case mxDOUBLE_CLASS: - { - mwSize nel = get_number_of_elements (); - - double *ppr = static_cast (m_pr); - - ComplexNDArray val (dv); - - Complex *ptr = val.fortran_vec (); - - double *ppi = static_cast (m_pi); - - for (mwIndex i = 0; i < nel; i++) - ptr[i] = Complex (ppr[i], ppi[i]); - - retval = val; - } - break; + return to_ov (dv); case mxSINGLE_CLASS: - { - mwSize nel = get_number_of_elements (); - - float *ppr = static_cast (m_pr); - - FloatComplexNDArray val (dv); - - FloatComplex *ptr = val.fortran_vec (); - - float *ppi = static_cast (m_pi); - - for (mwIndex i = 0; i < nel; i++) - ptr[i] = FloatComplex (ppr[i], ppi[i]); - - retval = val; - } - break; + return to_ov (dv); case mxLOGICAL_CLASS: case mxINT8_CLASS: @@ -2376,6 +2331,26 @@ private: + template + octave_value + to_ov (const dim_vector& dv) const + { + mwSize nel = get_number_of_elements (); + + T *ppr = static_cast (m_pr); + + Array> val (dv); + + std::complex *ptr = val.fortran_vec (); + + T *ppi = static_cast (m_pi); + + for (mwIndex i = 0; i < nel; i++) + ptr[i] = std::complex (ppr[i], ppi[i]); + + return octave_value (val); + } + // Pointer to the imaginary part of the data. void *m_pi; }; @@ -2481,16 +2456,18 @@ { octave_value retval; + dim_vector dv = dims_to_dim_vector (); + switch (get_class_id ()) { case mxDOUBLE_CLASS: - return is_complex () ? to_ov (): to_ov (); + return is_complex () ? to_ov (dv): to_ov (dv); case mxSINGLE_CLASS: error ("single precision sparse data type not supported"); case mxLOGICAL_CLASS: - return to_ov (); + return to_ov (dv); default: panic_impossible (); @@ -2503,21 +2480,16 @@ template octave_value - to_ov (void) const + to_ov (const dim_vector& dv) const { ELT_T *ppr = static_cast (m_pr); - Sparse val (get_m (), get_n (), - static_cast (m_nzmax)); - - for (mwIndex i = 0; i < m_nzmax; i++) - { - val.xdata (i) = ppr[i]; - val.xridx (i) = m_ir[i]; - } - - for (mwIndex i = 0; i < get_n () + 1; i++) - val.xcidx (i) = m_jc[i]; + Sparse val (dv, static_cast (m_nzmax), + ppr, m_ir, m_jc); + + maybe_disown_ptr (m_pr); + maybe_disown_ptr (m_ir); + maybe_disown_ptr (m_jc); return octave_value (val); } @@ -2641,6 +2613,8 @@ octave_value retval; + dim_vector dv = dims_to_dim_vector (); + switch (get_class_id ()) { case mxDOUBLE_CLASS: @@ -3604,6 +3578,17 @@ return ptr; } +static inline void +maybe_disown_ptr (void *ptr) +{ + if (mex_context) + { + mex_context->unmark (ptr); + mex_context->global_unmark (ptr); + mex_context->mark_foreign (ptr); + } +} + static inline mxArray * maybe_unmark_array (mxArray *ptr) { diff -r f3ffb4596bd8 -r b00ff462e0f2 liboctave/array/Array.h --- a/liboctave/array/Array.h Wed Sep 29 16:43:08 2021 -0400 +++ b/liboctave/array/Array.h Fri Oct 01 15:25:51 2021 -0400 @@ -167,6 +167,10 @@ std::fill_n (m_data, n, val); } + explicit ArrayRep (T *ptr, const dim_vector& dv) + : m_data (ptr), m_len (dv.safe_numel ()), m_count (1) + { } + ArrayRep (const ArrayRep& a) : m_data (new T [a.m_len]), m_len (a.m_len), m_count (1) { @@ -271,6 +275,20 @@ m_dimensions.chop_trailing_singletons (); } + // Construct an Array from a pointer to an externally allocated array + // of values. PTR must be allocated with operator new. The Array + // object takes ownership of PTR and will delete it when the Array + // 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) + : m_dimensions (dv), + m_rep (new typename Array::ArrayRep (ptr, dv)), + 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); diff -r f3ffb4596bd8 -r b00ff462e0f2 liboctave/array/Sparse.h --- a/liboctave/array/Sparse.h Wed Sep 29 16:43:08 2021 -0400 +++ b/liboctave/array/Sparse.h Fri Oct 01 15:25:51 2021 -0400 @@ -113,6 +113,13 @@ std::copy_n (c, nc + 1, m_cidx); } + template + SparseRep (const dim_vector& dv, octave_idx_type nz, + U *d, octave_idx_type *r, octave_idx_type *c) + : m_data (d), m_ridx (r), m_cidx (c), + m_nzmax (nz), m_nrows (dv(0)), m_ncols (dv(1)), m_count (1) + { } + SparseRep (const SparseRep& a) : m_data (new T [a.m_nzmax]), m_ridx (new octave_idx_type [a.m_nzmax]), m_cidx (new octave_idx_type [a.m_ncols + 1]), @@ -218,6 +225,19 @@ : m_rep (new typename Sparse::SparseRep (nr, nc, nz)), m_dimensions (dim_vector (nr, nc)) { } + // Construct a Sparse array from pointers to externally allocated + // arrays of values and indices. PTR, RIDX, and CIDX must be + // allocated with operator new. The Sparse object takes ownership of + // these arrays and will delete them when the Sparse object is + // deleted. The dimension vector DV must be consistent with the sizes + // of the allocated PTR, CIDX, and RIDX arrays. + + Sparse (const dim_vector& dv, octave_idx_type nz, + T *ptr, octave_idx_type *ridx, octave_idx_type *cidx) + : m_rep (new typename Sparse::SparseRep (dv, nz, ptr, ridx, cidx)), + m_dimensions (dv) + { } + // Both SparseMatrix and SparseBoolMatrix need this ctor, and this // is their only common ancestor. explicit OCTAVE_API Sparse (const PermMatrix& a);