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