GNU Octave 11.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
idx-vector.h
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 1993-2026 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_idx_vector_h)
27#define octave_idx_vector_h 1
28
29#include "octave-config.h"
30
31#include <cstring>
32
33#include <algorithm>
34#include <iosfwd>
35#include <memory>
36
37#include "Array-fwd.h"
38#include "Sparse-fwd.h"
39#include "dim-vector.h"
40#include "oct-error.h"
41#include "oct-inttypes.h"
42#include "oct-refcount.h"
43#include "range-fwd.h"
44
46
47// Design rationale:
48//
49// idx_vector is a reference-counting, polymorphic pointer, that can
50// contain 4 types of index objects: a magic colon, a range, a scalar,
51// or an index vector.
52//
53// Polymorphic methods for single element access are provided, as well
54// as templates implementing "early dispatch", i.e., hoisting the checks
55// for index type out of loops.
56
58{
59public:
60
62 {
63 class_invalid = -1,
64 class_colon = 0,
68 class_mask
69 };
70
71 template <typename T, typename D> friend class std::unique_ptr;
72
73private:
74
75 class OCTAVE_API idx_base_rep
76 {
77 public:
78
79 idx_base_rep () : m_count (1) { }
80
81 OCTAVE_DISABLE_COPY_MOVE (idx_base_rep)
82
83 virtual ~idx_base_rep () = default;
84
85 // Non-range-checking element query.
86 virtual octave_idx_type xelem (octave_idx_type i) const = 0;
87
88 // Range-checking element query.
89 virtual octave_idx_type checkelem (octave_idx_type i) const = 0;
90
91 // Length of the index vector.
92 virtual octave_idx_type length (octave_idx_type n) const = 0;
93
94 // The maximum index + 1. The actual dimension is passed in.
95 virtual octave_idx_type extent (octave_idx_type n) const = 0;
96
97 // Index class.
98 virtual idx_class_type idx_class () const { return class_invalid; }
99
100 // Sorts, maybe uniqifies, and returns a clone object pointer.
101 virtual idx_base_rep * sort_uniq_clone (bool uniq = false) = 0;
102 // Sorts, and returns a sorting permutation (aka Array::sort).
103 virtual idx_base_rep * sort_idx (Array<octave_idx_type>&) = 0;
104
105 // Checks whether the index is colon or a range equivalent to colon.
106 virtual bool is_colon_equiv (octave_idx_type) const { return false; }
107
108 // The original dimensions of object (used when subscribing by matrices).
109 virtual dim_vector orig_dimensions () const { return dim_vector (); }
110
111 // i/o
112 virtual std::ostream& print (std::ostream& os) const = 0;
113
114 virtual Array<octave_idx_type> as_array ();
115
117 };
118
119 // The magic colon index.
120 class OCTAVE_API idx_colon_rep : public idx_base_rep
121 {
122 public:
123
124 idx_colon_rep () = default;
125
126 OCTAVE_API idx_colon_rep (char c);
127
128 OCTAVE_DISABLE_COPY_MOVE (idx_colon_rep)
129
130 ~idx_colon_rep () = default;
131
132 octave_idx_type xelem (octave_idx_type i) const { return i; }
133
134 OCTAVE_API octave_idx_type checkelem (octave_idx_type i) const;
135
136 octave_idx_type length (octave_idx_type n) const { return n; }
137
138 octave_idx_type extent (octave_idx_type n) const { return n; }
139
140 idx_class_type idx_class () const { return class_colon; }
141
142 idx_base_rep * sort_uniq_clone (bool = false)
143 { m_count++; return this; }
144
145 OCTAVE_NORETURN idx_base_rep * sort_idx (Array<octave_idx_type>&);
146
147 bool is_colon_equiv (octave_idx_type) const { return true; }
148
149 OCTAVE_API std::ostream& print (std::ostream& os) const;
150 };
151
152 // To distinguish the "direct" constructors that blindly trust the data.
153 enum direct { DIRECT };
154
155 // The integer range index.
156 class OCTAVE_API idx_range_rep : public idx_base_rep
157 {
158 public:
159
160 idx_range_rep () = delete;
161
162 idx_range_rep (octave_idx_type start, octave_idx_type len,
163 octave_idx_type step, direct)
164 : idx_base_rep (), m_start (start), m_len (len), m_step (step) { }
165
166 // Zero-based constructor for index range starting at `start` (inclusive)
167 // and ending at `limit` (exclusive) in steps of `step`.
168 idx_range_rep (octave_idx_type start, octave_idx_type limit,
169 octave_idx_type step);
170
171 OCTAVE_API idx_range_rep (const range<double>&);
172
173 OCTAVE_DISABLE_COPY_MOVE (idx_range_rep)
174
175 ~idx_range_rep () = default;
176
177 octave_idx_type xelem (octave_idx_type i) const
178 { return m_start + i * m_step; }
179
180 octave_idx_type checkelem (octave_idx_type i) const;
181
182 octave_idx_type length (octave_idx_type) const { return m_len; }
183
184 octave_idx_type extent (octave_idx_type n) const
185 {
186 return m_len ? std::max (n, m_start + 1 + (m_step < 0 ? 0 : m_step * (m_len - 1))) : n;
187 }
188
189 idx_class_type idx_class () const { return class_range; }
190
191 OCTAVE_API idx_base_rep * sort_uniq_clone (bool uniq = false);
192
193 OCTAVE_API idx_base_rep * sort_idx (Array<octave_idx_type>&);
194
195 bool is_colon_equiv (octave_idx_type n) const
196 { return m_start == 0 && m_step == 1 && m_len == n; }
197
198 dim_vector orig_dimensions () const
199 { return dim_vector (1, m_len); }
200
201 octave_idx_type get_start () const { return m_start; }
202
203 octave_idx_type get_step () const { return m_step; }
204
205 OCTAVE_API std::ostream& print (std::ostream& os) const;
206
207 OCTAVE_API range<double> unconvert () const;
208
210
211 private:
212
213 octave_idx_type m_start, m_len, m_step;
214 };
215
216 // The integer scalar index.
217 class OCTAVE_API idx_scalar_rep : public idx_base_rep
218 {
219 public:
220
221 idx_scalar_rep () = delete;
222
223 idx_scalar_rep (octave_idx_type i, direct) : idx_base_rep (), m_data (i) { }
224
225 OCTAVE_DISABLE_COPY_MOVE (idx_scalar_rep)
226
227 ~idx_scalar_rep () = default;
228
229 // Zero-based constructor.
230 OCTAVE_API idx_scalar_rep (octave_idx_type i);
231
232 template <typename T>
233 idx_scalar_rep (T x);
234
235 octave_idx_type xelem (octave_idx_type) const { return m_data; }
236
237 OCTAVE_API octave_idx_type checkelem (octave_idx_type i) const;
238
239 octave_idx_type length (octave_idx_type) const { return 1; }
240
241 octave_idx_type extent (octave_idx_type n) const
242 { return std::max (n, m_data + 1); }
243
244 idx_class_type idx_class () const { return class_scalar; }
245
246 idx_base_rep * sort_uniq_clone (bool = false)
247 { m_count++; return this; }
248
249 OCTAVE_API idx_base_rep * sort_idx (Array<octave_idx_type>&);
250
251 bool is_colon_equiv (octave_idx_type n) const
252 { return n == 1 && m_data == 0; }
253
254 dim_vector orig_dimensions () const { return dim_vector (1, 1); }
255
256 octave_idx_type get_data () const { return m_data; }
257
258 OCTAVE_API std::ostream& print (std::ostream& os) const;
259
260 OCTAVE_API double unconvert () const;
261
263
264 private:
265
266 octave_idx_type m_data;
267 };
268
269 // The integer vector index.
270 class OCTAVE_API idx_vector_rep : public idx_base_rep
271 {
272 public:
273
274 idx_vector_rep ()
275 : m_data (nullptr), m_len (0), m_ext (0), m_aowner (nullptr), m_orig_dims () { }
276
277 // Direct constructor.
278 idx_vector_rep (octave_idx_type *data, octave_idx_type len,
279 octave_idx_type ext, const dim_vector& od, direct)
280 : idx_base_rep (), m_data (data), m_len (len), m_ext (ext),
281 m_aowner (nullptr), m_orig_dims (od)
282 { }
283
284 // Zero-based constructor.
285 OCTAVE_API idx_vector_rep (const Array<octave_idx_type>& inda);
286
287 OCTAVE_API idx_vector_rep (const Array<octave_idx_type>& inda,
288 octave_idx_type ext, direct);
289
290 template <typename T>
291 idx_vector_rep (const Array<T>&);
292
293 OCTAVE_API idx_vector_rep (bool);
294
295 OCTAVE_API idx_vector_rep (const Array<bool>&, octave_idx_type = -1);
296
297 OCTAVE_API idx_vector_rep (const Sparse<bool>&);
298
299 OCTAVE_DISABLE_COPY_MOVE (idx_vector_rep)
300
301 ~idx_vector_rep ();
302
303 octave_idx_type xelem (octave_idx_type i) const { return m_data[i]; }
304
305 OCTAVE_API octave_idx_type checkelem (octave_idx_type i) const;
306
307 octave_idx_type length (octave_idx_type) const { return m_len; }
308
309 octave_idx_type extent (octave_idx_type n) const
310 { return std::max (n, m_ext); }
311
312 idx_class_type idx_class () const { return class_vector; }
313
314 idx_base_rep * sort_uniq_clone (bool uniq = false);
315
316 OCTAVE_API idx_base_rep * sort_idx (Array<octave_idx_type>&);
317
318 dim_vector orig_dimensions () const { return m_orig_dims; }
319
320 const octave_idx_type * get_data () const { return m_data; }
321
322 OCTAVE_API std::ostream& print (std::ostream& os) const;
323
324 OCTAVE_API Array<double> unconvert () const;
325
327
328 private:
329
330 const octave_idx_type *m_data;
331 octave_idx_type m_len;
332 octave_idx_type m_ext;
333
334 // This is a trick to allow user-given zero-based arrays to be used
335 // as indices without copying. If the following pointer is nonzero,
336 // we do not own the data, but rather have an Array<octave_idx_type>
337 // object that provides us the data. Note that we need a pointer
338 // because we deferred the Array<T> declaration and we do not want
339 // it yet to be defined.
340
341 Array<octave_idx_type> *m_aowner;
342
343 dim_vector m_orig_dims;
344 };
345
346 // The logical mask index.
347 class OCTAVE_API idx_mask_rep : public idx_base_rep
348 {
349 public:
350
351 idx_mask_rep () = delete;
352
353 // Direct constructor.
354 idx_mask_rep (bool *data, octave_idx_type len,
355 octave_idx_type ext, const dim_vector& od, direct)
356 : idx_base_rep (), m_data (data), m_len (len), m_ext (ext),
357 m_lsti (-1), m_lste (-1), m_aowner (nullptr), m_orig_dims (od)
358 { }
359
360 OCTAVE_API idx_mask_rep (bool);
361
362 OCTAVE_API idx_mask_rep (const Array<bool>&, octave_idx_type = -1);
363
364 OCTAVE_DISABLE_COPY_MOVE (idx_mask_rep)
365
366 OCTAVE_API ~idx_mask_rep ();
367
368 octave_idx_type xelem (octave_idx_type i) const;
369
370 octave_idx_type checkelem (octave_idx_type i) const;
371
372 octave_idx_type length (octave_idx_type) const { return m_len; }
373
374 octave_idx_type extent (octave_idx_type n) const
375 { return std::max (n, m_ext); }
376
377 idx_class_type idx_class () const { return class_mask; }
378
379 idx_base_rep * sort_uniq_clone (bool = false)
380 { m_count++; return this; }
381
382 OCTAVE_API idx_base_rep * sort_idx (Array<octave_idx_type>&);
383
384 dim_vector orig_dimensions () const { return m_orig_dims; }
385
386 bool is_colon_equiv (octave_idx_type n) const
387 { return m_len == n && m_ext == n; }
388
389 const bool * get_data () const { return m_data; }
390
391 OCTAVE_API std::ostream& print (std::ostream& os) const;
392
393 OCTAVE_API Array<bool> unconvert () const;
394
396
397 private:
398
399 const bool *m_data;
400 octave_idx_type m_len;
401 octave_idx_type m_ext;
402
403 // FIXME: I'm not sure if this is a good design. Maybe it would be
404 // better to employ some sort of generalized iteration scheme.
405 mutable octave_idx_type m_lsti;
406 mutable octave_idx_type m_lste;
407
408 // This is a trick to allow user-given mask arrays to be used as
409 // indices without copying. If the following pointer is nonzero, we
410 // do not own the data, but rather have an Array<bool> object that
411 // provides us the data. Note that we need a pointer because we
412 // deferred the Array<T> declaration and we do not want it yet to be
413 // defined.
414
415 Array<bool> *m_aowner;
416
417 dim_vector m_orig_dims;
418 };
419
420 idx_vector (idx_base_rep *r) : m_rep (r) { }
421
422 // The shared empty vector representation (for fast default
423 // constructor).
424 static OCTAVE_API idx_vector_rep * nil_rep ();
425
426public:
427
428 // Fast empty constructor.
429 idx_vector () : m_rep (nil_rep ()) { m_rep->m_count++; }
430
431 // Zero-based constructors (for use from C++).
432 idx_vector (octave_idx_type i) : m_rep (new idx_scalar_rep (i)) { }
433
434#if OCTAVE_SIZEOF_INT != OCTAVE_SIZEOF_IDX_TYPE
435 idx_vector (int i)
436 : m_rep (new idx_scalar_rep (static_cast<octave_idx_type> (i))) { }
437#endif
438
439#if (OCTAVE_SIZEOF_F77_INT_TYPE != OCTAVE_SIZEOF_IDX_TYPE \
440 && OCTAVE_SIZEOF_F77_INT_TYPE != OCTAVE_SIZEOF_INT)
441 idx_vector (octave_f77_int_type i)
442 : m_rep (new idx_scalar_rep (static_cast<octave_idx_type> (i))) { }
443#endif
444
446 octave_idx_type step = 1)
447 : m_rep (new idx_range_rep (start, limit, step)) { }
448
449 static idx_vector
452 {
453 return idx_vector (new idx_range_rep (start, len, step, DIRECT));
454 }
455
457 : m_rep (new idx_vector_rep (inda)) { }
458
459 // Directly pass extent, no checking.
461 : m_rep (new idx_vector_rep (inda, ext, DIRECT)) { }
462
463 // Colon is best constructed by simply copying (or referencing) this member.
464 static const idx_vector colon;
465
466 // or passing ':' here
467 idx_vector (char c) : m_rep (new idx_colon_rep (c)) { }
468
469 // Conversion constructors (used by interpreter).
470
471 template <typename T>
472 idx_vector (octave_int<T> x) : m_rep (new idx_scalar_rep (x)) { }
473
474 idx_vector (double x) : m_rep (new idx_scalar_rep (x)) { }
475
476 idx_vector (float x) : m_rep (new idx_scalar_rep (x)) { }
477
478 // A scalar bool does not necessarily map to scalar index.
479 idx_vector (bool x) : m_rep (new idx_mask_rep (x)) { }
480
481 template <typename T>
483 : m_rep (new idx_vector_rep (nda)) { }
484
485 idx_vector (const Array<double>& nda) : m_rep (new idx_vector_rep (nda)) { }
486
487 idx_vector (const Array<float>& nda) : m_rep (new idx_vector_rep (nda)) { }
488
489 OCTAVE_API idx_vector (const Array<bool>& nda);
490
491 idx_vector (const range<double>& r) : m_rep (new idx_range_rep (r)) { }
492
493 idx_vector (const Sparse<bool>& nda) : m_rep (new idx_vector_rep (nda)) { }
494
495 idx_vector (const idx_vector& a) : m_rep (a.m_rep) { m_rep->m_count++; }
496
498 {
499 if (--m_rep->m_count == 0 && m_rep != nil_rep ())
500 delete m_rep;
501 }
502
503 idx_vector& operator = (const idx_vector& a)
504 {
505 if (this != &a)
506 {
507 if (--m_rep->m_count == 0 && m_rep != nil_rep ())
508 delete m_rep;
509
510 m_rep = a.m_rep;
511 m_rep->m_count++;
512 }
513 return *this;
514 }
515
516 idx_class_type idx_class () const { return m_rep->idx_class (); }
517
519 { return m_rep->length (n); }
520
522 { return m_rep->extent (n); }
523
525 { return m_rep->xelem (n); }
526
528 { return m_rep->xelem (n); }
529
530 octave_idx_type operator () (octave_idx_type n) const
531 { return m_rep->xelem (n); }
532
533 bool is_colon () const
534 { return m_rep->idx_class () == class_colon; }
535
536 bool is_scalar () const
537 { return m_rep->idx_class () == class_scalar; }
538
539 bool is_range () const
540 { return m_rep->idx_class () == class_range; }
541
543 { return m_rep->is_colon_equiv (n); }
544
545 idx_vector sorted (bool uniq = false) const
546 { return idx_vector (m_rep->sort_uniq_clone (uniq)); }
547
549 { return idx_vector (m_rep->sort_idx (sidx)); }
550
551 dim_vector orig_dimensions () const { return m_rep->orig_dimensions (); }
552
554 { return orig_dimensions () (0); }
555
557 { return orig_dimensions () (1); }
558
559 int orig_empty () const
560 { return (! is_colon () && orig_dimensions ().any_zero ()); }
561
562 // i/o
563
564 std::ostream& print (std::ostream& os) const { return m_rep->print (os); }
565
566 friend std::ostream& operator << (std::ostream& os, const idx_vector& a)
567 { return a.print (os); }
568
569 // Slice with specializations. No checking of bounds!
570 //
571 // This is equivalent to the following loop (but much faster):
572 //
573 // for (octave_idx_type i = 0; i < idx->length (n); i++)
574 // dest[i] = src[idx(i)];
575 // return i;
576 //
577 template <typename T>
579 index (const T *src, octave_idx_type n, T *dest) const
580 {
581 octave_idx_type len = m_rep->length (n);
582
583 switch (m_rep->idx_class ())
584 {
585 case class_invalid:
586 (*current_liboctave_error_handler) ("unexpected: invalid index");
587 break;
588
589 case class_colon:
590 std::copy_n (src, len, dest);
591 break;
592
593 case class_range:
594 {
595 idx_range_rep *r = dynamic_cast<idx_range_rep *> (m_rep);
596 octave_idx_type start = r->get_start ();
597 octave_idx_type step = r->get_step ();
598 const T *ssrc = src + start;
599 if (step == 1)
600 std::copy_n (ssrc, len, dest);
601 else if (step == -1)
602 std::reverse_copy (ssrc - len + 1, ssrc + 1, dest);
603 else if (step == 0)
604 std::fill_n (dest, len, *ssrc);
605 else
606 {
607 for (octave_idx_type i = 0, j = 0; i < len; i++, j += step)
608 dest[i] = ssrc[j];
609 }
610 }
611 break;
612
613 case class_scalar:
614 {
615 idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (m_rep);
616 dest[0] = src[r->get_data ()];
617 }
618 break;
619
620 case class_vector:
621 {
622 idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (m_rep);
623 const octave_idx_type *data = r->get_data ();
624 for (octave_idx_type i = 0; i < len; i++)
625 dest[i] = src[data[i]];
626 }
627 break;
628
629 case class_mask:
630 {
631 idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (m_rep);
632 const bool *data = r->get_data ();
633 octave_idx_type ext = r->extent (0);
634 for (octave_idx_type i = 0; i < ext; i++)
635 if (data[i]) *dest++ = src[i];
636 }
637 break;
638
639 // We should have handled all possible enum values above. Rely
640 // on compiler diagnostics to warn if we haven't. For example,
641 // GCC's -Wswitch option, enabled by -Wall, will provide a
642 // warning.
643 }
644
645 return len;
646 }
647
648 // Slice assignment with specializations. No checking of bounds!
649 //
650 // This is equivalent to the following loop (but much faster):
651 //
652 // for (octave_idx_type i = 0; i < idx->length (n); i++)
653 // dest[idx(i)] = src[i];
654 // return i;
655 //
656 template <typename T>
658 assign (const T *src, octave_idx_type n, T *dest) const
659 {
660 octave_idx_type len = m_rep->length (n);
661
662 switch (m_rep->idx_class ())
663 {
664 case class_invalid:
665 (*current_liboctave_error_handler) ("unexpected: invalid index");
666 break;
667
668 case class_colon:
669 std::copy_n (src, len, dest);
670 break;
671
672 case class_range:
673 {
674 idx_range_rep *r = dynamic_cast<idx_range_rep *> (m_rep);
675 octave_idx_type start = r->get_start ();
676 octave_idx_type step = r->get_step ();
677 T *sdest = dest + start;
678 if (step == 1)
679 std::copy_n (src, len, sdest);
680 else if (step == -1)
681 std::reverse_copy (src, src + len, sdest - len + 1);
682 else
683 {
684 for (octave_idx_type i = 0, j = 0; i < len; i++, j += step)
685 sdest[j] = src[i];
686 }
687 }
688 break;
689
690 case class_scalar:
691 {
692 idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (m_rep);
693 dest[r->get_data ()] = src[0];
694 }
695 break;
696
697 case class_vector:
698 {
699 idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (m_rep);
700 const octave_idx_type *data = r->get_data ();
701 for (octave_idx_type i = 0; i < len; i++)
702 dest[data[i]] = src[i];
703 }
704 break;
705
706 case class_mask:
707 {
708 idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (m_rep);
709 const bool *data = r->get_data ();
710 octave_idx_type ext = r->extent (0);
711 for (octave_idx_type i = 0; i < ext; i++)
712 if (data[i]) dest[i] = *src++;
713 }
714 break;
715
716 // We should have handled all possible enum values above. Rely
717 // on compiler diagnostics to warn if we haven't. For example,
718 // GCC's -Wswitch option, enabled by -Wall, will provide a
719 // warning.
720 }
721
722 return len;
723 }
724
725 // Slice fill with specializations. No checking of bounds!
726 //
727 // This is equivalent to the following loop (but much faster):
728 //
729 // for (octave_idx_type i = 0; i < idx->length (n); i++)
730 // dest[idx(i)] = val;
731 // return i;
732 //
733 template <typename T>
735 fill (const T& val, octave_idx_type n, T *dest) const
736 {
737 octave_idx_type len = m_rep->length (n);
738
739 switch (m_rep->idx_class ())
740 {
741 case class_invalid:
742 (*current_liboctave_error_handler) ("unexpected: invalid index");
743 break;
744
745 case class_colon:
746 std::fill_n (dest, len, val);
747 break;
748
749 case class_range:
750 {
751 idx_range_rep *r = dynamic_cast<idx_range_rep *> (m_rep);
752 octave_idx_type start = r->get_start ();
753 octave_idx_type step = r->get_step ();
754 T *sdest = dest + start;
755 if (step == 1)
756 std::fill_n (sdest, len, val);
757 else if (step == -1)
758 std::fill (sdest - len + 1, sdest + 1, val);
759 else
760 {
761 for (octave_idx_type i = 0, j = 0; i < len; i++, j += step)
762 sdest[j] = val;
763 }
764 }
765 break;
766
767 case class_scalar:
768 {
769 idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (m_rep);
770 dest[r->get_data ()] = val;
771 }
772 break;
773
774 case class_vector:
775 {
776 idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (m_rep);
777 const octave_idx_type *data = r->get_data ();
778 for (octave_idx_type i = 0; i < len; i++)
779 dest[data[i]] = val;
780 }
781 break;
782
783 case class_mask:
784 {
785 idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (m_rep);
786 const bool *data = r->get_data ();
787 octave_idx_type ext = r->extent (0);
788 for (octave_idx_type i = 0; i < ext; i++)
789 if (data[i]) dest[i] = val;
790 }
791 break;
792
793 // We should have handled all possible enum values above. Rely
794 // on compiler diagnostics to warn if we haven't. For example,
795 // GCC's -Wswitch option, enabled by -Wall, will provide a
796 // warning.
797 }
798
799 return len;
800 }
801
802 // Generic non-breakable indexed loop. The loop body should be
803 // encapsulated in a single functor body. This is equivalent to the
804 // following loop (but faster, at least for simple inlined bodies):
805 //
806 // for (octave_idx_type i = 0; i < idx->length (n); i++) body (idx(i));
807
808 template <typename Functor>
809 void
810 loop (octave_idx_type n, Functor body) const
811 {
812 octave_idx_type len = m_rep->length (n);
813
814 switch (m_rep->idx_class ())
815 {
816 case class_invalid:
817 (*current_liboctave_error_handler) ("unexpected: invalid index");
818 break;
819
820 case class_colon:
821 for (octave_idx_type i = 0; i < len; i++) body (i);
822 break;
823
824 case class_range:
825 {
826 idx_range_rep *r = dynamic_cast<idx_range_rep *> (m_rep);
827 octave_idx_type start = r->get_start ();
828 octave_idx_type step = r->get_step ();
829 octave_idx_type i, j;
830 if (step == 1)
831 for (i = start, j = start + len; i < j; i++) body (i);
832 else if (step == -1)
833 for (i = start, j = start - len; i > j; i--) body (i);
834 else
835 for (i = 0, j = start; i < len; i++, j += step) body (j);
836 }
837 break;
838
839 case class_scalar:
840 {
841 idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (m_rep);
842 body (r->get_data ());
843 }
844 break;
845
846 case class_vector:
847 {
848 idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (m_rep);
849 const octave_idx_type *data = r->get_data ();
850 for (octave_idx_type i = 0; i < len; i++) body (data[i]);
851 }
852 break;
853
854 case class_mask:
855 {
856 idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (m_rep);
857 const bool *data = r->get_data ();
858 octave_idx_type ext = r->extent (0);
859 for (octave_idx_type i = 0; i < ext; i++)
860 if (data[i]) body (i);
861 }
862 break;
863
864 // We should have handled all possible enum values above. Rely
865 // on compiler diagnostics to warn if we haven't. For example,
866 // GCC's -Wswitch option, enabled by -Wall, will provide a
867 // warning.
868 }
869
870 }
871
872 // Generic breakable indexed loop. The loop body should be
873 // encapsulated in a single functor body. This is equivalent to the
874 // following loop (but faster, at least for simple inlined bodies):
875 //
876 // for (octave_idx_type i = 0; i < idx->length (n); i++)
877 // if (body (idx(i))) break;
878 // return i;
879 //
880
881 template <typename Functor>
883 bloop (octave_idx_type n, Functor body) const
884 {
885 octave_idx_type len = m_rep->length (n), ret;
886
887 switch (m_rep->idx_class ())
888 {
889 case class_invalid:
890 (*current_liboctave_error_handler) ("unexpected: invalid index");
891 break;
892
893 case class_colon:
894 {
896 for (i = 0; i < len && body (i); i++) ;
897 ret = i;
898 }
899 break;
900
901 case class_range:
902 {
903 idx_range_rep *r = dynamic_cast<idx_range_rep *> (m_rep);
904 octave_idx_type start = r->get_start ();
905 octave_idx_type step = r->get_step ();
906 octave_idx_type i, j;
907 if (step == 1)
908 for (i = start, j = start + len; i < j && body (i); i++) ;
909 else if (step == -1)
910 for (i = start, j = start - len; i > j && body (i); i--) ;
911 else
912 for (i = 0, j = start; i < len && body (j); i++, j += step) ;
913 ret = i;
914 }
915 break;
916
917 case class_scalar:
918 {
919 idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (m_rep);
920 ret = (body (r->get_data ()) ? 1 : 0);
921 }
922 break;
923
924 case class_vector:
925 {
926 idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (m_rep);
927 const octave_idx_type *data = r->get_data ();
929 for (i = 0; i < len && body (data[i]); i++) ;
930 ret = i;
931 }
932 break;
933
934 case class_mask:
935 {
936 idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (m_rep);
937 const bool *data = r->get_data ();
938 octave_idx_type ext = r->extent (0);
939 octave_idx_type j = 0;
940 for (octave_idx_type i = 0; i < ext; i++)
941 {
942 if (data[i])
943 {
944 if (body (i))
945 break;
946 else
947 j++;
948 }
949 }
950
951 ret = j;
952 }
953 break;
954
955 // We should have handled all possible enum values above. Rely
956 // on compiler diagnostics to warn if we haven't. For example,
957 // GCC's -Wswitch option, enabled by -Wall, will provide a
958 // warning.
959 }
960
961 return ret;
962 }
963
964 // Rationale:
965 // This method is the key to "smart indexing". When indexing cartesian
966 // arrays, sometimes consecutive index vectors can be reduced into a
967 // single index. If rows (A) = k and i.maybe_reduce (j) gives k, then
968 // A(i,j)(:) is equal to A(k)(:).
969
970 // If the next index can be reduced, returns true and updates this.
971 OCTAVE_API bool
972 maybe_reduce (octave_idx_type n, const idx_vector& j, octave_idx_type nj);
973
974 OCTAVE_API bool
975 is_cont_range (octave_idx_type n, octave_idx_type& l,
976 octave_idx_type& u) const;
977
978 // Returns the increment for ranges and colon, 0 for scalars and empty
979 // vectors, 1st difference otherwise.
980 OCTAVE_API octave_idx_type increment () const;
981
983 complement (octave_idx_type n) const;
984
985 OCTAVE_API bool is_permutation (octave_idx_type n) const;
986
987 // Returns the inverse permutation. If this is not a permutation on 1:n, the
988 // result is undefined (but no error unless extent () != n).
989 OCTAVE_API idx_vector inverse_permutation (octave_idx_type n) const;
990
991 // Copies all the indices to a given array. Not allowed for colons.
992 OCTAVE_API void copy_data (octave_idx_type *data) const;
993
994 // If the index is a mask, convert it to index vector.
995 OCTAVE_API idx_vector unmask () const;
996
997 // Unconverts the index to a scalar, Range, double array or a mask.
998 OCTAVE_API void
999 unconvert (idx_class_type& iclass, double& scalar, range<double>& range,
1000 Array<double>& array, Array<bool>& mask) const;
1001
1002 OCTAVE_API Array<octave_idx_type> as_array () const;
1003
1004 // Raw pointer to index array. This is non-const because it may be
1005 // necessary to mutate the index.
1006 const OCTAVE_API octave_idx_type * raw ();
1007
1008 OCTAVE_API bool isvector () const;
1009
1010 // FIXME: these are here for compatibility. They should be removed
1011 // when no longer in use.
1012
1014 { return (*this) (n); }
1015
1017 { return is_colon_equiv (n); }
1018
1020 freeze (octave_idx_type z_len, const char *tag, bool resize_ok = false);
1021
1022 void sort (bool uniq = false)
1023 { *this = sorted (uniq); }
1024
1025 OCTAVE_API octave_idx_type ones_count () const;
1026
1027 octave_idx_type max () const { return extent (1) - 1; }
1028
1029private:
1030
1031 idx_base_rep *m_rep;
1032
1033};
1034
1035OCTAVE_END_NAMESPACE(octave)
1036
1037// Provide the following typedef for backward compatibility. Don't
1038// deprecate (yet) because it is used extensively.
1039
1040typedef octave::idx_vector idx_vector;
1041
1042#endif
template std::ostream & operator<<(std::ostream &, const Array< bool > &)
dim_vector freeze(Array< octave::idx_vector > &ra_idx, const dim_vector &dimensions, int resize_ok)
bool isvector(const dim_vector &dim)
N Dimensional Array with copy-on-write semantics.
Definition Array-base.h:130
Vector representing the dimensions (size) of an Array.
Definition dim-vector.h:92
octave_idx_type xelem(octave_idx_type n) const
Definition idx-vector.h:524
octave_idx_type orig_rows() const
Definition idx-vector.h:553
idx_class_type idx_class() const
Definition idx-vector.h:516
idx_vector(const Array< octave_idx_type > &inda, octave_idx_type ext)
Definition idx-vector.h:460
idx_vector sorted(bool uniq=false) const
Definition idx-vector.h:545
octave_idx_type fill(const T &val, octave_idx_type n, T *dest) const
Definition idx-vector.h:735
static const idx_vector colon
Definition idx-vector.h:464
idx_vector(octave_int< T > x)
Definition idx-vector.h:472
idx_vector(const range< double > &r)
Definition idx-vector.h:491
dim_vector orig_dimensions() const
Definition idx-vector.h:551
idx_vector(const Sparse< bool > &nda)
Definition idx-vector.h:493
void loop(octave_idx_type n, Functor body) const
Definition idx-vector.h:810
idx_vector(const Array< double > &nda)
Definition idx-vector.h:485
bool is_range() const
Definition idx-vector.h:539
octave_idx_type bloop(octave_idx_type n, Functor body) const
Definition idx-vector.h:883
octave_idx_type length(octave_idx_type n=0) const
Definition idx-vector.h:518
idx_vector(double x)
Definition idx-vector.h:474
octave_idx_type index(const T *src, octave_idx_type n, T *dest) const
Definition idx-vector.h:579
void sort(bool uniq=false)
octave_idx_type elem(octave_idx_type n) const
idx_vector(bool x)
Definition idx-vector.h:479
idx_vector(const Array< octave_int< T > > &nda)
Definition idx-vector.h:482
bool is_scalar() const
Definition idx-vector.h:536
idx_vector(char c)
Definition idx-vector.h:467
octave_idx_type assign(const T *src, octave_idx_type n, T *dest) const
Definition idx-vector.h:658
octave_idx_type checkelem(octave_idx_type n) const
Definition idx-vector.h:527
idx_vector(const Array< float > &nda)
Definition idx-vector.h:487
idx_vector sorted(Array< octave_idx_type > &sidx) const
Definition idx-vector.h:548
static idx_vector make_range(octave_idx_type start, octave_idx_type step, octave_idx_type len)
Definition idx-vector.h:450
bool is_colon() const
Definition idx-vector.h:533
idx_vector(const Array< octave_idx_type > &inda)
Definition idx-vector.h:456
octave_idx_type max() const
idx_vector(const idx_vector &a)
Definition idx-vector.h:495
idx_vector(octave_idx_type start, octave_idx_type limit, octave_idx_type step=1)
Definition idx-vector.h:445
bool is_colon_equiv(octave_idx_type n, int) const
std::ostream & print(std::ostream &os) const
Definition idx-vector.h:564
octave_idx_type extent(octave_idx_type n) const
Definition idx-vector.h:521
int orig_empty() const
Definition idx-vector.h:559
bool is_colon_equiv(octave_idx_type n) const
Definition idx-vector.h:542
idx_vector(octave_idx_type i)
Definition idx-vector.h:432
octave_idx_type orig_columns() const
Definition idx-vector.h:556
idx_vector(float x)
Definition idx-vector.h:476
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
#define OCTAVE_API
Definition main.in.cc:55
F77_RET_T const F77_DBLE * x
F77_RET_T len
Definition xerbla.cc:61