|
@@ -0,0 +1,92 @@
|
|
|
+using Invercargill.DataStructures;
|
|
|
+namespace Invercargill.Modifiers {
|
|
|
+
|
|
|
+ public class ParallelFilter<T> : Enumerable<T>{
|
|
|
+ private PredicateDelegate<T> predicate;
|
|
|
+ private Enumerable<T> input;
|
|
|
+ private int workers;
|
|
|
+
|
|
|
+ public ParallelFilter(Enumerable<T> input, owned PredicateDelegate<T> predicate, int workers) {
|
|
|
+ this.input = input;
|
|
|
+ this.workers = workers;
|
|
|
+ this.predicate = (owned)predicate;
|
|
|
+ }
|
|
|
+
|
|
|
+ public override int? peek_count() {
|
|
|
+ return input.peek_count();
|
|
|
+ }
|
|
|
+
|
|
|
+ public override EnumerableInfo get_info() {
|
|
|
+ return new EnumerableInfo.infer_single(this, EnumerableCategory.COMPUTED, input);
|
|
|
+ }
|
|
|
+
|
|
|
+ public override Tracker<T> get_tracker() {
|
|
|
+ return new ParallelFilterTracker<T>(i => predicate(i), workers, input.get_tracker());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private class ParallelFilterTracker<T> : Tracker<T> {
|
|
|
+
|
|
|
+ private Fifo<T> queue;
|
|
|
+ private Tracker<T> queue_tracker;
|
|
|
+ private PredicateDelegate<T> predicate;
|
|
|
+ private Tracker<T> input_tracker;
|
|
|
+ private int remaining_workers;
|
|
|
+
|
|
|
+ public ParallelFilterTracker(owned PredicateDelegate<T> predicate, int workers, Tracker<T> input) {
|
|
|
+ input_tracker = input;
|
|
|
+ queue = new Fifo<T>();
|
|
|
+ queue_tracker = queue.get_tracker();
|
|
|
+ this.predicate = (owned)predicate;
|
|
|
+
|
|
|
+ remaining_workers = workers;
|
|
|
+ for(int i = 0; i < workers; i++) {
|
|
|
+ new Thread<bool>(@"Invercargill Parallel Job Thread #$i", do_work);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private WorkerItem<T> next_for_worker() {
|
|
|
+ lock(input_tracker) {
|
|
|
+ var item = new WorkerItem<T>();
|
|
|
+ if(input_tracker.has_next()) {
|
|
|
+ item.item = input_tracker.get_next();
|
|
|
+ return item;
|
|
|
+ }
|
|
|
+ item.complete = true;
|
|
|
+ return item;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private bool do_work() {
|
|
|
+ var job = next_for_worker();
|
|
|
+ while(!job.complete) {
|
|
|
+ if(predicate(job.item)) {
|
|
|
+ queue.push(job.item);
|
|
|
+ }
|
|
|
+ job = next_for_worker();
|
|
|
+ }
|
|
|
+
|
|
|
+ lock(remaining_workers) {
|
|
|
+ remaining_workers--;
|
|
|
+ if(remaining_workers == 0) {
|
|
|
+ queue.unblock();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ public override bool has_next() {
|
|
|
+ return queue_tracker.has_next();
|
|
|
+ }
|
|
|
+ public override T get_next() {
|
|
|
+ return queue_tracker.get_next();
|
|
|
+ }
|
|
|
+
|
|
|
+ private class WorkerItem<TIn> {
|
|
|
+ public TIn? item { get; set; }
|
|
|
+ public bool complete { get; set; }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+}
|