RobotCore 1.0
WPILib port to raspberry Pi
Loading...
Searching...
No Matches
ConflictDetector.java
1// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
4
5package org.wpilib.command3;
6
7import static org.wpilib.util.ErrorMessages.requireNonNullParam;
8
9import java.util.ArrayList;
10import java.util.Collection;
11import java.util.HashSet;
12import java.util.List;
13import java.util.Set;
14import java.util.stream.Collectors;
15
17public final class ConflictDetector {
18 private ConflictDetector() {
19 // This is a utility class!
20 }
21
30 public record Conflict(Command a, Command b, Set<Mechanism> sharedRequirements) {
37 public String description() {
38 var shared =
39 sharedRequirements.stream()
41 .sorted()
42 .collect(Collectors.joining(", "));
43 return "%s and %s both require %s".formatted(a.name(), b.name(), shared);
44 }
45 }
46
55 public static void throwIfConflicts(Collection<? extends Command> commands) {
56 requireNonNullParam(commands, "commands", "ConflictDetector.throwIfConflicts");
57 if (commands.size() <= 1) {
58 // can't have conflicts with only one command
59 return;
60 }
61
62 var conflicts = findAllConflicts(commands);
63 if (conflicts.isEmpty()) {
64 // No conflicts, all good
65 return;
66 }
67
68 StringBuilder message =
69 new StringBuilder("Commands running in parallel cannot share requirements: ");
70 for (int i = 0; i < conflicts.size(); i++) {
71 Conflict conflict = conflicts.get(i);
72 message.append(conflict.description());
73 if (i < conflicts.size() - 1) {
74 message.append("; ");
75 }
76 }
77
78 throw new IllegalArgumentException(message.toString());
79 }
80
87 @SuppressWarnings("PMD.CompareObjectsWithEquals")
88 public static List<Conflict> findAllConflicts(Collection<? extends Command> commands) {
89 requireNonNullParam(commands, "commands", "ConflictDetector.findAllConflicts");
90
91 List<Conflict> conflicts = new ArrayList<>();
92 if (commands.size() <= 1) {
93 return conflicts;
94 }
95
96 int i = 0;
97 for (Command command : commands) {
98 i++;
99 int j = 0;
100 for (Command other : commands) {
101 j++;
102 if (j <= i) {
103 // Skip all elements in 0..i so the inner loop only checks elements from i + 1 onward.
104 // Ordering of the elements in the pair doesn't matter, and this prevents finding every
105 // pair twice eg (A, B) and (B, A).
106 continue;
107 }
108
109 if (command == other) {
110 // Commands cannot conflict with themselves, so just in case the input collection happens
111 // to have duplicate elements we just skip any pairs of a command with itself.
112 continue;
113 }
114
115 if (command.conflictsWith(other)) {
116 conflicts.add(findConflict(command, other));
117 }
118 }
119 }
120
121 return conflicts;
122 }
123
124 private static Conflict findConflict(Command a, Command b) {
125 Set<Mechanism> sharedRequirements = new HashSet<>(a.requirements());
126 sharedRequirements.retainAll(b.requirements());
127 return new Conflict(a, b, Set.copyOf(sharedRequirements));
128 }
129}
static List< Conflict > findAllConflicts(Collection<? extends Command > commands)
record Conflict(Command a, Command b, Set< Mechanism > sharedRequirements)
static void throwIfConflicts(Collection<? extends Command > commands)
Set< Mechanism > requirements()