GNU Octave 7.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-2022 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 Array<double (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
126template <typename T, typename Alloc>
127class
128Array
129{
130protected:
131
132 //! The real representation of all arrays.
133 class ArrayRep : public Alloc
134 {
135 public:
136
137 typedef std::allocator_traits<Alloc> Alloc_traits;
138
139 typedef typename Alloc_traits::template rebind_traits<T> T_Alloc_traits;
140 typedef typename T_Alloc_traits::pointer pointer;
141
145
147 : Alloc (), m_data (allocate (len)), m_len (len), m_count (1)
148 {
149 std::copy_n (d, len, m_data);
150 }
151
152 template <typename U>
154 : Alloc (), m_data (allocate (len)), m_len (len), m_count (1)
155 {
156 std::copy_n (d, len, m_data);
157 }
158
159 // Use new instead of setting data to 0 so that fortran_vec and
160 // data always return valid addresses, even for zero-size arrays.
161
162 ArrayRep (void)
163 : Alloc (), m_data (allocate (0)), m_len (0), m_count (1) { }
164
166 : Alloc (), m_data (allocate (len)), m_len (len), m_count (1) { }
167
168 explicit ArrayRep (octave_idx_type len, const T& val)
169 : Alloc (), m_data (allocate (len)), m_len (len), m_count (1)
170 {
171 std::fill_n (m_data, len, val);
172 }
173
174 explicit ArrayRep (pointer ptr, const dim_vector& dv,
175 const Alloc& xallocator = Alloc ())
176 : Alloc (xallocator), m_data (ptr), m_len (dv.safe_numel ()), m_count (1)
177 { }
178
179 // FIXME: Should the allocator be copied or created with the default?
181 : Alloc (), m_data (allocate (a.m_len)), m_len (a.m_len),
182 m_count (1)
183 {
184 std::copy_n (a.m_data, a.m_len, m_data);
185 }
186
187 ~ArrayRep (void) { deallocate (m_data, m_len); }
188
189 octave_idx_type numel (void) const { return m_len; }
190
191 // No assignment!
192
193 ArrayRep& operator = (const ArrayRep&) = delete;
194
196 {
197 pointer data = Alloc_traits::allocate (*this, len);
198 for (size_t i = 0; i < len; i++)
199 T_Alloc_traits::construct (*this, data+i);
200 return data;
201 }
202
203 void deallocate (pointer data, size_t len)
204 {
205 for (size_t i = 0; i < len; i++)
206 T_Alloc_traits::destroy (*this, data+i);
207 Alloc_traits::deallocate (*this, data, len);
208 }
209 };
210
211 //--------------------------------------------------------------------
212
213public:
214
215 void make_unique (void)
216 {
217 if (m_rep->m_count > 1)
218 {
219 ArrayRep *r = new ArrayRep (m_slice_data, m_slice_len);
220
221 if (--m_rep->m_count == 0)
222 delete m_rep;
223
224 m_rep = r;
225 m_slice_data = m_rep->m_data;
226 }
227 }
228
229 typedef T element_type;
230
231 typedef T value_type;
232
233 //! Used for operator(), and returned by numel() and size()
234 //! (beware: signed integer)
236
237 typedef typename ref_param<T>::type crefT;
238
239 typedef bool (*compare_fcn_type) (typename ref_param<T>::type,
240 typename ref_param<T>::type);
241
242protected:
243
245
247
248 // Rationale:
249 // m_slice_data is a pointer to m_rep->m_data, denoting together with m_slice_len the
250 // actual portion of the data referenced by this Array<T> object. This
251 // allows to make shallow copies not only of a whole array, but also of
252 // contiguous subranges. Every time m_rep is directly manipulated, m_slice_data
253 // and m_slice_len need to be properly updated.
254
257
258 //! slice constructor
259 Array (const Array<T, Alloc>& a, const dim_vector& dv,
261 : m_dimensions (dv), m_rep(a.m_rep), m_slice_data (a.m_slice_data+l), m_slice_len (u-l)
262 {
263 m_rep->m_count++;
264 m_dimensions.chop_trailing_singletons ();
265 }
266
267private:
268
269 static OCTARRAY_API typename Array<T, Alloc>::ArrayRep *nil_rep (void);
270
271public:
272
273 //! Empty ctor (0 by 0).
274 Array (void)
275 : m_dimensions (), m_rep (nil_rep ()), m_slice_data (m_rep->m_data),
276 m_slice_len (m_rep->m_len)
277 {
278 m_rep->m_count++;
279 }
280
281 //! nD uninitialized ctor.
282 explicit Array (const dim_vector& dv)
283 : m_dimensions (dv),
284 m_rep (new typename Array<T, Alloc>::ArrayRep (dv.safe_numel ())),
285 m_slice_data (m_rep->m_data), m_slice_len (m_rep->m_len)
286 {
287 m_dimensions.chop_trailing_singletons ();
288 }
289
290 //! nD initialized ctor.
291 explicit Array (const dim_vector& dv, const T& val)
292 : m_dimensions (dv),
293 m_rep (new typename Array<T, Alloc>::ArrayRep (dv.safe_numel ())),
294 m_slice_data (m_rep->m_data), m_slice_len (m_rep->m_len)
295 {
296 fill (val);
297 m_dimensions.chop_trailing_singletons ();
298 }
299
300 // Construct an Array from a pointer to an externally allocated array
301 // of values. PTR must be allocated with operator new. The Array
302 // object takes ownership of PTR and will delete it when the Array
303 // object is deleted. The dimension vector DV must be consistent with
304 // the size of the allocated PTR array.
305
306 explicit Array (T *ptr, const dim_vector& dv,
307 const Alloc& xallocator = Alloc ())
308 : m_dimensions (dv),
309 m_rep (new typename Array<T, Alloc>::ArrayRep (ptr, dv, xallocator)),
310 m_slice_data (m_rep->m_data), m_slice_len (m_rep->m_len)
311 {
312 m_dimensions.chop_trailing_singletons ();
313 }
314
315 //! Reshape constructor.
316 OCTARRAY_API Array (const Array<T, Alloc>& a, const dim_vector& dv);
317
318 //! Constructor from standard library sequence containers.
319 template<template <typename...> class Container>
320 Array (const Container<T>& a, const dim_vector& dv);
321
322 //! Type conversion case.
323 template <typename U, typename A = Alloc>
325 : m_dimensions (a.dims ()),
326 m_rep (new typename Array<T, Alloc>::ArrayRep (a.data (), a.numel ())),
327 m_slice_data (m_rep->m_data), m_slice_len (m_rep->m_len)
328 { }
329
330 //! No type conversion case.
332 : m_dimensions (a.m_dimensions), m_rep (a.m_rep), m_slice_data (a.m_slice_data),
333 m_slice_len (a.m_slice_len)
334 {
335 m_rep->m_count++;
336 }
337
339 : m_dimensions (std::move (a.m_dimensions)), m_rep (a.m_rep),
340 m_slice_data (a.m_slice_data), m_slice_len (a.m_slice_len)
341 {
342 a.m_rep = nullptr;
343 a.m_slice_data = nullptr;
344 a.m_slice_len = 0;
345 }
346
347public:
348
349 virtual ~Array (void)
350 {
351 // Because we define a move constructor and a move assignment
352 // operator, m_rep may be a nullptr here. We should only need to
353 // protect the move assignment operator in a similar way.
354
355 if (m_rep && --m_rep->m_count == 0)
356 delete m_rep;
357 }
358
359 Array<T, Alloc>& operator = (const Array<T, Alloc>& a)
360 {
361 if (this != &a)
362 {
363 if (--m_rep->m_count == 0)
364 delete m_rep;
365
366 m_rep = a.m_rep;
367 m_rep->m_count++;
368
369 m_dimensions = a.m_dimensions;
370 m_slice_data = a.m_slice_data;
371 m_slice_len = a.m_slice_len;
372 }
373
374 return *this;
375 }
376
378 {
379 if (this != &a)
380 {
381 m_dimensions = std::move (a.m_dimensions);
382
383 // Because we define a move constructor and a move assignment
384 // operator, m_rep may be a nullptr here. We should only need to
385 // protect the destructor in a similar way.
386
387 if (m_rep && --m_rep->m_count == 0)
388 delete m_rep;
389
390 m_rep = a.m_rep;
391 m_slice_data = a.m_slice_data;
392 m_slice_len = a.m_slice_len;
393
394 a.m_rep = nullptr;
395 a.m_slice_data = nullptr;
396 a.m_slice_len = 0;
397 }
398
399 return *this;
400 }
401
402 OCTARRAY_API void fill (const T& val);
403
404 OCTARRAY_API void clear (void);
405 OCTARRAY_API void clear (const dim_vector& dv);
406
408 { clear (dim_vector (r, c)); }
409
410 //! Number of elements in the array.
411 octave_idx_type numel (void) const { return m_slice_len; }
412 //@}
413
414 //! Return the array as a column vector.
416 {
417 Array<T, Alloc> retval (*this);
418 if (m_dimensions.ndims () != 2 || m_dimensions(1) != 1)
419 retval.m_dimensions = dim_vector (numel (), 1);
420
421 return retval;
422 }
423
424 //! Return the array as a row vector.
426 {
427 Array<T, Alloc> retval (*this);
428 if (m_dimensions.ndims () != 2 || m_dimensions(0) != 1)
429 retval.m_dimensions = dim_vector (1, numel ());
430
431 return retval;
432 }
433
434 //! Return the array as a matrix.
436 {
437 Array<T, Alloc> retval (*this);
438 if (m_dimensions.ndims () != 2)
439 retval.m_dimensions = m_dimensions.redim (2);
440
441 return retval;
442 }
443
444 //! @name First dimension
445 //!
446 //! Get the first dimension of the array (number of rows)
447 //@{
448 octave_idx_type dim1 (void) const { return m_dimensions(0); }
449 octave_idx_type rows (void) const { return dim1 (); }
450 //@}
451
452 //! @name Second dimension
453 //!
454 //! Get the second dimension of the array (number of columns)
455 //@{
456 octave_idx_type dim2 (void) const { return m_dimensions(1); }
457 octave_idx_type cols (void) const { return dim2 (); }
458 octave_idx_type columns (void) const { return dim2 (); }
459 //@}
460
461 //! @name Third dimension
462 //!
463 //! Get the third dimension of the array (number of pages)
464 //@{
465 octave_idx_type dim3 (void) const { return m_dimensions(2); }
466 octave_idx_type pages (void) const { return dim3 (); }
467 //@}
468
469 //! Size of the specified dimension.
470 //!
471 //! Dimensions beyond the Array number of dimensions return 1 as
472 //! those are implicit singleton dimensions.
473 //!
474 //! Equivalent to Octave's 'size (A, DIM)'
475
476 size_type size (const size_type d) const
477 {
478 // Should we throw for negative values?
479 // Should >= ndims () be handled by dim_vector operator() instead ?
480 return d >= ndims () ? 1 : m_dimensions(d);
481 }
482
483 std::size_t byte_size (void) const
484 { return static_cast<std::size_t> (numel ()) * sizeof (T); }
485
486 //! Return a const-reference so that dims ()(i) works efficiently.
487 const dim_vector& dims (void) const { return m_dimensions; }
488
489 //! Chop off leading singleton dimensions
490 OCTARRAY_API Array<T, Alloc> squeeze (void) const;
491
494 octave_idx_type k) const;
496
498 {
499 return m_dimensions.compute_index (ra_idx.data (), ra_idx.numel ());
500 }
501
502 // No checking, even for multiple references, ever.
503
504 T& xelem (octave_idx_type n) { return m_slice_data[n]; }
505 crefT xelem (octave_idx_type n) const { return m_slice_data[n]; }
506
508 { return xelem (dim1 ()*j+i); }
510 { return xelem (dim1 ()*j+i); }
511
513 { return xelem (i, dim2 ()*k+j); }
515 { return xelem (i, dim2 ()*k+j); }
516
518 { return xelem (compute_index_unchecked (ra_idx)); }
519
521 { return xelem (compute_index_unchecked (ra_idx)); }
522
523 // FIXME: would be nice to fix this so that we don't unnecessarily force
524 // a copy, but that is not so easy, and I see no clean way to do it.
525
526 OCTARRAY_API T& checkelem (octave_idx_type n);
527
528 OCTARRAY_API T& checkelem (octave_idx_type i, octave_idx_type j);
529
530 OCTARRAY_API T& checkelem (octave_idx_type i, octave_idx_type j, octave_idx_type k);
531
532 OCTARRAY_API T& checkelem (const Array<octave_idx_type>& ra_idx);
533
535 {
536 make_unique ();
537 return xelem (n);
538 }
539
540 T& elem (octave_idx_type i, octave_idx_type j) { return elem (dim1 ()*j+i); }
541
543 { return elem (i, dim2 ()*k+j); }
544
546 { return Array<T, Alloc>::elem (compute_index_unchecked (ra_idx)); }
547
548 T& operator () (octave_idx_type n) { return elem (n); }
549 T& operator () (octave_idx_type i, octave_idx_type j) { return elem (i, j); }
551 { return elem (i, j, k); }
552 T& operator () (const Array<octave_idx_type>& ra_idx)
553 { return elem (ra_idx); }
554
555 OCTARRAY_API crefT checkelem (octave_idx_type n) const;
556
557 OCTARRAY_API crefT checkelem (octave_idx_type i, octave_idx_type j) const;
558
559 OCTARRAY_API crefT checkelem (octave_idx_type i, octave_idx_type j,
560 octave_idx_type k) const;
561
562 OCTARRAY_API crefT checkelem (const Array<octave_idx_type>& ra_idx) const;
563
564 crefT elem (octave_idx_type n) const { return xelem (n); }
565
567 { return xelem (i, j); }
568
570 { return xelem (i, j, k); }
571
573 { return Array<T, Alloc>::xelem (compute_index_unchecked (ra_idx)); }
574
575 crefT operator () (octave_idx_type n) const { return elem (n); }
576 crefT operator () (octave_idx_type i, octave_idx_type j) const
577 { return elem (i, j); }
579 octave_idx_type k) const
580 { return elem (i, j, k); }
581 crefT operator () (const Array<octave_idx_type>& ra_idx) const
582 { return elem (ra_idx); }
583
584 // Fast extractors. All of these produce shallow copies.
585
586 //! Extract column: A(:,k+1).
587 OCTARRAY_API Array<T, Alloc> column (octave_idx_type k) const;
588 //! Extract page: A(:,:,k+1).
589 OCTARRAY_API Array<T, Alloc> page (octave_idx_type k) const;
590
591 //! Extract a slice from this array as a column vector: A(:)(lo+1:up).
592 //! Must be 0 <= lo && up <= numel. May be up < lo.
593 OCTARRAY_API Array<T, Alloc> linear_slice (octave_idx_type lo, octave_idx_type up) const;
594
596 { return Array<T, Alloc> (*this, dim_vector (nr, nc)); }
597
598 Array<T, Alloc> reshape (const dim_vector& new_dims) const
599 { return Array<T, Alloc> (*this, new_dims); }
600
601 OCTARRAY_API Array<T, Alloc> permute (const Array<octave_idx_type>& vec, bool inv = false) const;
603 { return permute (vec, true); }
604
605 bool issquare (void) const { return (dim1 () == dim2 ()); }
606
607 bool isempty (void) const { return numel () == 0; }
608
609 bool isvector (void) const { return m_dimensions.isvector (); }
610
611 bool is_nd_vector (void) const { return m_dimensions.is_nd_vector (); }
612
613 OCTARRAY_API Array<T, Alloc> transpose (void) const;
614 OCTARRAY_API Array<T, Alloc> hermitian (T (*fcn) (const T&) = nullptr) const;
615
616 const T * data (void) const { return m_slice_data; }
617
618#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
619 OCTAVE_DEPRECATED (7, "for read-only access, use 'data' method instead")
620 const T * fortran_vec (void) const { return data (); }
621#endif
622
623 OCTARRAY_API T * fortran_vec (void);
624
625 bool is_shared (void) { return m_rep->m_count > 1; }
626
627 int ndims (void) const { return m_dimensions.ndims (); }
628
629 //@{
630 //! Indexing without resizing.
631 OCTARRAY_API Array<T, Alloc> index (const octave::idx_vector& i) const;
632
633 OCTARRAY_API Array<T, Alloc> index (const octave::idx_vector& i, const octave::idx_vector& j) const;
634
635 OCTARRAY_API Array<T, Alloc> index (const Array<octave::idx_vector>& ia) const;
636 //@}
637
638 virtual OCTARRAY_API T resize_fill_value (void) const;
639
640 //@{
641 //! Resizing (with fill).
642 OCTARRAY_API void resize2 (octave_idx_type nr, octave_idx_type nc, const T& rfv);
644 {
645 resize2 (nr, nc, resize_fill_value ());
646 }
647
648 OCTARRAY_API void resize1 (octave_idx_type n, const T& rfv);
649 void resize1 (octave_idx_type n) { resize1 (n, resize_fill_value ()); }
650
651 OCTARRAY_API void resize (const dim_vector& dv, const T& rfv);
652 void resize (const dim_vector& dv) { resize (dv, resize_fill_value ()); }
653 //@}
654
655 //@{
656 //! Indexing with possible resizing and fill
657
658 // FIXME: this is really a corner case, that should better be
659 // handled directly in liboctinterp.
660
661 OCTARRAY_API Array<T, Alloc> index (const octave::idx_vector& i, bool resize_ok, const T& rfv) const;
662 Array<T, Alloc> index (const octave::idx_vector& i, bool resize_ok) const
663 {
664 return index (i, resize_ok, resize_fill_value ());
665 }
666
667 OCTARRAY_API Array<T, Alloc> index (const octave::idx_vector& i, const octave::idx_vector& j,
668 bool resize_ok,
669 const T& rfv) const;
671 bool resize_ok) const
672 {
673 return index (i, j, resize_ok, resize_fill_value ());
674 }
675
676 OCTARRAY_API Array<T, Alloc> index (const Array<octave::idx_vector>& ia, bool resize_ok,
677 const T& rfv) const;
678 Array<T, Alloc> index (const Array<octave::idx_vector>& ia, bool resize_ok) const
679 {
680 return index (ia, resize_ok, resize_fill_value ());
681 }
682 //@}
683
684 //@{
685 //! Indexed assignment (always with resize & fill).
686 OCTARRAY_API void assign (const octave::idx_vector& i, const Array<T, Alloc>& rhs, const T& rfv);
687 void assign (const octave::idx_vector& i, const Array<T, Alloc>& rhs)
688 {
689 assign (i, rhs, resize_fill_value ());
690 }
691
692 OCTARRAY_API void assign (const octave::idx_vector& i, const octave::idx_vector& j,
693 const Array<T, Alloc>& rhs,
694 const T& rfv);
695 void assign (const octave::idx_vector& i, const octave::idx_vector& j, const Array<T, Alloc>& rhs)
696 {
697 assign (i, j, rhs, resize_fill_value ());
698 }
699
700 OCTARRAY_API void assign (const Array<octave::idx_vector>& ia, const Array<T, Alloc>& rhs, const T& rfv);
702 {
703 assign (ia, rhs, resize_fill_value ());
704 }
705 //@}
706
707 //@{
708 //! Deleting elements.
709
710 //! A(I) = [] (with a single subscript)
711 OCTARRAY_API void delete_elements (const octave::idx_vector& i);
712
713 //! A(:,...,I,...,:) = [] (>= 2 subscripts, one of them is non-colon)
714 OCTARRAY_API void delete_elements (int dim, const octave::idx_vector& i);
715
716 //! Dispatcher to the above two.
717 OCTARRAY_API void delete_elements (const Array<octave::idx_vector>& ia);
718 //@}
719
720 //! Insert an array into another at a specified position. If
721 //! size (a) is [d1 d2 ... dN] and idx is [i1 i2 ... iN], this
722 //! method is equivalent to x(i1:i1+d1-1, i2:i2+d2-1, ... ,
723 //! iN:iN+dN-1) = a.
724 OCTARRAY_API Array<T, Alloc>& insert (const Array<T, Alloc>& a, const Array<octave_idx_type>& idx);
725
726 //! This is just a special case for idx = [r c 0 ...]
727 OCTARRAY_API Array<T, Alloc>& insert (const Array<T, Alloc>& a, octave_idx_type r, octave_idx_type c);
728
729 void maybe_economize (void)
730 {
731 if (m_rep->m_count == 1 && m_slice_len != m_rep->m_len)
732 {
733 ArrayRep *new_rep = new ArrayRep (m_slice_data, m_slice_len);
734 delete m_rep;
735 m_rep = new_rep;
736 m_slice_data = m_rep->m_data;
737 }
738 }
739
740 OCTARRAY_API void print_info (std::ostream& os, const std::string& prefix) const;
741
742 OCTARRAY_API Array<T, Alloc> sort (int dim = 0, sortmode mode = ASCENDING) const;
743 OCTARRAY_API Array<T, Alloc> sort (Array<octave_idx_type>& sidx, int dim = 0,
744 sortmode mode = ASCENDING) const;
745
746 //! Ordering is auto-detected or can be specified.
747 OCTARRAY_API sortmode issorted (sortmode mode = UNSORTED) const;
748
749 //! Sort by rows returns only indices.
750 OCTARRAY_API Array<octave_idx_type> sort_rows_idx (sortmode mode = ASCENDING) const;
751
752 //! Ordering is auto-detected or can be specified.
753 OCTARRAY_API sortmode is_sorted_rows (sortmode mode = UNSORTED) const;
754
755 //! Do a binary lookup in a sorted array. Must not contain NaNs.
756 //! Mode can be specified or is auto-detected by comparing 1st and last element.
757 OCTARRAY_API octave_idx_type lookup (const T& value, sortmode mode = UNSORTED) const;
758
759 //! Ditto, but for an array of values, specializing on the case when values
760 //! are sorted. NaNs get the value N.
761 OCTARRAY_API Array<octave_idx_type> lookup (const Array<T, Alloc>& values,
762 sortmode mode = UNSORTED) const;
763
764 //! Count nonzero elements.
765 OCTARRAY_API octave_idx_type nnz (void) const;
766
767 //! Find indices of (at most n) nonzero elements. If n is specified,
768 //! backward specifies search from backward.
769 OCTARRAY_API Array<octave_idx_type> find (octave_idx_type n = -1,
770 bool backward = false) const;
771
772 //! Returns the n-th element in increasing order, using the same
773 //! ordering as used for sort. n can either be a scalar index or a
774 //! contiguous range.
775 OCTARRAY_API Array<T, Alloc> nth_element (const octave::idx_vector& n, int dim = 0) const;
776
777 //! Get the kth super or subdiagonal. The zeroth diagonal is the
778 //! ordinary diagonal.
779 OCTARRAY_API Array<T, Alloc> diag (octave_idx_type k = 0) const;
780
781 OCTARRAY_API Array<T, Alloc> diag (octave_idx_type m, octave_idx_type n) const;
782
783 //! Concatenation along a specified (0-based) dimension, equivalent
784 //! to cat(). dim = -1 corresponds to dim = 0 and dim = -2
785 //! corresponds to dim = 1, but apply the looser matching rules of
786 //! vertcat/horzcat.
787 static OCTARRAY_API Array<T, Alloc>
788 cat (int dim, octave_idx_type n, const Array<T, Alloc> *array_list);
789
790 //! Apply function fcn to each element of the Array<T, Alloc>. This function
791 //! is optimized with a manually unrolled loop.
792#if defined (OCTAVE_HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR)
793 template <typename U, typename F,
794 typename A = std::pmr::polymorphic_allocator<U>>
795#else
796 template <typename U, typename F, typename A = std::allocator<U>>
797#endif
799 map (F fcn) const
800 {
802
803 const T *m = data ();
804
805 Array<U, A> result (dims ());
806 U *p = result.fortran_vec ();
807
809 for (i = 0; i < len - 3; i += 4)
810 {
811 octave_quit ();
812
813 p[i] = fcn (m[i]);
814 p[i+1] = fcn (m[i+1]);
815 p[i+2] = fcn (m[i+2]);
816 p[i+3] = fcn (m[i+3]);
817 }
818
819 octave_quit ();
820
821 for (; i < len; i++)
822 p[i] = fcn (m[i]);
823
824 return result;
825 }
826
827 //@{
828 //! Overloads for function references.
829#if defined (OCTAVE_HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR)
830 template <typename U, typename A = std::pmr::polymorphic_allocator<U>>
831#else
832 template <typename U, typename A = std::allocator<U>>
833#endif
835 map (U (&fcn) (T)) const
836 { return map<U, U (&) (T), A> (fcn); }
837
838#if defined (OCTAVE_HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR)
839 template <typename U, typename A = std::pmr::polymorphic_allocator<U>>
840#else
841 template <typename U, typename A = std::allocator<U>>
842#endif
844 map (U (&fcn) (const T&)) const
845 { return map<U, U (&) (const T&), A> (fcn); }
846 //@}
847
848 //! Generic any/all test functionality with arbitrary predicate.
849 template <typename F, bool zero>
850 bool test (F fcn) const
851 {
852 return octave::any_all_test<F, T, zero> (fcn, data (), numel ());
853 }
854
855 //@{
856 //! Simpler calls.
857 template <typename F>
858 bool test_any (F fcn) const
859 { return test<F, false> (fcn); }
860
861 template <typename F>
862 bool test_all (F fcn) const
863 { return test<F, true> (fcn); }
864 //@}
865
866 //@{
867 //! Overloads for function references.
868 bool test_any (bool (&fcn) (T)) const
869 { return test<bool (&) (T), false> (fcn); }
870
871 bool test_any (bool (&fcn) (const T&)) const
872 { return test<bool (&) (const T&), false> (fcn); }
873
874 bool test_all (bool (&fcn) (T)) const
875 { return test<bool (&) (T), true> (fcn); }
876
877 bool test_all (bool (&fcn) (const T&)) const
878 { return test<bool (&) (const T&), true> (fcn); }
879 //@}
880
881 template <typename U, typename A> friend class Array;
882
883 //! Returns true if this->dims () == dv, and if so, replaces this->m_dimensions
884 //! by a shallow copy of dv. This is useful for maintaining several arrays
885 //! with supposedly equal dimensions (e.g. structs in the interpreter).
886 OCTARRAY_API bool optimize_dimensions (const dim_vector& dv);
887
888private:
889 OCTARRAY_API static void instantiation_guard ();
890};
891
892// We use a variadic template for template template parameter so that
893// we don't have to specify all the template parameters and limit this
894// to Container<T>. http://stackoverflow.com/a/20499809/1609556
895template<typename T, typename Alloc>
896template<template <typename...> class Container>
897Array<T, Alloc>::Array (const Container<T>& a, const dim_vector& dv)
898 : m_dimensions (dv), m_rep (new typename Array<T, Alloc>::ArrayRep (dv.safe_numel ())),
899 m_slice_data (m_rep->m_data), m_slice_len (m_rep->m_len)
900{
901 if (m_dimensions.safe_numel () != octave_idx_type (a.size ()))
902 {
903 std::string new_dims_str = m_dimensions.str ();
904
905 (*current_liboctave_error_handler)
906 ("reshape: can't reshape %zi elements into %s array",
907 a.size (), new_dims_str.c_str ());
908 }
909
910 octave_idx_type i = 0;
911 for (const T& x : a)
912 m_slice_data[i++] = x;
913
915}
916
917template <typename T, typename Alloc>
918OCTARRAY_API std::ostream&
919operator << (std::ostream& os, const Array<T, Alloc>& a);
920
921#endif
class OCTARRAY_API Array
Definition: Array-fwd.h:40
octave_idx_type compute_index(octave_idx_type n, const dim_vector &dims)
Definition: Array-util.cc:177
OCTARRAY_API std::ostream & operator<<(std::ostream &os, const Array< T, Alloc > &a)
Definition: Array.cc:2778
static int elem
Definition: __contourc__.cc:54
octave_idx_type lookup(const T *x, octave_idx_type n, T y)
The real representation of all arrays.
Definition: Array.h:134
T_Alloc_traits::pointer pointer
Definition: Array.h:140
~ArrayRep(void)
Definition: Array.h:187
pointer allocate(size_t len)
Definition: Array.h:195
ArrayRep(U *d, octave_idx_type len)
Definition: Array.h:153
octave_idx_type numel(void) const
Definition: Array.h:189
ArrayRep(pointer d, octave_idx_type len)
Definition: Array.h:146
octave_idx_type m_len
Definition: Array.h:143
octave::refcount< octave_idx_type > m_count
Definition: Array.h:144
ArrayRep(octave_idx_type len)
Definition: Array.h:165
ArrayRep(octave_idx_type len, const T &val)
Definition: Array.h:168
ArrayRep(pointer ptr, const dim_vector &dv, const Alloc &xallocator=Alloc())
Definition: Array.h:174
std::allocator_traits< Alloc > Alloc_traits
Definition: Array.h:137
ArrayRep(const ArrayRep &a)
Definition: Array.h:180
pointer m_data
Definition: Array.h:142
void deallocate(pointer data, size_t len)
Definition: Array.h:203
ArrayRep(void)
Definition: Array.h:162
Alloc_traits::template rebind_traits< T > T_Alloc_traits
Definition: Array.h:139
N Dimensional Array with copy-on-write semantics.
Definition: Array.h:129
bool issquare(void) const
Size of the specified dimension.
Definition: Array.h:605
Array< T, Alloc >::ArrayRep * m_rep
Definition: Array.h:246
bool test_all(bool(&fcn)(const T &)) const
Size of the specified dimension.
Definition: Array.h:877
T & xelem(octave_idx_type n)
Size of the specified dimension.
Definition: Array.h:504
void make_unique(void)
Definition: Array.h:215
void resize2(octave_idx_type nr, octave_idx_type nc)
Size of the specified dimension.
Definition: Array.h:643
crefT xelem(octave_idx_type n) const
Size of the specified dimension.
Definition: Array.h:505
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:411
size_type size(const size_type d) const
Size of the specified dimension.
Definition: Array.h:476
Array< T, Alloc > index(const Array< octave::idx_vector > &ia, bool resize_ok) const
Size of the specified dimension.
Definition: Array.h:678
T & xelem(octave_idx_type i, octave_idx_type j)
Size of the specified dimension.
Definition: Array.h:507
friend class Array
Size of the specified dimension.
Definition: Array.h:881
crefT xelem(octave_idx_type i, octave_idx_type j) const
Size of the specified dimension.
Definition: Array.h:509
octave_idx_type size_type
Used for operator(), and returned by numel() and size() (beware: signed integer)
Definition: Array.h:235
Array< T, Alloc > ipermute(const Array< octave_idx_type > &vec) const
Size of the specified dimension.
Definition: Array.h:602
void resize(const dim_vector &dv)
Size of the specified dimension.
Definition: Array.h:652
crefT elem(octave_idx_type n) const
Size of the specified dimension.
Definition: Array.h:564
bool test_all(bool(&fcn)(T)) const
Size of the specified dimension.
Definition: Array.h:874
T & elem(octave_idx_type i, octave_idx_type j)
Size of the specified dimension.
Definition: Array.h:540
Array(T *ptr, const dim_vector &dv, const Alloc &xallocator=Alloc())
Definition: Array.h:306
octave_idx_type cols(void) const
Definition: Array.h:457
bool test_all(F fcn) const
Size of the specified dimension.
Definition: Array.h:862
const dim_vector & dims(void) const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:487
Array(const Array< U, A > &a)
Type conversion case.
Definition: Array.h:324
octave_idx_type compute_index_unchecked(const Array< octave_idx_type > &ra_idx) const
Size of the specified dimension.
Definition: Array.h:497
Array(void)
Empty ctor (0 by 0).
Definition: Array.h:274
void resize1(octave_idx_type n)
Size of the specified dimension.
Definition: Array.h:649
bool is_nd_vector(void) const
Size of the specified dimension.
Definition: Array.h:611
octave_idx_type dim2(void) const
Definition: Array.h:456
T & elem(octave_idx_type n)
Size of the specified dimension.
Definition: Array.h:534
octave_idx_type m_slice_len
Definition: Array.h:256
ref_param< T >::type crefT
Definition: Array.h:237
crefT elem(octave_idx_type i, octave_idx_type j) const
Size of the specified dimension.
Definition: Array.h:566
virtual ~Array(void)
Definition: Array.h:349
octave_idx_type rows(void) const
Definition: Array.h:449
static OCTARRAY_API void instantiation_guard()
Size of the specified dimension.
Definition: Array.cc:2753
T & xelem(const Array< octave_idx_type > &ra_idx)
Size of the specified dimension.
Definition: Array.h:517
crefT xelem(octave_idx_type i, octave_idx_type j, octave_idx_type k) const
Size of the specified dimension.
Definition: Array.h:514
Array< U, A > map(U(&fcn)(const T &)) const
Size of the specified dimension.
Definition: Array.h:844
bool isvector(void) const
Size of the specified dimension.
Definition: Array.h:609
bool isempty(void) const
Size of the specified dimension.
Definition: Array.h:607
Array< U, A > map(F fcn) const
Apply function fcn to each element of the Array<T, Alloc>.
Definition: Array.h:799
OCTARRAY_API 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.cc:2743
Array< T, Alloc > as_row(void) const
Return the array as a row vector.
Definition: Array.h:425
void clear(octave_idx_type r, octave_idx_type c)
Definition: Array.h:407
Array(const dim_vector &dv, const T &val)
nD initialized ctor.
Definition: Array.h:291
Array(const dim_vector &dv)
nD uninitialized ctor.
Definition: Array.h:282
T * m_slice_data
Definition: Array.h:255
bool test_any(F fcn) const
Simpler calls.
Definition: Array.h:858
octave_idx_type columns(void) const
Definition: Array.h:458
const T * data(void) const
Size of the specified dimension.
Definition: Array.h:616
Array< T, Alloc > index(const octave::idx_vector &i, bool resize_ok) const
Size of the specified dimension.
Definition: Array.h:662
Array< U, A > map(U(&fcn)(T)) const
Overloads for function references.
Definition: Array.h:835
void assign(const octave::idx_vector &i, const Array< T, Alloc > &rhs)
Size of the specified dimension.
Definition: Array.h:687
Array< T, Alloc > reshape(const dim_vector &new_dims) const
Size of the specified dimension.
Definition: Array.h:598
void assign(const Array< octave::idx_vector > &ia, const Array< T, Alloc > &rhs)
Size of the specified dimension.
Definition: Array.h:701
octave_idx_type dim1(void) const
Definition: Array.h:448
OCTARRAY_API T * fortran_vec(void)
Size of the specified dimension.
Definition: Array.cc:1744
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:695
Array< T, Alloc > as_matrix(void) const
Return the array as a matrix.
Definition: Array.h:435
std::size_t byte_size(void) const
Size of the specified dimension.
Definition: Array.h:483
Array(Array< T, Alloc > &&a)
Definition: Array.h:338
dim_vector m_dimensions
Definition: Array.h:244
Array(const Array< T, Alloc > &a, const dim_vector &dv, octave_idx_type l, octave_idx_type u)
slice constructor
Definition: Array.h:259
Array< T, Alloc > as_column(void) const
Return the array as a column vector.
Definition: Array.h:415
Array< T, Alloc > reshape(octave_idx_type nr, octave_idx_type nc) const
Size of the specified dimension.
Definition: Array.h:595
bool test_any(bool(&fcn)(const T &)) const
Size of the specified dimension.
Definition: Array.h:871
T element_type
Definition: Array.h:229
int ndims(void) const
Size of the specified dimension.
Definition: Array.h:627
bool test(F fcn) const
Generic any/all test functionality with arbitrary predicate.
Definition: Array.h:850
Array(const Container< T > &a, const dim_vector &dv)
Constructor from standard library sequence containers.
Definition: Array.h:897
T & xelem(octave_idx_type i, octave_idx_type j, octave_idx_type k)
Size of the specified dimension.
Definition: Array.h:512
octave_idx_type dim3(void) const
Size of the specified dimension.
Definition: Array.h:465
octave_idx_type pages(void) const
Size of the specified dimension.
Definition: Array.h:466
crefT elem(octave_idx_type i, octave_idx_type j, octave_idx_type k) const
Size of the specified dimension.
Definition: Array.h:569
T value_type
Definition: Array.h:231
crefT elem(const Array< octave_idx_type > &ra_idx) const
Size of the specified dimension.
Definition: Array.h:572
T & elem(octave_idx_type i, octave_idx_type j, octave_idx_type k)
Size of the specified dimension.
Definition: Array.h:542
T & elem(const Array< octave_idx_type > &ra_idx)
Size of the specified dimension.
Definition: Array.h:545
void maybe_economize(void)
Size of the specified dimension.
Definition: Array.h:729
bool test_any(bool(&fcn)(T)) const
Overloads for function references.
Definition: Array.h:868
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:670
crefT xelem(const Array< octave_idx_type > &ra_idx) const
Size of the specified dimension.
Definition: Array.h:520
bool is_shared(void)
Size of the specified dimension.
Definition: Array.h:625
Array(const Array< T, Alloc > &a)
No type conversion case.
Definition: Array.h:331
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_API std::string str(char sep='x') const
Definition: dim-vector.cc:68
bool isvector(void) const
Definition: dim-vector.h:395
void chop_trailing_singletons(void)
Definition: dim-vector.h:164
octave_idx_type ndims(void) const
Number of dimensions.
Definition: dim-vector.h:257
bool is_nd_vector(void) const
Definition: dim-vector.h:400
OCTAVE_API dim_vector redim(int n) const
Force certain dimensionality, preserving numel ().
Definition: dim-vector.cc:226
OCTAVE_API 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:98
virtual octave_idx_type numel(void) const
Definition: ov-base.h:365
if_then_else< is_class_type< T >::no, T, Tconst & >::result type
Definition: lo-traits.h:121
static octave_idx_type find(octave_idx_type i, octave_idx_type *pp)
Definition: colamd.cc:106
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
void F(const TSRC *v, TRES *r, octave_idx_type m, octave_idx_type n)
Definition: mx-inlines.cc:757
STL namespace.
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:71
const octave_base_value const Array< octave_idx_type > & ra_idx
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:391
F77_RET_T len
Definition: xerbla.cc:61