added variants of map and filter with contexts
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 3 Jan 2022 02:25:22 +0000 (20:25 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 3 Jan 2022 02:25:22 +0000 (20:25 -0600)
core/container/iter.onyx
tests/lazy_iterators.onyx

index 7f4930379f2bb4b7e70479ce4894279db8ff2750..a6bc7ee30337bc62263a0963dcfb2cc91941ccd6 100644 (file)
@@ -13,7 +13,8 @@ close :: (it: Iterator($T)) {
     it.close(it.data);
 }
 
-filter :: (it: Iterator($T), predicate: (T) -> bool) -> Iterator(T) {
+filter :: #match {}
+#match filter (it: Iterator($T), predicate: (T) -> bool) -> Iterator(T) {
     FilterIterator :: struct (T: type_expr) {
         iterator:  Iterator(T);
         predicate: (T) -> bool;
@@ -49,7 +50,46 @@ filter :: (it: Iterator($T), predicate: (T) -> bool) -> Iterator(T) {
     };
 }
 
-map :: (it: Iterator($T), transform: (T) -> $R) -> Iterator(R) {
+#match filter (it: Iterator($T), ctx: $Ctx, predicate: (T, Ctx) -> bool) -> Iterator(T) {
+    FilterIterator :: struct (T: type_expr, Ctx: type_expr) {
+        iterator:  Iterator(T);
+        predicate: (T, Ctx) -> bool;
+        ctx: Ctx;
+    }
+
+    filter_iterator := new(FilterIterator(T, Ctx));
+    filter_iterator.iterator = it;
+    filter_iterator.predicate = predicate;
+    filter_iterator.ctx = ctx;
+
+    next :: (fi: ^FilterIterator($T, $_)) -> (T, bool) {
+        value, cont := fi.iterator.next(fi.iterator.data);
+        if cont {
+            while !fi.predicate(value, fi.ctx) {
+                value, cont = fi.iterator.next(fi.iterator.data);
+                if !cont do return value, false;
+            }
+
+            return value, true;
+        } else {
+            return value, false;
+        }
+    }
+
+    close :: (fi: ^FilterIterator($T, $_)) {
+        if fi.iterator.close != null_proc do fi.iterator.close(fi.iterator.data);
+        cfree(fi);
+    }
+
+    return .{
+        data  = filter_iterator,
+        next  = #solidify next  { T=T, _=Ctx },
+        close = #solidify close { T=T, _=Ctx },
+    };
+}
+
+map :: #match {}
+#match map (it: Iterator($T), transform: (T) -> $R) -> Iterator(R) {
     MapIterator :: struct (T: type_expr, R: type_expr) {
         iterator:  Iterator(T);
         transform: (T) -> R;
@@ -78,6 +118,37 @@ map :: (it: Iterator($T), transform: (T) -> $R) -> Iterator(R) {
     };
 }
 
+#match map (it: Iterator($T), ctx: $Ctx, transform: (T, Ctx) -> $R) -> Iterator(R) {
+    MapIterator :: struct (T: type_expr, R: type_expr, Ctx: type_expr) {
+        iterator:  Iterator(T);
+        transform: (T, Ctx) -> R;
+        ctx: Ctx;
+    }
+
+    map_iterator := new(MapIterator(T, R, Ctx));
+    map_iterator.iterator = it;
+    map_iterator.transform = transform;
+    map_iterator.ctx = ctx;
+
+    next :: (mi: ^MapIterator($T, $R, $Ctx)) -> (R, bool) {
+        value, cont := mi.iterator.next(mi.iterator.data);
+        if !cont do return __zero_value(R), false;
+
+        return mi.transform(value, mi.ctx), true;
+    }
+
+    close :: (mi: ^MapIterator($T, $R, $Ctx)) {
+        if mi.iterator.close != null_proc do mi.iterator.close(mi.iterator.data);
+        cfree(mi);
+    }
+
+    return .{
+        data  = map_iterator,
+        next  = #solidify next  { T=T, R=R, Ctx=Ctx },
+        close = #solidify close { T=T, R=R, Ctx=Ctx },
+    };
+}
+
 take_one :: (it: Iterator($T), no_close := false) -> (T, bool) {
     ret, cont := it.next(it.data);
     if !cont && !no_close do it.close(it.data);
index 8000388fd6ba46fe306498485bf8d34054ca387a..a87ff4cc4d27eb08896ee5efea8bba85f3042a0b 100644 (file)
@@ -37,11 +37,14 @@ main :: (args: [] cstr) {
     // Hopefully soon, the following will be possible.
 
     {
+        lower_bound := 10;
+        addition    := 42;
+
         quick_iterator :=
                     count_iterator(1.0f, 20.0f)
                     |> iter.map((x) => x * 2)
-                    |> iter.filter((x) => x > 10)
-                    |> iter.map((x) => x + 42)
+                    |> iter.filter(lower_bound, (x, l) => x > ~~l)
+                    |> iter.map(addition, (x, addition) => x + ~~addition)
                     |> iter.take(5);
 
         for v: quick_iterator {