1 module aermicioi.aedi.util.range;
2 
3 import std.range.primitives;
4 
5 /**
6 Buffering output range into a static array
7 
8 Parameters:
9     T = static array buffer.
10 **/
11 struct BufferSink(T : Z[N], Z, size_t N) {
12     private T buffer;
13     private size_t fillage;
14 
15     /**
16     Pull elements out of range and save them in buffer
17 
18     Params:
19         range = range from which to pull out elements.
20     **/
21     void put(R)(ref R range)
22         if (isInputRange!R && is(ElementType!R == Z)){
23 
24         if (range.empty) {
25             return;
26         }
27 
28         foreach (index, ref slot; buffer) {
29             if (range.empty) {
30                 break;
31             }
32 
33             slot = range.front;
34             range.popFront;
35             fillage = index;
36         }
37 
38         ++fillage;
39     }
40 
41     /**
42     Get buffered data.
43 
44     Returns:
45         Z[] a slice of static array
46     **/
47     Z[] slice() {
48         return buffer[0 .. fillage];
49     }
50 }
51 
52 /**
53 A forward range representing an exception chain.
54 
55 Params:
56     throwable = starting point of exception chain
57 
58 Returns:
59     a forward range of exceptions
60 **/
61 auto exceptions(Throwable throwable) {
62     return ExceptionChain(throwable);
63 }
64 
65 /**
66 ditto
67 **/
68 @safe struct ExceptionChain {
69 
70     private Throwable current;
71 
72     public {
73         /**
74         Constructor for exception chain
75 
76         Params:
77             exception = initial exception in chain of exceptions
78         **/
79         this(Throwable exception) {
80             this.current = exception;
81         }
82 
83         private this(ref ExceptionChain chain) {
84             this.current = chain.current;
85         }
86 
87         /**
88         Get current throwable in exception chain
89 
90         Returns:
91             current throwable
92         **/
93         Throwable front() {
94             return current;
95         }
96 
97         /**
98         Check if exception chain exhausted or not.
99 
100         Returns:
101             true if exausted false otherwise
102         **/
103         bool empty() {
104             return current is null;
105         }
106 
107         /**
108         Move to next exception in chain
109         **/
110         void popFront() {
111             if (!empty) {
112                 current = current.next;
113             }
114         }
115 
116         /**
117         Save exception chain at current point.
118 
119         Returns:
120             A copy of current exception chain
121         **/
122         typeof(this) save() {
123             return ExceptionChain(this);
124         }
125     }
126 }
127 
128 /**
129 Given a range of objects filter them by Interface they are implementing.
130 
131 Params:
132 	Interface = interface by which to filter the range
133 	range = range of objects to filter
134 
135 Returns:
136 	InterfaceFilter!(Range, Interface) a range of filtered objects by Interface
137 **/
138 InterfaceFilter!(Range, Interface) filterByInterface(Interface, Range)(auto ref Range range) {
139 	return InterfaceFilter!(Range, Interface)(range);
140 }
141 
142 /**
143 ditto
144 **/
145 @safe struct InterfaceFilter(Range, Interface)
146 if (isForwardRange!Range && (is(ElementType!Range == class) || is(ElementType!Range == interface))) {
147 
148 	private Range range;
149 	private Interface current;
150 
151 	this(this) {
152 		range = range.save;
153 	}
154 
155     /**
156     Constructor for interface filtering range
157 
158     Params:
159         range = range to filter out.
160     **/
161 	this(ref Range range) {
162 		this.range = range.save;
163 		this.popFront;
164 	}
165 
166 	private this(ref Range range, Interface current) {
167 		this.range = range.save;
168 		this.current = current;
169 	}
170 
171     /**
172     Whether there are more elements that implement interface or not.
173 
174     Returns:
175         true if there are no more elements implementing interface
176     **/
177 	bool empty() {
178 		return current is null;
179 	}
180 
181     /**
182     Get current implementing element
183 
184     Returns:
185         current element that implements interface
186     **/
187 	Interface front() {
188 		return current;
189 	}
190 
191     /**
192     Move to next element implementing interface.
193     **/
194 	void popFront() @trusted {
195 		while (!range.empty) {
196 			auto front = range.front;
197 			range.popFront;
198 
199 			current = cast(Interface) front;
200 
201 			if (current !is null) {
202 				return;
203 			}
204 		}
205 
206 		current = null;
207 	}
208 
209     /**
210     Save range at current point.
211 
212     Returns:
213         A copy of current range.
214     **/
215 	typeof(this) save() {
216 		return typeof(this)(range, current);
217 	}
218 }
219 
220 /**
221 Create a range of all base classes and interfaces a component implements.
222 
223 Warning no order of inherited interfaces and classes is guaranteed.
224 
225 Params:
226     classinfo = typeinfo of component for which to create inheritance chain.
227 
228 Returns:
229     A range of ClassInfo elements.
230 **/
231 auto inheritance(ClassInfo classinfo) {
232     return InheritanceRange(classinfo);
233 }
234 
235 /**
236 ditto
237 **/
238 @safe struct InheritanceRange {
239     private {
240         ClassInfo[] stack;
241         ClassInfo[] processed;
242     }
243 
244     /**
245     Constructor for inheritance range
246 
247     Params:
248         component = component for which to create inheritance range.
249     **/
250     this(ClassInfo component) {
251         stack = [ component ];
252     }
253 
254     /**
255     Copy constructor for InheritanceRange, ala save.
256 
257     Params:
258         range = copied range.
259     **/
260     this(ref InheritanceRange range) {
261         this.stack = range.stack[];
262         this.processed = range.processed[];
263     }
264 
265     /**
266     Get current element in range.
267 
268     Returns:
269         Current type that component inherits.
270     **/
271     ClassInfo front() {
272         return stack.front;
273     }
274 
275     /**
276     Whether there are more inherited types or not.
277 
278     Returns:
279         true if not.
280     **/
281     bool empty() {
282         return stack.empty;
283     }
284 
285     /**
286     Move to next inherited type.
287     **/
288     void popFront() {
289         import std.algorithm.iteration : map, filter;
290         import std.algorithm.searching : canFind;
291         import std.range : chain, only;
292         ClassInfo removed = stack.front;
293         stack.popFront;
294         processed ~= removed;
295 
296         foreach (
297             unprocessed;
298             removed.interfaces
299                 .map!(iface => iface.classinfo)
300                 .chain(removed.base.only)
301                 .filter!(iface => iface !is null)
302                 .filter!(iface => !processed.canFind!((f, s) => f is s)(iface))
303         ) {
304             stack ~= unprocessed;
305         }
306     }
307 
308     /**
309     Save range at current state.
310 
311     Returns:
312         A copy of range.
313     **/
314     InheritanceRange save() {
315         return InheritanceRange(this);
316     }
317 }