001// Copyright (c) FIRST and other WPILib contributors. 002// Open Source Software; you can modify and/or share it under the terms of 003// the WPILib BSD license file in the root directory of this project. 004 005package edu.wpi.first.wpilibj2.command; 006 007import java.util.Collection; 008import java.util.Collections; 009import java.util.Set; 010import java.util.WeakHashMap; 011 012/** 013 * A base for CommandGroups. Statically tracks commands that have been allocated to groups to ensure 014 * those commands are not also used independently, which can result in inconsistent command state 015 * and unpredictable execution. 016 */ 017public abstract class CommandGroupBase extends CommandBase { 018 private static final Set<Command> m_groupedCommands = 019 Collections.newSetFromMap(new WeakHashMap<>()); 020 021 static void registerGroupedCommands(Command... commands) { 022 m_groupedCommands.addAll(Set.of(commands)); 023 } 024 025 /** 026 * Clears the list of grouped commands, allowing all commands to be freely used again. 027 * 028 * <p>WARNING: Using this haphazardly can result in unexpected/undesirable behavior. Do not use 029 * this unless you fully understand what you are doing. 030 */ 031 public static void clearGroupedCommands() { 032 m_groupedCommands.clear(); 033 } 034 035 /** 036 * Removes a single command from the list of grouped commands, allowing it to be freely used 037 * again. 038 * 039 * <p>WARNING: Using this haphazardly can result in unexpected/undesirable behavior. Do not use 040 * this unless you fully understand what you are doing. 041 * 042 * @param command the command to remove from the list of grouped commands 043 */ 044 public static void clearGroupedCommand(Command command) { 045 m_groupedCommands.remove(command); 046 } 047 048 /** 049 * Requires that the specified commands not have been already allocated to a CommandGroup. Throws 050 * an {@link IllegalArgumentException} if commands have been allocated. 051 * 052 * @param commands The commands to check 053 */ 054 public static void requireUngrouped(Command... commands) { 055 requireUngrouped(Set.of(commands)); 056 } 057 058 /** 059 * Requires that the specified commands not have been already allocated to a CommandGroup. Throws 060 * an {@link IllegalArgumentException} if commands have been allocated. 061 * 062 * @param commands The commands to check 063 */ 064 public static void requireUngrouped(Collection<Command> commands) { 065 if (!Collections.disjoint(commands, getGroupedCommands())) { 066 throw new IllegalArgumentException("Commands cannot be added to more than one CommandGroup"); 067 } 068 } 069 070 static Set<Command> getGroupedCommands() { 071 return m_groupedCommands; 072 } 073 074 /** 075 * Adds the given commands to the command group. 076 * 077 * @param commands The commands to add. 078 */ 079 public abstract void addCommands(Command... commands); 080 081 /** 082 * Factory method for {@link SequentialCommandGroup}, included for brevity/convenience. 083 * 084 * @param commands the commands to include 085 * @return the command group 086 */ 087 public static CommandGroupBase sequence(Command... commands) { 088 return new SequentialCommandGroup(commands); 089 } 090 091 /** 092 * Factory method for {@link ParallelCommandGroup}, included for brevity/convenience. 093 * 094 * @param commands the commands to include 095 * @return the command group 096 */ 097 public static CommandGroupBase parallel(Command... commands) { 098 return new ParallelCommandGroup(commands); 099 } 100 101 /** 102 * Factory method for {@link ParallelRaceGroup}, included for brevity/convenience. 103 * 104 * @param commands the commands to include 105 * @return the command group 106 */ 107 public static CommandGroupBase race(Command... commands) { 108 return new ParallelRaceGroup(commands); 109 } 110 111 /** 112 * Factory method for {@link ParallelDeadlineGroup}, included for brevity/convenience. 113 * 114 * @param deadline the deadline command 115 * @param commands the commands to include 116 * @return the command group 117 */ 118 public static CommandGroupBase deadline(Command deadline, Command... commands) { 119 return new ParallelDeadlineGroup(deadline, commands); 120 } 121}