misc/persolijn

osm-routing/src/main/java/osm/planner/TargetIterable.java in master
Repositories | Summary | Log | Files

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}