mirror of
https://github.com/kmc7468/cs220.git
synced 2025-12-14 22:18:46 +00:00
163 lines
3.9 KiB
Rust
163 lines
3.9 KiB
Rust
//! Implement functions using `Iterator` trait
|
|
|
|
struct FindIter<'s, T: Eq> {
|
|
query: &'s [T],
|
|
base: &'s [T],
|
|
curr: usize,
|
|
}
|
|
|
|
impl<T: Eq> Iterator for FindIter<'_, T> {
|
|
type Item = usize;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
while self.curr + self.query.len() <= self.base.len() {
|
|
let curr = self.curr;
|
|
self.curr += 1;
|
|
|
|
if &self.base[curr..(curr + self.query.len())] == self.query {
|
|
return Some(curr);
|
|
}
|
|
}
|
|
None
|
|
}
|
|
}
|
|
|
|
/// Returns an iterator over substring query indexes in the base.
|
|
pub fn find<'s, T: Eq>(query: &'s [T], base: &'s [T]) -> impl 's + Iterator<Item = usize> {
|
|
FindIter {
|
|
query,
|
|
base,
|
|
curr: 0,
|
|
}
|
|
}
|
|
|
|
/// Implement generic fibonacci iterator
|
|
struct FibIter<T> {
|
|
first: T,
|
|
second: T,
|
|
}
|
|
|
|
impl<T: std::ops::Add<Output = T> + Copy> FibIter<T> {
|
|
fn new(first: T, second: T) -> Self {
|
|
Self { first, second }
|
|
}
|
|
}
|
|
|
|
impl<T> Iterator for FibIter<T>
|
|
where
|
|
T: std::ops::Add<Output = T> + Copy,
|
|
{
|
|
type Item = T;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
let value = self.first;
|
|
self.first = self.second;
|
|
self.second = self.second + value;
|
|
Some(value)
|
|
}
|
|
}
|
|
|
|
/// Returns and iterator over the generic fibonacci sequence starting from `first` and `second`.
|
|
/// This is a generic version of `fibonacci` function, which works for any types that implements
|
|
/// `std::ops::Add` trait.
|
|
pub fn fib<T>(first: T, second: T) -> impl Iterator<Item = T>
|
|
where
|
|
T: std::ops::Add<Output = T> + Copy,
|
|
{
|
|
FibIter::new(first, second)
|
|
}
|
|
|
|
/// Endpoint of range, inclusive or exclusive.
|
|
#[derive(Debug)]
|
|
pub enum Endpoint {
|
|
/// Inclusive endpoint
|
|
Inclusive(isize),
|
|
|
|
/// Exclusive endpoint
|
|
Exclusive(isize),
|
|
}
|
|
|
|
struct RangeIter {
|
|
curr: isize,
|
|
step: isize,
|
|
last: isize,
|
|
}
|
|
|
|
impl RangeIter {
|
|
fn new(endpoints: (Endpoint, Endpoint), step: isize) -> Self {
|
|
let c = if step > 0 { 1 } else { -1 };
|
|
Self {
|
|
curr: match endpoints.0 {
|
|
Endpoint::Inclusive(v) => v,
|
|
Endpoint::Exclusive(v) => v + c,
|
|
},
|
|
step,
|
|
last: match endpoints.1 {
|
|
Endpoint::Inclusive(v) => v,
|
|
Endpoint::Exclusive(v) => v - c,
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Iterator for RangeIter {
|
|
type Item = isize;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
if self.step > 0 && self.curr > self.last || self.step < 0 && self.curr < self.last {
|
|
None
|
|
} else {
|
|
let value = self.curr;
|
|
self.curr += self.step;
|
|
Some(value)
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Returns an iterator over the range [left, right) with the given step.
|
|
pub fn range(left: Endpoint, right: Endpoint, step: isize) -> impl Iterator<Item = isize> {
|
|
RangeIter::new((left, right), step)
|
|
}
|
|
|
|
/// Write an iterator that returns all divisors of n in increasing order.
|
|
/// Assume n > 0.
|
|
///
|
|
/// Hint: trying all candidates from 1 to n will most likely time out!
|
|
/// To optimize it, make use of the following fact:
|
|
/// if x is a divisor of n that is greater than sqrt(n),
|
|
/// then n/x is a divisor of n that is smaller than sqrt(n).
|
|
struct Divisors {
|
|
n: u64,
|
|
curr: u64,
|
|
vec: Vec<u64>,
|
|
}
|
|
|
|
impl Iterator for Divisors {
|
|
type Item = u64;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
while self.curr * self.curr <= self.n {
|
|
let curr = self.curr;
|
|
self.curr += 1;
|
|
|
|
if self.n % curr == 0 {
|
|
if curr * curr != self.n {
|
|
self.vec.push(self.n / curr);
|
|
}
|
|
return Some(curr);
|
|
}
|
|
}
|
|
|
|
self.vec.pop()
|
|
}
|
|
}
|
|
|
|
/// Returns an iterator over the divisors of n.
|
|
pub fn divisors(n: u64) -> impl Iterator<Item = u64> {
|
|
Divisors {
|
|
n,
|
|
curr: 1,
|
|
vec: vec![],
|
|
}
|
|
}
|