GNU Octave 10.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
idx-vector.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 1993-2025 The Octave Project Developers
4//
5// See the file COPYRIGHT.md in the top-level directory of this
6// distribution or <https://octave.org/copyright/>.
7//
8// This file is part of Octave.
9//
10// Octave is free software: you can redistribute it and/or modify it
11// under the terms of the GNU General Public License as published by
12// the Free Software Foundation, either version 3 of the License, or
13// (at your option) any later version.
14//
15// Octave is distributed in the hope that it will be useful, but
16// WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18// GNU General Public License for more details.
19//
20// You should have received a copy of the GNU General Public License
21// along with Octave; see the file COPYING. If not, see
22// <https://www.gnu.org/licenses/>.
23//
24////////////////////////////////////////////////////////////////////////
25
26#if defined (HAVE_CONFIG_H)
27# include "config.h"
28#endif
29
30#include <cinttypes>
31#include <cstdlib>
32
33#include <ostream>
34
35#include "idx-vector.h"
36#include "Array.h"
37#include "Array-util.h"
38#include "Sparse.h"
39#include "Range.h"
40
41#include "oct-locbuf.h"
42#include "lo-error.h"
43#include "lo-mappers.h"
44
46
47OCTAVE_NORETURN static void err_invalid_range ()
48{
49 (*current_liboctave_error_handler) ("invalid range used as index");
50}
51
52OCTAVE_NORETURN static void
53err_index_out_of_range ()
54{
55 (*current_liboctave_error_handler)
56 ("internal error: idx_vector index out of range");
57}
58
59idx_vector::idx_vector_rep *
60idx_vector::nil_rep ()
61{
62 static idx_vector_rep ivr;
63 return &ivr;
64}
65
67idx_vector::idx_base_rep::as_array ()
68{
69 (*current_liboctave_error_handler)
70 ("internal error: as_array not allowed for this index class");
71
72 // Never actually executed, but required to silence compiler warning
73 return Array<octave_idx_type> ();
74}
75
76idx_vector::idx_colon_rep::idx_colon_rep (char c)
77 : idx_base_rep ()
78{
79 if (c != ':')
80 (*current_liboctave_error_handler)
81 ("internal error: invalid character converted to idx_vector; must be ':'");
82}
83
85idx_vector::idx_colon_rep::checkelem (octave_idx_type i) const
86{
87 if (i < 0)
88 err_index_out_of_range ();
89
90 return i;
91}
92
93idx_vector::idx_base_rep *
94idx_vector::idx_colon_rep::sort_idx (Array<octave_idx_type>&)
95{
96 (*current_liboctave_error_handler)
97 ("internal error: idx_colon_rep::sort_idx");
98}
99
100std::ostream&
101idx_vector::idx_colon_rep::print (std::ostream& os) const
102{
103 return os << ':';
104}
105
106idx_vector::idx_range_rep::idx_range_rep (octave_idx_type start,
107 octave_idx_type limit,
108 octave_idx_type step)
109 : idx_base_rep (), m_start(start),
110 // Round length away from zero to catch incomplete intervals
111 m_len (step
112 ? std::max ((limit - start + step - (step > 0 ? 1 : -1)) / step,
113 static_cast<octave_idx_type> (0))
114 : -1),
115 m_step (step)
116{
117 if (m_len < 0)
118 err_invalid_range ();
119 if (m_start < 0)
120 err_invalid_index (m_start);
121 if (m_step < 0 && m_start + (m_len-1)*m_step < 0)
122 err_invalid_index (m_start + (m_len-1)*m_step);
123}
124
125idx_vector::idx_range_rep::idx_range_rep (const range<double>& r)
126 : idx_base_rep (), m_start (0), m_len (r.numel ()), m_step (1)
127{
128 if (m_len < 0)
129 err_invalid_range ();
130
131 if (m_len > 0)
132 {
133 if (r.all_elements_are_ints ())
134 {
135 m_start = static_cast<octave_idx_type> (r.base ()) - 1;
136 m_step = static_cast<octave_idx_type> (r.increment ());
137 if (m_start < 0)
138 err_invalid_index (m_start);
139 if (m_step < 0 && m_start + (m_len - 1)*m_step < 0)
140 err_invalid_index (m_start + (m_len - 1)*m_step);
141 }
142 else
143 {
144 // find first non-integer, then gripe about it
145 double b = r.base ();
146 double inc = r.increment ();
147 err_invalid_index (b != std::trunc (b) ? b : b + inc);
148 }
149 }
150}
151
153idx_vector::idx_range_rep::checkelem (octave_idx_type i) const
154{
155 if (i < 0 || i >= m_len)
156 err_index_out_of_range ();
157
158 return m_start + i*m_step;
159}
160
161idx_vector::idx_base_rep *
162idx_vector::idx_range_rep::sort_uniq_clone (bool)
163{
164 if (m_step < 0)
165 return new idx_range_rep (m_start + (m_len - 1)*m_step, m_len, -m_step, DIRECT);
166 else
167 {
168 m_count++;
169 return this;
170 }
171}
172
173idx_vector::idx_base_rep *
174idx_vector::idx_range_rep::sort_idx (Array<octave_idx_type>& idx)
175{
176 if (m_step < 0 && m_len > 0)
177 {
178 idx.clear (1, m_len);
179 for (octave_idx_type i = 0; i < m_len; i++)
180 idx.xelem (i) = m_len - 1 - i;
181 return new idx_range_rep (m_start + (m_len - 1)*m_step, m_len, -m_step, DIRECT);
182 }
183 else
184 {
185 idx.clear (1, m_len);
186 for (octave_idx_type i = 0; i < m_len; i++)
187 idx.xelem (i) = i;
188 m_count++;
189 return this;
190 }
191}
192
193std::ostream&
194idx_vector::idx_range_rep::print (std::ostream& os) const
195{
196 os << m_start << ':' << m_step << ':' << m_start + m_len *m_step;
197 return os;
198}
199
201idx_vector::idx_range_rep::unconvert () const
202{
204 (static_cast<double> (m_start+1), static_cast<double> (m_step), m_len);
205}
206
208idx_vector::idx_range_rep::as_array ()
209{
210 Array<octave_idx_type> retval (dim_vector (1, m_len));
211 for (octave_idx_type i = 0; i < m_len; i++)
212 retval.xelem (i) = m_start + i*m_step;
213
214 return retval;
215}
216
217inline octave_idx_type
219{
220 if (i <= 0)
221 err_invalid_index (i-1);
222
223 if (ext < i)
224 ext = i;
225
226 return i - 1;
227}
228
229inline octave_idx_type
231{
232 octave_idx_type i = static_cast<octave_idx_type> (x);
233
234 if (static_cast<double> (i) != x)
236
237 return convert_index (i, ext);
238}
239
240inline octave_idx_type
242{
243 return convert_index (static_cast<double> (x), ext);
244}
245
246template <typename T>
247inline octave_idx_type
254
255template <typename T>
256idx_vector::idx_scalar_rep::idx_scalar_rep (T x)
257 : idx_base_rep (), m_data (0)
258{
259 octave_idx_type dummy = 0;
260
261 m_data = convert_index (x, dummy);
262}
263
264idx_vector::idx_scalar_rep::idx_scalar_rep (octave_idx_type i)
265 : idx_base_rep (), m_data (i)
266{
267 if (m_data < 0)
268 err_invalid_index (m_data);
269}
270
272idx_vector::idx_scalar_rep::checkelem (octave_idx_type i) const
273{
274 if (i != 0)
275 err_index_out_of_range ();
276
277 return m_data;
278}
279
280idx_vector::idx_base_rep *
281idx_vector::idx_scalar_rep::sort_idx (Array<octave_idx_type>& idx)
282{
283 idx.clear (1, 1);
284 idx.fill (0);
285 m_count++;
286 return this;
287}
288
289std::ostream&
290idx_vector::idx_scalar_rep::print (std::ostream& os) const
291{
292 return os << m_data;
293}
294
295double
296idx_vector::idx_scalar_rep::unconvert () const
297{
298 return m_data + 1;
299}
300
302idx_vector::idx_scalar_rep::as_array ()
303{
304 return Array<octave_idx_type> (dim_vector (1, 1), m_data);
305}
306
307template <typename T>
308idx_vector::idx_vector_rep::idx_vector_rep (const Array<T>& nda)
309 : idx_base_rep (), m_data (nullptr), m_len (nda.numel ()), m_ext (0),
310 m_aowner (nullptr), m_orig_dims (nda.dims ())
311{
312 if (m_len != 0)
313 {
314 std::unique_ptr<octave_idx_type []> d (new octave_idx_type [m_len]);
315
316 for (octave_idx_type i = 0; i < m_len; i++)
317 d[i] = convert_index (nda.xelem (i), m_ext);
318
319 m_data = d.release ();
320 }
321}
322
323// Note that this makes a shallow copy of the index array.
324
325idx_vector::idx_vector_rep::idx_vector_rep (const Array<octave_idx_type>& inda)
326 : idx_base_rep (), m_data (inda.data ()), m_len (inda.numel ()), m_ext (0),
327 m_aowner (new Array<octave_idx_type> (inda)), m_orig_dims (inda.dims ())
328{
329 if (m_len != 0)
330 {
331 octave_idx_type max = -1;
332 for (octave_idx_type i = 0; i < m_len; i++)
333 {
334 octave_idx_type k = inda.xelem (i);
335 if (k < 0)
337 else if (k > max)
338 max = k;
339 }
340
341 m_ext = max + 1;
342 }
343}
344
345idx_vector::idx_vector_rep::idx_vector_rep (const Array<octave_idx_type>& inda,
346 octave_idx_type ext, direct)
347 : idx_base_rep (), m_data (inda.data ()), m_len (inda.numel ()),
348 m_ext (ext), m_aowner (new Array<octave_idx_type> (inda)),
349 m_orig_dims (inda.dims ())
350{
351 // No checking.
352 if (m_ext < 0)
353 {
354 octave_idx_type max = -1;
355 for (octave_idx_type i = 0; i < m_len; i++)
356 if (m_data[i] > max)
357 max = m_data[i];
358
359 m_ext = max + 1;
360 }
361}
362
363idx_vector::idx_vector_rep::idx_vector_rep (bool b)
364 : idx_base_rep (), m_data (nullptr), m_len (b ? 1 : 0), m_ext (0),
365 m_aowner (nullptr), m_orig_dims (m_len, m_len)
366{
367 if (m_len != 0)
368 {
370 d[0] = 0;
371 m_data = d;
372 m_ext = 1;
373 }
374}
375
376idx_vector::idx_vector_rep::idx_vector_rep (const Array<bool>& bnda,
377 octave_idx_type nnz)
378 : idx_base_rep (), m_data (nullptr), m_len (nnz), m_ext (0),
379 m_aowner (nullptr), m_orig_dims ()
380{
381 if (nnz < 0)
382 m_len = bnda.nnz ();
383
384 const dim_vector dv = bnda.dims ();
385
386 m_orig_dims = dv.make_nd_vector (m_len);
387
388 if (m_len != 0)
389 {
390 octave_idx_type *d = new octave_idx_type [m_len];
391
392 octave_idx_type ntot = bnda.numel ();
393
394 octave_idx_type k = 0;
395 for (octave_idx_type i = 0; i < ntot; i++)
396 if (bnda.xelem (i))
397 d[k++] = i;
398
399 m_data = d;
400
401 m_ext = d[k-1] + 1;
402 }
403}
404
405idx_vector::idx_vector_rep::idx_vector_rep (const Sparse<bool>& bnda)
406 : idx_base_rep (), m_data (nullptr), m_len (bnda.nnz ()), m_ext (0),
407 m_aowner (nullptr), m_orig_dims ()
408{
409 const dim_vector dv = bnda.dims ();
410
411 m_orig_dims = dv.make_nd_vector (m_len);
412
413 if (m_len != 0)
414 {
415 octave_idx_type *d = new octave_idx_type [m_len];
416
417 octave_idx_type k = 0;
418 octave_idx_type nc = bnda.cols ();
419 octave_idx_type nr = bnda.rows ();
420
421 for (octave_idx_type j = 0; j < nc; j++)
422 for (octave_idx_type i = bnda.cidx (j); i < bnda.cidx (j+1); i++)
423 if (bnda.data (i))
424 d[k++] = j * nr + bnda.ridx (i);
425
426 m_data = d;
427
428 m_ext = d[k-1] + 1;
429 }
430}
431
432idx_vector::idx_vector_rep::~idx_vector_rep ()
433{
434 if (m_aowner)
435 delete m_aowner;
436 else
437 delete [] m_data;
438}
439
441idx_vector::idx_vector_rep::checkelem (octave_idx_type n) const
442{
443 if (n < 0 || n >= m_len)
445
446 return xelem (n);
447}
448
449idx_vector::idx_base_rep *
450idx_vector::idx_vector_rep::sort_uniq_clone (bool uniq)
451{
452 if (m_len == 0)
453 {
454 m_count++;
455 return this;
456 }
457
458 // This is wrapped in unique_ptr so that we don't leak on out-of-memory.
459 std::unique_ptr<idx_vector_rep> new_rep
460 (new idx_vector_rep (nullptr, m_len, m_ext, m_orig_dims, DIRECT));
461
462 if (m_ext > m_len*math::log2 (1.0 + m_len))
463 {
464 // Use standard sort via octave_sort.
465 octave_idx_type *new_data = new octave_idx_type [m_len];
466 new_rep->m_data = new_data;
467
468 std::copy_n (m_data, m_len, new_data);
470 lsort.set_compare (ASCENDING);
471 lsort.sort (new_data, m_len);
472
473 if (uniq)
474 {
475 octave_idx_type new_len = std::unique (new_data, new_data + m_len)
476 - new_data;
477 new_rep->m_len = new_len;
478 if (new_rep->m_orig_dims.ndims () == 2 && new_rep->m_orig_dims(0) == 1)
479 new_rep->m_orig_dims = dim_vector (1, new_len);
480 else
481 new_rep->m_orig_dims = dim_vector (new_len, 1);
482 }
483 }
484 else if (uniq)
485 {
486 // Use two-pass bucket sort (only a mask array needed).
487 OCTAVE_LOCAL_BUFFER_INIT (bool, has, m_ext, false);
488 for (octave_idx_type i = 0; i < m_len; i++)
489 has[m_data[i]] = true;
490
491 octave_idx_type new_len = 0;
492 for (octave_idx_type i = 0; i < m_ext; i++)
493 new_len += has[i];
494
495 new_rep->m_len = new_len;
496 if (new_rep->m_orig_dims.ndims () == 2 && new_rep->m_orig_dims(0) == 1)
497 new_rep->m_orig_dims = dim_vector (1, new_len);
498 else
499 new_rep->m_orig_dims = dim_vector (new_len, 1);
500
501 octave_idx_type *new_data = new octave_idx_type [new_len];
502 new_rep->m_data = new_data;
503
504 for (octave_idx_type i = 0, j = 0; i < m_ext; i++)
505 if (has[i])
506 new_data[j++] = i;
507 }
508 else
509 {
510 // Use two-pass bucket sort.
512 for (octave_idx_type i = 0; i < m_len; i++)
513 cnt[m_data[i]]++;
514
515 octave_idx_type *new_data = new octave_idx_type [m_len];
516 new_rep->m_data = new_data;
517
518 for (octave_idx_type i = 0, j = 0; i < m_ext; i++)
519 {
520 for (octave_idx_type k = 0; k < cnt[i]; k++)
521 new_data[j++] = i;
522 }
523 }
524
525 return new_rep.release ();
526}
527
528idx_vector::idx_base_rep *
529idx_vector::idx_vector_rep::sort_idx (Array<octave_idx_type>& idx)
530{
531 // This is wrapped in unique_ptr so that we don't leak on out-of-memory.
532 std::unique_ptr<idx_vector_rep> new_rep
533 (new idx_vector_rep (nullptr, m_len, m_ext, m_orig_dims, DIRECT));
534
535 if (m_ext > m_len*math::log2 (1.0 + m_len))
536 {
537 // Use standard sort via octave_sort.
538 idx.clear (m_orig_dims);
539 octave_idx_type *idx_data = idx.rwdata ();
540 for (octave_idx_type i = 0; i < m_len; i++)
541 idx_data[i] = i;
542
543 octave_idx_type *new_data = new octave_idx_type [m_len];
544 new_rep->m_data = new_data;
545 std::copy_n (m_data, m_len, new_data);
546
548 lsort.set_compare (ASCENDING);
549 lsort.sort (new_data, idx_data, m_len);
550 }
551 else
552 {
553 // Use two-pass bucket sort.
555
556 for (octave_idx_type i = 0; i < m_len; i++)
557 cnt[m_data[i]]++;
558
559 idx.clear (m_orig_dims);
560 octave_idx_type *idx_data = idx.rwdata ();
561
562 octave_idx_type *new_data = new octave_idx_type [m_len];
563 new_rep->m_data = new_data;
564
565 for (octave_idx_type i = 0, k = 0; i < m_ext; i++)
566 {
567 octave_idx_type j = cnt[i];
568 cnt[i] = k;
569 k += j;
570 }
571
572 for (octave_idx_type i = 0; i < m_len; i++)
573 {
574 octave_idx_type j = m_data[i];
575 octave_idx_type k = cnt[j]++;
576 new_data[k] = j;
577 idx_data[k] = i;
578 }
579 }
580
581 return new_rep.release ();
582}
583
584std::ostream&
585idx_vector::idx_vector_rep::print (std::ostream& os) const
586{
587 os << '[';
588
589 for (octave_idx_type i = 0; i < m_len - 1; i++)
590 os << m_data[i] << ',' << ' ';
591
592 if (m_len > 0)
593 os << m_data[m_len-1];
594
595 os << ']';
596
597 return os;
598}
599
601idx_vector::idx_vector_rep::unconvert () const
602{
603 Array<double> retval (m_orig_dims);
604 for (octave_idx_type i = 0; i < m_len; i++)
605 retval.xelem (i) = m_data[i] + 1;
606 return retval;
607}
608
610idx_vector::idx_vector_rep::as_array ()
611{
612 if (m_aowner)
613 return *m_aowner;
614 else
615 {
616 Array<octave_idx_type> retval (m_orig_dims);
617
618 if (m_data)
619 {
620 std::memcpy (retval.rwdata (), m_data, m_len* sizeof (octave_idx_type));
621 // Delete the old copy and share the m_data instead to save memory.
622 delete [] m_data;
623 }
624
625 m_data = retval.rwdata ();
626 m_aowner = new Array<octave_idx_type> (retval);
627
628 return retval;
629 }
630}
631
632idx_vector::idx_mask_rep::idx_mask_rep (bool b)
633 : idx_base_rep (), m_data (nullptr), m_len (b ? 1 : 0), m_ext (0),
634 m_lsti (-1), m_lste (-1), m_aowner (nullptr), m_orig_dims (m_len, m_len)
635{
636 if (m_len != 0)
637 {
638 bool *d = new bool [1];
639 d[0] = true;
640 m_data = d;
641 m_ext = 1;
642 }
643}
644
645idx_vector::idx_mask_rep::idx_mask_rep (const Array<bool>& bnda,
646 octave_idx_type nnz)
647 : idx_base_rep (), m_data (nullptr), m_len (nnz), m_ext (bnda.numel ()),
648 m_lsti (-1), m_lste (-1), m_aowner (nullptr), m_orig_dims ()
649{
650 if (nnz < 0)
651 m_len = bnda.nnz ();
652
653 // We truncate the extent as much as possible. For Matlab
654 // compatibility, but maybe it's not a bad idea anyway.
655 while (m_ext > 0 && ! bnda(m_ext-1))
656 m_ext--;
657
658 const dim_vector dv = bnda.dims ();
659
660 m_orig_dims = dv.make_nd_vector (m_len);
661
662 m_aowner = new Array<bool> (bnda);
663 m_data = bnda.data ();
664}
665
666idx_vector::idx_mask_rep::~idx_mask_rep ()
667{
668 if (m_aowner)
669 delete m_aowner;
670 else
671 delete [] m_data;
672}
673
675idx_vector::idx_mask_rep::xelem (octave_idx_type n) const
676{
677 if (n == m_lsti + 1)
678 {
679 m_lsti = n;
680 while (! m_data[++m_lste]) ;
681 }
682 else
683 {
684 m_lsti = n++;
685 m_lste = -1;
686 while (n > 0)
687 if (m_data[++m_lste]) --n;
688 }
689 return m_lste;
690}
691
693idx_vector::idx_mask_rep::checkelem (octave_idx_type n) const
694{
695 if (n < 0 || n >= m_len)
697
698 return xelem (n);
699}
700
701std::ostream&
702idx_vector::idx_mask_rep::print (std::ostream& os) const
703{
704 os << '[';
705
706 for (octave_idx_type i = 0; i < m_ext - 1; i++)
707 os << m_data[i] << ',' << ' ';
708
709 if (m_ext > 0)
710 os << m_data[m_ext-1];
711
712 os << ']';
713
714 return os;
715}
716
718idx_vector::idx_mask_rep::unconvert () const
719{
720 if (m_aowner)
721 return *m_aowner;
722 else
723 {
724 Array<bool> retval (dim_vector (m_ext, 1));
725 for (octave_idx_type i = 0; i < m_ext; i++)
726 retval.xelem (i) = m_data[i];
727 return retval;
728 }
729}
730
732idx_vector::idx_mask_rep::as_array ()
733{
734 if (m_aowner)
735 return m_aowner->find ().reshape (m_orig_dims);
736 else
737 {
738 Array<bool> retval (m_orig_dims);
739 for (octave_idx_type i = 0, j = 0; i < m_ext; i++)
740 if (m_data[i])
741 retval.xelem (j++) = i;
742
743 return retval;
744 }
745}
746
747idx_vector::idx_base_rep *
748idx_vector::idx_mask_rep::sort_idx (Array<octave_idx_type>& idx)
749{
750 idx.clear (m_len, 1);
751 for (octave_idx_type i = 0; i < m_len; i++)
752 idx.xelem (i) = i;
753
754 m_count++;
755 return this;
756}
757
758const idx_vector idx_vector::colon (new idx_vector::idx_colon_rep ());
759
760idx_vector::idx_vector (const Array<bool>& bnda)
761 : m_rep (nullptr)
762{
763 // Convert only if it means saving at least half the memory.
764 static constexpr int factor = (2 * sizeof (octave_idx_type));
765 octave_idx_type nnz = bnda.nnz ();
766 if (nnz <= bnda.numel () / factor)
767 m_rep = new idx_vector_rep (bnda, nnz);
768 else
769 m_rep = new idx_mask_rep (bnda, nnz);
770}
771
772bool
775{
776 bool reduced = false;
777
778 // Empty index always reduces.
779 if (m_rep->length (n) == 0)
780 {
781 *this = idx_vector ();
782 return true;
783 }
784
785 // Possibly skip singleton dims.
786 if (n == 1 && m_rep->is_colon_equiv (n))
787 {
788 *this = j;
789 return true;
790 }
791
792 if (nj == 1 && j.is_colon_equiv (nj))
793 return true;
794
795 switch (j.idx_class ())
796 {
797 case class_colon:
798 switch (m_rep->idx_class ())
799 {
800 case class_colon:
801 // (:,:) reduces to (:)
802 reduced = true;
803 break;
804
805 case class_scalar:
806 {
807 // (i,:) reduces to a range.
808 idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (m_rep);
809 octave_idx_type k = r->get_data ();
810 *this = new idx_range_rep (k, nj, n, DIRECT);
811 reduced = true;
812 }
813 break;
814
815 case class_range:
816 {
817 // (i:k:end,:) reduces to a range if i <= k and k divides n.
818 idx_range_rep *r = dynamic_cast<idx_range_rep *> (m_rep);
819 octave_idx_type s = r->get_start ();
820 octave_idx_type l = r->length (n);
821 octave_idx_type t = r->get_step ();
822 if (l*t == n)
823 {
824 *this = new idx_range_rep (s, l * nj, t, DIRECT);
825 reduced = true;
826 }
827 }
828 break;
829
830 default:
831 break;
832 }
833 break;
834
835 case class_range:
836 switch (m_rep->idx_class ())
837 {
838 case class_colon:
839 {
840 // (:,i:j) reduces to a range (the m_step must be 1)
841 idx_range_rep *rj = dynamic_cast<idx_range_rep *> (j.m_rep);
842 if (rj->get_step () == 1)
843 {
844 octave_idx_type sj = rj->get_start ();
845 octave_idx_type lj = rj->length (nj);
846 *this = new idx_range_rep (sj * n, lj * n, 1, DIRECT);
847 reduced = true;
848 }
849 }
850 break;
851
852 case class_scalar:
853 {
854 // (k,i:d:j) reduces to a range.
855 idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (m_rep);
856 idx_range_rep *rj = dynamic_cast<idx_range_rep *> (j.m_rep);
857 octave_idx_type k = r->get_data ();
858 octave_idx_type sj = rj->get_start ();
859 octave_idx_type lj = rj->length (nj);
860 octave_idx_type tj = rj->get_step ();
861 *this = new idx_range_rep (n * sj + k, lj, n * tj, DIRECT);
862 reduced = true;
863 }
864 break;
865
866 case class_range:
867 {
868 // (i:k:end,p:q) reduces to a range if i <= k and k divides n.
869 // (ones (1, m), ones (1, n)) reduces to (ones (1, m*n))
870 idx_range_rep *r = dynamic_cast<idx_range_rep *> (m_rep);
871 octave_idx_type s = r->get_start ();
872 octave_idx_type l = r->length (n);
873 octave_idx_type t = r->get_step ();
874 idx_range_rep *rj = dynamic_cast<idx_range_rep *> (j.m_rep);
875 octave_idx_type sj = rj->get_start ();
876 octave_idx_type lj = rj->length (nj);
877 octave_idx_type tj = rj->get_step ();
878 if ((l*t == n && tj == 1) || (t == 0 && tj == 0))
879 {
880 *this = new idx_range_rep (s + n * sj, l * lj, t, DIRECT);
881 reduced = true;
882 }
883 }
884 break;
885
886 default:
887 break;
888 }
889 break;
890
891 case class_scalar:
892 switch (m_rep->idx_class ())
893 {
894 case class_scalar:
895 {
896 // (i,j) reduces to a single index.
897 idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (m_rep);
898 idx_scalar_rep *rj = dynamic_cast<idx_scalar_rep *> (j.m_rep);
899 octave_idx_type k = r->get_data () + n * rj->get_data ();
900 *this = new idx_scalar_rep (k, DIRECT);
901 reduced = true;
902 }
903 break;
904
905 case class_range:
906 {
907 // (i:d:j,k) reduces to a range.
908 idx_range_rep *r = dynamic_cast<idx_range_rep *> (m_rep);
909 idx_scalar_rep *rj = dynamic_cast<idx_scalar_rep *> (j.m_rep);
910 octave_idx_type s = r->get_start ();
911 octave_idx_type l = r->length (nj);
912 octave_idx_type t = r->get_step ();
913 octave_idx_type k = rj->get_data ();
914 *this = new idx_range_rep (n * k + s, l, t, DIRECT);
915 reduced = true;
916 }
917 break;
918
919 case class_colon:
920 {
921 // (:,k) reduces to a range.
922 idx_scalar_rep *rj = dynamic_cast<idx_scalar_rep *> (j.m_rep);
923 octave_idx_type k = rj->get_data ();
924 *this = new idx_range_rep (n * k, n, 1, DIRECT);
925 reduced = true;
926 }
927 break;
928
929 default:
930 break;
931 }
932 break;
933
934 default:
935 break;
936 }
937
938 return reduced;
939}
940
941bool
943 octave_idx_type& u) const
944{
945 bool res = false;
946
947 switch (m_rep->idx_class ())
948 {
949 case class_colon:
950 l = 0; u = n;
951 res = true;
952 break;
953
954 case class_range:
955 {
956 idx_range_rep *r = dynamic_cast<idx_range_rep *> (m_rep);
957 if (r->get_step () == 1)
958 {
959 l = r->get_start ();
960 u = l + r->length (n);
961 res = true;
962 }
963 }
964 break;
965
966 case class_scalar:
967 {
968 idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (m_rep);
969 l = r->get_data ();
970 u = l + 1;
971 res = true;
972 }
973 break;
974
975 case class_mask:
976 {
977 idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (m_rep);
978 octave_idx_type m_ext = r->extent (0);
979 octave_idx_type m_len = r->length (0);
980 if (m_ext == m_len)
981 {
982 l = 0;
983 u = m_len;
984 res = true;
985 }
986 }
987
988 default:
989 break;
990 }
991
992 return res;
993}
994
997{
998 octave_idx_type retval = 0;
999
1000 switch (m_rep->idx_class ())
1001 {
1002 case class_colon:
1003 retval = 1;
1004 break;
1005
1006 case class_range:
1007 retval = dynamic_cast<idx_range_rep *> (m_rep) -> get_step ();
1008 break;
1009
1010 case class_vector:
1011 case class_mask:
1012 {
1013 if (length (0) > 1)
1014 retval = elem (1) - elem (0);
1015 }
1016 break;
1017
1018 default:
1019 break;
1020 }
1021
1022 return retval;
1023}
1024
1025const octave_idx_type *
1027{
1028 if (m_rep->idx_class () != class_vector)
1029 *this = idx_vector (as_array (), extent (0));
1030
1031 idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (m_rep);
1032
1033 liboctave_panic_unless (r != nullptr);
1034
1035 return r->get_data ();
1036}
1037
1038void
1040{
1041 octave_idx_type m_len = m_rep->length (0);
1042
1043 switch (m_rep->idx_class ())
1044 {
1045 case class_invalid:
1046 (*current_liboctave_error_handler) ("unexpected: invalid index");
1047 break;
1048
1049 case class_colon:
1050 (*current_liboctave_error_handler) ("colon not allowed");
1051 break;
1052
1053 case class_range:
1054 {
1055 idx_range_rep *r = dynamic_cast<idx_range_rep *> (m_rep);
1056 octave_idx_type m_start = r->get_start ();
1057 octave_idx_type m_step = r->get_step ();
1058 octave_idx_type i, j;
1059 if (m_step == 1)
1060 for (i = m_start, j = m_start + m_len; i < j; i++) *m_data++ = i;
1061 else if (m_step == -1)
1062 for (i = m_start, j = m_start - m_len; i > j; i--) *m_data++ = i;
1063 else
1064 for (i = 0, j = m_start; i < m_len; i++, j += m_step) *m_data++ = j;
1065 }
1066 break;
1067
1068 case class_scalar:
1069 {
1070 idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (m_rep);
1071 *m_data = r->get_data ();
1072 }
1073 break;
1074
1075 case class_vector:
1076 {
1077 idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (m_rep);
1078 const octave_idx_type *rdata = r->get_data ();
1079 std::copy_n (rdata, m_len, m_data);
1080 }
1081 break;
1082
1083 case class_mask:
1084 {
1085 idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (m_rep);
1086 const bool *mask = r->get_data ();
1087 octave_idx_type m_ext = r->extent (0);
1088 for (octave_idx_type i = 0, j = 0; i < m_ext; i++)
1089 if (mask[i])
1090 m_data[j++] = i;
1091 }
1092 break;
1093
1094 // We should have handled all possible enum values above. Rely on
1095 // compiler diagnostics to warn if we haven't. For example, GCC's
1096 // -Wswitch option, enabled by -Wall, will provide a warning.
1097 }
1098}
1099
1102{
1103 idx_vector retval;
1104 if (extent (n) > n)
1105 (*current_liboctave_error_handler)
1106 ("internal error: out of range complement index requested");
1107
1108 if (idx_class () == class_mask)
1109 {
1110 idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (m_rep);
1111 octave_idx_type nz = r->length (0);
1112 octave_idx_type m_ext = r->extent (0);
1113 Array<bool> mask (dim_vector (n, 1));
1114 const bool *m_data = r->get_data ();
1115 bool *ndata = mask.rwdata ();
1116 for (octave_idx_type i = 0; i < m_ext; i++)
1117 ndata[i] = ! m_data[i];
1118 std::fill_n (ndata + m_ext, n - m_ext, true);
1119 retval = new idx_mask_rep (mask, n - nz);
1120 }
1121 else
1122 {
1123 Array<bool> mask (dim_vector (n, 1), true);
1124 fill (false, length (n), mask.rwdata ());
1125 retval = idx_vector (mask);
1126 }
1127
1128 return retval;
1129}
1130
1131bool
1133{
1134 bool retval = false;
1135
1136 if (is_colon_equiv (n))
1137 retval = true;
1138 else if (length(n) == n && extent(n) == n)
1139 {
1140 OCTAVE_LOCAL_BUFFER_INIT (bool, left, n, true);
1141
1142 retval = true;
1143
1144 for (octave_idx_type i = 0, m_len = length (); i < m_len; i++)
1145 {
1146 octave_idx_type k = xelem (i);
1147 if (left[k])
1148 left[k] = false;
1149 else
1150 {
1151 retval = false;
1152 break;
1153 }
1154 }
1155 }
1156
1157 return retval;
1158}
1159
1162{
1163 liboctave_panic_unless (n == length (n));
1164
1165 idx_vector retval;
1166
1167 switch (idx_class ())
1168 {
1169 case class_range:
1170 {
1171 if (increment () == -1)
1172 retval = sorted ();
1173 else
1174 retval = *this;
1175 break;
1176 }
1177 case class_vector:
1178 {
1179 idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (m_rep);
1180 const octave_idx_type *ri = r->get_data ();
1182 for (octave_idx_type i = 0; i < n; i++)
1183 idx.xelem (ri[i]) = i;
1184 retval = new idx_vector_rep (idx, r->extent (0), DIRECT);
1185 break;
1186 }
1187 default:
1188 retval = *this;
1189 break;
1190 }
1191
1192 return retval;
1193}
1194
1197{
1198 if (idx_class () == class_mask)
1199 {
1200 idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (m_rep);
1201 const bool *m_data = r->get_data ();
1202 octave_idx_type m_ext = r->extent (0);
1203 octave_idx_type m_len = r->length (0);
1204 octave_idx_type *idata = new octave_idx_type [m_len];
1205
1206 for (octave_idx_type i = 0, j = 0; i < m_ext; i++)
1207 if (m_data[i])
1208 idata[j++] = i;
1209
1210 m_ext = (m_len > 0 ? idata[m_len - 1] + 1 : 0);
1211
1212 return new idx_vector_rep (idata, m_len, m_ext, r->orig_dimensions (),
1213 DIRECT);
1214 }
1215 else
1216 return *this;
1217}
1218
1219void
1221 double& scalar, range<double>& range,
1222 Array<double>& array, Array<bool>& mask) const
1223{
1224 iclass = idx_class ();
1225 switch (iclass)
1226 {
1227 case class_invalid:
1228 (*current_liboctave_error_handler) ("unexpected: invalid index");
1229 break;
1230
1231 case class_colon:
1232 break;
1233
1234 case class_range:
1235 {
1236 idx_range_rep *r = dynamic_cast<idx_range_rep *> (m_rep);
1237 range = r->unconvert ();
1238 }
1239 break;
1240
1241 case class_scalar:
1242 {
1243 idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (m_rep);
1244 scalar = r->unconvert ();
1245 }
1246 break;
1247
1248 case class_vector:
1249 {
1250 idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (m_rep);
1251 array = r->unconvert ();
1252 }
1253 break;
1254
1255 case class_mask:
1256 {
1257 idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (m_rep);
1258 mask = r->unconvert ();
1259 }
1260 break;
1261
1262 // We should have handled all possible enum values above. Rely on
1263 // compiler diagnostics to warn if we haven't. For example, GCC's
1264 // -Wswitch option, enabled by -Wall, will provide a warning.
1265 }
1266}
1267
1270{
1271 return m_rep->as_array ();
1272}
1273
1274bool
1276{
1277 return idx_class () != class_vector || orig_dimensions ().isvector ();
1278}
1279
1281idx_vector::freeze (octave_idx_type z_len, const char *, bool resize_ok)
1282{
1283 if (! resize_ok && extent (z_len) > z_len)
1284 (*current_liboctave_error_handler)
1285 ("invalid matrix index = %" OCTAVE_IDX_TYPE_FORMAT, extent (z_len));
1286
1287 return length (z_len);
1288}
1289
1292{
1293 octave_idx_type n = 0;
1294
1295 if (is_colon ())
1296 n = 1;
1297 else
1298 {
1299 for (octave_idx_type i = 0; i < length (1); i++)
1300 if (xelem (i) == 0)
1301 n++;
1302 }
1303
1304 return n;
1305}
1306
1307// Instantiate the octave_int constructors we want.
1308#define INSTANTIATE_SCALAR_VECTOR_REP_CONST(T) \
1309 template OCTAVE_API idx_vector::idx_scalar_rep::idx_scalar_rep (T); \
1310 template OCTAVE_API idx_vector::idx_vector_rep::idx_vector_rep (const Array<T>&);
1311
1322
1323OCTAVE_END_NAMESPACE(octave)
1324
1325/*
1326
1327%!error id=Octave:index-out-of-bounds 1(find ([1,1] != 0))
1328%!assert ((1:3)(find ([1,0,1] != 0)), [1,3])
1329
1330*/
charNDArray max(char d, const charNDArray &m)
Definition chNDArray.cc:230
N Dimensional Array with copy-on-write semantics.
Definition Array.h:130
const dim_vector & dims() const
Return a const-reference so that dims ()(i) works efficiently.
Definition Array.h:507
T & xelem(octave_idx_type n)
Size of the specified dimension.
Definition Array.h:525
void clear()
octave_idx_type nnz() const
Count nonzero elements.
Array< octave_idx_type > find(octave_idx_type n=-1, bool backward=false) const
Find indices of (at most n) nonzero elements.
Array< T, Alloc > reshape(octave_idx_type nr, octave_idx_type nc) const
Size of the specified dimension.
Definition Array.h:636
const T * data() const
Size of the specified dimension.
Definition Array.h:665
T * rwdata()
Size of the specified dimension.
void fill(const T &val)
Definition Array-base.cc:96
octave_idx_type numel() const
Number of elements in the array.
Definition Array.h:418
octave_idx_type cols() const
Definition Sparse.h:349
octave_idx_type * cidx()
Definition Sparse.h:593
T * data()
Definition Sparse.h:571
octave_idx_type * ridx()
Definition Sparse.h:580
octave_idx_type rows() const
Definition Sparse.h:348
dim_vector dims() const
Definition Sparse.h:368
Vector representing the dimensions (size) of an Array.
Definition dim-vector.h:90
bool isvector() const
Definition dim-vector.h:391
dim_vector make_nd_vector(octave_idx_type n) const
Definition dim-vector.h:417
idx_vector unmask() const
octave_idx_type xelem(octave_idx_type n) const
Definition idx-vector.h:524
idx_class_type idx_class() const
Definition idx-vector.h:516
octave_idx_type ones_count() const
idx_vector sorted(bool uniq=false) const
Definition idx-vector.h:550
octave_idx_type fill(const T &val, octave_idx_type n, T *dest) const
Definition idx-vector.h:740
static const idx_vector colon
Definition idx-vector.h:464
dim_vector orig_dimensions() const
Definition idx-vector.h:556
bool maybe_reduce(octave_idx_type n, const idx_vector &j, octave_idx_type nj)
void copy_data(octave_idx_type *data) const
void unconvert(idx_class_type &iclass, double &scalar, range< double > &range, Array< double > &array, Array< bool > &mask) const
octave_idx_type length(octave_idx_type n=0) const
Definition idx-vector.h:518
octave_idx_type elem(octave_idx_type n) const
octave_idx_type freeze(octave_idx_type z_len, const char *tag, bool resize_ok=false)
bool is_cont_range(octave_idx_type n, octave_idx_type &l, octave_idx_type &u) const
idx_vector complement(octave_idx_type n) const
Array< octave_idx_type > as_array() const
bool is_permutation(octave_idx_type n) const
bool isvector() const
idx_vector inverse_permutation(octave_idx_type n) const
bool is_colon() const
Definition idx-vector.h:538
octave_idx_type increment() const
octave_idx_type extent(octave_idx_type n) const
Definition idx-vector.h:521
const octave_idx_type * raw()
bool is_colon_equiv(octave_idx_type n) const
Definition idx-vector.h:547
T value() const
void set_compare(const compare_fcn_type &comp)
Definition oct-sort.h:115
void sort(T *data, octave_idx_type nel)
Definition oct-sort.cc:1521
bool all_elements_are_ints() const
Definition Range.cc:308
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
#define INSTANTIATE_SCALAR_VECTOR_REP_CONST(T)
octave_idx_type convert_index(octave_idx_type i, octave_idx_type &ext)
void err_invalid_index(const std::string &idx, octave_idx_type nd, octave_idx_type dim, const std::string &)
#define liboctave_panic_unless(cond)
Definition lo-error.h:102
F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE * d
F77_RET_T const F77_DBLE * x
#define OCTAVE_LOCAL_BUFFER_INIT(T, buf, size, value)
Definition oct-locbuf.h:50
@ ASCENDING
Definition oct-sort.h:97
T::size_type numel(const T &str)
Definition oct-string.cc:74