aboutsummaryrefslogtreecommitdiff
path: root/std/prelude/iterators.pk
blob: 1e60379a416937bfc69f6a96e9ea811b84f17305 (plain) (blame)
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
## std.iterators: The Iter class and associated functions.
## This module is imported by default.
# reference: https://doc.rust-lang.org/std/iter/
# reference: https://docs.rs/itertools/latest/itertools/

use std.queue.ring

## The Iter class. Any type implementing `next()` is iterable.
pub type Iter[T] = class
  next(mut Self): T? # should T be lent?

## The IntoIter class.
## Any type implementing `iter()` may be converted to an iterable type.
pub type IntoIter[T] = class
  iter(Self): Iter[T]

## The Peek class.
## Any type implementing `Iter`, `peek`, and `peek_nth` is peekable.
pub type Peek[T] = class
  next(mut Self): T?
  peek(mut Self): T?
  peek_nth(mut Self, int): T?

## A concrete Peekable structure formed from a generic Iter type.
## Implements the Peek class. Can be formed with `.peekable()`
type PeekImpl = struct
  iter: ref Iter[T] # this is probably bad... heap allocated...
  buf: Queue[T]

## Convert any Iter into a peekable equivalent.
# https://github.com/LukeMathWalker/multipeek/blob/main/src/lib.rs
pub func peekable[T](iter: owned Iter[T]): PeekImpl[T] =
  { iter, buf: ... } # todo: implement Queue, somewhere

pub func next[T](self: mut PeekImpl[T]): T? =
  match self.buf.pop()
  of None then
    self.iter.next()
  of Some(val) then
    val
pub func peek[T](self: mut PeekImpl[T]): T? =
  match self.buf.peek()
  of None then
    self.buf.push(self.iter.next())
    self.buf.peek()
  of Some(val) then
    val
pub func peek_nth[T](self: mut PeekImpl[T], i: uint): T? =
  if self.buf.len > i then
    self.buf.get(i)!
  else
    for _ in self.buf.len .. i do # fixme
      match self.buf.next()
      of None then
        return None
      of Some(val) then
        self.buf.push(val)
    self.buf.peek()

# todo: useful functions for an iterator
# https://doc.rust-lang.org/std/iter/trait.Iterator.html#provided-methods

func advance_by[T](self: Iter[T], n: uint) =
  for i in 0 .. n do
    if self.next().is_none() then return

pub func get[T](self: Iter[T], at: uint): T?
  self.advance_by(at-1).ok? # fixme
  self.next()

## Returns true if every element in an Iter fulfills the conditional.
pub func all[T](self: Iter[T], cond: T -> bool): bool =
  for elem in self do
    if not cond(elem) then return false
  true

## Returns true if any element in an Iter fulfills the conditional.
pub func any[T](self: Iter[T], cond: T -> bool): bool =
  for elem in self do
    if cond(elem) then return true
  false

## Returns true if an Iter contains the given element.
pub func contains[T](self: Iter[T], val: T): bool =
  self.any(elem => elem == val)

## Returns the first element matching a condition, if it exists.
pub func find[T](self: Iter[T], cond: T -> bool): T? =
  for elem in self do
    if cond(elem) then return Some(elem)
  None

## Returns the position of the first element matching a condition, if it exists.
pub func position[T](self: Iter[T], cond: T -> bool): T? =
  var i = 0
  for elem in self do
    if cond(elem) then return Some(i)
    i += 1
  None

@[inline]
pub func fold[T, U](self: Iter[T], init: U, op: (U, T) -> U) =
  var res = init
  for elem in self do
    res = res.op(elem)
  res

pub func reduce[T, U](self: Iter[T], op: (U, T) -> U): U? =
  match self.next()
  of None then None
  of Some(val) then
    var res = val
    for elem in self do res = op(res, elem)
    Some(res)

pub func count[T](self: Iter[T], element: T): uint =
  self.fold(0, (elem, acc) => if elem == element then acc + 1 else acc)

pub func count[T](self: Iter[T]): uint =
  self.fold(0, (elem, acc) => acc + 1)

pub func last[T](self: Iter[T]): T =
  var res = None
  for elem in self do res = elem
  res

pub func ==[T](first: Iter[T], second: Iter[T]): bool =
  if first.len != second.len then return false
  for (a, b) in zip(first, second) do
    if a != b then return false
  true

type LazyIter = struct
  ...

pub func apply[T](self: mut LazyIter[T], fn: T -> T)
pub func map[T, S](self: Iter[T], fn: T -> S): LazyIter[S]
pub func foreach[T, S](self: Iter[T], fn: T -> S): LazyIter[T]

pub func enumerate[T](self: LazyIter[T]): LazyIter[T] # todo: impl with map or similar

pub func dedup[T](self: Iter[T], sorted = false): LazyIter[T]
pub func filter[T](self: Iter[T], cond: T -> bool): LazyIter[T]

## Takes (at most) the first `n` elements of an iterator.
pub func take[T](self: Iter[T], n: uint): LazyIter[T]
## Skips (at most) the first `n` elements of an iterator.
pub func skip[T](self: Iter[T], n: uint): LazyIter[T]

pub func repeat[T](self: Iter[T], n: uint): LazyIter[T] # cycle??
pub func intersperse[T](self: Iter[T], item: T): LazyIter[T]
pub func step[T](self: Iter[T], step: uint): LazyIter[T]
pub func flatten[T](self: Iter[Iter[T]]): LazyIter[T]

pub func chain[T](first: Iter[T], second: Iter[T]): LazyIter[T]

pub func zip[T, U](first: Iter[T], second: Iter[U]): Iter[(T, U)]
pub func unzip[T, U](self: Iter[(T, U)]): (Iter[T], Iter[U])

# equivalent of collect. useful for type conversion
pub func to[T](self: LazyIter[T]): list[T]
pub func to(self: LazyIter[char]): str

pub type BoundIter[T] = class
  next(mut Self): T?
  pop(mut Self): T?

pub func rev[T](self: BoundIter[T]): BoundIter[T]

pub type SizedIter[T] = class
  next(mut Self): T?
  pop(mut Self): T?
  len(Self): uint
  get(mut Self): T?

pub func max(self: Iter[Comparable[T]]): T
pub func min(self: Iter[Comparable[T]]): T
pub func sorted(self: Iter[Comparable[T]]): bool