1 /// Lazy filter-based range (destroy on function.) 2 module tern.algorithm.lazy_filter; 3 4 // TODO: Barter? 5 import tern.traits; 6 import std.conv; 7 8 /// Lazy filter-based range implementation. 9 public struct LazyFilter(alias F, T) 10 if (isForward!T && isCallable!F) 11 { 12 T _range; 13 alias _range this; 14 15 private: 16 final: 17 size_t _length = -1; 18 19 public: 20 string toString() 21 { 22 return this[0..length].to!string; 23 } 24 25 /// Gets the internally held range after predication. 26 T range() 27 { 28 if (length == 0) 29 return T.init; 30 31 return this[0..length]; 32 } 33 34 this(T range) 35 { 36 _range = range; 37 } 38 39 size_t length() 40 { 41 if (_length != -1) 42 return _length; 43 44 _length = 0; 45 foreach (u; _range) 46 { 47 if (F(u)) 48 _length++; 49 } 50 return _length; 51 } 52 53 T opSlice(ptrdiff_t start, ptrdiff_t end) 54 { 55 T slice; 56 foreach (ref u; _range) 57 { 58 slice ~= opIndex(start++); 59 60 if (start >= end) 61 break; 62 } 63 return slice; 64 } 65 66 auto opSliceAssign(A)(A ahs, ptrdiff_t start, ptrdiff_t end) 67 { 68 T slice; 69 foreach (ref u; _range) 70 { 71 slice ~= opIndex(ahs[start], start++); 72 73 if (start >= end) 74 break; 75 } 76 return slice; 77 } 78 79 ref auto opIndex(ptrdiff_t index) 80 { 81 foreach (ref u; _range) 82 { 83 if (F(u) && index-- <= 0) 84 return u; 85 } 86 throw new Throwable("Lazy filter index out of bounds!"); 87 } 88 89 auto opIndexAssign(A)(A ahs, ptrdiff_t index) 90 { 91 foreach (ref u; _range) 92 { 93 if (F(u) && index-- <= 0) 94 return u = ahs; 95 } 96 throw new Throwable("Lazy filter index out of bounds!"); 97 } 98 99 size_t opDollar() 100 { 101 return length; 102 } 103 }