GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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