GNU Octave 10.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-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_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 "dim-vector.h"
39#include "lo-error.h"
40#include "oct-inttypes.h"
41#include "oct-refcount.h"
42#include "Sparse-fwd.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 // FIXME: idx_vector objects are either created successfully or an
534 // error is thrown, so this method no longer makes sense.
535 OCTAVE_DEPRECATED (9, "idx_vector::bool () is obsolete and always returns true")
536 operator bool () const { return true; }
537
538 bool is_colon () const
539 { return m_rep->idx_class () == class_colon; }
540
541 bool is_scalar () const
542 { return m_rep->idx_class () == class_scalar; }
543
544 bool is_range () const
545 { return m_rep->idx_class () == class_range; }
546
548 { return m_rep->is_colon_equiv (n); }
549
550 idx_vector sorted (bool uniq = false) const
551 { return idx_vector (m_rep->sort_uniq_clone (uniq)); }
552
554 { return idx_vector (m_rep->sort_idx (sidx)); }
555
556 dim_vector orig_dimensions () const { return m_rep->orig_dimensions (); }
557
559 { return orig_dimensions () (0); }
560
562 { return orig_dimensions () (1); }
563
564 int orig_empty () const
565 { return (! is_colon () && orig_dimensions ().any_zero ()); }
566
567 // i/o
568
569 std::ostream& print (std::ostream& os) const { return m_rep->print (os); }
570
571 friend std::ostream& operator << (std::ostream& os, const idx_vector& a)
572 { return a.print (os); }
573
574 // Slice with specializations. No checking of bounds!
575 //
576 // This is equivalent to the following loop (but much faster):
577 //
578 // for (octave_idx_type i = 0; i < idx->length (n); i++)
579 // dest[i] = src[idx(i)];
580 // return i;
581 //
582 template <typename T>
584 index (const T *src, octave_idx_type n, T *dest) const
585 {
586 octave_idx_type len = m_rep->length (n);
587
588 switch (m_rep->idx_class ())
589 {
590 case class_invalid:
591 (*current_liboctave_error_handler) ("unexpected: invalid index");
592 break;
593
594 case class_colon:
595 std::copy_n (src, len, dest);
596 break;
597
598 case class_range:
599 {
600 idx_range_rep *r = dynamic_cast<idx_range_rep *> (m_rep);
601 octave_idx_type start = r->get_start ();
602 octave_idx_type step = r->get_step ();
603 const T *ssrc = src + start;
604 if (step == 1)
605 std::copy_n (ssrc, len, dest);
606 else if (step == -1)
607 std::reverse_copy (ssrc - len + 1, ssrc + 1, dest);
608 else if (step == 0)
609 std::fill_n (dest, len, *ssrc);
610 else
611 {
612 for (octave_idx_type i = 0, j = 0; i < len; i++, j += step)
613 dest[i] = ssrc[j];
614 }
615 }
616 break;
617
618 case class_scalar:
619 {
620 idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (m_rep);
621 dest[0] = src[r->get_data ()];
622 }
623 break;
624
625 case class_vector:
626 {
627 idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (m_rep);
628 const octave_idx_type *data = r->get_data ();
629 for (octave_idx_type i = 0; i < len; i++)
630 dest[i] = src[data[i]];
631 }
632 break;
633
634 case class_mask:
635 {
636 idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (m_rep);
637 const bool *data = r->get_data ();
638 octave_idx_type ext = r->extent (0);
639 for (octave_idx_type i = 0; i < ext; i++)
640 if (data[i]) *dest++ = src[i];
641 }
642 break;
643
644 // We should have handled all possible enum values above. Rely
645 // on compiler diagnostics to warn if we haven't. For example,
646 // GCC's -Wswitch option, enabled by -Wall, will provide a
647 // warning.
648 }
649
650 return len;
651 }
652
653 // Slice assignment with specializations. No checking of bounds!
654 //
655 // This is equivalent to the following loop (but much faster):
656 //
657 // for (octave_idx_type i = 0; i < idx->length (n); i++)
658 // dest[idx(i)] = src[i];
659 // return i;
660 //
661 template <typename T>
663 assign (const T *src, octave_idx_type n, T *dest) const
664 {
665 octave_idx_type len = m_rep->length (n);
666
667 switch (m_rep->idx_class ())
668 {
669 case class_invalid:
670 (*current_liboctave_error_handler) ("unexpected: invalid index");
671 break;
672
673 case class_colon:
674 std::copy_n (src, len, dest);
675 break;
676
677 case class_range:
678 {
679 idx_range_rep *r = dynamic_cast<idx_range_rep *> (m_rep);
680 octave_idx_type start = r->get_start ();
681 octave_idx_type step = r->get_step ();
682 T *sdest = dest + start;
683 if (step == 1)
684 std::copy_n (src, len, sdest);
685 else if (step == -1)
686 std::reverse_copy (src, src + len, sdest - len + 1);
687 else
688 {
689 for (octave_idx_type i = 0, j = 0; i < len; i++, j += step)
690 sdest[j] = src[i];
691 }
692 }
693 break;
694
695 case class_scalar:
696 {
697 idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (m_rep);
698 dest[r->get_data ()] = src[0];
699 }
700 break;
701
702 case class_vector:
703 {
704 idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (m_rep);
705 const octave_idx_type *data = r->get_data ();
706 for (octave_idx_type i = 0; i < len; i++)
707 dest[data[i]] = src[i];
708 }
709 break;
710
711 case class_mask:
712 {
713 idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (m_rep);
714 const bool *data = r->get_data ();
715 octave_idx_type ext = r->extent (0);
716 for (octave_idx_type i = 0; i < ext; i++)
717 if (data[i]) dest[i] = *src++;
718 }
719 break;
720
721 // We should have handled all possible enum values above. Rely
722 // on compiler diagnostics to warn if we haven't. For example,
723 // GCC's -Wswitch option, enabled by -Wall, will provide a
724 // warning.
725 }
726
727 return len;
728 }
729
730 // Slice fill with specializations. No checking of bounds!
731 //
732 // This is equivalent to the following loop (but much faster):
733 //
734 // for (octave_idx_type i = 0; i < idx->length (n); i++)
735 // dest[idx(i)] = val;
736 // return i;
737 //
738 template <typename T>
740 fill (const T& val, octave_idx_type n, T *dest) const
741 {
742 octave_idx_type len = m_rep->length (n);
743
744 switch (m_rep->idx_class ())
745 {
746 case class_invalid:
747 (*current_liboctave_error_handler) ("unexpected: invalid index");
748 break;
749
750 case class_colon:
751 std::fill_n (dest, len, val);
752 break;
753
754 case class_range:
755 {
756 idx_range_rep *r = dynamic_cast<idx_range_rep *> (m_rep);
757 octave_idx_type start = r->get_start ();
758 octave_idx_type step = r->get_step ();
759 T *sdest = dest + start;
760 if (step == 1)
761 std::fill_n (sdest, len, val);
762 else if (step == -1)
763 std::fill (sdest - len + 1, sdest + 1, val);
764 else
765 {
766 for (octave_idx_type i = 0, j = 0; i < len; i++, j += step)
767 sdest[j] = val;
768 }
769 }
770 break;
771
772 case class_scalar:
773 {
774 idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (m_rep);
775 dest[r->get_data ()] = val;
776 }
777 break;
778
779 case class_vector:
780 {
781 idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (m_rep);
782 const octave_idx_type *data = r->get_data ();
783 for (octave_idx_type i = 0; i < len; i++)
784 dest[data[i]] = val;
785 }
786 break;
787
788 case class_mask:
789 {
790 idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (m_rep);
791 const bool *data = r->get_data ();
792 octave_idx_type ext = r->extent (0);
793 for (octave_idx_type i = 0; i < ext; i++)
794 if (data[i]) dest[i] = val;
795 }
796 break;
797
798 // We should have handled all possible enum values above. Rely
799 // on compiler diagnostics to warn if we haven't. For example,
800 // GCC's -Wswitch option, enabled by -Wall, will provide a
801 // warning.
802 }
803
804 return len;
805 }
806
807 // Generic non-breakable indexed loop. The loop body should be
808 // encapsulated in a single functor body. This is equivalent to the
809 // following loop (but faster, at least for simple inlined bodies):
810 //
811 // for (octave_idx_type i = 0; i < idx->length (n); i++) body (idx(i));
812
813 template <typename Functor>
814 void
815 loop (octave_idx_type n, Functor body) const
816 {
817 octave_idx_type len = m_rep->length (n);
818
819 switch (m_rep->idx_class ())
820 {
821 case class_invalid:
822 (*current_liboctave_error_handler) ("unexpected: invalid index");
823 break;
824
825 case class_colon:
826 for (octave_idx_type i = 0; i < len; i++) body (i);
827 break;
828
829 case class_range:
830 {
831 idx_range_rep *r = dynamic_cast<idx_range_rep *> (m_rep);
832 octave_idx_type start = r->get_start ();
833 octave_idx_type step = r->get_step ();
834 octave_idx_type i, j;
835 if (step == 1)
836 for (i = start, j = start + len; i < j; i++) body (i);
837 else if (step == -1)
838 for (i = start, j = start - len; i > j; i--) body (i);
839 else
840 for (i = 0, j = start; i < len; i++, j += step) body (j);
841 }
842 break;
843
844 case class_scalar:
845 {
846 idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (m_rep);
847 body (r->get_data ());
848 }
849 break;
850
851 case class_vector:
852 {
853 idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (m_rep);
854 const octave_idx_type *data = r->get_data ();
855 for (octave_idx_type i = 0; i < len; i++) body (data[i]);
856 }
857 break;
858
859 case class_mask:
860 {
861 idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (m_rep);
862 const bool *data = r->get_data ();
863 octave_idx_type ext = r->extent (0);
864 for (octave_idx_type i = 0; i < ext; i++)
865 if (data[i]) body (i);
866 }
867 break;
868
869 // We should have handled all possible enum values above. Rely
870 // on compiler diagnostics to warn if we haven't. For example,
871 // GCC's -Wswitch option, enabled by -Wall, will provide a
872 // warning.
873 }
874
875 }
876
877 // Generic breakable indexed loop. The loop body should be
878 // encapsulated in a single functor body. This is equivalent to the
879 // following loop (but faster, at least for simple inlined bodies):
880 //
881 // for (octave_idx_type i = 0; i < idx->length (n); i++)
882 // if (body (idx(i))) break;
883 // return i;
884 //
885
886 template <typename Functor>
888 bloop (octave_idx_type n, Functor body) const
889 {
890 octave_idx_type len = m_rep->length (n), ret;
891
892 switch (m_rep->idx_class ())
893 {
894 case class_invalid:
895 (*current_liboctave_error_handler) ("unexpected: invalid index");
896 break;
897
898 case class_colon:
899 {
901 for (i = 0; i < len && body (i); i++) ;
902 ret = i;
903 }
904 break;
905
906 case class_range:
907 {
908 idx_range_rep *r = dynamic_cast<idx_range_rep *> (m_rep);
909 octave_idx_type start = r->get_start ();
910 octave_idx_type step = r->get_step ();
911 octave_idx_type i, j;
912 if (step == 1)
913 for (i = start, j = start + len; i < j && body (i); i++) ;
914 else if (step == -1)
915 for (i = start, j = start - len; i > j && body (i); i--) ;
916 else
917 for (i = 0, j = start; i < len && body (j); i++, j += step) ;
918 ret = i;
919 }
920 break;
921
922 case class_scalar:
923 {
924 idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (m_rep);
925 ret = (body (r->get_data ()) ? 1 : 0);
926 }
927 break;
928
929 case class_vector:
930 {
931 idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (m_rep);
932 const octave_idx_type *data = r->get_data ();
934 for (i = 0; i < len && body (data[i]); i++) ;
935 ret = i;
936 }
937 break;
938
939 case class_mask:
940 {
941 idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (m_rep);
942 const bool *data = r->get_data ();
943 octave_idx_type ext = r->extent (0);
944 octave_idx_type j = 0;
945 for (octave_idx_type i = 0; i < ext; i++)
946 {
947 if (data[i])
948 {
949 if (body (i))
950 break;
951 else
952 j++;
953 }
954 }
955
956 ret = j;
957 }
958 break;
959
960 // We should have handled all possible enum values above. Rely
961 // on compiler diagnostics to warn if we haven't. For example,
962 // GCC's -Wswitch option, enabled by -Wall, will provide a
963 // warning.
964 }
965
966 return ret;
967 }
968
969 // Rationale:
970 // This method is the key to "smart indexing". When indexing cartesian
971 // arrays, sometimes consecutive index vectors can be reduced into a
972 // single index. If rows (A) = k and i.maybe_reduce (j) gives k, then
973 // A(i,j)(:) is equal to A(k)(:).
974
975 // If the next index can be reduced, returns true and updates this.
976 OCTAVE_API bool
977 maybe_reduce (octave_idx_type n, const idx_vector& j, octave_idx_type nj);
978
979 OCTAVE_API bool
980 is_cont_range (octave_idx_type n, octave_idx_type& l,
981 octave_idx_type& u) const;
982
983 // Returns the increment for ranges and colon, 0 for scalars and empty
984 // vectors, 1st difference otherwise.
985 OCTAVE_API octave_idx_type increment () const;
986
988 complement (octave_idx_type n) const;
989
990 OCTAVE_API bool is_permutation (octave_idx_type n) const;
991
992 // Returns the inverse permutation. If this is not a permutation on 1:n, the
993 // result is undefined (but no error unless extent () != n).
994 OCTAVE_API idx_vector inverse_permutation (octave_idx_type n) const;
995
996 // Copies all the indices to a given array. Not allowed for colons.
997 OCTAVE_API void copy_data (octave_idx_type *data) const;
998
999 // If the index is a mask, convert it to index vector.
1000 OCTAVE_API idx_vector unmask () const;
1001
1002 // Unconverts the index to a scalar, Range, double array or a mask.
1003 OCTAVE_API void
1004 unconvert (idx_class_type& iclass, double& scalar, range<double>& range,
1005 Array<double>& array, Array<bool>& mask) const;
1006
1007 OCTAVE_API Array<octave_idx_type> as_array () const;
1008
1009 // Raw pointer to index array. This is non-const because it may be
1010 // necessary to mutate the index.
1011 const OCTAVE_API octave_idx_type * raw ();
1012
1013 OCTAVE_API bool isvector () const;
1014
1015 // FIXME: these are here for compatibility. They should be removed
1016 // when no longer in use.
1017
1019 { return (*this) (n); }
1020
1022 { return is_colon_equiv (n); }
1023
1025 freeze (octave_idx_type z_len, const char *tag, bool resize_ok = false);
1026
1027 void sort (bool uniq = false)
1028 { *this = sorted (uniq); }
1029
1030 OCTAVE_API octave_idx_type ones_count () const;
1031
1032 octave_idx_type max () const { return extent (1) - 1; }
1033
1034private:
1035
1036 idx_base_rep *m_rep;
1037
1038};
1039
1040OCTAVE_END_NAMESPACE(octave)
1041
1042// Provide the following typedef for backward compatibility. Don't
1043// deprecate (yet) because it is used extensively.
1044
1045typedef octave::idx_vector idx_vector;
1046
1047#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.h:130
Vector representing the dimensions (size) of an Array.
Definition dim-vector.h:90
octave_idx_type xelem(octave_idx_type n) const
Definition idx-vector.h:524
octave_idx_type orig_rows() const
Definition idx-vector.h:558
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:550
octave_idx_type fill(const T &val, octave_idx_type n, T *dest) const
Definition idx-vector.h:740
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:556
idx_vector(const Sparse< bool > &nda)
Definition idx-vector.h:493
void loop(octave_idx_type n, Functor body) const
Definition idx-vector.h:815
idx_vector(const Array< double > &nda)
Definition idx-vector.h:485
bool is_range() const
Definition idx-vector.h:544
octave_idx_type bloop(octave_idx_type n, Functor body) const
Definition idx-vector.h:888
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:584
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:541
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:663
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:553
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:538
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:569
octave_idx_type extent(octave_idx_type n) const
Definition idx-vector.h:521
int orig_empty() const
Definition idx-vector.h:564
bool is_colon_equiv(octave_idx_type n) const
Definition idx-vector.h:547
idx_vector(octave_idx_type i)
Definition idx-vector.h:432
octave_idx_type orig_columns() const
Definition idx-vector.h:561
idx_vector(float x)
Definition idx-vector.h:476
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
F77_RET_T const F77_DBLE * x
#define OCTAVE_API
Definition main.in.cc:55
F77_RET_T len
Definition xerbla.cc:61