GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
Array.h
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1993-2024 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if ! defined (octave_Array_h)
27 #define octave_Array_h 1
28 
29 #include "octave-config.h"
30 
31 #include <cassert>
32 #include <cstddef>
33 
34 #include <algorithm>
35 #include <iosfwd>
36 #include <string>
37 
38 #include "Array-fwd.h"
39 #include "dim-vector.h"
40 #include "idx-vector.h"
41 #include "lo-error.h"
42 #include "lo-traits.h"
43 #include "lo-utils.h"
44 #include "oct-refcount.h"
45 #include "oct-sort.h"
46 #include "quit.h"
47 
48 //! N Dimensional Array with copy-on-write semantics.
49 //!
50 //! The Array class is at the root of Octave. It provides a container
51 //! with an arbitrary number of dimensions. The operator () provides
52 //! access to individual elements via subscript and linear indexing.
53 //! Indexing starts at 0. Arrays are column-major order as in Fortran.
54 //!
55 //! @code{.cc}
56 //! // 3 D Array with 10 rows, 20 columns, and 5 pages, filled with 7.0
57 //! Array<double> A (dim_vector (10, 20, 5), 7.0);
58 //!
59 //! // set value for row 0, column 10, and page 3
60 //! A(0, 10, 3) = 2.5;
61 //!
62 //! // get value for row 1, column 2, and page 0
63 //! double v = A(1, 2, 0);
64 //!
65 //! // get value for 25th element (row 4, column 3, page 1)
66 //! double v = A(24);
67 //! @endcode
68 //!
69 //! ## Notes on STL compatibility
70 //!
71 //! ### size() and length()
72 //!
73 //! To access the total number of elements in an Array, use numel()
74 //! which is short for number of elements and is equivalent to the
75 //! Octave function with same name.
76 //!
77 //! @code{.cc}
78 //! Array<int> A (dim_vector (10, 20, 4), 1);
79 //!
80 //! octave_idx_type n = A.numel (); // returns 800 (10x20x4)
81 //!
82 //! octave_idx_type nr = A.size (0); // returns 10 (number of rows/dimension 0)
83 //! octave_idx_type nc = A.size (1); // returns 20 (number of columns)
84 //! octave_idx_type nc = A.size (2); // returns 4 (size of dimension 3)
85 //! octave_idx_type l6 = A.size (6); // returns 1 (implicit singleton dimension)
86 //!
87 //! // Alternatively, get a dim_vector which represents the dimensions.
88 //! dim_vector dims = A.dims ();
89 //! @endcode
90 //!
91 //! The methods size() and length() as they exist in the STL cause
92 //! confusion in the context of a N dimensional array.
93 //!
94 //! The size() of an array is the length of all dimensions. In Octave,
95 //! the size() function returns a row vector with the length of each
96 //! dimension, or the size of a specific dimension. Only the latter is
97 //! present in liboctave.
98 //!
99 //! Since there is more than 1 dimension, length() would not make sense
100 //! without expliciting which dimension. If the function existed, which
101 //! length should it return? Octave length() function returns the length
102 //! of the longest dimension which is an odd definition, only useful for
103 //! vectors and square matrices. The alternatives numel(), rows(),
104 //! columns(), and size(d) are more explicit and recommended.
105 //!
106 //! ### size_type
107 //!
108 //! Array::size_type is 'octave_idx_type' which is a typedef for 'int'
109 //! or 'long int', depending whether Octave was configured for 64-bit
110 //! indexing.
111 //!
112 //! This is a signed integer which may cause problems when mixed with
113 //! STL containers. The reason is that Octave interacts with Fortran
114 //! routines, providing an interface many Fortran numeric libraries.
115 //!
116 //! ## Subclasses
117 //!
118 //! The following subclasses specializations, will be of most use:
119 //! - Matrix: Array<double> with only 2 dimensions
120 //! - ComplexMatrix: Array<std::complex<double>> with only 2 dimensions
121 //! - boolNDArray: N dimensional Array<bool>
122 //! - ColumnVector: Array<double> with 1 column
123 //! - string_vector: Array<std::string> with 1 column
124 //! - Cell: Array<octave_value>, equivalent to an Octave cell.
125 
126 template <typename T, typename Alloc>
127 class
128 OCTARRAY_TEMPLATE_API
129 Array
130 {
131 protected:
132 
133  //! The real representation of all arrays.
134  class ArrayRep : public Alloc
135  {
136  public:
137 
138  typedef std::allocator_traits<Alloc> Alloc_traits;
139 
140  typedef typename Alloc_traits::template rebind_traits<T> T_Alloc_traits;
141  typedef typename T_Alloc_traits::pointer pointer;
142 
145  octave::refcount<octave_idx_type> m_count;
146 
148  : Alloc (), m_data (allocate (len)), m_len (len), m_count (1)
149  {
150  std::copy_n (d, len, m_data);
151  }
152 
153  template <typename U>
155  : Alloc (), m_data (allocate (len)), m_len (len), m_count (1)
156  {
157  std::copy_n (d, len, m_data);
158  }
159 
160  // Use new instead of setting data to 0 so that fortran_vec and
161  // data always return valid addresses, even for zero-size arrays.
162 
164  : Alloc (), m_data (allocate (0)), m_len (0), m_count (1) { }
165 
167  : Alloc (), m_data (allocate (len)), m_len (len), m_count (1) { }
168 
169  explicit ArrayRep (octave_idx_type len, const T& val)
170  : Alloc (), m_data (allocate (len)), m_len (len), m_count (1)
171  {
172  std::fill_n (m_data, len, val);
173  }
174 
175  explicit ArrayRep (pointer ptr, const dim_vector& dv,
176  const Alloc& xallocator = Alloc ())
177  : Alloc (xallocator), m_data (ptr), m_len (dv.safe_numel ()), m_count (1)
178  { }
179 
180  // FIXME: Should the allocator be copied or created with the default?
181  ArrayRep (const ArrayRep& a)
182  : Alloc (), m_data (allocate (a.m_len)), m_len (a.m_len),
183  m_count (1)
184  {
185  std::copy_n (a.m_data, a.m_len, m_data);
186  }
187 
188  ~ArrayRep () { deallocate (m_data, m_len); }
189 
190  octave_idx_type numel () const { return m_len; }
191 
192  // No assignment!
193 
194  ArrayRep& operator = (const ArrayRep&) = delete;
195 
197  {
198  pointer data = Alloc_traits::allocate (*this, len);
199  for (size_t i = 0; i < len; i++)
200  T_Alloc_traits::construct (*this, data+i);
201  return data;
202  }
203 
204  void deallocate (pointer data, size_t len)
205  {
206  for (size_t i = 0; i < len; i++)
207  T_Alloc_traits::destroy (*this, data+i);
208  Alloc_traits::deallocate (*this, data, len);
209  }
210  };
211 
212  //--------------------------------------------------------------------
213 
214 public:
215 
216  OCTARRAY_OVERRIDABLE_FUNC_API void make_unique ()
217  {
218  if (m_rep->m_count > 1)
219  {
220  ArrayRep *r = new ArrayRep (m_slice_data, m_slice_len);
221 
222  if (--m_rep->m_count == 0)
223  delete m_rep;
224 
225  m_rep = r;
226  m_slice_data = m_rep->m_data;
227  }
228  }
229 
230  typedef T element_type;
231 
232  typedef T value_type;
233 
234  //! Used for operator(), and returned by numel() and size()
235  //! (beware: signed integer)
237 
238  typedef typename ref_param<T>::type crefT;
239 
240  typedef bool (*compare_fcn_type) (typename ref_param<T>::type,
241  typename ref_param<T>::type);
242 
243 protected:
244 
246 
248 
249  // Rationale:
250  // m_slice_data is a pointer to m_rep->m_data, denoting together with m_slice_len the
251  // actual portion of the data referenced by this Array<T> object. This
252  // allows to make shallow copies not only of a whole array, but also of
253  // contiguous subranges. Every time m_rep is directly manipulated, m_slice_data
254  // and m_slice_len need to be properly updated.
255 
258 
259  //! slice constructor
260  Array (const Array<T, Alloc>& a, const dim_vector& dv,
262  : m_dimensions (dv), m_rep(a.m_rep), m_slice_data (a.m_slice_data+l), m_slice_len (u-l)
263  {
264  m_rep->m_count++;
265  m_dimensions.chop_trailing_singletons ();
266  }
267 
268 private:
269 
270  static OCTARRAY_API typename Array<T, Alloc>::ArrayRep *nil_rep ();
271 
272 public:
273 
274  //! Empty ctor (0 by 0).
275  Array ()
276  : m_dimensions (), m_rep (nil_rep ()), m_slice_data (m_rep->m_data),
277  m_slice_len (m_rep->m_len)
278  {
279  m_rep->m_count++;
280  }
281 
282  //! nD uninitialized ctor.
283  explicit Array (const dim_vector& dv)
284  : m_dimensions (dv),
285  m_rep (new typename Array<T, Alloc>::ArrayRep (dv.safe_numel ())),
286  m_slice_data (m_rep->m_data), m_slice_len (m_rep->m_len)
287  {
288  m_dimensions.chop_trailing_singletons ();
289  }
290 
291  //! nD initialized ctor.
292  explicit Array (const dim_vector& dv, const T& val)
293  : m_dimensions (dv),
294  m_rep (new typename Array<T, Alloc>::ArrayRep (dv.safe_numel ())),
295  m_slice_data (m_rep->m_data), m_slice_len (m_rep->m_len)
296  {
297  fill (val);
298  m_dimensions.chop_trailing_singletons ();
299  }
300 
301  // Construct an Array from a pointer to an externally allocated array
302  // of values. PTR must be allocated with operator new. The Array
303  // object takes ownership of PTR and will delete it when the Array
304  // object is deleted. The dimension vector DV must be consistent with
305  // the size of the allocated PTR array.
306 
307  OCTARRAY_OVERRIDABLE_FUNC_API
308  explicit Array (T *ptr, const dim_vector& dv,
309  const Alloc& xallocator = Alloc ())
310  : m_dimensions (dv),
311  m_rep (new typename Array<T, Alloc>::ArrayRep (ptr, dv, xallocator)),
312  m_slice_data (m_rep->m_data), m_slice_len (m_rep->m_len)
313  {
314  m_dimensions.chop_trailing_singletons ();
315  }
316 
317  //! Reshape constructor.
318  OCTARRAY_API Array (const Array<T, Alloc>& a, const dim_vector& dv);
319 
320  //! Constructor from standard library sequence containers.
321  template<template <typename...> class Container>
322  Array (const Container<T>& a, const dim_vector& dv);
323 
324  //! Type conversion case.
325  template <typename U, typename A = Alloc>
326  Array (const Array<U, A>& a)
327  : m_dimensions (a.dims ()),
328  m_rep (new typename Array<T, Alloc>::ArrayRep (a.data (), a.numel ())),
329  m_slice_data (m_rep->m_data), m_slice_len (m_rep->m_len)
330  { }
331 
332  //! No type conversion case.
334  : m_dimensions (a.m_dimensions), m_rep (a.m_rep), m_slice_data (a.m_slice_data),
335  m_slice_len (a.m_slice_len)
336  {
337  m_rep->m_count++;
338  }
339 
341  : m_dimensions (std::move (a.m_dimensions)), m_rep (a.m_rep),
342  m_slice_data (a.m_slice_data), m_slice_len (a.m_slice_len)
343  {
344  a.m_rep = nullptr;
345  a.m_slice_data = nullptr;
346  a.m_slice_len = 0;
347  }
348 
349 public:
350 
351  virtual ~Array ()
352  {
353  // Because we define a move constructor and a move assignment
354  // operator, m_rep may be a nullptr here. We should only need to
355  // protect the move assignment operator in a similar way.
356 
357  if (m_rep && --m_rep->m_count == 0)
358  delete m_rep;
359  }
360 
361  Array<T, Alloc>& operator = (const Array<T, Alloc>& a)
362  {
363  if (this != &a)
364  {
365  if (--m_rep->m_count == 0)
366  delete m_rep;
367 
368  m_rep = a.m_rep;
369  m_rep->m_count++;
370 
371  m_dimensions = a.m_dimensions;
372  m_slice_data = a.m_slice_data;
373  m_slice_len = a.m_slice_len;
374  }
375 
376  return *this;
377  }
378 
380  {
381  if (this != &a)
382  {
383  m_dimensions = std::move (a.m_dimensions);
384 
385  // Because we define a move constructor and a move assignment
386  // operator, m_rep may be a nullptr here. We should only need to
387  // protect the destructor in a similar way.
388 
389  if (m_rep && --m_rep->m_count == 0)
390  delete m_rep;
391 
392  m_rep = a.m_rep;
393  m_slice_data = a.m_slice_data;
394  m_slice_len = a.m_slice_len;
395 
396  a.m_rep = nullptr;
397  a.m_slice_data = nullptr;
398  a.m_slice_len = 0;
399  }
400 
401  return *this;
402  }
403 
404  OCTARRAY_API void fill (const T& val);
405 
406  OCTARRAY_API void clear ();
407  OCTARRAY_API void clear (const dim_vector& dv);
408 
410  { clear (dim_vector (r, c)); }
411 
412  //! Number of elements in the array.
413  OCTARRAY_OVERRIDABLE_FUNC_API octave_idx_type
414  numel () const
415  { return m_slice_len; }
416  //@}
417 
418  //! Return the array as a column vector.
419  OCTARRAY_OVERRIDABLE_FUNC_API Array<T, Alloc>
420  as_column () const
421  {
422  Array<T, Alloc> retval (*this);
423  if (m_dimensions.ndims () != 2 || m_dimensions(1) != 1)
424  retval.m_dimensions = dim_vector (numel (), 1);
425 
426  return retval;
427  }
428 
429  //! Return the array as a row vector.
430  OCTARRAY_OVERRIDABLE_FUNC_API Array<T, Alloc>
431  as_row () const
432  {
433  Array<T, Alloc> retval (*this);
434  if (m_dimensions.ndims () != 2 || m_dimensions(0) != 1)
435  retval.m_dimensions = dim_vector (1, numel ());
436 
437  return retval;
438  }
439 
440  //! Return the array as a matrix.
441  OCTARRAY_OVERRIDABLE_FUNC_API Array<T, Alloc>
442  as_matrix () const
443  {
444  Array<T, Alloc> retval (*this);
445  if (m_dimensions.ndims () != 2)
446  retval.m_dimensions = m_dimensions.redim (2);
447 
448  return retval;
449  }
450 
451  //! @name First dimension
452  //!
453  //! Get the first dimension of the array (number of rows)
454  //@{
455  OCTARRAY_OVERRIDABLE_FUNC_API octave_idx_type
456  dim1 () const
457  { return m_dimensions(0); }
458  OCTARRAY_OVERRIDABLE_FUNC_API octave_idx_type
459  rows () const
460  { return dim1 (); }
461  //@}
462 
463  //! @name Second dimension
464  //!
465  //! Get the second dimension of the array (number of columns)
466  //@{
467  OCTARRAY_OVERRIDABLE_FUNC_API octave_idx_type dim2 () const
468  { return m_dimensions(1); }
469  OCTARRAY_OVERRIDABLE_FUNC_API octave_idx_type cols () const
470  { return dim2 (); }
471  OCTARRAY_OVERRIDABLE_FUNC_API octave_idx_type columns () const
472  { return dim2 (); }
473  //@}
474 
475  //! @name Third dimension
476  //!
477  //! Get the third dimension of the array (number of pages)
478  //@{
479  OCTARRAY_OVERRIDABLE_FUNC_API octave_idx_type dim3 () const
480  { return m_dimensions.ndims () >= 3 ? m_dimensions(2) : 1; }
481  OCTARRAY_OVERRIDABLE_FUNC_API octave_idx_type pages () const
482  { return dim3 (); }
483  //@}
484 
485  //! Size of the specified dimension.
486  //!
487  //! Dimensions beyond the Array number of dimensions return 1 as
488  //! those are implicit singleton dimensions.
489  //!
490  //! Equivalent to Octave's 'size (A, DIM)'
491 
492  OCTARRAY_OVERRIDABLE_FUNC_API size_type size (const size_type d) const
493  {
494  // Should we throw for negative values?
495  // Should >= ndims () be handled by dim_vector operator() instead ?
496  return d >= ndims () ? 1 : m_dimensions(d);
497  }
498 
499  OCTARRAY_OVERRIDABLE_FUNC_API std::size_t byte_size () const
500  { return static_cast<std::size_t> (numel ()) * sizeof (T); }
501 
502  //! Return a const-reference so that dims ()(i) works efficiently.
503  OCTARRAY_OVERRIDABLE_FUNC_API const dim_vector& dims () const
504  { return m_dimensions; }
505 
506  //! Chop off leading singleton dimensions
507  OCTARRAY_API Array<T, Alloc> squeeze () const;
508 
509  OCTARRAY_API octave_idx_type
511  OCTARRAY_API octave_idx_type
513  OCTARRAY_API octave_idx_type
515 
516  OCTARRAY_OVERRIDABLE_FUNC_API octave_idx_type
518  {
519  return m_dimensions.compute_index (ra_idx.data (), ra_idx.numel ());
520  }
521 
522  // No checking, even for multiple references, ever.
523 
524  OCTARRAY_OVERRIDABLE_FUNC_API T& xelem (octave_idx_type n)
525  { return m_slice_data[n]; }
526  OCTARRAY_OVERRIDABLE_FUNC_API crefT xelem (octave_idx_type n) const
527  { return m_slice_data[n]; }
528 
529  OCTARRAY_OVERRIDABLE_FUNC_API T&
531  { return xelem (dim1 ()*j+i); }
532  OCTARRAY_OVERRIDABLE_FUNC_API crefT
534  { return xelem (dim1 ()*j+i); }
535 
536  OCTARRAY_OVERRIDABLE_FUNC_API T&
538  { return xelem (i, dim2 ()*k+j); }
539  OCTARRAY_OVERRIDABLE_FUNC_API crefT
541  { return xelem (i, dim2 ()*k+j); }
542 
543  OCTARRAY_OVERRIDABLE_FUNC_API T&
545  { return xelem (compute_index_unchecked (ra_idx)); }
546 
547  OCTARRAY_OVERRIDABLE_FUNC_API crefT
549  { return xelem (compute_index_unchecked (ra_idx)); }
550 
551  // FIXME: would be nice to fix this so that we don't unnecessarily force
552  // a copy, but that is not so easy, and I see no clean way to do it.
553 
554  OCTARRAY_API T& checkelem (octave_idx_type n);
555 
556  OCTARRAY_API T& checkelem (octave_idx_type i, octave_idx_type j);
557 
558  OCTARRAY_API T& checkelem (octave_idx_type i, octave_idx_type j, octave_idx_type k);
559 
560  OCTARRAY_API T& checkelem (const Array<octave_idx_type>& ra_idx);
561 
562  OCTARRAY_OVERRIDABLE_FUNC_API T& elem (octave_idx_type n)
563  {
564  make_unique ();
565  return xelem (n);
566  }
567 
568  OCTARRAY_OVERRIDABLE_FUNC_API T& elem (octave_idx_type i, octave_idx_type j)
569  { return elem (dim1 ()*j+i); }
570 
571  OCTARRAY_OVERRIDABLE_FUNC_API T& elem (octave_idx_type i, octave_idx_type j, octave_idx_type k)
572  { return elem (i, dim2 ()*k+j); }
573 
574  OCTARRAY_OVERRIDABLE_FUNC_API T& elem (const Array<octave_idx_type>& ra_idx)
575  { return Array<T, Alloc>::elem (compute_index_unchecked (ra_idx)); }
576 
577  OCTARRAY_OVERRIDABLE_FUNC_API T& operator () (octave_idx_type n)
578  { return elem (n); }
579  OCTARRAY_OVERRIDABLE_FUNC_API T& operator () (octave_idx_type i, octave_idx_type j)
580  { return elem (i, j); }
581  OCTARRAY_OVERRIDABLE_FUNC_API T& operator () (octave_idx_type i, octave_idx_type j, octave_idx_type k)
582  { return elem (i, j, k); }
583  OCTARRAY_OVERRIDABLE_FUNC_API T& operator () (const Array<octave_idx_type>& ra_idx)
584  { return elem (ra_idx); }
585 
586  OCTARRAY_API crefT checkelem (octave_idx_type n) const;
587 
588  OCTARRAY_API crefT checkelem (octave_idx_type i, octave_idx_type j) const;
589 
590  OCTARRAY_API crefT checkelem (octave_idx_type i, octave_idx_type j,
591  octave_idx_type k) const;
592 
593  OCTARRAY_API crefT checkelem (const Array<octave_idx_type>& ra_idx) const;
594 
595  OCTARRAY_OVERRIDABLE_FUNC_API crefT elem (octave_idx_type n) const
596  { return xelem (n); }
597 
598  OCTARRAY_OVERRIDABLE_FUNC_API crefT
600  { return xelem (i, j); }
601 
602  OCTARRAY_OVERRIDABLE_FUNC_API crefT
604  { return xelem (i, j, k); }
605 
606  OCTARRAY_OVERRIDABLE_FUNC_API crefT
608  { return Array<T, Alloc>::xelem (compute_index_unchecked (ra_idx)); }
609 
610  OCTARRAY_OVERRIDABLE_FUNC_API crefT
611  operator () (octave_idx_type n) const { return elem (n); }
612  OCTARRAY_OVERRIDABLE_FUNC_API crefT
613  operator () (octave_idx_type i, octave_idx_type j) const
614  { return elem (i, j); }
615  OCTARRAY_OVERRIDABLE_FUNC_API crefT
616  operator () (octave_idx_type i, octave_idx_type j, octave_idx_type k) const
617  { return elem (i, j, k); }
618  OCTARRAY_OVERRIDABLE_FUNC_API crefT
619  operator () (const Array<octave_idx_type>& ra_idx) const
620  { return elem (ra_idx); }
621 
622  // Fast extractors. All of these produce shallow copies.
623 
624  //! Extract column: A(:,k+1).
625  OCTARRAY_API Array<T, Alloc> column (octave_idx_type k) const;
626  //! Extract page: A(:,:,k+1).
627  OCTARRAY_API Array<T, Alloc> page (octave_idx_type k) const;
628 
629  //! Extract a slice from this array as a column vector: A(:)(lo+1:up).
630  //! Must be 0 <= lo && up <= numel. May be up < lo.
631  OCTARRAY_API Array<T, Alloc>
632  linear_slice (octave_idx_type lo, octave_idx_type up) const;
633 
634  OCTARRAY_OVERRIDABLE_FUNC_API Array<T, Alloc>
636  { return Array<T, Alloc> (*this, dim_vector (nr, nc)); }
637 
638  OCTARRAY_OVERRIDABLE_FUNC_API Array<T, Alloc>
639  reshape (const dim_vector& new_dims) const
640  { return Array<T, Alloc> (*this, new_dims); }
641 
642  OCTARRAY_API Array<T, Alloc>
643  permute (const Array<octave_idx_type>& vec, bool inv = false) const;
644  OCTARRAY_OVERRIDABLE_FUNC_API Array<T, Alloc>
645  ipermute (const Array<octave_idx_type>& vec) const
646  { return permute (vec, true); }
647 
648  OCTARRAY_OVERRIDABLE_FUNC_API bool issquare () const
649  { return (dim1 () == dim2 ()); }
650 
651  OCTARRAY_OVERRIDABLE_FUNC_API bool isempty () const
652  { return numel () == 0; }
653 
654  OCTARRAY_OVERRIDABLE_FUNC_API bool isvector () const
655  { return m_dimensions.isvector (); }
656 
657  OCTARRAY_OVERRIDABLE_FUNC_API bool is_nd_vector () const
658  { return m_dimensions.is_nd_vector (); }
659 
660  OCTARRAY_API Array<T, Alloc> transpose () const;
661  OCTARRAY_API Array<T, Alloc> hermitian (T (*fcn) (const T&) = nullptr) const;
662 
663  OCTARRAY_OVERRIDABLE_FUNC_API const T * data () const
664  { return m_slice_data; }
665 
666  OCTARRAY_API T * fortran_vec ();
667 
668  OCTARRAY_OVERRIDABLE_FUNC_API bool is_shared () const
669  { return m_rep->m_count > 1; }
670 
671  OCTARRAY_OVERRIDABLE_FUNC_API int ndims () const
672  { return m_dimensions.ndims (); }
673 
674  //@{
675  //! Indexing without resizing.
676  OCTARRAY_API Array<T, Alloc> index (const octave::idx_vector& i) const;
677 
678  OCTARRAY_API Array<T, Alloc> index (const octave::idx_vector& i, const octave::idx_vector& j) const;
679 
680  OCTARRAY_API Array<T, Alloc> index (const Array<octave::idx_vector>& ia) const;
681  //@}
682 
683  virtual OCTARRAY_API T resize_fill_value () const;
684 
685  //@{
686  //! Resizing (with fill).
687  OCTARRAY_API void resize2 (octave_idx_type nr, octave_idx_type nc, const T& rfv);
688  OCTARRAY_OVERRIDABLE_FUNC_API void resize2 (octave_idx_type nr, octave_idx_type nc)
689  {
690  resize2 (nr, nc, resize_fill_value ());
691  }
692 
693  OCTARRAY_API void resize1 (octave_idx_type n, const T& rfv);
694  OCTARRAY_OVERRIDABLE_FUNC_API void resize1 (octave_idx_type n)
695  { resize1 (n, resize_fill_value ()); }
696 
697  OCTARRAY_API void resize (const dim_vector& dv, const T& rfv);
698  OCTARRAY_OVERRIDABLE_FUNC_API void resize (const dim_vector& dv)
699  { resize (dv, resize_fill_value ()); }
700  //@}
701 
702  //@{
703  //! Indexing with possible resizing and fill
704 
705  // FIXME: this is really a corner case, that should better be
706  // handled directly in liboctinterp.
707 
708  OCTARRAY_API Array<T, Alloc>
709  index (const octave::idx_vector& i, bool resize_ok, const T& rfv) const;
710  OCTARRAY_OVERRIDABLE_FUNC_API Array<T, Alloc>
711  index (const octave::idx_vector& i, bool resize_ok) const
712  {
713  return index (i, resize_ok, resize_fill_value ());
714  }
715 
716  OCTARRAY_API Array<T, Alloc>
717  index (const octave::idx_vector& i, const octave::idx_vector& j,
718  bool resize_ok, const T& rfv) const;
719  OCTARRAY_OVERRIDABLE_FUNC_API Array<T, Alloc>
721  bool resize_ok) const
722  {
723  return index (i, j, resize_ok, resize_fill_value ());
724  }
725 
726  OCTARRAY_API Array<T, Alloc>
727  index (const Array<octave::idx_vector>& ia, bool resize_ok,
728  const T& rfv) const;
729  OCTARRAY_OVERRIDABLE_FUNC_API Array<T, Alloc>
730  index (const Array<octave::idx_vector>& ia, bool resize_ok) const
731  {
732  return index (ia, resize_ok, resize_fill_value ());
733  }
734  //@}
735 
736  //@{
737  //! Indexed assignment (always with resize & fill).
738  OCTARRAY_API void
739  assign (const octave::idx_vector& i, const Array<T, Alloc>& rhs, const T& rfv);
740  OCTARRAY_OVERRIDABLE_FUNC_API void
742  {
743  assign (i, rhs, resize_fill_value ());
744  }
745 
746  OCTARRAY_API void
747  assign (const octave::idx_vector& i, const octave::idx_vector& j,
748  const Array<T, Alloc>& rhs, const T& rfv);
749  OCTARRAY_OVERRIDABLE_FUNC_API void
751  const Array<T, Alloc>& rhs)
752  {
753  assign (i, j, rhs, resize_fill_value ());
754  }
755 
756  OCTARRAY_API void
757  assign (const Array<octave::idx_vector>& ia, const Array<T, Alloc>& rhs, const T& rfv);
758  OCTARRAY_OVERRIDABLE_FUNC_API void
760  {
761  assign (ia, rhs, resize_fill_value ());
762  }
763  //@}
764 
765  //@{
766  //! Deleting elements.
767 
768  //! A(I) = [] (with a single subscript)
769  OCTARRAY_API void delete_elements (const octave::idx_vector& i);
770 
771  //! A(:,...,I,...,:) = [] (>= 2 subscripts, one of them is non-colon)
772  OCTARRAY_API void delete_elements (int dim, const octave::idx_vector& i);
773 
774  //! Dispatcher to the above two.
775  OCTARRAY_API void delete_elements (const Array<octave::idx_vector>& ia);
776  //@}
777 
778  //! Insert an array into another at a specified position. If
779  //! size (a) is [d1 d2 ... dN] and idx is [i1 i2 ... iN], this
780  //! method is equivalent to x(i1:i1+d1-1, i2:i2+d2-1, ... ,
781  //! iN:iN+dN-1) = a.
782  OCTARRAY_API Array<T, Alloc>&
783  insert (const Array<T, Alloc>& a, const Array<octave_idx_type>& idx);
784 
785  //! This is just a special case for idx = [r c 0 ...]
786  OCTARRAY_API Array<T, Alloc>&
787  insert (const Array<T, Alloc>& a, octave_idx_type r, octave_idx_type c);
788 
789  OCTARRAY_OVERRIDABLE_FUNC_API void maybe_economize ()
790  {
791  if (m_rep->m_count == 1 && m_slice_len != m_rep->m_len)
792  {
793  ArrayRep *new_rep = new ArrayRep (m_slice_data, m_slice_len);
794  delete m_rep;
795  m_rep = new_rep;
796  m_slice_data = m_rep->m_data;
797  }
798  }
799 
800  OCTARRAY_API void print_info (std::ostream& os, const std::string& prefix) const;
801 
802  OCTARRAY_API Array<T, Alloc> sort (int dim = 0, sortmode mode = ASCENDING) const;
803  OCTARRAY_API Array<T, Alloc> sort (Array<octave_idx_type>& sidx, int dim = 0,
804  sortmode mode = ASCENDING) const;
805 
806  //! Ordering is auto-detected or can be specified.
807  OCTARRAY_API sortmode issorted (sortmode mode = UNSORTED) const;
808 
809  //! Sort by rows returns only indices.
810  OCTARRAY_API Array<octave_idx_type> sort_rows_idx (sortmode mode = ASCENDING) const;
811 
812  //! Ordering is auto-detected or can be specified.
813  OCTARRAY_API sortmode is_sorted_rows (sortmode mode = UNSORTED) const;
814 
815  //! Do a binary lookup in a sorted array. Must not contain NaNs.
816  //! Mode can be specified or is auto-detected by comparing 1st and last element.
817  OCTARRAY_API octave_idx_type lookup (const T& value, sortmode mode = UNSORTED) const;
818 
819  //! Ditto, but for an array of values, specializing on the case when values
820  //! are sorted. NaNs get the value N.
821  OCTARRAY_API Array<octave_idx_type> lookup (const Array<T, Alloc>& values,
822  sortmode mode = UNSORTED) const;
823 
824  //! Count nonzero elements.
825  OCTARRAY_API octave_idx_type nnz () const;
826 
827  //! Find indices of (at most n) nonzero elements. If n is specified,
828  //! backward specifies search from backward.
829  OCTARRAY_API Array<octave_idx_type> find (octave_idx_type n = -1,
830  bool backward = false) const;
831 
832  //! Returns the n-th element in increasing order, using the same
833  //! ordering as used for sort. n can either be a scalar index or a
834  //! contiguous range.
835  OCTARRAY_API Array<T, Alloc> nth_element (const octave::idx_vector& n, int dim = 0) const;
836 
837  //! Get the kth super or subdiagonal. The zeroth diagonal is the
838  //! ordinary diagonal.
839  OCTARRAY_API Array<T, Alloc> diag (octave_idx_type k = 0) const;
840 
841  OCTARRAY_API Array<T, Alloc> diag (octave_idx_type m, octave_idx_type n) const;
842 
843  //! Concatenation along a specified (0-based) dimension, equivalent
844  //! to cat(). dim = -1 corresponds to dim = 0 and dim = -2
845  //! corresponds to dim = 1, but apply the looser matching rules of
846  //! vertcat/horzcat.
847  static OCTARRAY_API Array<T, Alloc>
848  cat (int dim, octave_idx_type n, const Array<T, Alloc> *array_list);
849 
850  //! Apply function fcn to each element of the Array<T, Alloc>. This function
851  //! is optimized with a manually unrolled loop.
852 #if defined (OCTAVE_HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR)
853  template <typename U, typename F,
854  typename A = std::pmr::polymorphic_allocator<U>>
855 #else
856  template <typename U, typename F, typename A = std::allocator<U>>
857 #endif
859  map (F fcn) const
860  {
862 
863  const T *m = data ();
864 
865  Array<U, A> result (dims ());
866  U *p = result.fortran_vec ();
867 
868  octave_idx_type i;
869  for (i = 0; i < len - 3; i += 4)
870  {
871  octave_quit ();
872 
873  p[i] = fcn (m[i]);
874  p[i+1] = fcn (m[i+1]);
875  p[i+2] = fcn (m[i+2]);
876  p[i+3] = fcn (m[i+3]);
877  }
878 
879  octave_quit ();
880 
881  for (; i < len; i++)
882  p[i] = fcn (m[i]);
883 
884  return result;
885  }
886 
887  //@{
888  //! Overloads for function references.
889 #if defined (OCTAVE_HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR)
890  template <typename U, typename A = std::pmr::polymorphic_allocator<U>>
891 #else
892  template <typename U, typename A = std::allocator<U>>
893 #endif
895  map (U (&fcn) (T)) const
896  { return map<U, U (&) (T), A> (fcn); }
897 
898 #if defined (OCTAVE_HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR)
899  template <typename U, typename A = std::pmr::polymorphic_allocator<U>>
900 #else
901  template <typename U, typename A = std::allocator<U>>
902 #endif
904  map (U (&fcn) (const T&)) const
905  { return map<U, U (&) (const T&), A> (fcn); }
906  //@}
907 
908  //! Generic any/all test functionality with arbitrary predicate.
909  template <typename F, bool zero>
910  bool test (F fcn) const
911  {
912  return octave::any_all_test<F, T, zero> (fcn, data (), numel ());
913  }
914 
915  //@{
916  //! Simpler calls.
917  template <typename F>
918  bool test_any (F fcn) const
919  { return test<F, false> (fcn); }
920 
921  template <typename F>
922  bool test_all (F fcn) const
923  { return test<F, true> (fcn); }
924  //@}
925 
926  //@{
927  //! Overloads for function references.
928  bool test_any (bool (&fcn) (T)) const
929  { return test<bool (&) (T), false> (fcn); }
930 
931  bool test_any (bool (&fcn) (const T&)) const
932  { return test<bool (&) (const T&), false> (fcn); }
933 
934  bool test_all (bool (&fcn) (T)) const
935  { return test<bool (&) (T), true> (fcn); }
936 
937  bool test_all (bool (&fcn) (const T&)) const
938  { return test<bool (&) (const T&), true> (fcn); }
939  //@}
940 
941  template <typename U, typename A> friend class Array;
942 
943  //! Returns true if this->dims () == dv, and if so, replaces this->m_dimensions
944  //! by a shallow copy of dv. This is useful for maintaining several arrays
945  //! with supposedly equal dimensions (e.g. structs in the interpreter).
946  OCTARRAY_API bool optimize_dimensions (const dim_vector& dv);
947 
948 private:
949  OCTARRAY_API static void instantiation_guard ();
950 };
951 
952 // We use a variadic template for template template parameter so that
953 // we don't have to specify all the template parameters and limit this
954 // to Container<T>. http://stackoverflow.com/a/20499809/1609556
955 template<typename T, typename Alloc>
956 template<template <typename...> class Container>
957 Array<T, Alloc>::Array (const Container<T>& a, const dim_vector& dv)
958  : m_dimensions (dv), m_rep (new typename Array<T, Alloc>::ArrayRep (dv.safe_numel ())),
959  m_slice_data (m_rep->m_data), m_slice_len (m_rep->m_len)
960 {
961  if (m_dimensions.safe_numel () != octave_idx_type (a.size ()))
962  {
963  std::string new_dims_str = m_dimensions.str ();
964 
965  (*current_liboctave_error_handler)
966  ("reshape: can't reshape %zi elements into %s array",
967  a.size (), new_dims_str.c_str ());
968  }
969 
970  octave_idx_type i = 0;
971  for (const T& x : a)
972  m_slice_data[i++] = x;
973 
975 }
976 
977 template <typename T, typename Alloc>
978 OCTARRAY_API std::ostream&
979 operator << (std::ostream& os, const Array<T, Alloc>& a);
980 
981 #endif
octave_idx_type compute_index(octave_idx_type n, const dim_vector &dims)
Definition: Array-util.cc:177
std::ostream & operator<<(std::ostream &os, const Array< T, Alloc > &a)
Definition: Array-base.cc:2792
octave_idx_type lookup(const T *x, octave_idx_type n, T y)
The real representation of all arrays.
Definition: Array.h:135
T_Alloc_traits::pointer pointer
Definition: Array.h:141
pointer allocate(size_t len)
Definition: Array.h:196
ArrayRep(U *d, octave_idx_type len)
Definition: Array.h:154
ArrayRep(pointer d, octave_idx_type len)
Definition: Array.h:147
octave_idx_type m_len
Definition: Array.h:144
octave::refcount< octave_idx_type > m_count
Definition: Array.h:145
ArrayRep(octave_idx_type len)
Definition: Array.h:166
octave_idx_type numel() const
Definition: Array.h:190
ArrayRep(octave_idx_type len, const T &val)
Definition: Array.h:169
ArrayRep(pointer ptr, const dim_vector &dv, const Alloc &xallocator=Alloc())
Definition: Array.h:175
std::allocator_traits< Alloc > Alloc_traits
Definition: Array.h:138
ArrayRep(const ArrayRep &a)
Definition: Array.h:181
pointer m_data
Definition: Array.h:143
void deallocate(pointer data, size_t len)
Definition: Array.h:204
Alloc_traits::template rebind_traits< T > T_Alloc_traits
Definition: Array.h:140
N Dimensional Array with copy-on-write semantics.
Definition: Array.h:130
T & elem(octave_idx_type n)
Size of the specified dimension.
Definition: Array.h:562
bool test_all(bool(&fcn)(const T &)) const
Size of the specified dimension.
Definition: Array.h:937
T * fortran_vec()
Size of the specified dimension.
Definition: Array-base.cc:1764
void resize2(octave_idx_type nr, octave_idx_type nc)
Size of the specified dimension.
Definition: Array.h:688
crefT xelem(octave_idx_type n) const
Size of the specified dimension.
Definition: Array.h:526
size_type size(const size_type d) const
Size of the specified dimension.
Definition: Array.h:492
friend class Array
Size of the specified dimension.
Definition: Array.h:941
Array< T, Alloc > reshape(const dim_vector &new_dims) const
Size of the specified dimension.
Definition: Array.h:639
crefT xelem(octave_idx_type i, octave_idx_type j) const
Size of the specified dimension.
Definition: Array.h:533
octave_idx_type size_type
Used for operator(), and returned by numel() and size() (beware: signed integer)
Definition: Array.h:236
std::size_t byte_size() const
Size of the specified dimension.
Definition: Array.h:499
void resize(const dim_vector &dv)
Size of the specified dimension.
Definition: Array.h:698
crefT elem(octave_idx_type n) const
Size of the specified dimension.
Definition: Array.h:595
bool test_all(bool(&fcn)(T)) const
Size of the specified dimension.
Definition: Array.h:934
void maybe_economize()
Size of the specified dimension.
Definition: Array.h:789
Array(T *ptr, const dim_vector &dv, const Alloc &xallocator=Alloc())
Definition: Array.h:308
octave_idx_type pages() const
Size of the specified dimension.
Definition: Array.h:481
bool test_all(F fcn) const
Size of the specified dimension.
Definition: Array.h:922
octave_idx_type dim3() const
Size of the specified dimension.
Definition: Array.h:479
bool issquare() const
Size of the specified dimension.
Definition: Array.h:648
Array(const Array< U, A > &a)
Type conversion case.
Definition: Array.h:326
octave_idx_type compute_index_unchecked(const Array< octave_idx_type > &ra_idx) const
Size of the specified dimension.
Definition: Array.h:517
Array< T, Alloc > as_column() const
Return the array as a column vector.
Definition: Array.h:420
Array< T, Alloc > as_matrix() const
Return the array as a matrix.
Definition: Array.h:442
void resize1(octave_idx_type n)
Size of the specified dimension.
Definition: Array.h:694
Array< T, Alloc > as_row() const
Return the array as a row vector.
Definition: Array.h:431
T & xelem(octave_idx_type i, octave_idx_type j, octave_idx_type k)
Size of the specified dimension.
Definition: Array.h:537
Array< T, Alloc > index(const octave::idx_vector &i, bool resize_ok) const
Size of the specified dimension.
Definition: Array.h:711
bool isvector() const
Size of the specified dimension.
Definition: Array.h:654
int ndims() const
Size of the specified dimension.
Definition: Array.h:671
octave_idx_type m_slice_len
Definition: Array.h:257
ref_param< T >::type crefT
Definition: Array.h:238
crefT elem(octave_idx_type i, octave_idx_type j) const
Size of the specified dimension.
Definition: Array.h:599
T & xelem(const Array< octave_idx_type > &ra_idx)
Size of the specified dimension.
Definition: Array.h:544
crefT xelem(octave_idx_type i, octave_idx_type j, octave_idx_type k) const
Size of the specified dimension.
Definition: Array.h:540
Array< T, Alloc > ipermute(const Array< octave_idx_type > &vec) const
Size of the specified dimension.
Definition: Array.h:645
Array< U, A > map(U(&fcn)(T)) const
Overloads for function references.
Definition: Array.h:895
bool optimize_dimensions(const dim_vector &dv)
Returns true if this->dims () == dv, and if so, replaces this->m_dimensions by a shallow copy of dv.
Definition: Array-base.cc:2764
void clear(octave_idx_type r, octave_idx_type c)
Definition: Array.h:409
Array(const dim_vector &dv, const T &val)
nD initialized ctor.
Definition: Array.h:292
octave_idx_type rows() const
Definition: Array.h:459
Array(const dim_vector &dv)
nD uninitialized ctor.
Definition: Array.h:283
T * m_slice_data
Definition: Array.h:256
bool test_any(F fcn) const
Simpler calls.
Definition: Array.h:918
const T * data() const
Size of the specified dimension.
Definition: Array.h:663
void assign(const octave::idx_vector &i, const Array< T, Alloc > &rhs)
Size of the specified dimension.
Definition: Array.h:741
void assign(const Array< octave::idx_vector > &ia, const Array< T, Alloc > &rhs)
Size of the specified dimension.
Definition: Array.h:759
octave_idx_type dim2() const
Definition: Array.h:467
void assign(const octave::idx_vector &i, const octave::idx_vector &j, const Array< T, Alloc > &rhs)
Size of the specified dimension.
Definition: Array.h:750
bool is_nd_vector() const
Size of the specified dimension.
Definition: Array.h:657
octave_idx_type columns() const
Definition: Array.h:471
Array(Array< T, Alloc > &&a)
Definition: Array.h:340
octave_idx_type dim1() const
Definition: Array.h:456
octave_idx_type cols() const
Definition: Array.h:469
void make_unique()
Definition: Array.h:216
dim_vector m_dimensions
Definition: Array.h:245
Array(const Array< T, Alloc > &a, const dim_vector &dv, octave_idx_type l, octave_idx_type u)
slice constructor
Definition: Array.h:260
bool test_any(bool(&fcn)(const T &)) const
Size of the specified dimension.
Definition: Array.h:931
Array< T, Alloc > index(const octave::idx_vector &i, const octave::idx_vector &j, bool resize_ok) const
Size of the specified dimension.
Definition: Array.h:720
bool isempty() const
Size of the specified dimension.
Definition: Array.h:651
T element_type
Definition: Array.h:230
T & xelem(octave_idx_type i, octave_idx_type j)
Size of the specified dimension.
Definition: Array.h:530
bool is_shared() const
Size of the specified dimension.
Definition: Array.h:668
bool test(F fcn) const
Generic any/all test functionality with arbitrary predicate.
Definition: Array.h:910
Array(const Container< T > &a, const dim_vector &dv)
Constructor from standard library sequence containers.
Definition: Array.h:957
const dim_vector & dims() const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:503
T & xelem(octave_idx_type n)
Size of the specified dimension.
Definition: Array.h:524
Array< U, A > map(F fcn) const
Apply function fcn to each element of the Array<T, Alloc>.
Definition: Array.h:859
Array< T, Alloc > reshape(octave_idx_type nr, octave_idx_type nc) const
Size of the specified dimension.
Definition: Array.h:635
crefT elem(octave_idx_type i, octave_idx_type j, octave_idx_type k) const
Size of the specified dimension.
Definition: Array.h:603
Array< U, A > map(U(&fcn)(const T &)) const
Size of the specified dimension.
Definition: Array.h:904
T value_type
Definition: Array.h:232
Array< T, Alloc > index(const Array< octave::idx_vector > &ia, bool resize_ok) const
Size of the specified dimension.
Definition: Array.h:730
crefT elem(const Array< octave_idx_type > &ra_idx) const
Size of the specified dimension.
Definition: Array.h:607
Array< T, Alloc >::ArrayRep * m_rep
Definition: Array.h:247
T & elem(octave_idx_type i, octave_idx_type j, octave_idx_type k)
Size of the specified dimension.
Definition: Array.h:571
T & elem(octave_idx_type i, octave_idx_type j)
Size of the specified dimension.
Definition: Array.h:568
bool test_any(bool(&fcn)(T)) const
Overloads for function references.
Definition: Array.h:928
T & elem(const Array< octave_idx_type > &ra_idx)
Size of the specified dimension.
Definition: Array.h:574
crefT xelem(const Array< octave_idx_type > &ra_idx) const
Size of the specified dimension.
Definition: Array.h:548
virtual ~Array()
Definition: Array.h:351
Array(const Array< T, Alloc > &a)
No type conversion case.
Definition: Array.h:333
octave_idx_type numel() const
Number of elements in the array.
Definition: Array.h:414
Array()
Empty ctor (0 by 0).
Definition: Array.h:275
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
octave_idx_type compute_index(const octave_idx_type *idx) const
Linear index from an index tuple.
Definition: dim-vector.h:456
octave_idx_type safe_numel() const
The following function will throw a std::bad_alloc () exception if the requested size is larger than ...
Definition: dim-vector.cc:98
std::string str(char sep='x') const
Definition: dim-vector.cc:68
void chop_trailing_singletons()
Definition: dim-vector.h:164
bool is_nd_vector() const
Definition: dim-vector.h:400
octave_idx_type ndims() const
Number of dimensions.
Definition: dim-vector.h:257
bool isvector() const
Definition: dim-vector.h:395
dim_vector redim(int n) const
Force certain dimensionality, preserving numel ().
Definition: dim-vector.cc:226
virtual octave_idx_type numel() const
Definition: ov-base.h:391
if_then_else< is_class_type< T >::no, T, T const & >::result type
Definition: lo-traits.h:121
octave::idx_vector idx_vector
Definition: idx-vector.h:1022
F77_RET_T const F77_INT F77_CMPLX * A
F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE * d
F77_RET_T const F77_DBLE * x
T octave_idx_type m
Definition: mx-inlines.cc:781
octave_idx_type n
Definition: mx-inlines.cc:761
T * r
Definition: mx-inlines.cc:781
sortmode
Definition: oct-sort.h:97
@ UNSORTED
Definition: oct-sort.h:97
@ ASCENDING
Definition: oct-sort.h:97
T::size_type numel(const T &str)
Definition: oct-string.cc:74
const octave_base_value const Array< octave_idx_type > & ra_idx
F77_RET_T len
Definition: xerbla.cc:61