1 /// Lazy substitute-based range (replace on state.)
2 module tern.algorithm.lazy_substitute;
3 
4 
5 import tern.traits;
6 import tern.object : loadLength;
7 import std.conv;
8 
9 /// Lazy substitute-based range implementation.
10 public struct LazySubstitute(A, B, C)
11     if (isForward!A && isIndexable!A && isCallable!F)
12 {
13     A _range;
14     alias _range this;
15     
16 public:
17 final:
18     size_t length;
19     B from;
20     C to;
21 
22     string toString()
23     {
24         return this[0..length].to!string;
25     }
26 
27     /// Gets the internally held range after predication.
28     T range()
29     {
30         if (length == 0)
31             return T.init;
32             
33         return this[0..length];
34     }
35     
36     this(A _range, B from, C to)
37     {
38         _range = _range;
39         length = _range.loadLength;
40         this.from = from;
41         this.to = to;
42     }
43 
44     A opSlice(ptrdiff_t start, ptrdiff_t end)
45     {
46         A slice;
47         foreach (ref u; _range)
48         {
49             slice ~= opIndex(start++);        
50 
51             if (start >= end)
52                 break;
53         }
54         return slice;
55     }
56 
57     auto opSliceAssign(T)(T ahs, ptrdiff_t start, ptrdiff_t end) 
58     {
59         A slice;
60         foreach (ref u; _range)
61         {
62             slice ~= opIndex(ahs[start], start++);        
63 
64             if (start >= end)
65                 break;
66         }
67         return slice;
68     }
69 
70     ref auto opIndex(ptrdiff_t index)
71     {
72         if (_range[index] == from)
73             return _range[index] = to;
74         else
75             return _range[index];
76     }
77 
78     size_t opDollar()
79     {
80         return length;
81     }
82 }