iterator work

improve performance of split, chars, chars_ref
properly implement lily.iter.Iterator.fold
partially implement lily.iter.Iterator.collect
fix lily.iter.Skip logic
code cleanup
write proposed iterator spec
This commit is contained in:
koniifer 2025-01-18 18:49:46 +00:00
parent bfe75481e3
commit 33cf8d7209
6 changed files with 71 additions and 57 deletions

View file

@ -1,2 +1,20 @@
# iterators # iterators
## spec to-be-defined ## spec to-be-defined
## proposed spec:
```rust
.{IterNext, Iterator} := @use("lily").iter
Iterable := struct {
// ! required
// IterNext == struct { finished: bool, val: T }
next := fn(self: ^Self): IterNext(T)
into_iter := fn(self: Self): Iterator(Self)
// ! proposed
// addition of these two would allow for cheap implementation of `skip`, and `nth` in lily.iter.Iterator
peek := fn(self: ^Self): IterNext(T)
advance := fn(self: ^Self, n: uint): IterNext(T)
// ! proposed (waiting on compiler)
iter := fn(self: ^Self): Iterator(^Self)
}

View file

@ -5,8 +5,12 @@ Item := fn($Key: type, $Value: type): type return packed struct {
value: Value, value: Value,
} }
Bucket := fn($Key: type, $Value: type, $Allocator: type): type return Vec(Item(Key, Value), Allocator) Bucket := fn($Key: type, $Value: type, $Allocator: type): type {
Buckets := fn($Key: type, $Value: type, $Allocator: type): type return Vec(Bucket(Key, Value, Allocator), Allocator) return Vec(Item(Key, Value), Allocator)
}
Buckets := fn($Key: type, $Value: type, $Allocator: type): type {
return Vec(Bucket(Key, Value, Allocator), Allocator)
}
HashMap := fn($Key: type, $Value: type, $Hasher: type, $Allocator: type): type return struct { HashMap := fn($Key: type, $Value: type, $Hasher: type, $Allocator: type): type return struct {
allocator: ^Allocator, allocator: ^Allocator,

View file

@ -69,9 +69,6 @@ Vec := fn($T: type, $Allocator: type): type return struct {
i := 0 i := 0
loop if self.get(i) == rhs return i else if i == self.slice.len return null else i += 1 loop if self.get(i) == rhs return i else if i == self.slice.len return null else i += 1
} }
$into_iter := fn(self: Self): iter.Iterator(iter.SliceIter(T)) {
return .(.(self.slice, 0))
}
$sort := fn(self: ^Self): void { $sort := fn(self: ^Self): void {
_ = quicksort(compare, self.slice, 0, self.slice.len - 1) _ = quicksort(compare, self.slice, 0, self.slice.len - 1)
} }

View file

@ -46,9 +46,8 @@ Iterator := fn($T: type): type {
fold := fn(self: ^Self, $_fold: type, sum: Value): Value { fold := fn(self: ^Self, $_fold: type, sum: Value): Value {
loop { loop {
x := self.next() x := self.next()
y := self.next() if x.finished return sum
if y.finished return sum sum = _fold(sum, x.val)
sum += _fold(x.val, y.val)
} }
} }
nth := fn(self: ^Self, n: uint): ?Value { nth := fn(self: ^Self, n: uint): ?Value {
@ -59,6 +58,23 @@ Iterator := fn($T: type): type {
i += 1 i += 1
} }
} }
collect := fn(self: ^Self, $A: type): ?A {
if Type(A).kind() != .Array {
@error("unsupported collect (for now)")
}
if @ChildOf(A) != Value {
@error("cannot collect of iterator of type", Value, "into type", A)
}
cont := Type(A).uninit()
i := 0
loop {
defer i += 1
x := self.next()
if i == @lenof(A) & x.finished return cont
if i == @lenof(A) | x.finished return null
cont[i] = x.val
}
}
} }
} }
@ -114,7 +130,7 @@ Skip := fn($T: type): type {
n := 0 n := 0
loop { loop {
x := self.iter.next() x := self.iter.next()
if n == self.step return x if n == self.step | x.finished return x
n += 1 n += 1
} }
} }

View file

@ -68,21 +68,20 @@ split_once := fn(haystack: []u8, needle: @Any()): ?struct {left: []u8, right: []
} }
} }
split := fn(str: []u8, needle: @Any()): Iterator(struct { $split := fn(str: []u8, needle: @Any()): Iterator(struct {
str: []u8, str: []u8,
needle: @TypeOf(needle), needle: @TypeOf(needle),
finished: bool = false, finished: bool = false,
next := fn(self: ^Self): IterNext([]u8) { next := fn(self: ^Self): IterNext([]u8) {
splits := split_once(self.str, self.needle)
if self.finished return .(true, Type([]u8).uninit()) if self.finished return .(true, Type([]u8).uninit())
splits := split_once(self.str, self.needle)
if splits != null { if splits != null {
self.str = splits.right self.str = splits.right
return .(false, splits.left) return .(false, splits.left)
} else {
self.finished = true
return .(false, self.str)
} }
self.finished = true
return .(false, self.str)
} }
}) { }) {
T := @TypeOf(needle) T := @TypeOf(needle)
@ -92,11 +91,11 @@ split := fn(str: []u8, needle: @Any()): Iterator(struct {
return .(.{str, needle}) return .(.{str, needle})
} }
chars := fn(iter: []u8): Iterator(struct { $chars := fn(iter: []u8): Iterator(struct {
str: []u8, str: []u8,
$next := fn(self: ^Self): IterNext(u8) { $next := fn(self: ^Self): IterNext(u8) {
tmp := IterNext(u8).(self.str.len == 0, self.str[0]) tmp := IterNext(u8).(self.str.len == 0, *self.str.ptr)
self.str = self.str[1..] self.str = self.str[1..]
return tmp return tmp
} }
@ -104,7 +103,7 @@ chars := fn(iter: []u8): Iterator(struct {
return .(.(iter)) return .(.(iter))
} }
chars_ref := fn(iter: []u8): Iterator(struct { $chars_ref := fn(iter: []u8): Iterator(struct {
str: []u8, str: []u8,
$next := fn(self: ^Self): IterNext(^u8) { $next := fn(self: ^Self): IterNext(^u8) {

View file

@ -1,15 +1,4 @@
lily := @use("lily/lib.hb") lily := @use("lily/lib.hb");
Allocator := lily.alloc.SimpleAllocator
Vec := lily.collections.Vec
HashMap := lily.collections.HashMap
Random := lily.rand.SimpleRandom
Result := lily.result.Result
Hasher := lily.hash.FoldHasher
$ref_char_to_str := fn(char: ^u8): []u8 {
return char[0..1]
}
Generator := struct { Generator := struct {
n: uint = 0, n: uint = 0,
@ -22,37 +11,28 @@ Generator := struct {
} }
} }
$add := fn(lhs: uint, rhs: uint): uint { $add := fn(sum: uint, x: uint): uint {
return lhs + rhs return sum + x
} }
chars_ref := lily.string.chars_ref
main := fn(argc: uint, argv: []^void): uint { main := fn(argc: uint, argv: []^void): uint {
a := Generator.{}.into_iter().take(50).fold(add, 0) sum := Generator.{}.into_iter().take(50).fold(add, 0)
lily.print(a) lily.print(sum)
b := chars_ref("Hello,_").chain(chars_ref("World!")).map(ref_char_to_str).for_each(lily.log.info) // ! (libc) (compiler) bug: .collect(T) does not work.
c := chars_ref("Hello,_").intersperse(chars_ref("World!")).map(ref_char_to_str).for_each(lily.log.info) if lily.Target.current() != .LibC {
str := lily.string.chars("Hello, ").intersperse(
lily.string.chars("World!"),
).collect([13]u8)
// allocator := Allocator.new() if str != null {
// defer allocator.deinit() lily.log.info(@as([13]u8, str)[..])
// // ! HashMap only works on AbleOS target (due to compiler bugs) } else {
// map := HashMap(uint, uint, Hasher, Allocator).new(&allocator) lily.panic("could not collect (array wrong size)")
// defer map.deinit() }
} else {
// _ = map.insert(101, 20) lily.log.info("HWeolrllod,! ")
// _ = map.insert(202, 30) }
// _ = map.insert(303, 40)
// // ! This iterator only works on AbleOS target (due to compiler bugs)
// map.items().enumerate().for_each(print)
return 0 return 0
} }
// $print := fn(thing: @Any()): void {
// .{n, val: item} := thing
// // ! printf ALSO only works on AbleOS target (due to compiler bugs)
// lily.printf("nth: {}, key: {}, value: {}", .(n, item.key, item.value))
// }