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