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