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