forked from starkware-libs/cairo
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrange.cairo
More file actions
320 lines (286 loc) · 9.31 KB
/
Copy pathrange.cairo
File metadata and controls
320 lines (286 loc) · 9.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
//! Range and iteration utilities.
//!
//! This module provides functionality for creating and iterating over ranges of values.
//! A range represents an interval of values from a start point to an end point.
//!
//! # Range Operator Forms
//!
//! There are currently two range operator forms:
//! `start..end`, representing a range from `start` (inclusive) to `end` (exclusive).
//! `start..=end`, representing a range from `start` (inclusive) to `end` (inclusive).
use core::iter::{IntoIterator, Iterator};
use core::num::traits::One;
use core::traits::Add;
/// A (half-open) range bounded inclusively below and exclusively above
/// (`start..end`).
///
/// The range `start..end` contains all values with `start <= x < end`.
/// It is empty if `start >= end`.
///
/// # Examples
///
/// The `start..end` syntax is a `Range`:
///
/// ```
/// assert!((3..5) == core::ops::Range { start: 3, end: 5 });
///
/// let mut sum = 0;
/// for i in 3..6 {
/// sum += i;
/// }
/// assert!(sum == 3 + 4 + 5);
/// ```
#[derive(Clone, Drop, PartialEq)]
pub struct Range<T> {
/// The lower bound of the range (inclusive).
pub start: T,
/// The upper bound of the range (exclusive).
pub end: T,
}
#[generate_trait]
pub impl RangeImpl<T, +Destruct<T>, +PartialOrd<@T>> of RangeTrait<T> {
/// Returns `true` if `item` is contained in the range.
///
/// # Examples
///
/// ```
/// assert!(!(3..5).contains(@2));
/// assert!( (3..5).contains(@3));
/// assert!( (3..5).contains(@4));
/// assert!(!(3..5).contains(@5));
///
/// assert!(!(3..3).contains(@3));
/// assert!(!(3..2).contains(@3));
/// ```
fn contains(self: @Range<T>, item: @T) -> bool {
@self.start <= item && item < @self.end
}
/// Returns `true` if the range contains no items.
///
/// # Examples
///
/// ```
/// assert!(!(3_u8..5_u8).is_empty());
/// assert!( (3_u8..3_u8).is_empty());
/// assert!( (3_u8..2_u8).is_empty());
/// ```
#[inline]
fn is_empty(self: @Range<T>) -> bool {
!(@self.start < @self.end)
}
}
impl RangeDebug<T, impl TDebug: crate::fmt::Debug<T>> of crate::fmt::Debug<Range<T>> {
fn fmt(self: @Range<T>, ref f: crate::fmt::Formatter) -> Result<(), crate::fmt::Error> {
self.start.fmt(ref f)?;
write!(f, "..")?;
self.end.fmt(ref f)?;
Ok(())
}
}
/// Handles the range binary operator (`..`).
/// Used by the compiler to create a `Range` from the given `start` (inclusive) and `end`
/// (exclusive) values.
pub trait RangeOp<T> {
fn range(start: T, end: T) -> Range<T>;
}
impl RangeOpImpl<T> of RangeOp<T> {
fn range(start: T, end: T) -> Range<T> {
Range { start, end }
}
}
/// Represents an iterator located at `cur`, whose end is `end` (`cur <= end`).
#[derive(Clone, Drop, PartialEq)]
pub struct RangeIterator<T> {
/// The current value of the iterator.
cur: T,
/// The upper bound of the range (exclusive).
end: T,
}
impl RangeIteratorImpl<
T, impl OneT: One<T>, +Add<T>, +Copy<T>, +Drop<T>, +PartialEq<T>,
> of Iterator<RangeIterator<T>> {
type Item = T;
fn next(ref self: RangeIterator<T>) -> Option<T> {
if self.cur != self.end {
let value = self.cur;
self.cur = value + OneT::one();
Some(value)
} else {
None
}
}
}
impl RangeIntoIterator<
T,
+One<T>,
+Add<T>,
+Copy<T>,
+Drop<T>,
+PartialEq<T>,
+PartialOrd<T>,
-SierraIntRangeSupport<T>,
> of IntoIterator<Range<T>> {
type IntoIter = RangeIterator<T>;
fn into_iter(self: Range<T>) -> Self::IntoIter {
let start = self.start;
let end = self.end;
if start < end {
Self::IntoIter { cur: start, end }
} else {
// Invalid range, return an empty range.
Self::IntoIter { cur: end, end }
}
}
}
/// Represents the range [start, end].
#[derive(Clone, Drop, PartialEq)]
pub struct RangeInclusive<T> {
/// The lower bound of the range (inclusive).
pub start: T,
/// The upper bound of the range (inclusive).
pub end: T,
}
#[derive(Clone, Drop)]
pub struct RangeInclusiveIterator<T> {
/// The current value of the iterator.
pub(crate) cur: T,
/// The upper bound of the range (inclusive).
pub(crate) end: T,
// This field is:
// - `false` upon construction
// - `false` when iteration has yielded an element and the iterator is not exhausted
// - `true` when iteration has been used to exhaust the iterator
//
// This is required to differentiate between the last element and the end of the range.
pub(crate) exhausted: bool,
}
/// Handles the range inclusive operator (`..=`).
pub trait RangeInclusiveOp<T> {
/// Handles the `..=` operator. Returns the value of the expression `start..=end`.
fn range_inclusive(start: T, end: T) -> RangeInclusive<T>;
}
impl RangeInclusiveOpImpl<T> of RangeInclusiveOp<T> {
fn range_inclusive(start: T, end: T) -> RangeInclusive<T> {
RangeInclusive { start, end }
}
}
#[generate_trait]
pub impl RangeInclusiveImpl<T, +Destruct<T>, +PartialOrd<@T>> of RangeInclusiveTrait<T> {
/// Returns `true` if `item` is contained in the range.
///
/// # Examples
///
/// ```
/// assert!(!(3..=5).contains(@2));
/// assert!( (3..=5).contains(@3));
/// assert!( (3..=5).contains(@4));
/// assert!( (3..=5).contains(@5));
/// assert!(!(3..=5).contains(@6));
///
/// assert!( (3..=3).contains(@3));
/// assert!(!(3..=2).contains(@3));
/// ```
fn contains(self: @RangeInclusive<T>, item: @T) -> bool {
@self.start <= item && item <= @self.end
}
/// Returns `true` if the range contains no items.
///
/// # Examples
///
/// ```
/// assert!(!(3_u8..=5_u8).is_empty());
/// assert!(!(3_u8..=3_u8).is_empty());
/// assert!( (3_u8..=2_u8).is_empty());
/// ```
#[inline]
fn is_empty(self: @RangeInclusive<T>) -> bool {
@self.start > @self.end
}
}
impl RangeInclusiveDebug<
T, impl TDebug: crate::fmt::Debug<T>,
> of crate::fmt::Debug<RangeInclusive<T>> {
fn fmt(
self: @RangeInclusive<T>, ref f: crate::fmt::Formatter,
) -> Result<(), crate::fmt::Error> {
self.start.fmt(ref f)?;
write!(f, "..=")?;
self.end.fmt(ref f)?;
Ok(())
}
}
impl RangeInclusiveIteratorImpl<
T, +One<T>, +Add<T>, +Copy<T>, +Drop<T>, +PartialEq<T>, +PartialOrd<T>,
> of Iterator<RangeInclusiveIterator<T>> {
type Item = T;
fn next(ref self: RangeInclusiveIterator<T>) -> Option<T> {
if self.exhausted {
return None;
}
let current = self.cur;
// If this is the last element, mark as exhausted for next iteration
if current == self.end {
self.exhausted = true;
return Some(current);
}
// We know current < self.end here, because the iterator is not exhausted
self.cur = current + One::one();
Some(current)
}
}
pub impl RangeInclusiveIntoIterator<
T, +One<T>, +Add<T>, +Copy<T>, +Drop<T>, +PartialEq<T>, +PartialOrd<T>,
> of IntoIterator<RangeInclusive<T>> {
type IntoIter = RangeInclusiveIterator<T>;
fn into_iter(self: RangeInclusive<T>) -> Self::IntoIter {
let exhausted = self.start > self.end;
Self::IntoIter { cur: self.start, end: self.end, exhausted }
}
}
// Sierra optimization.
mod internal {
use core::internal::OptionRev;
use core::iter::Iterator;
pub extern type IntRange<T>;
impl IntRangeCopy<T> of Copy<IntRange<T>>;
impl IntRangeDrop<T> of Drop<IntRange<T>>;
pub extern fn int_range_try_new<T>(
x: T, y: T,
) -> Result<IntRange<T>, IntRange<T>> implicits(core::RangeCheck) nopanic;
pub extern fn int_range_pop_front<T>(range: IntRange<T>) -> OptionRev<(IntRange<T>, T)> nopanic;
impl IntRangeIteratorImpl<T, +Copy<T>, +Drop<T>> of Iterator<IntRange<T>> {
type Item = T;
fn next(ref self: IntRange<T>) -> Option<T> {
match int_range_pop_front(self) {
OptionRev::None => None,
OptionRev::Some((new_range, value)) => {
self = new_range;
Some(value)
},
}
}
}
}
/// Marker trait to enable using the Sierra libfuncs for integer range iteration (`IntRange`).
trait SierraIntRangeSupport<T>;
impl SierraIntRangeSupportU8 of SierraIntRangeSupport<u8>;
impl SierraIntRangeSupportU16 of SierraIntRangeSupport<u16>;
impl SierraIntRangeSupportU32 of SierraIntRangeSupport<u32>;
impl SierraIntRangeSupportU64 of SierraIntRangeSupport<u64>;
impl SierraIntRangeSupportU128 of SierraIntRangeSupport<u128>;
impl SierraIntRangeSupportI8 of SierraIntRangeSupport<i8>;
impl SierraIntRangeSupportI16 of SierraIntRangeSupport<i16>;
impl SierraIntRangeSupportI32 of SierraIntRangeSupport<i32>;
impl SierraIntRangeSupportI64 of SierraIntRangeSupport<i64>;
impl SierraIntRangeSupportI128 of SierraIntRangeSupport<i128>;
impl SierraRangeIntoIterator<
T, +Copy<T>, +Drop<T>, +SierraIntRangeSupport<T>,
> of IntoIterator<Range<T>> {
type IntoIter = internal::IntRange<T>;
fn into_iter(self: Range<T>) -> Self::IntoIter {
match internal::int_range_try_new(self.start, self.end) {
Ok(range) => range,
Err(range) => range,
}
}
}