GNU Octave  3.8.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
idx-vector.h
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1993-2013 John W. Eaton
4 Copyright (C) 2008-2009 Jaroslav Hajek
5 Copyright (C) 2009 VZLU Prague
6 
7 This file is part of Octave.
8 
9 Octave is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 3 of the License, or (at your
12 option) any later version.
13 
14 Octave is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Octave; see the file COPYING. If not, see
21 <http://www.gnu.org/licenses/>.
22 
23 */
24 
25 #if !defined (octave_idx_vector_h)
26 #define octave_idx_vector_h 1
27 
28 #include <cassert>
29 
30 #include <algorithm>
31 #include <iosfwd>
32 #include <memory>
33 
34 #include "dim-vector.h"
35 #include "oct-inttypes.h"
36 #include "oct-alloc.h"
37 #include "oct-mem.h"
38 #include "oct-refcount.h"
39 
40 template<class T> class Array;
41 template<class T> class Sparse;
42 class Range;
43 
44 // Design rationale:
45 // idx_vector is a reference-counting, polymorphic pointer, that can contain
46 // 4 types of index objects: a magic colon, a range, a scalar, or an index vector.
47 // Polymorphic methods for single element access are provided, as well as
48 // templates implementing "early dispatch", i.e. hoisting the checks for index
49 // type out of loops.
50 
51 class
52 OCTAVE_API
54 {
55 public:
56 
58  {
59  class_invalid = -1,
60  class_colon = 0,
64  class_mask
65  };
66 
67  template<class T> friend class std::auto_ptr;
68 
69 private:
70 
71  class OCTAVE_API idx_base_rep
72  {
73  public:
74  idx_base_rep (void) : count (1), err (false) { }
75 
76  virtual ~idx_base_rep (void) { }
77 
78  // Non-range-checking element query.
79  virtual octave_idx_type xelem (octave_idx_type i) const = 0;
80 
81  // Range-checking element query.
82  virtual octave_idx_type checkelem (octave_idx_type i) const = 0;
83 
84  // Length of the index vector.
85  virtual octave_idx_type length (octave_idx_type n) const = 0;
86 
87  // The maximum index + 1. The actual dimension is passed in.
88  virtual octave_idx_type extent (octave_idx_type n) const = 0;
89 
90  // Index class.
91  virtual idx_class_type idx_class (void) const { return class_invalid; }
92 
93  // Sorts, maybe uniqifies, and returns a clone object pointer.
94  virtual idx_base_rep *sort_uniq_clone (bool uniq = false) = 0;
95  // Sorts, and returns a sorting permutation (aka Array::sort).
96  virtual idx_base_rep *sort_idx (Array<octave_idx_type>&) = 0;
97 
98  // Checks whether the index is colon or a range equivalent to colon.
99  virtual bool is_colon_equiv (octave_idx_type) const { return false; }
100 
101  // The original dimensions of object (used when subscribing by matrices).
102  virtual dim_vector orig_dimensions (void) const { return dim_vector (); }
103 
104  // i/o
105  virtual std::ostream& print (std::ostream& os) const = 0;
106 
107  virtual Array<octave_idx_type> as_array (void);
108 
110 
111  bool err;
112 
113  private:
114 
115  // No copying!
116  idx_base_rep (const idx_base_rep&);
117  idx_base_rep& operator = (const idx_base_rep&);
118  };
119 
120  // The magic colon index.
121  class OCTAVE_API idx_colon_rep : public idx_base_rep
122  {
123  public:
124  idx_colon_rep (void) { }
125 
126  idx_colon_rep (char c);
127 
128  octave_idx_type xelem (octave_idx_type i) const { return i; }
129 
131 
132  octave_idx_type length (octave_idx_type n) const { return n; }
133 
134  octave_idx_type extent (octave_idx_type n) const { return n; }
135 
136  idx_class_type idx_class (void) const { return class_colon; }
137 
139  { count++; return this; }
140 
142 
143  bool is_colon_equiv (octave_idx_type) const { return true; }
144 
145  std::ostream& print (std::ostream& os) const;
146 
147  private:
148 
150 
151  // No copying!
152  idx_colon_rep (const idx_colon_rep& idx);
154  };
155 
156  // To distinguish the "direct" constructors that blindly trust the data.
157  enum direct { DIRECT };
158 
159  // The integer range index.
160  class OCTAVE_API idx_range_rep : public idx_base_rep
161  {
162  public:
164  octave_idx_type _step, direct)
165  : idx_base_rep (), start(_start), len(_len), step(_step) { }
166 
168  : start(0), len(0), step(1) { }
169 
170  // Zero-based constructor.
172  octave_idx_type _step);
173 
174  idx_range_rep (const Range&);
175 
177  { return start + i * step; }
178 
180 
181  octave_idx_type length (octave_idx_type) const { return len; }
182 
184  { return len ? std::max (n, (start + 1 + (step < 0 ? 0 : step * (len - 1))))
185  : n; }
186 
187  idx_class_type idx_class (void) const { return class_range; }
188 
189  idx_base_rep *sort_uniq_clone (bool uniq = false);
190 
192 
194  { return start == 0 && step == 1 && len == n; }
195 
197  { return dim_vector (1, len); }
198 
199  octave_idx_type get_start (void) const { return start; }
200 
201  octave_idx_type get_step (void) const { return step; }
202 
203  std::ostream& print (std::ostream& os) const;
204 
205  Range unconvert (void) const;
206 
208 
209  private:
210 
212 
213  // No copying!
214  idx_range_rep (const idx_range_rep& idx);
216 
217  octave_idx_type start, len, step;
218 
219  };
220 
221  // The integer scalar index.
222  class OCTAVE_API idx_scalar_rep : public idx_base_rep
223  {
224  public:
226  : data (i) { }
227 
229  : data (0) { }
230 
231  // Zero-based constructor.
233 
234  template <class T>
235  idx_scalar_rep (T x);
236 
237  octave_idx_type xelem (octave_idx_type) const { return data; }
238 
240 
241  octave_idx_type length (octave_idx_type) const { return 1; }
242 
244  { return std::max (n, data + 1); }
245 
246  idx_class_type idx_class (void) const { return class_scalar; }
247 
249  { count++; return this; }
250 
252 
254  { return n == 1 && data == 0; }
255 
256  dim_vector orig_dimensions (void) const { return dim_vector (1, 1); }
257 
258  octave_idx_type get_data (void) const { return data; }
259 
260  std::ostream& print (std::ostream& os) const;
261 
262  double unconvert (void) const;
263 
265 
266  private:
267 
269 
270  // No copying!
271  idx_scalar_rep (const idx_scalar_rep& idx);
273 
275 
276  };
277 
278  // The integer vector index.
279  class OCTAVE_API idx_vector_rep : public idx_base_rep
280  {
281  public:
282  // Direct constructor.
284  octave_idx_type _ext, const dim_vector& od, direct)
285  : data (_data), len (_len), ext (_ext), aowner (0), orig_dims (od) { }
286 
288  : data (0), len (0), ext (0), aowner (0), orig_dims ()
289  { }
290 
291  // Zero-based constructor.
293 
295  octave_idx_type _ext, direct);
296 
297  template <class T>
298  idx_vector_rep (const Array<T>&);
299 
300  idx_vector_rep (bool);
301 
303 
304  idx_vector_rep (const Sparse<bool>&);
305 
306  ~idx_vector_rep (void);
307 
308  octave_idx_type xelem (octave_idx_type i) const { return data[i]; }
309 
311 
312  octave_idx_type length (octave_idx_type) const { return len; }
313 
315  { return std::max (n, ext); }
316 
317  idx_class_type idx_class (void) const { return class_vector; }
318 
319  idx_base_rep *sort_uniq_clone (bool uniq = false);
320 
322 
323  dim_vector orig_dimensions (void) const { return orig_dims; }
324 
325  const octave_idx_type *get_data (void) const { return data; }
326 
327  std::ostream& print (std::ostream& os) const;
328 
329  Array<double> unconvert (void) const;
330 
332 
333  private:
334 
336 
337  // No copying!
338  idx_vector_rep (const idx_vector_rep& idx);
340 
344 
345  // This is a trick to allow user-given zero-based arrays to be used
346  // as indices without copying. If the following pointer is nonzero,
347  // we do not own the data, but rather have an Array<octave_idx_type>
348  // object that provides us the data. Note that we need a pointer
349  // because we deferred the Array<T> declaration and we do not want
350  // it yet to be defined.
351 
353 
355  };
356 
357  // The logical mask index.
358  class OCTAVE_API idx_mask_rep : public idx_base_rep
359  {
360  public:
361  // Direct constructor.
362  idx_mask_rep (bool *_data, octave_idx_type _len,
363  octave_idx_type _ext, const dim_vector& od, direct)
364  : data (_data), len (_len), ext (_ext), lsti (-1), lste (-1),
365  aowner (0), orig_dims (od) { }
366 
368  : data (0), len (0), ext (0), lsti (-1), lste (-1), aowner (0),
369  orig_dims ()
370  { }
371 
372  idx_mask_rep (bool);
373 
375 
376  ~idx_mask_rep (void);
377 
379 
381 
382  octave_idx_type length (octave_idx_type) const { return len; }
383 
385  { return std::max (n, ext); }
386 
387  idx_class_type idx_class (void) const { return class_mask; }
388 
390  { count++; return this; }
391 
393 
394  dim_vector orig_dimensions (void) const { return orig_dims; }
395 
397  { return len == n && ext == n; }
398 
399  const bool *get_data (void) const { return data; }
400 
401  std::ostream& print (std::ostream& os) const;
402 
403  Array<bool> unconvert (void) const;
404 
406 
407  private:
408 
410 
411  // No copying!
412  idx_mask_rep (const idx_mask_rep& idx);
414 
415  const bool *data;
418 
419  // FIXME: I'm not sure if this is a good design. Maybe it would be
420  // better to employ some sort of generalized iteration scheme.
423 
424  // This is a trick to allow user-given mask arrays to be used as
425  // indices without copying. If the following pointer is nonzero, we
426  // do not own the data, but rather have an Array<bool> object that
427  // provides us the data. Note that we need a pointer because we
428  // deferred the Array<T> declaration and we do not want it yet to be
429  // defined.
430 
432 
434  };
435 
436  idx_vector (idx_base_rep *r) : rep (r) { }
437 
438  // The shared empty vector representation (for fast default
439  // constructor).
440  static idx_vector_rep *nil_rep (void)
441  {
442  static idx_vector_rep ivr;
443  return &ivr;
444  }
445 
446  // The shared empty vector representation with the error flag set.
447  static idx_vector_rep *err_rep (void)
448  {
449  static idx_vector_rep ivr;
450  ivr.err = true;
451  return &ivr;
452  }
453 
454  // If there was an error in constructing the rep, replace it with
455  // empty vector for safety.
456  void chkerr (void)
457  {
458  if (rep->err)
459  {
460  if (--rep->count == 0)
461  delete rep;
462  rep = err_rep ();
463  rep->count++;
464  }
465  }
466 
467 public:
468 
469  // Fast empty constructor.
470  idx_vector (void) : rep (nil_rep ()) { rep->count++; }
471 
472  // Zero-based constructors (for use from C++).
474  { chkerr (); }
475 
477  octave_idx_type step = 1)
478  : rep (new idx_range_rep (start, limit, step))
479  { chkerr (); }
480 
481  static idx_vector
482  make_range (octave_idx_type start, octave_idx_type step,
483  octave_idx_type len)
484  {
485  return idx_vector (new idx_range_rep (start, len, step, DIRECT));
486  }
487 
489  : rep (new idx_vector_rep (inda))
490  { chkerr (); }
491 
492  // Directly pass extent, no checking.
494  : rep (new idx_vector_rep (inda, ext, DIRECT))
495  { }
496 
497  // Colon is best constructed by simply copying (or referencing) this member.
498  static const idx_vector colon;
499 
500  // or passing ':' here
501  idx_vector (char c) : rep (new idx_colon_rep (c)) { chkerr (); }
502 
503  // Conversion constructors (used by interpreter).
504 
505  template <class T>
506  idx_vector (octave_int<T> x) : rep (new idx_scalar_rep (x)) { chkerr (); }
507 
508  idx_vector (double x) : rep (new idx_scalar_rep (x)) { chkerr (); }
509 
510  idx_vector (float x) : rep (new idx_scalar_rep (x)) { chkerr (); }
511 
512  // A scalar bool does not necessarily map to scalar index.
513  idx_vector (bool x) : rep (new idx_mask_rep (x)) { chkerr (); }
514 
515  template <class T>
516  idx_vector (const Array<octave_int<T> >& nda) : rep (new idx_vector_rep (nda))
517  { chkerr (); }
518 
519  idx_vector (const Array<double>& nda) : rep (new idx_vector_rep (nda))
520  { chkerr (); }
521 
522  idx_vector (const Array<float>& nda) : rep (new idx_vector_rep (nda))
523  { chkerr (); }
524 
525  idx_vector (const Array<bool>& nda);
526 
527  idx_vector (const Range& r)
528  : rep (new idx_range_rep (r))
529  { chkerr (); }
530 
531  idx_vector (const Sparse<bool>& nda) : rep (new idx_vector_rep (nda))
532  { chkerr (); }
533 
534  idx_vector (const idx_vector& a) : rep (a.rep) { rep->count++; }
535 
536  ~idx_vector (void)
537  {
538  if (--rep->count == 0)
539  delete rep;
540  }
541 
542  idx_vector& operator = (const idx_vector& a)
543  {
544  if (this != &a)
545  {
546  if (--rep->count == 0)
547  delete rep;
548 
549  rep = a.rep;
550  rep->count++;
551  }
552  return *this;
553  }
554 
555  idx_class_type idx_class (void) const { return rep->idx_class (); }
556 
558  { return rep->length (n); }
559 
561  { return rep->extent (n); }
562 
564  { return rep->xelem (n); }
565 
566  octave_idx_type checkelem (octave_idx_type n) const
567  { return rep->checkelem (n); }
568 
569  octave_idx_type operator () (octave_idx_type n) const
570  {
571 #if defined (BOUNDS_CHECKING)
572  return rep->checkelem (n);
573 #else
574  return rep->xelem (n);
575 #endif
576  }
577 
578  operator bool (void) const
579  { return ! rep->err; }
580 
581  bool is_colon (void) const
582  { return rep->idx_class () == class_colon; }
583 
584  bool is_scalar (void) const
585  { return rep->idx_class () == class_scalar; }
586 
587  bool is_range (void) const
588  { return rep->idx_class () == class_range; }
589 
590  bool is_colon_equiv (octave_idx_type n) const
591  { return rep->is_colon_equiv (n); }
592 
593  idx_vector sorted (bool uniq = false) const
594  { return idx_vector (rep->sort_uniq_clone (uniq)); }
595 
596  idx_vector sorted (Array<octave_idx_type>& sidx) const
597  { return idx_vector (rep->sort_idx (sidx)); }
598 
599  dim_vector orig_dimensions (void) const { return rep->orig_dimensions (); }
600 
601  octave_idx_type orig_rows (void) const
602  { return orig_dimensions () (0); }
603 
604  octave_idx_type orig_columns (void) const
605  { return orig_dimensions () (1); }
606 
607  int orig_empty (void) const
608  { return (! is_colon () && orig_dimensions ().any_zero ()); }
609 
610  // i/o
611 
612  std::ostream& print (std::ostream& os) const { return rep->print (os); }
613 
614  friend std::ostream& operator << (std::ostream& os, const idx_vector& a)
615  { return a.print (os); }
616 
617  // Slice with specializations. No checking of bounds!
618  //
619  // This is equivalent to the following loop (but much faster):
620  //
621  // for (octave_idx_type i = 0; i < idx->length (n); i++)
622  // dest[i] = src[idx(i)];
623  // return i;
624  //
625  template <class T>
627  index (const T *src, octave_idx_type n, T *dest) const
628  {
629  octave_idx_type len = rep->length (n);
630 
631  switch (rep->idx_class ())
632  {
633  case class_colon:
634  copy_or_memcpy (len, src, dest);
635  break;
636 
637  case class_range:
638  {
639  idx_range_rep * r = dynamic_cast<idx_range_rep *> (rep);
640  octave_idx_type start = r->get_start (), step = r->get_step ();
641  const T *ssrc = src + start;
642  if (step == 1)
643  copy_or_memcpy (len, ssrc, dest);
644  else if (step == -1)
645  std::reverse_copy (ssrc - len + 1, ssrc + 1, dest);
646  else if (step == 0)
647  std::fill_n (dest, len, *ssrc);
648  else
649  {
650  for (octave_idx_type i = 0, j = 0; i < len; i++, j += step)
651  dest[i] = ssrc[j];
652  }
653  }
654  break;
655 
656  case class_scalar:
657  {
658  idx_scalar_rep * r = dynamic_cast<idx_scalar_rep *> (rep);
659  dest[0] = src[r->get_data ()];
660  }
661  break;
662 
663  case class_vector:
664  {
665  idx_vector_rep * r = dynamic_cast<idx_vector_rep *> (rep);
666  const octave_idx_type *data = r->get_data ();
667  for (octave_idx_type i = 0; i < len; i++)
668  dest[i] = src[data[i]];
669  }
670  break;
671 
672  case class_mask:
673  {
674  idx_mask_rep * r = dynamic_cast<idx_mask_rep *> (rep);
675  const bool *data = r->get_data ();
676  octave_idx_type ext = r->extent (0);
677  for (octave_idx_type i = 0; i < ext; i++)
678  if (data[i]) *dest++ = src[i];
679  }
680  break;
681 
682  default:
683  assert (false);
684  break;
685  }
686 
687  return len;
688  }
689 
690  // Slice assignment with specializations. No checking of bounds!
691  //
692  // This is equivalent to the following loop (but much faster):
693  //
694  // for (octave_idx_type i = 0; i < idx->length (n); i++)
695  // dest[idx(i)] = src[i];
696  // return i;
697  //
698  template <class T>
700  assign (const T *src, octave_idx_type n, T *dest) const
701  {
702  octave_idx_type len = rep->length (n);
703 
704  switch (rep->idx_class ())
705  {
706  case class_colon:
707  copy_or_memcpy (len, src, dest);
708  break;
709 
710  case class_range:
711  {
712  idx_range_rep * r = dynamic_cast<idx_range_rep *> (rep);
713  octave_idx_type start = r->get_start (), step = r->get_step ();
714  T *sdest = dest + start;
715  if (step == 1)
716  copy_or_memcpy (len, src, sdest);
717  else if (step == -1)
718  std::reverse_copy (src, src + len, sdest - len + 1);
719  else
720  {
721  for (octave_idx_type i = 0, j = 0; i < len; i++, j += step)
722  sdest[j] = src[i];
723  }
724  }
725  break;
726 
727  case class_scalar:
728  {
729  idx_scalar_rep * r = dynamic_cast<idx_scalar_rep *> (rep);
730  dest[r->get_data ()] = src[0];
731  }
732  break;
733 
734  case class_vector:
735  {
736  idx_vector_rep * r = dynamic_cast<idx_vector_rep *> (rep);
737  const octave_idx_type *data = r->get_data ();
738  for (octave_idx_type i = 0; i < len; i++)
739  dest[data[i]] = src[i];
740  }
741  break;
742 
743  case class_mask:
744  {
745  idx_mask_rep * r = dynamic_cast<idx_mask_rep *> (rep);
746  const bool *data = r->get_data ();
747  octave_idx_type ext = r->extent (0);
748  for (octave_idx_type i = 0; i < ext; i++)
749  if (data[i]) dest[i] = *src++;
750  }
751  break;
752 
753  default:
754  assert (false);
755  break;
756  }
757 
758  return len;
759  }
760 
761  // Slice fill with specializations. No checking of bounds!
762  //
763  // This is equivalent to the following loop (but much faster):
764  //
765  // for (octave_idx_type i = 0; i < idx->length (n); i++)
766  // dest[idx(i)] = val;
767  // return i;
768  //
769  template <class T>
771  fill (const T& val, octave_idx_type n, T *dest) const
772  {
773  octave_idx_type len = rep->length (n);
774 
775  switch (rep->idx_class ())
776  {
777  case class_colon:
778  std::fill (dest, dest + len, val);
779  break;
780 
781  case class_range:
782  {
783  idx_range_rep * r = dynamic_cast<idx_range_rep *> (rep);
784  octave_idx_type start = r->get_start (), step = r->get_step ();
785  T *sdest = dest + start;
786  if (step == 1)
787  std::fill (sdest, sdest + len, val);
788  else if (step == -1)
789  std::fill (sdest - len + 1, sdest + 1, val);
790  else
791  {
792  for (octave_idx_type i = 0, j = 0; i < len; i++, j += step)
793  sdest[j] = val;
794  }
795  }
796  break;
797 
798  case class_scalar:
799  {
800  idx_scalar_rep * r = dynamic_cast<idx_scalar_rep *> (rep);
801  dest[r->get_data ()] = val;
802  }
803  break;
804 
805  case class_vector:
806  {
807  idx_vector_rep * r = dynamic_cast<idx_vector_rep *> (rep);
808  const octave_idx_type *data = r->get_data ();
809  for (octave_idx_type i = 0; i < len; i++)
810  dest[data[i]] = val;
811  }
812  break;
813 
814  case class_mask:
815  {
816  idx_mask_rep * r = dynamic_cast<idx_mask_rep *> (rep);
817  const bool *data = r->get_data ();
818  octave_idx_type ext = r->extent (0);
819  for (octave_idx_type i = 0; i < ext; i++)
820  if (data[i]) dest[i] = val;
821  }
822  break;
823 
824  default:
825  assert (false);
826  break;
827  }
828 
829  return len;
830  }
831 
832  // Generic non-breakable indexed loop. The loop body should be
833  // encapsulated in a single functor body. This is equivalent to the
834  // following loop (but faster, at least for simple inlined bodies):
835  //
836  // for (octave_idx_type i = 0; i < idx->length (n); i++) body (idx(i));
837 
838  template <class Functor>
839  void
840  loop (octave_idx_type n, Functor body) const
841  {
842  octave_idx_type len = rep->length (n);
843 
844  switch (rep->idx_class ())
845  {
846  case class_colon:
847  for (octave_idx_type i = 0; i < len; i++) body (i);
848  break;
849 
850  case class_range:
851  {
852  idx_range_rep * r = dynamic_cast<idx_range_rep *> (rep);
853  octave_idx_type start = r->get_start (), step = r->get_step ();
854  octave_idx_type i, j;
855  if (step == 1)
856  for (i = start, j = start + len; i < j; i++) body (i);
857  else if (step == -1)
858  for (i = start, j = start - len; i > j; i--) body (i);
859  else
860  for (i = 0, j = start; i < len; i++, j += step) body (j);
861  }
862  break;
863 
864  case class_scalar:
865  {
866  idx_scalar_rep * r = dynamic_cast<idx_scalar_rep *> (rep);
867  body (r->get_data ());
868  }
869  break;
870 
871  case class_vector:
872  {
873  idx_vector_rep * r = dynamic_cast<idx_vector_rep *> (rep);
874  const octave_idx_type *data = r->get_data ();
875  for (octave_idx_type i = 0; i < len; i++) body (data[i]);
876  }
877  break;
878 
879  case class_mask:
880  {
881  idx_mask_rep * r = dynamic_cast<idx_mask_rep *> (rep);
882  const bool *data = r->get_data ();
883  octave_idx_type ext = r->extent (0);
884  for (octave_idx_type i = 0; i < ext; i++)
885  if (data[i]) body (i);
886  }
887  break;
888 
889  default:
890  assert (false);
891  break;
892  }
893 
894  }
895 
896  // Generic breakable indexed loop. The loop body should be
897  // encapsulated in a single functor body. This is equivalent to the
898  // following loop (but faster, at least for simple inlined bodies):
899  //
900  // for (octave_idx_type i = 0; i < idx->length (n); i++)
901  // if (body (idx(i))) break;
902  // return i;
903  //
904 
905  template <class Functor>
907  bloop (octave_idx_type n, Functor body) const
908  {
909  octave_idx_type len = rep->length (n), ret;
910 
911  switch (rep->idx_class ())
912  {
913  case class_colon:
914  {
915  octave_idx_type i;
916  for (i = 0; i < len && body (i); i++) ;
917  ret = i;
918  }
919  break;
920 
921  case class_range:
922  {
923  idx_range_rep * r = dynamic_cast<idx_range_rep *> (rep);
924  octave_idx_type start = r->get_start (), 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), j = 0;
958  for (octave_idx_type i = 0; i < ext; i++)
959  {
960  if (data[i])
961  {
962  if (body (i))
963  break;
964  else
965  j++;
966  }
967  }
968 
969  ret = j;
970  }
971  break;
972 
973  default:
974  assert (false);
975  break;
976  }
977 
978  return ret;
979  }
980 
981  // Rationale:
982  // This method is the key to "smart indexing". When indexing cartesian
983  // arrays, sometimes consecutive index vectors can be reduced into a
984  // single index. If rows (A) = k and i.maybe_reduce (j) gives k, then
985  // A(i,j)(:) is equal to A(k)(:).
986 
987  // If the next index can be reduced, returns true and updates this.
988  bool maybe_reduce (octave_idx_type n, const idx_vector& j,
989  octave_idx_type nj);
990 
991  bool is_cont_range (octave_idx_type n,
992  octave_idx_type& l, octave_idx_type& u) const;
993 
994  // Returns the increment for ranges and colon, 0 for scalars and empty
995  // vectors, 1st difference otherwise.
996  octave_idx_type increment (void) const;
997 
998  idx_vector
999  complement (octave_idx_type n) const;
1000 
1001  bool is_permutation (octave_idx_type n) const;
1002 
1003  // Returns the inverse permutation. If this is not a permutation on 1:n, the
1004  // result is undefined (but no error unless extent () != n).
1005  idx_vector inverse_permutation (octave_idx_type n) const;
1006 
1007  // Copies all the indices to a given array. Not allowed for colons.
1008  void copy_data (octave_idx_type *data) const;
1009 
1010  // If the index is a mask, convert it to index vector.
1011  idx_vector unmask (void) const;
1012 
1013  // Unconverts the index to a scalar, Range, double array or a mask.
1014  void unconvert (idx_class_type& iclass,
1015  double& scalar, Range& range,
1016  Array<double>& array, Array<bool>& mask) const;
1017 
1018  Array<octave_idx_type> as_array (void) const;
1019 
1020  // Raw pointer to index array. This is non-const because it may be
1021  // necessary to mutate the index.
1022  const octave_idx_type *raw (void);
1023 
1024  bool is_vector (void) const;
1025 
1026  // FIXME: these are here for compatibility. They should be removed
1027  // when no longer in use.
1028 
1030  { return (*this) (n); }
1031 
1032  bool is_colon_equiv (octave_idx_type n, int) const
1033  { return is_colon_equiv (n); }
1034 
1036  freeze (octave_idx_type z_len, const char *tag, bool resize_ok = false);
1037 
1038  void sort (bool uniq = false)
1039  { *this = sorted (uniq); }
1040 
1041  octave_idx_type ones_count (void) const;
1042 
1043  octave_idx_type max (void) const { return extent (1) - 1; }
1044 
1045 private:
1046 
1048 
1049 };
1050 
1051 #endif