|
@@ -0,0 +1,60 @@
|
|
|
+
|
|
|
+using Invercargill.DataStructures;
|
|
|
+namespace Invercargill.Modifiers {
|
|
|
+
|
|
|
+ public class Union<T, TKey> : Enumerable<T> {
|
|
|
+
|
|
|
+ private Enumerable<T> e1;
|
|
|
+ private Enumerable<T> e2;
|
|
|
+ private TransformDelegate<T, TKey> key_sf;
|
|
|
+ private HashDelegate<TKey> key_hf;
|
|
|
+ private EqualityDelegate<TKey> key_ef;
|
|
|
+
|
|
|
+ public Union(Enumerable<T> first, Enumerable<T> second, owned TransformDelegate<T, TKey> key_selector, owned HashDelegate<TKey>? key_hasher = null, owned EqualityDelegate<TKey>? key_equator = null) {
|
|
|
+ e1 = first;
|
|
|
+ e2 = second;
|
|
|
+ key_sf = (owned)key_selector;
|
|
|
+ key_ef = (owned)key_equator ?? Operators.equality<TKey>();
|
|
|
+ key_hf = (owned)key_hasher ?? Operators.hash<TKey>();
|
|
|
+ }
|
|
|
+
|
|
|
+ public override int? peek_count() {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ public override EnumerableInfo get_info() {
|
|
|
+ return new EnumerableInfo.infer(this, EnumerableCategory.COMPUTED, Iterate.these(e1, e2));
|
|
|
+ }
|
|
|
+
|
|
|
+ public override Tracker<T> get_tracker() {
|
|
|
+ var tracker1 = e1.get_tracker();
|
|
|
+ var tracker2 = e2.get_tracker();
|
|
|
+ var touched = new HashSet<TKey>(key_hf, key_ef);
|
|
|
+
|
|
|
+ return new AdvanceTracker<T>((out result) => {
|
|
|
+ T? item = null;
|
|
|
+ while(item != null) {
|
|
|
+ if(tracker1.has_next()) {
|
|
|
+ item = tracker1.get_next();
|
|
|
+ }
|
|
|
+ else if(tracker2.has_next()) {
|
|
|
+ item = tracker2.get_next();
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ result = null;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ var key = key_sf(item);
|
|
|
+ if(!touched.add(key)) {
|
|
|
+ item = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ result = item;
|
|
|
+ return true;
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+}
|