TargetIterable.java (8612B)
1 package osm.planner; 2 3 import java.util.List; 4 import java.util.AbstractSet; 5 import java.util.Collection; 6 import java.util.HashMap; 7 import java.util.Iterator; 8 import java.util.Map; 9 import java.util.Objects; 10 import java.util.function.Function; 11 import 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 */ 20 public 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 }