GNU Octave 10.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
Range.h
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 (octave_Range_h)
27#define octave_Range_h 1
28
29#include "octave-config.h"
30
31#include <iosfwd>
32#include <type_traits>
33
34#include "Array-fwd.h"
35#include "dMatrix.h"
36#include "dim-vector.h"
37#include "lo-error.h"
38#include "oct-sort.h"
39#include "range-fwd.h"
40
42
43// For now, only define for floating point types. However, we only
44// need range<float> as a temporary local variable in make_float_range
45// in ov.cc.
46
47template <typename T>
48class range<T, typename std::enable_if<std::is_floating_point<T>::value>::type>
49{
50public:
51
53 : m_base (0), m_increment (0), m_limit (0), m_final (0), m_numel (0),
54 m_reverse (false)
55 { }
56
57 // LIMIT is an upper limit and may be outside the range of actual
58 // values. For floating point ranges, we perform a tolerant check
59 // to attempt to capture limit in the set of values if it is "close"
60 // to the value of base + a multiple of the increment.
61
62 range (const T& base, const T& increment, const T& limit,
63 bool reverse = false)
64 : m_base (base), m_increment (increment), m_limit (limit),
65 m_final (), m_numel (), m_reverse (reverse)
66 {
67 init ();
68 }
69
70 range (const T& base, const T& limit)
71 : m_base (base), m_increment (1), m_limit (limit), m_final (), m_numel (),
72 m_reverse (false)
73 {
74 init ();
75 }
76
77 // Allow conversion from (presumably) properly constructed Range
78 // objects. The values of base, limit, increment, and numel must be
79 // consistent.
80
81 // FIXME: Actually check that base, limit, increment, and numel are
82 // consistent?
83
84 range (const T& base, const T& increment, const T& limit,
85 octave_idx_type numel, bool reverse = false)
86 : m_base (base), m_increment (increment), m_limit (limit),
87 m_final (limit), m_numel (numel), m_reverse (reverse)
88 { }
89
90 // We don't use a constructor for this because it will conflict with
91 // range<T> (base, limit, increment) when T is octave_idx_type.
92
93 static range<T> make_n_element_range (const T& base, const T& increment,
95 bool reverse = false)
96 {
97 // We could just make this constructor public, but it allows
98 // inconsistent ranges to be constructed. And it is probably much
99 // clearer to see "make_n_element_range" instead of puzzling over the
100 // purpose of this strange constructor form.
101
102 T final_val = (reverse ? base - (numel - 1) * increment
103 : base + (numel - 1) * increment);
104
105 return range<T> (base, increment, final_val, numel, reverse);
106 }
107
108 OCTAVE_DEFAULT_COPY_MOVE_DELETE (range)
109
110 T base () const { return m_base; }
111 T increment () const { return m_increment; }
112 T limit () const { return m_limit; }
113 bool reverse () const { return m_reverse; }
114
115 T final_value () const { return m_final; }
116
117 T min () const
118 {
119 return (m_numel > 0
120 ? ((m_reverse ? m_increment > T (0)
121 : m_increment > T (0)) ? base () : final_value ())
122 : T (0));
123 }
124
125 T max () const
126 {
127 return (m_numel > 0
128 ? ((m_reverse ? m_increment < T (0)
129 : m_increment > T (0)) ? final_value () : base ())
130 : T (0));
131 }
132
133 octave_idx_type numel () const { return m_numel; }
134
135 // To support things like "for i = 1:Inf; ...; end" that are
136 // required for Matlab compatibility, creation of a range object
137 // like 1:Inf is allowed with m_numel set to
138 // numeric_limits<octave_idx_type>::max(). However, it is not
139 // possible to store these ranges. The following function allows
140 // us to easily distinguish ranges with an infinite number of
141 // elements. There are specializations for double and float.
142
143 bool is_storable () const { return true; }
144
145 dim_vector dims () const { return dim_vector (1, m_numel); }
146
147 octave_idx_type rows () const { return 1; }
148
149 octave_idx_type cols () const { return numel (); }
150 octave_idx_type columns () const { return numel (); }
151
152 bool isempty () const { return numel () == 0; }
153
154 bool all_elements_are_ints () const { return true; }
155
157 {
158 if (m_numel > 1 && (m_reverse ? m_increment < T (0)
159 : m_increment > T (0)))
160 mode = ((mode == DESCENDING) ? UNSORTED : ASCENDING);
161 else if (m_numel > 1 && (m_reverse ? m_increment > T (0)
162 : m_increment < T (0)))
163 mode = ((mode == ASCENDING) ? UNSORTED : DESCENDING);
164 else
165 mode = ((mode == UNSORTED) ? ASCENDING : mode);
166
167 return mode;
168 }
169
171
172 // Support for single-index subscripting, without generating matrix cache.
173
175 {
176 if (i < 0 || i >= m_numel)
177 err_index_out_of_range (2, 2, i+1, m_numel, dims ());
178
179 if (i == 0)
180 // Required for proper NaN handling.
181 return (m_numel == 1 ? final_value () : m_base);
182 else if (i < m_numel - 1)
183 return (m_reverse ? m_base + T (i) * m_increment
184 : m_base + T (i) * m_increment);
185 else
186 return final_value ();
187 }
188
190 {
191 // Ranges are *always* row vectors.
192 if (i != 0)
193 err_index_out_of_range (1, 1, i+1, m_numel, dims ());
194
195 return checkelem (j);
196 }
197
199 {
200 if (i == 0)
201 // Required for proper NaN handling.
202 return (m_numel == 1 ? final_value () : m_base);
203 else if (i < m_numel - 1)
204 return (m_reverse ? m_base - T (i) * m_increment
205 : m_base + T (i) * m_increment);
206 else
207 return final_value ();
208 }
209
211 {
212 return elem (j);
213 }
214
215 T operator () (octave_idx_type i) const
216 {
217 return elem (i);
218 }
219
220 T operator () (octave_idx_type i, octave_idx_type j) const
221 {
222 return elem (i, j);
223 }
224
225 Array<T> index (const idx_vector& idx) const
226 {
227 Array<T> retval;
228
229 octave_idx_type n = m_numel;
230
231 if (idx.is_colon ())
232 {
233 retval = array_value ().reshape (dim_vector (m_numel, 1));
234 }
235 else
236 {
237 if (idx.extent (n) != n)
238 err_index_out_of_range (1, 1, idx.extent (n), n, dims ());
239
240 dim_vector idx_dims = idx.orig_dimensions ();
241 octave_idx_type idx_len = idx.length (n);
242
243 // taken from Array.cc.
244 if (n != 1 && idx_dims.isvector ())
245 idx_dims = dim_vector (1, idx_len);
246
247 retval.clear (idx_dims);
248
249 // Loop over all values in IDX, executing the lambda
250 // expression for each index value.
251
252 T *array = retval.rwdata ();
253
254 idx.loop (n, [this, &array] (octave_idx_type i)
255 {
256 if (i == 0)
257 // Required for proper NaN handling.
258 *array++ = (m_numel == 0 ? m_final : m_base);
259 else if (i < m_numel - 1)
260 *array++ = (m_reverse ? m_base - T (i) * m_increment
261 : m_base + T (i) * m_increment);
262 else
263 *array++ = m_final;
264 });
265 }
266
267 return retval;
268 }
269
271 {
272 return array_value ().diag (k);
273 }
274
276 {
277 octave_idx_type nel = numel ();
278
279 Array<T> retval (dim_vector (1, nel));
280
281 if (nel == 1)
282 // Required for proper NaN handling.
283 retval(0) = final_value ();
284 else if (nel > 1)
285 {
286 // The first element must always be *exactly* the base.
287 // E.g, -0 would otherwise become +0 in the loop (-0 + 0*increment).
288 retval(0) = m_base;
289
290 if (m_reverse)
291 for (octave_idx_type i = 1; i < nel - 1; i++)
292 retval.xelem (i) = m_base - i * m_increment;
293 else
294 for (octave_idx_type i = 1; i < nel - 1; i++)
295 retval.xelem (i) = m_base + i * m_increment;
296
297 retval.xelem (nel - 1) = final_value ();
298 }
299
300 return retval;
301 }
302
303private:
304
305 T m_base;
306 T m_increment;
307 T m_limit;
308 T m_final;
309 octave_idx_type m_numel;
310 bool m_reverse;
311
312 // Setting the number of elements to zero when the increment is zero
313 // is intentional and matches the behavior of Matlab's colon
314 // operator.
315
316 // These calculations are appropriate for integer ranges. There are
317 // specializations for double and float.
318
319 void init ()
320 {
321 if (m_reverse)
322 {
323 m_numel = ((m_increment == T (0)
324 || (m_limit > m_base && m_increment > T (0))
325 || (m_limit < m_base && m_increment < T (0)))
326 ? T (0)
327 : (m_base - m_limit - m_increment) / m_increment);
328
329 m_final = m_base - (m_numel - 1) * m_increment;
330 }
331 else
332 {
333 m_numel = ((m_increment == T (0)
334 || (m_limit > m_base && m_increment < T (0))
335 || (m_limit < m_base && m_increment > T (0)))
336 ? T (0)
337 : (m_limit - m_base + m_increment) / m_increment);
338
339 m_final = m_base + (m_numel - 1) * m_increment;
340 }
341 }
342};
343
344// Specializations defined externally.
345
348
349template <> OCTAVE_API void range<double>::init ();
350template <> OCTAVE_API void range<float>::init ();
351
352// For now, only define for floating point types. However, we only
353// need range<float> as a temporary local variable in make_float_range
354// in ov.cc.
355
356template <> OCTAVE_API bool range<double>::is_storable () const;
357template <> OCTAVE_API bool range<float>::is_storable () const;
358
361
362OCTAVE_END_NAMESPACE(octave)
363
364#endif
N Dimensional Array with copy-on-write semantics.
Definition Array.h:130
T & xelem(octave_idx_type n)
Size of the specified dimension.
Definition Array.h:525
void clear()
Array< T, Alloc > reshape(octave_idx_type nr, octave_idx_type nc) const
Size of the specified dimension.
Definition Array.h:636
T * rwdata()
Size of the specified dimension.
Array< T, Alloc > diag(octave_idx_type k=0) const
Get the kth super or subdiagonal.
Vector representing the dimensions (size) of an Array.
Definition dim-vector.h:90
bool isvector() const
Definition dim-vector.h:391
dim_vector orig_dimensions() const
Definition idx-vector.h:556
void loop(octave_idx_type n, Functor body) const
Definition idx-vector.h:815
octave_idx_type length(octave_idx_type n=0) const
Definition idx-vector.h:518
bool is_colon() const
Definition idx-vector.h:538
octave_idx_type extent(octave_idx_type n) const
Definition idx-vector.h:521
range(const T &base, const T &increment, const T &limit, bool reverse=false)
Definition Range.h:62
static range< T > make_n_element_range(const T &base, const T &increment, octave_idx_type numel, bool reverse=false)
Definition Range.h:93
range(const T &base, const T &increment, const T &limit, octave_idx_type numel, bool reverse=false)
Definition Range.h:84
bool is_storable() const
Definition Range.cc:338
octave_idx_type nnz() const
Definition Range.cc:386
void init()
Definition Range.cc:322
bool all_elements_are_ints() const
Definition Range.cc:308
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void err_index_out_of_range(int nd, int dim, octave_idx_type idx, octave_idx_type ext, const dim_vector &dv)
#define OCTAVE_API
Definition main.in.cc:55
sortmode
Definition oct-sort.h:97
@ UNSORTED
Definition oct-sort.h:97
@ ASCENDING
Definition oct-sort.h:97
@ DESCENDING
Definition oct-sort.h:97
T::size_type numel(const T &str)
Definition oct-string.cc:74