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