|
|
@@ -0,0 +1,80 @@
|
|
|
+namespace Invercargill.Modifiers {
|
|
|
+
|
|
|
+ public class TakeLast<T> : Enumerable<T> {
|
|
|
+ private Enumerable<T> input;
|
|
|
+ private int n_items {get; set;}
|
|
|
+
|
|
|
+ public TakeLast(Enumerable<T> input, int count) {
|
|
|
+ this.input = input;
|
|
|
+ n_items = count;
|
|
|
+ }
|
|
|
+
|
|
|
+ public override int? peek_count() {
|
|
|
+ var c = input.peek_count();
|
|
|
+ if(c == null)
|
|
|
+ return null;
|
|
|
+ return int.min(c, n_items);
|
|
|
+ }
|
|
|
+
|
|
|
+ public override EnumerableInfo get_info() {
|
|
|
+ return new EnumerableInfo.infer_single(this, EnumerableCategory.COMPUTED, input);
|
|
|
+ }
|
|
|
+
|
|
|
+ public override Tracker<T> get_tracker() {
|
|
|
+ var tracker = input.get_tracker();
|
|
|
+ DataStructures.RingBuffer<T>? buffer = null;
|
|
|
+ var index = 0;
|
|
|
+ var input_exhausted = false;
|
|
|
+ var output_index = 0;
|
|
|
+ var output_started = false;
|
|
|
+ var actual_count = 0;
|
|
|
+
|
|
|
+ return new AdvanceTracker<T>((out obj) => {
|
|
|
+ obj = null;
|
|
|
+
|
|
|
+ // First, fill the buffer with all items from the input
|
|
|
+ if (!input_exhausted) {
|
|
|
+ // Initialize buffer with the requested size
|
|
|
+ buffer = new DataStructures.RingBuffer<T>((uint)n_items);
|
|
|
+
|
|
|
+ while(tracker.has_next()) {
|
|
|
+ var item = tracker.get_next();
|
|
|
+
|
|
|
+ // Add item to buffer, overwriting oldest if buffer is full
|
|
|
+ buffer.set((uint)index, item);
|
|
|
+ index = (index + 1) % n_items;
|
|
|
+
|
|
|
+ // Track how many items we've actually seen
|
|
|
+ if (actual_count < n_items) {
|
|
|
+ actual_count++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ input_exhausted = true;
|
|
|
+
|
|
|
+ // Set the output index to the oldest item
|
|
|
+ if (actual_count == n_items) {
|
|
|
+ // Buffer is full, oldest item is at current index
|
|
|
+ output_index = index;
|
|
|
+ } else {
|
|
|
+ // Buffer not full, start from beginning
|
|
|
+ output_index = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // After exhausting the input, return items from the buffer
|
|
|
+ if (!output_started) {
|
|
|
+ output_started = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(output_index < actual_count) {
|
|
|
+ obj = buffer.get((uint)output_index);
|
|
|
+ output_index++;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+}
|