TargetIterable.java (8612B) download
1package osm.planner;
2
3import java.util.List;
4import java.util.AbstractSet;
5import java.util.Collection;
6import java.util.HashMap;
7import java.util.Iterator;
8import java.util.Map;
9import java.util.Objects;
10import java.util.function.Function;
11import java.util.function.Supplier;
12
13/**
14 * An iterable representing a set of target entries, each associated with a
15 * visitation state.
16 *
17 * @param <P> The type of target points.
18 * @param <T> The type of elements in the iterable.
19 */
20public class TargetIterable<P, T> implements Iterable<TargetIterable.TargetSet<P, T>> {
21
22 /**
23 * Enumeration representing the visitation states of target points in the
24 * {@link TargetIterable}.
25 */
26 public static enum Visited {
27 /**
28 * Represents a target point that has finished processing.
29 */
30 FINISHED(false, null),
31
32 /**
33 * Represents a target point that is currently being processed.
34 */
35 BUSY(true, FINISHED),
36
37 /**
38 * Represents a target point that is pending processing.
39 */
40 PENDING(true, BUSY);
41
42 private final boolean include;
43 private final Visited next;
44
45 /**
46 * Constructs a Visited enum with the specified inclusion flag and the next
47 * visitation state.
48 *
49 * @param include The flag indicating whether the target point should be
50 * included in processing.
51 * @param next The next visitation state after this one.
52 */
53 private Visited(boolean include, Visited next) {
54 this.include = include;
55 this.next = next;
56 }
57
58 /**
59 * Gets the next visitation state after this one.
60 *
61 * @return The next visitation state.
62 */
63 public Visited getNext() {
64 return next;
65 }
66
67 /**
68 * Checks if the target point should be included in processing.
69 *
70 * @return {@code true} if the target point should be included, {@code false}
71 * otherwise.
72 */
73 public boolean doInclude() {
74 return include;
75 }
76 }
77
78 /**
79 * Represents a set of target entries associated with their visitation states.
80 *
81 * @param <P> The type of target points.
82 * @param <T> The type of elements in the set.
83 */
84 public static class TargetSet<P, T> extends AbstractSet<T> {
85
86 /**
87 * The iterable to which this set belongs.
88 */
89 public final TargetIterable<P, T> iterable;
90
91 /**
92 * A map associating each target point with its visitation state.
93 */
94 public final Map<P, Visited> targetMap;
95
96 /**
97 * The list of target elements in this set.
98 */
99 public final List<T> targets;
100
101 /**
102 * Constructs a TargetSet with the specified iterable, target map, and target
103 * elements.
104 *
105 * @param iterable The iterable to which this set belongs.
106 * @param targetMap A map associating each target point with its visitation
107 * state.
108 * @param targets The list of target elements in this set.
109 */
110 private TargetSet(TargetIterable<P, T> iterable, Map<P, Visited> targetMap, List<T> targets) {
111 this.iterable = iterable;
112 this.targetMap = targetMap;
113 this.targets = targets;
114 }
115
116 /**
117 * Returns a string representation of this TargetSet.
118 *
119 * @return A string representation of this TargetSet.
120 */
121 @Override
122 public String toString() {
123 return String.format("TargetSet(%s)", targets);
124 }
125
126 /**
127 * Returns the number of elements in this set.
128 *
129 * @return The number of elements in this set.
130 */
131 @Override
132 public int size() {
133 return targets.size();
134 }
135
136 /**
137 * Returns an iterator over the elements in this set.
138 *
139 * @return An iterator over the elements in this set.
140 */
141 @Override
142 public Iterator<T> iterator() {
143 return targets.iterator();
144 }
145
146 /**
147 * Creates a new iterable to continue processing with additional targets.
148 *
149 * @param supplier A supplier providing the next element.
150 * @return An iterable with additional targets.
151 */
152 public Iterable<TargetSet<P, T>> doContinue(Supplier<T> supplier) {
153 return new TargetIterable<>(iterable.garage, iterable.targetList, targetMap,
154 supplier, iterable.startPoint, iterable.targetPoint);
155 }
156 }
157
158 private final T garage;
159 private final Collection<P> targetList;
160 private final Supplier<T> supplier;
161 private final Function<P, T> startPoint;
162 private final Function<P, T> targetPoint;
163 private final Map<P, Visited> originalMap;
164
165 /**
166 * Constructs a TargetIterable.
167 *
168 * @param garage The garage element.
169 * @param targetList The list of target points.
170 * @param targetMap A map associating each target point with its visitation
171 * state.
172 * @param supplier A supplier providing the next element.
173 * @param startPoint A function providing the starting point for a target.
174 * @param targetPoint A function providing the target point for a target.
175 */
176 public TargetIterable(T garage, Collection<P> targetList, Map<P, Visited> targetMap,
177 Supplier<T> supplier, Function<P, T> startPoint, Function<P, T> targetPoint) {
178 this.garage = garage;
179 this.targetList = targetList;
180 this.supplier = supplier;
181 this.startPoint = startPoint;
182 this.targetPoint = targetPoint;
183 this.originalMap = targetMap;
184 }
185
186 /**
187 * Constructs a TargetIterable with an empty target map.
188 *
189 * @param garage The garage element.
190 * @param targetList The list of target points.
191 * @param supplier A supplier providing the next element.
192 * @param startPoint A function providing the starting point for a target.
193 * @param targetPoint A function providing the target point for a target.
194 */
195 public TargetIterable(T garage, Collection<P> targetList,
196 Supplier<T> supplier, Function<P, T> startPoint, Function<P, T> targetPoint) {
197 this.garage = garage;
198 this.targetList = targetList;
199 this.supplier = supplier;
200 this.startPoint = startPoint;
201 this.targetPoint = targetPoint;
202 this.originalMap = Map.of();
203 }
204
205 @Override
206 public Iterator<TargetSet<P, T>> iterator() {
207 return new Iterator<TargetIterable.TargetSet<P, T>>() {
208 final Map<P, Visited> targetMap = new HashMap<>(TargetIterable.this.originalMap);
209
210 private Visited checkVisited(P p, T current) {
211 Visited visited = targetMap.getOrDefault(p, Visited.PENDING);
212
213 if (startPoint.apply(p).equals(current) && visited == Visited.PENDING)
214 visited = visited.getNext();
215
216 if (targetPoint.apply(p).equals(current) && visited == Visited.BUSY)
217 visited = visited.getNext();
218
219 return visited;
220 }
221
222 @Override
223 public boolean hasNext() {
224 T current = supplier.get();
225
226 return current != garage || targetList.stream()
227 .map(p -> checkVisited(p, current))
228 .anyMatch(Visited::doInclude);
229 }
230
231 @Override
232 public TargetSet<P, T> next() {
233 T current = supplier.get();
234
235 List<T> targetNodes = targetList.stream()
236 .map(p -> Map.entry(p, checkVisited(p, current)))
237 .peek(e -> targetMap.put(e.getKey(), e.getValue()))
238
239 .map(e -> switch (e.getValue()) {
240 case PENDING -> startPoint.apply(e.getKey());
241 case BUSY -> targetPoint.apply(e.getKey());
242 case FINISHED -> null;
243 })
244 .filter(Objects::nonNull)
245 .toList();
246
247 if (targetNodes.isEmpty() && current != garage)
248 return new TargetSet<>(TargetIterable.this, targetMap, List.of(garage));
249
250 return new TargetSet<>(TargetIterable.this, targetMap, targetNodes);
251 }
252 };
253 }
254}