mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-21 01:01:43 +00:00
Replace SFINAE with concepts (#5361)
Concepts are cleaner to use and result in much better error messages for incorrect template use.
This commit is contained in:
@@ -4,17 +4,16 @@
|
||||
|
||||
#include "glass/Storage.h"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <wpi/StringExtras.h>
|
||||
#include <wpi/concepts.h>
|
||||
#include <wpi/json.h>
|
||||
|
||||
using namespace glass;
|
||||
|
||||
template <typename To>
|
||||
bool ConvertFromString(To* out, std::string_view str) {
|
||||
if constexpr (std::is_same_v<To, bool>) {
|
||||
if constexpr (std::same_as<To, bool>) {
|
||||
if (str == "true") {
|
||||
*out = true;
|
||||
} else if (str == "false") {
|
||||
@@ -24,7 +23,7 @@ bool ConvertFromString(To* out, std::string_view str) {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else if constexpr (std::is_floating_point_v<To>) {
|
||||
} else if constexpr (std::floating_point<To>) {
|
||||
if (auto val = wpi::parse_float<To>(str)) {
|
||||
*out = val.value();
|
||||
} else {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <wpi/SmallString.h>
|
||||
#include <wpi/SpanExtras.h>
|
||||
#include <wpi/StringExtras.h>
|
||||
#include <wpi/concepts.h>
|
||||
#include <wpi/mpack.h>
|
||||
#include <wpi/raw_ostream.h>
|
||||
|
||||
@@ -82,9 +83,8 @@ static std::string IntegerArrayToString(std::span<const int64_t> in) {
|
||||
return fmt::format("[{:d}]", fmt::join(in, ","));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <std::floating_point T>
|
||||
static std::string FloatArrayToString(std::span<const T> in) {
|
||||
static_assert(std::is_same_v<T, float> || std::is_same_v<T, double>);
|
||||
return fmt::format("[{:.6f}]", fmt::join(in, ","));
|
||||
}
|
||||
|
||||
@@ -729,9 +729,8 @@ static bool StringToIntegerArray(std::string_view in,
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <std::floating_point T>
|
||||
static bool StringToFloatArray(std::string_view in, std::vector<T>* out) {
|
||||
static_assert(std::is_same_v<T, float> || std::is_same_v<T, double>);
|
||||
in = wpi::trim(in);
|
||||
if (in.empty()) {
|
||||
return false;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <fmt/format.h>
|
||||
#include <wpi/Logger.h>
|
||||
#include <wpi/SpanExtras.h>
|
||||
#include <wpi/concepts.h>
|
||||
#include <wpi/json.h>
|
||||
#include <wpi/mpack.h>
|
||||
|
||||
@@ -104,12 +105,10 @@ static bool ObjGetStringArray(wpi::json::object_t& obj, std::string_view key,
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
requires(std::same_as<T, ClientMessageHandler> ||
|
||||
std::same_as<T, ServerMessageHandler>)
|
||||
static void WireDecodeTextImpl(std::string_view in, T& out,
|
||||
wpi::Logger& logger) {
|
||||
static_assert(std::is_same_v<T, ClientMessageHandler> ||
|
||||
std::is_same_v<T, ServerMessageHandler>,
|
||||
"T must be ClientMessageHandler or ServerMessageHandler");
|
||||
|
||||
wpi::json j;
|
||||
try {
|
||||
j = wpi::json::parse(in);
|
||||
@@ -150,7 +149,7 @@ static void WireDecodeTextImpl(std::string_view in, T& out,
|
||||
goto err;
|
||||
}
|
||||
|
||||
if constexpr (std::is_same_v<T, ClientMessageHandler>) {
|
||||
if constexpr (std::same_as<T, ClientMessageHandler>) {
|
||||
if (*method == PublishMsg::kMethodStr) {
|
||||
// name
|
||||
auto name = ObjGetString(*params, "name", &error);
|
||||
@@ -302,7 +301,7 @@ static void WireDecodeTextImpl(std::string_view in, T& out,
|
||||
error = fmt::format("unrecognized method '{}'", *method);
|
||||
goto err;
|
||||
}
|
||||
} else if constexpr (std::is_same_v<T, ServerMessageHandler>) {
|
||||
} else if constexpr (std::same_as<T, ServerMessageHandler>) {
|
||||
if (*method == AnnounceMsg::kMethodStr) {
|
||||
// name
|
||||
auto name = ObjGetString(*params, "name", &error);
|
||||
|
||||
@@ -12,10 +12,11 @@
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <wpi/concepts.h>
|
||||
|
||||
#include "ntcore_c.h"
|
||||
|
||||
namespace nt {
|
||||
@@ -377,11 +378,10 @@ class Value final {
|
||||
* time)
|
||||
* @return The entry value
|
||||
*/
|
||||
template <typename T,
|
||||
typename std::enable_if<std::is_same<T, std::string>::value>::type>
|
||||
template <std::same_as<std::string> T>
|
||||
static Value MakeString(T&& value, int64_t time = 0) {
|
||||
Value val{NT_STRING, time, private_init{}};
|
||||
auto data = std::make_shared<std::string>(std::forward(value));
|
||||
auto data = std::make_shared<std::string>(std::forward<T>(value));
|
||||
val.m_val.data.v_string.str = const_cast<char*>(data->c_str());
|
||||
val.m_val.data.v_string.len = data->size();
|
||||
val.m_storage = std::move(data);
|
||||
@@ -414,11 +414,10 @@ class Value final {
|
||||
* time)
|
||||
* @return The entry value
|
||||
*/
|
||||
template <typename T, typename std::enable_if<
|
||||
std::is_same<T, std::vector<uint8_t>>::value>::type>
|
||||
template <std::same_as<std::vector<uint8_t>> T>
|
||||
static Value MakeRaw(T&& value, int64_t time = 0) {
|
||||
Value val{NT_RAW, time, private_init{}};
|
||||
auto data = std::make_shared<std::vector<uint8_t>>(std::forward(value));
|
||||
auto data = std::make_shared<std::vector<uint8_t>>(std::forward<T>(value));
|
||||
val.m_val.data.v_raw.data = const_cast<uint8_t*>(data->data());
|
||||
val.m_val.data.v_raw.size = data->size();
|
||||
val.m_storage = std::move(data);
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include <wpi/concepts.h>
|
||||
|
||||
#include "../MockLogger.h"
|
||||
#include "../PubSubOptionsMatcher.h"
|
||||
#include "../SpanMatcher.h"
|
||||
@@ -99,12 +101,12 @@ static std::vector<uint8_t> EncodeServerBinary(const T& msgs) {
|
||||
std::vector<uint8_t> data;
|
||||
wpi::raw_uvector_ostream os{data};
|
||||
for (auto&& msg : msgs) {
|
||||
if constexpr (std::is_same_v<typename T::value_type, net::ServerMessage>) {
|
||||
if constexpr (std::same_as<typename T::value_type, net::ServerMessage>) {
|
||||
if (auto m = std::get_if<net::ServerValueMsg>(&msg.contents)) {
|
||||
net::WireEncodeBinary(os, m->topic, m->value.time(), m->value);
|
||||
}
|
||||
} else if constexpr (std::is_same_v<typename T::value_type,
|
||||
net::ClientMessage>) {
|
||||
} else if constexpr (std::same_as<typename T::value_type,
|
||||
net::ClientMessage>) {
|
||||
if (auto m = std::get_if<net::ClientValueMsg>(&msg.contents)) {
|
||||
net::WireEncodeBinary(os, Handle{m->pubHandle}.GetIndex(),
|
||||
m->value.time(), m->value);
|
||||
|
||||
@@ -5,9 +5,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <wpi/concepts.h>
|
||||
|
||||
#include "frc2/command/Command.h"
|
||||
#include "frc2/command/CommandPtr.h"
|
||||
|
||||
@@ -21,8 +22,7 @@ namespace frc2 {
|
||||
*
|
||||
* This class is provided by the NewCommands VendorDep
|
||||
*/
|
||||
template <typename Base, typename CRTP,
|
||||
typename = std::enable_if_t<std::is_base_of_v<Command, Base>>>
|
||||
template <std::derived_from<Command> Base, typename CRTP>
|
||||
class CommandHelper : public Base {
|
||||
using Base::Base;
|
||||
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <wpi/concepts.h>
|
||||
|
||||
#include "frc2/command/CommandBase.h"
|
||||
|
||||
namespace frc2 {
|
||||
@@ -30,11 +32,11 @@ class CommandPtr final {
|
||||
explicit CommandPtr(std::unique_ptr<CommandBase>&& command)
|
||||
: m_ptr(std::move(command)) {}
|
||||
|
||||
template <class T, typename = std::enable_if_t<std::is_base_of_v<
|
||||
Command, std::remove_reference_t<T>>>>
|
||||
template <std::derived_from<Command> T>
|
||||
// NOLINTNEXTLINE (bugprone-forwarding-reference-overload)
|
||||
explicit CommandPtr(T&& command)
|
||||
: CommandPtr(std::make_unique<std::remove_reference_t<T>>(
|
||||
std::forward<T>(command))) {}
|
||||
: CommandPtr(
|
||||
std::make_unique<std::decay_t<T>>(std::forward<T>(command))) {}
|
||||
|
||||
CommandPtr(CommandPtr&&) = default;
|
||||
CommandPtr& operator=(CommandPtr&&) = default;
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <networktables/NTSendable.h>
|
||||
#include <units/time.h>
|
||||
#include <wpi/FunctionExtras.h>
|
||||
#include <wpi/concepts.h>
|
||||
#include <wpi/deprecated.h>
|
||||
#include <wpi/sendable/SendableHelper.h>
|
||||
|
||||
@@ -175,16 +176,14 @@ class CommandScheduler final : public nt::NTSendable,
|
||||
* @param subsystem the subsystem whose default command will be set
|
||||
* @param defaultCommand the default command to associate with the subsystem
|
||||
*/
|
||||
template <class T, typename = std::enable_if_t<std::is_base_of_v<
|
||||
Command, std::remove_reference_t<T>>>>
|
||||
template <std::derived_from<Command> T>
|
||||
void SetDefaultCommand(Subsystem* subsystem, T&& defaultCommand) {
|
||||
if (!defaultCommand.HasRequirement(subsystem)) {
|
||||
throw FRC_MakeError(frc::err::CommandIllegalUse,
|
||||
"Default commands must require their subsystem!");
|
||||
}
|
||||
SetDefaultCommandImpl(subsystem,
|
||||
std::make_unique<std::remove_reference_t<T>>(
|
||||
std::forward<T>(defaultCommand)));
|
||||
SetDefaultCommandImpl(subsystem, std::make_unique<std::decay_t<T>>(
|
||||
std::forward<T>(defaultCommand)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <wpi/concepts.h>
|
||||
|
||||
#include "frc2/command/CommandPtr.h"
|
||||
#include "frc2/command/SelectCommand.h"
|
||||
|
||||
@@ -166,10 +168,10 @@ CommandPtr Either(CommandPtr&& onTrue, CommandPtr&& onFalse,
|
||||
* @param selector the selector function
|
||||
* @param commands map of commands to select from
|
||||
*/
|
||||
template <typename Key, class... Types>
|
||||
template <typename Key, std::convertible_to<CommandPtr>... CommandPtrs>
|
||||
[[nodiscard]]
|
||||
CommandPtr Select(std::function<Key()> selector,
|
||||
std::pair<Key, Types>&&... commands) {
|
||||
std::pair<Key, CommandPtrs>&&... commands) {
|
||||
std::vector<std::pair<Key, std::unique_ptr<Command>>> vec;
|
||||
|
||||
((void)vec.emplace_back(commands.first, std::move(commands.second).Unwrap()),
|
||||
@@ -185,7 +187,7 @@ namespace impl {
|
||||
/**
|
||||
* Create a vector of commands.
|
||||
*/
|
||||
template <typename... Args>
|
||||
template <std::convertible_to<CommandPtr>... Args>
|
||||
std::vector<CommandPtr> MakeVector(Args&&... args) {
|
||||
std::vector<CommandPtr> data;
|
||||
data.reserve(sizeof...(Args));
|
||||
@@ -204,10 +206,10 @@ CommandPtr Sequence(std::vector<CommandPtr>&& commands);
|
||||
/**
|
||||
* Runs a group of commands in series, one after the other.
|
||||
*/
|
||||
template <typename... Args>
|
||||
template <std::convertible_to<CommandPtr>... CommandPtrs>
|
||||
[[nodiscard]]
|
||||
CommandPtr Sequence(Args&&... commands) {
|
||||
return Sequence(impl::MakeVector(std::forward<Args>(commands)...));
|
||||
CommandPtr Sequence(CommandPtrs&&... commands) {
|
||||
return Sequence(impl::MakeVector(std::forward<CommandPtrs>(commands)...));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -221,10 +223,11 @@ CommandPtr RepeatingSequence(std::vector<CommandPtr>&& commands);
|
||||
* Runs a group of commands in series, one after the other. Once the last
|
||||
* command ends, the group is restarted.
|
||||
*/
|
||||
template <typename... Args>
|
||||
template <std::convertible_to<CommandPtr>... CommandPtrs>
|
||||
[[nodiscard]]
|
||||
CommandPtr RepeatingSequence(Args&&... commands) {
|
||||
return RepeatingSequence(impl::MakeVector(std::forward<Args>(commands)...));
|
||||
CommandPtr RepeatingSequence(CommandPtrs&&... commands) {
|
||||
return RepeatingSequence(
|
||||
impl::MakeVector(std::forward<CommandPtrs>(commands)...));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -238,10 +241,10 @@ CommandPtr Parallel(std::vector<CommandPtr>&& commands);
|
||||
* Runs a group of commands at the same time. Ends once all commands in the
|
||||
* group finish.
|
||||
*/
|
||||
template <typename... Args>
|
||||
template <std::convertible_to<CommandPtr>... CommandPtrs>
|
||||
[[nodiscard]]
|
||||
CommandPtr Parallel(Args&&... commands) {
|
||||
return Parallel(impl::MakeVector(std::forward<Args>(commands)...));
|
||||
CommandPtr Parallel(CommandPtrs&&... commands) {
|
||||
return Parallel(impl::MakeVector(std::forward<CommandPtrs>(commands)...));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -255,10 +258,10 @@ CommandPtr Race(std::vector<CommandPtr>&& commands);
|
||||
* Runs a group of commands at the same time. Ends once any command in the group
|
||||
* finishes, and cancels the others.
|
||||
*/
|
||||
template <typename... Args>
|
||||
template <std::convertible_to<CommandPtr>... CommandPtrs>
|
||||
[[nodiscard]]
|
||||
CommandPtr Race(Args&&... commands) {
|
||||
return Race(impl::MakeVector(std::forward<Args>(commands)...));
|
||||
CommandPtr Race(CommandPtrs&&... commands) {
|
||||
return Race(impl::MakeVector(std::forward<CommandPtrs>(commands)...));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -272,11 +275,11 @@ CommandPtr Deadline(CommandPtr&& deadline, std::vector<CommandPtr>&& others);
|
||||
* Runs a group of commands at the same time. Ends once a specific command
|
||||
* finishes, and cancels the others.
|
||||
*/
|
||||
template <typename... Args>
|
||||
template <std::convertible_to<CommandPtr>... CommandPtrs>
|
||||
[[nodiscard]]
|
||||
CommandPtr Deadline(CommandPtr&& deadline, Args&&... commands) {
|
||||
CommandPtr Deadline(CommandPtr&& deadline, CommandPtrs&&... commands) {
|
||||
return Deadline(std::move(deadline),
|
||||
impl::MakeVector(std::forward<Args>(commands)...));
|
||||
impl::MakeVector(std::forward<CommandPtrs>(commands)...));
|
||||
}
|
||||
|
||||
} // namespace cmd
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include <wpi/concepts.h>
|
||||
|
||||
#include "frc2/command/CommandBase.h"
|
||||
#include "frc2/command/CommandHelper.h"
|
||||
|
||||
@@ -35,16 +37,14 @@ class ConditionalCommand
|
||||
* @param onFalse the command to run if the condition is false
|
||||
* @param condition the condition to determine which command to run
|
||||
*/
|
||||
template <class T1, class T2,
|
||||
typename = std::enable_if_t<
|
||||
std::is_base_of_v<Command, std::remove_reference_t<T1>>>,
|
||||
typename = std::enable_if_t<
|
||||
std::is_base_of_v<Command, std::remove_reference_t<T2>>>>
|
||||
ConditionalCommand(T1&& onTrue, T2&& onFalse, std::function<bool()> condition)
|
||||
: ConditionalCommand(std::make_unique<std::remove_reference_t<T1>>(
|
||||
std::forward<T1>(onTrue)),
|
||||
std::make_unique<std::remove_reference_t<T2>>(
|
||||
std::forward<T2>(onFalse)),
|
||||
template <std::derived_from<Command> Command1,
|
||||
std::derived_from<Command> Command2>
|
||||
ConditionalCommand(Command1&& onTrue, Command2&& onFalse,
|
||||
std::function<bool()> condition)
|
||||
: ConditionalCommand(std::make_unique<std::decay_t<Command1>>(
|
||||
std::forward<Command1>(onTrue)),
|
||||
std::make_unique<std::decay_t<Command2>>(
|
||||
std::forward<Command2>(onFalse)),
|
||||
condition) {}
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,9 +10,13 @@
|
||||
#endif
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <wpi/DecayedDerivedFrom.h>
|
||||
#include <wpi/concepts.h>
|
||||
|
||||
#include "frc2/command/CommandGroupBase.h"
|
||||
#include "frc2/command/CommandHelper.h"
|
||||
|
||||
@@ -50,11 +54,9 @@ class ParallelCommandGroup
|
||||
*
|
||||
* @param commands the commands to include in this composition.
|
||||
*/
|
||||
template <class... Types,
|
||||
typename = std::enable_if_t<std::conjunction_v<
|
||||
std::is_base_of<Command, std::remove_reference_t<Types>>...>>>
|
||||
explicit ParallelCommandGroup(Types&&... commands) {
|
||||
AddCommands(std::forward<Types>(commands)...);
|
||||
template <wpi::DecayedDerivedFrom<Command>... Commands>
|
||||
explicit ParallelCommandGroup(Commands&&... commands) {
|
||||
AddCommands(std::forward<Commands>(commands)...);
|
||||
}
|
||||
|
||||
ParallelCommandGroup(ParallelCommandGroup&& other) = default;
|
||||
@@ -65,13 +67,11 @@ class ParallelCommandGroup
|
||||
// Prevent template expansion from emulating copy ctor
|
||||
ParallelCommandGroup(ParallelCommandGroup&) = delete;
|
||||
|
||||
template <class... Types,
|
||||
typename = std::enable_if_t<std::conjunction_v<
|
||||
std::is_base_of<Command, std::remove_reference_t<Types>>...>>>
|
||||
void AddCommands(Types&&... commands) {
|
||||
template <wpi::DecayedDerivedFrom<Command>... Commands>
|
||||
void AddCommands(Commands&&... commands) {
|
||||
std::vector<std::unique_ptr<Command>> foo;
|
||||
((void)foo.emplace_back(std::make_unique<std::remove_reference_t<Types>>(
|
||||
std::forward<Types>(commands))),
|
||||
((void)foo.emplace_back(std::make_unique<std::decay_t<Commands>>(
|
||||
std::forward<Commands>(commands))),
|
||||
...);
|
||||
AddCommands(std::move(foo));
|
||||
}
|
||||
|
||||
@@ -10,9 +10,13 @@
|
||||
#endif
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <wpi/DecayedDerivedFrom.h>
|
||||
#include <wpi/concepts.h>
|
||||
|
||||
#include "frc2/command/CommandGroupBase.h"
|
||||
#include "frc2/command/CommandHelper.h"
|
||||
|
||||
@@ -54,15 +58,11 @@ class ParallelDeadlineGroup
|
||||
* @param deadline the command that determines when the composition ends
|
||||
* @param commands the commands to be executed
|
||||
*/
|
||||
template <class T, class... Types,
|
||||
typename = std::enable_if_t<
|
||||
std::is_base_of_v<Command, std::remove_reference_t<T>>>,
|
||||
typename = std::enable_if_t<std::conjunction_v<
|
||||
std::is_base_of<Command, std::remove_reference_t<Types>>...>>>
|
||||
explicit ParallelDeadlineGroup(T&& deadline, Types&&... commands) {
|
||||
SetDeadline(std::make_unique<std::remove_reference_t<T>>(
|
||||
std::forward<T>(deadline)));
|
||||
AddCommands(std::forward<Types>(commands)...);
|
||||
template <wpi::DecayedDerivedFrom<Command> T,
|
||||
wpi::DecayedDerivedFrom<Command>... Commands>
|
||||
explicit ParallelDeadlineGroup(T&& deadline, Commands&&... commands) {
|
||||
SetDeadline(std::make_unique<std::decay_t<T>>(std::forward<T>(deadline)));
|
||||
AddCommands(std::forward<Commands>(commands)...);
|
||||
}
|
||||
|
||||
ParallelDeadlineGroup(ParallelDeadlineGroup&& other) = default;
|
||||
@@ -73,13 +73,11 @@ class ParallelDeadlineGroup
|
||||
// Prevent template expansion from emulating copy ctor
|
||||
ParallelDeadlineGroup(ParallelDeadlineGroup&) = delete;
|
||||
|
||||
template <class... Types,
|
||||
typename = std::enable_if_t<std::conjunction_v<
|
||||
std::is_base_of<Command, std::remove_reference_t<Types>>...>>>
|
||||
void AddCommands(Types&&... commands) {
|
||||
template <wpi::DecayedDerivedFrom<Command>... Commands>
|
||||
void AddCommands(Commands&&... commands) {
|
||||
std::vector<std::unique_ptr<Command>> foo;
|
||||
((void)foo.emplace_back(std::make_unique<std::remove_reference_t<Types>>(
|
||||
std::forward<Types>(commands))),
|
||||
((void)foo.emplace_back(std::make_unique<std::decay_t<Commands>>(
|
||||
std::forward<Commands>(commands))),
|
||||
...);
|
||||
AddCommands(std::move(foo));
|
||||
}
|
||||
|
||||
@@ -10,9 +10,13 @@
|
||||
#endif
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <wpi/DecayedDerivedFrom.h>
|
||||
#include <wpi/concepts.h>
|
||||
|
||||
#include "frc2/command/CommandGroupBase.h"
|
||||
#include "frc2/command/CommandHelper.h"
|
||||
|
||||
@@ -40,11 +44,9 @@ class ParallelRaceGroup
|
||||
*/
|
||||
explicit ParallelRaceGroup(std::vector<std::unique_ptr<Command>>&& commands);
|
||||
|
||||
template <class... Types,
|
||||
typename = std::enable_if_t<std::conjunction_v<
|
||||
std::is_base_of<Command, std::remove_reference_t<Types>>...>>>
|
||||
explicit ParallelRaceGroup(Types&&... commands) {
|
||||
AddCommands(std::forward<Types>(commands)...);
|
||||
template <wpi::DecayedDerivedFrom<Command>... Commands>
|
||||
explicit ParallelRaceGroup(Commands&&... commands) {
|
||||
AddCommands(std::forward<Commands>(commands)...);
|
||||
}
|
||||
|
||||
ParallelRaceGroup(ParallelRaceGroup&& other) = default;
|
||||
@@ -55,11 +57,11 @@ class ParallelRaceGroup
|
||||
// Prevent template expansion from emulating copy ctor
|
||||
ParallelRaceGroup(ParallelRaceGroup&) = delete;
|
||||
|
||||
template <class... Types>
|
||||
void AddCommands(Types&&... commands) {
|
||||
template <wpi::DecayedDerivedFrom<Command>... Commands>
|
||||
void AddCommands(Commands&&... commands) {
|
||||
std::vector<std::unique_ptr<Command>> foo;
|
||||
((void)foo.emplace_back(std::make_unique<std::remove_reference_t<Types>>(
|
||||
std::forward<Types>(commands))),
|
||||
((void)foo.emplace_back(std::make_unique<std::decay_t<Commands>>(
|
||||
std::forward<Commands>(commands))),
|
||||
...);
|
||||
AddCommands(std::move(foo));
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include <wpi/concepts.h>
|
||||
|
||||
#include "frc2/command/CommandBase.h"
|
||||
#include "frc2/command/CommandHelper.h"
|
||||
|
||||
@@ -46,10 +48,9 @@ class PerpetualCommand : public CommandHelper<CommandBase, PerpetualCommand> {
|
||||
WPI_DEPRECATED(
|
||||
"PerpetualCommand violates the assumption that execute() doesn't get "
|
||||
"called after isFinished() returns true -- an assumption that should be "
|
||||
"valid."
|
||||
"This was unsafe/undefined behavior from the start, and RepeatCommand "
|
||||
"provides an easy way to achieve similar end results with slightly "
|
||||
"different (and safe) semantics.")
|
||||
"valid. This was unsafe/undefined behavior from the start, and "
|
||||
"RepeatCommand provides an easy way to achieve similar end results with "
|
||||
"slightly different (and safe) semantics.")
|
||||
explicit PerpetualCommand(std::unique_ptr<Command>&& command);
|
||||
WPI_IGNORE_DEPRECATED
|
||||
|
||||
@@ -60,18 +61,17 @@ class PerpetualCommand : public CommandHelper<CommandBase, PerpetualCommand> {
|
||||
*
|
||||
* @param command the command to run perpetually
|
||||
*/
|
||||
template <class T, typename = std::enable_if_t<std::is_base_of_v<
|
||||
Command, std::remove_reference_t<T>>>>
|
||||
template <std::derived_from<Command> T>
|
||||
WPI_DEPRECATED(
|
||||
"PerpetualCommand violates the assumption that execute() doesn't get "
|
||||
"called after isFinished() returns true -- an assumption that should be "
|
||||
"valid."
|
||||
"This was unsafe/undefined behavior from the start, and RepeatCommand "
|
||||
"provides an easy way to achieve similar end results with slightly "
|
||||
"different (and safe) semantics.")
|
||||
"called after isFinished() returns true -- an assumption that should "
|
||||
"be valid. This was unsafe/undefined behavior from the start, and "
|
||||
"RepeatCommand provides an easy way to achieve similar end results "
|
||||
"with slightly different (and safe) semantics.")
|
||||
// NOLINTNEXTLINE (bugprone-forwarding-reference-overload)
|
||||
explicit PerpetualCommand(T&& command)
|
||||
: PerpetualCommand(std::make_unique<std::remove_reference_t<T>>(
|
||||
std::forward<T>(command))) {}
|
||||
: PerpetualCommand(
|
||||
std::make_unique<std::decay_t<T>>(std::forward<T>(command))) {}
|
||||
WPI_UNIGNORE_DEPRECATED
|
||||
|
||||
PerpetualCommand(PerpetualCommand&& other) = default;
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include <wpi/concepts.h>
|
||||
|
||||
#include "frc2/command/CommandBase.h"
|
||||
#include "frc2/command/CommandHelper.h"
|
||||
|
||||
@@ -44,11 +46,11 @@ class RepeatCommand : public CommandHelper<CommandBase, RepeatCommand> {
|
||||
*
|
||||
* @param command the command to run repeatedly
|
||||
*/
|
||||
template <class T, typename = std::enable_if_t<std::is_base_of_v<
|
||||
Command, std::remove_reference_t<T>>>>
|
||||
template <std::derived_from<Command> T>
|
||||
// NOLINTNEXTLINE (bugprone-forwarding-reference-overload)
|
||||
explicit RepeatCommand(T&& command)
|
||||
: RepeatCommand(std::make_unique<std::remove_reference_t<T>>(
|
||||
std::forward<T>(command))) {}
|
||||
: RepeatCommand(
|
||||
std::make_unique<std::decay_t<T>>(std::forward<T>(command))) {}
|
||||
|
||||
RepeatCommand(RepeatCommand&& other) = default;
|
||||
|
||||
|
||||
@@ -11,11 +11,11 @@
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <wpi/concepts.h>
|
||||
#include <wpi/sendable/SendableBuilder.h>
|
||||
|
||||
#include "frc2/command/CommandBase.h"
|
||||
@@ -43,17 +43,15 @@ class SelectCommand : public CommandHelper<CommandBase, SelectCommand<Key>> {
|
||||
* @param commands the map of commands to choose from
|
||||
* @param selector the selector to determine which command to run
|
||||
*/
|
||||
template <class... Types,
|
||||
typename = std::enable_if_t<std::conjunction_v<
|
||||
std::is_base_of<Command, std::remove_reference_t<Types>>...>>>
|
||||
template <std::derived_from<Command>... Commands>
|
||||
explicit SelectCommand(std::function<Key()> selector,
|
||||
std::pair<Key, Types>... commands)
|
||||
std::pair<Key, Commands>... commands)
|
||||
: m_selector{std::move(selector)} {
|
||||
std::vector<std::pair<Key, std::unique_ptr<Command>>> foo;
|
||||
|
||||
((void)foo.emplace_back(commands.first,
|
||||
std::make_unique<std::remove_reference_t<Types>>(
|
||||
std::move(commands.second))),
|
||||
((void)foo.emplace_back(
|
||||
commands.first,
|
||||
std::make_unique<std::decay_t<Commands>>(std::move(commands.second))),
|
||||
...);
|
||||
|
||||
for (auto&& command : foo) {
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <wpi/DecayedDerivedFrom.h>
|
||||
#include <wpi/concepts.h>
|
||||
|
||||
#include "frc2/command/CommandGroupBase.h"
|
||||
#include "frc2/command/CommandHelper.h"
|
||||
|
||||
@@ -53,11 +56,9 @@ class SequentialCommandGroup
|
||||
*
|
||||
* @param commands the commands to include in this composition.
|
||||
*/
|
||||
template <class... Types,
|
||||
typename = std::enable_if_t<std::conjunction_v<
|
||||
std::is_base_of<Command, std::remove_reference_t<Types>>...>>>
|
||||
explicit SequentialCommandGroup(Types&&... commands) {
|
||||
AddCommands(std::forward<Types>(commands)...);
|
||||
template <wpi::DecayedDerivedFrom<Command>... Commands>
|
||||
explicit SequentialCommandGroup(Commands&&... commands) {
|
||||
AddCommands(std::forward<Commands>(commands)...);
|
||||
}
|
||||
|
||||
SequentialCommandGroup(SequentialCommandGroup&& other) = default;
|
||||
@@ -68,13 +69,11 @@ class SequentialCommandGroup
|
||||
// Prevent template expansion from emulating copy ctor
|
||||
SequentialCommandGroup(SequentialCommandGroup&) = delete;
|
||||
|
||||
template <class... Types,
|
||||
typename = std::enable_if_t<std::conjunction_v<
|
||||
std::is_base_of<Command, std::remove_reference_t<Types>>...>>>
|
||||
void AddCommands(Types&&... commands) {
|
||||
template <wpi::DecayedDerivedFrom<Command>... Commands>
|
||||
void AddCommands(Commands&&... commands) {
|
||||
std::vector<std::unique_ptr<Command>> foo;
|
||||
((void)foo.emplace_back(std::make_unique<std::remove_reference_t<Types>>(
|
||||
std::forward<Types>(commands))),
|
||||
((void)foo.emplace_back(std::make_unique<std::decay_t<Commands>>(
|
||||
std::forward<Commands>(commands))),
|
||||
...);
|
||||
AddCommands(std::move(foo));
|
||||
}
|
||||
|
||||
@@ -4,9 +4,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <wpi/concepts.h>
|
||||
|
||||
#include "frc2/command/CommandScheduler.h"
|
||||
|
||||
namespace frc2 {
|
||||
@@ -65,8 +66,7 @@ class Subsystem {
|
||||
*
|
||||
* @param defaultCommand the default command to associate with this subsystem
|
||||
*/
|
||||
template <class T, typename = std::enable_if_t<std::is_base_of_v<
|
||||
Command, std::remove_reference_t<T>>>>
|
||||
template <std::derived_from<Command> T>
|
||||
void SetDefaultCommand(T&& defaultCommand) {
|
||||
CommandScheduler::GetInstance().SetDefaultCommand(
|
||||
this, std::forward<T>(defaultCommand));
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include <wpi/concepts.h>
|
||||
|
||||
#include "frc2/command/CommandBase.h"
|
||||
#include "frc2/command/CommandHelper.h"
|
||||
|
||||
@@ -39,11 +41,11 @@ class WrapperCommand : public CommandHelper<CommandBase, WrapperCommand> {
|
||||
* @param command the command being wrapped. Trying to directly schedule this
|
||||
* command or add it to a group will throw an exception.
|
||||
*/
|
||||
template <class T, typename = std::enable_if_t<std::is_base_of_v<
|
||||
Command, std::remove_reference_t<T>>>>
|
||||
template <std::derived_from<Command> T>
|
||||
// NOLINTNEXTLINE (bugprone-forwarding-reference-overload)
|
||||
explicit WrapperCommand(T&& command)
|
||||
: WrapperCommand(std::make_unique<std::remove_reference_t<T>>(
|
||||
std::forward<T>(command))) {}
|
||||
: WrapperCommand(
|
||||
std::make_unique<std::decay_t<T>>(std::forward<T>(command))) {}
|
||||
|
||||
WrapperCommand(WrapperCommand&& other) = default;
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <span>
|
||||
#include <utility>
|
||||
|
||||
#include <wpi/concepts.h>
|
||||
#include <wpi/deprecated.h>
|
||||
|
||||
#include "Trigger.h"
|
||||
@@ -65,8 +66,7 @@ class Button : public Trigger {
|
||||
* @return The trigger, for chained calls.
|
||||
* @deprecated Replace with Trigger::OnTrue()
|
||||
*/
|
||||
template <class T, typename = std::enable_if_t<std::is_base_of_v<
|
||||
Command, std::remove_reference_t<T>>>>
|
||||
template <std::derived_from<Command> T>
|
||||
WPI_DEPRECATED("Replace with Trigger#OnTrue()")
|
||||
Button WhenPressed(T&& command) {
|
||||
WhenActive(std::forward<T>(command));
|
||||
@@ -117,8 +117,7 @@ class Button : public Trigger {
|
||||
* @return The button, for chained calls.
|
||||
* @deprecated Replace with Trigger::WhileTrue(command.Repeatedly())
|
||||
*/
|
||||
template <class T, typename = std::enable_if_t<std::is_base_of_v<
|
||||
Command, std::remove_reference_t<T>>>>
|
||||
template <std::derived_from<Command> T>
|
||||
WPI_DEPRECATED("Replace with Trigger#WhileTrue(command.Repeatedly())")
|
||||
Button WhileHeld(T&& command) {
|
||||
WhileActiveContinous(std::forward<T>(command));
|
||||
@@ -169,8 +168,7 @@ class Button : public Trigger {
|
||||
* @return The button, for chained calls.
|
||||
* @deprecated Replace with Trigger::WhileTrue()
|
||||
*/
|
||||
template <class T, typename = std::enable_if_t<std::is_base_of_v<
|
||||
Command, std::remove_reference_t<T>>>>
|
||||
template <std::derived_from<Command> T>
|
||||
WPI_DEPRECATED("Replace with Trigger#WhileTrue()")
|
||||
Button WhenHeld(T&& command) {
|
||||
WhileActiveOnce(std::forward<T>(command));
|
||||
@@ -199,8 +197,7 @@ class Button : public Trigger {
|
||||
* @return The button, for chained calls.
|
||||
* @deprecated Replace with Trigger::OnFalse()
|
||||
*/
|
||||
template <class T, typename = std::enable_if_t<std::is_base_of_v<
|
||||
Command, std::remove_reference_t<T>>>>
|
||||
template <std::derived_from<Command> T>
|
||||
WPI_DEPRECATED("Replace with Trigger#OnFalse()")
|
||||
Button WhenReleased(T&& command) {
|
||||
WhenInactive(std::forward<T>(command));
|
||||
@@ -251,8 +248,7 @@ class Button : public Trigger {
|
||||
* @return The button, for chained calls.
|
||||
* @deprecated Replace with Trigger::ToggleOnTrue()
|
||||
*/
|
||||
template <class T, typename = std::enable_if_t<std::is_base_of_v<
|
||||
Command, std::remove_reference_t<T>>>>
|
||||
template <std::derived_from<Command> T>
|
||||
WPI_DEPRECATED("Replace with Trigger#ToggleOnTrue()")
|
||||
Button ToggleWhenPressed(T&& command) {
|
||||
ToggleWhenActive(std::forward<T>(command));
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <frc/event/EventLoop.h>
|
||||
#include <frc/filter/Debouncer.h>
|
||||
#include <units/time.h>
|
||||
#include <wpi/concepts.h>
|
||||
#include <wpi/deprecated.h>
|
||||
|
||||
#include "frc2/command/Command.h"
|
||||
@@ -226,12 +227,11 @@ class Trigger {
|
||||
* @return The trigger, for chained calls.
|
||||
* @deprecated Use OnTrue(Command) instead
|
||||
*/
|
||||
template <class T, typename = std::enable_if_t<std::is_base_of_v<
|
||||
Command, std::remove_reference_t<T>>>>
|
||||
template <std::derived_from<Command> T>
|
||||
WPI_DEPRECATED("Use OnTrue(Command) instead")
|
||||
Trigger WhenActive(T&& command) {
|
||||
m_loop->Bind([condition = m_condition, previous = m_condition(),
|
||||
command = std::make_unique<std::remove_reference_t<T>>(
|
||||
command = std::make_unique<std::decay_t<T>>(
|
||||
std::forward<T>(command))]() mutable {
|
||||
bool current = condition();
|
||||
|
||||
@@ -296,14 +296,13 @@ class Trigger {
|
||||
* @deprecated Use WhileTrue(Command) with RepeatCommand, or bind
|
||||
command::Schedule with IfHigh(std::function<void()>).
|
||||
*/
|
||||
template <class T, typename = std::enable_if_t<std::is_base_of_v<
|
||||
Command, std::remove_reference_t<T>>>>
|
||||
template <std::derived_from<Command> T>
|
||||
WPI_DEPRECATED(
|
||||
"Use WhileTrue(Command) with RepeatCommand, or bind command::Schedule "
|
||||
"with IfHigh(std::function<void()>).")
|
||||
Trigger WhileActiveContinous(T&& command) {
|
||||
m_loop->Bind([condition = m_condition, previous = m_condition(),
|
||||
command = std::make_unique<std::remove_reference_t<T>>(
|
||||
command = std::make_unique<std::decay_t<T>>(
|
||||
std::forward<T>(command))]() mutable {
|
||||
bool current = condition();
|
||||
|
||||
@@ -363,12 +362,11 @@ class Trigger {
|
||||
* @return The trigger, for chained calls.
|
||||
* @deprecated Use WhileTrue(Command) instead.
|
||||
*/
|
||||
template <class T, typename = std::enable_if_t<std::is_base_of_v<
|
||||
Command, std::remove_reference_t<T>>>>
|
||||
template <std::derived_from<Command> T>
|
||||
WPI_DEPRECATED("Use WhileTrue(Command) instead.")
|
||||
Trigger WhileActiveOnce(T&& command) {
|
||||
m_loop->Bind([condition = m_condition, previous = m_condition(),
|
||||
command = std::make_unique<std::remove_reference_t<T>>(
|
||||
command = std::make_unique<std::decay_t<T>>(
|
||||
std::forward<T>(command))]() mutable {
|
||||
bool current = condition();
|
||||
|
||||
@@ -405,12 +403,11 @@ class Trigger {
|
||||
* @return The trigger, for chained calls.
|
||||
* @deprecated Use OnFalse(Command) instead.
|
||||
*/
|
||||
template <class T, typename = std::enable_if_t<std::is_base_of_v<
|
||||
Command, std::remove_reference_t<T>>>>
|
||||
template <std::derived_from<Command> T>
|
||||
WPI_DEPRECATED("Use OnFalse(Command) instead.")
|
||||
Trigger WhenInactive(T&& command) {
|
||||
m_loop->Bind([condition = m_condition, previous = m_condition(),
|
||||
command = std::make_unique<std::remove_reference_t<T>>(
|
||||
command = std::make_unique<std::decay_t<T>>(
|
||||
std::forward<T>(command))]() mutable {
|
||||
bool current = condition();
|
||||
|
||||
@@ -471,12 +468,11 @@ class Trigger {
|
||||
* @return The trigger, for chained calls.
|
||||
* @deprecated Use ToggleOnTrue(Command) instead.
|
||||
*/
|
||||
template <class T, typename = std::enable_if_t<std::is_base_of_v<
|
||||
Command, std::remove_reference_t<T>>>>
|
||||
template <std::derived_from<Command> T>
|
||||
WPI_DEPRECATED("Use ToggleOnTrue(Command) instead.")
|
||||
Trigger ToggleWhenActive(T&& command) {
|
||||
m_loop->Bind([condition = m_condition, previous = m_condition(),
|
||||
command = std::make_unique<std::remove_reference_t<T>>(
|
||||
command = std::make_unique<std::decay_t<T>>(
|
||||
std::forward<T>(command))]() mutable {
|
||||
bool current = condition();
|
||||
|
||||
|
||||
@@ -34,8 +34,12 @@ struct all_constructible_and_convertible<T, First, Rest...>
|
||||
std::is_constructible_v<T, First> && std::is_convertible_v<First, T>,
|
||||
all_constructible_and_convertible<T, Rest...>, std::false_type> {};
|
||||
|
||||
template <typename T, typename... Args,
|
||||
typename std::enable_if_t<!std::is_trivially_copyable_v<T>, int> = 0>
|
||||
template <typename T, typename First, typename... Rest>
|
||||
inline constexpr bool all_constructible_and_convertible_v =
|
||||
all_constructible_and_convertible<T, First, Rest...>::value;
|
||||
|
||||
template <typename T, typename... Args>
|
||||
requires(!std::is_trivially_copyable_v<T>)
|
||||
std::vector<T> make_vector_impl(Args&&... args) {
|
||||
std::vector<T> vec;
|
||||
vec.reserve(sizeof...(Args));
|
||||
@@ -44,19 +48,17 @@ std::vector<T> make_vector_impl(Args&&... args) {
|
||||
return vec;
|
||||
}
|
||||
|
||||
template <typename T, typename... Args,
|
||||
typename std::enable_if_t<std::is_trivially_copyable_v<T>, int> = 0>
|
||||
template <typename T, typename... Args>
|
||||
requires std::is_trivially_copyable_v<T>
|
||||
std::vector<T> make_vector_impl(Args&&... args) {
|
||||
return std::vector<T>{std::forward<Args>(args)...};
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <
|
||||
typename T = void, typename... Args,
|
||||
typename V = detail::vec_type_helper_t<T, Args...>,
|
||||
typename std::enable_if_t<
|
||||
detail::all_constructible_and_convertible<V, Args...>::value, int> = 0>
|
||||
template <typename T = void, typename... Args,
|
||||
typename V = detail::vec_type_helper_t<T, Args...>>
|
||||
requires detail::all_constructible_and_convertible_v<V, Args...>
|
||||
std::vector<V> make_vector(Args&&... args) {
|
||||
return detail::make_vector_impl<V>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
#include <functional>
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <hal/Types.h>
|
||||
#include <units/time.h>
|
||||
#include <wpi/concepts.h>
|
||||
#include <wpi/mutex.h>
|
||||
|
||||
namespace frc {
|
||||
@@ -36,9 +36,8 @@ class Notifier {
|
||||
*/
|
||||
explicit Notifier(std::function<void()> handler);
|
||||
|
||||
template <
|
||||
typename Callable, typename Arg, typename... Args,
|
||||
typename = std::enable_if_t<std::is_invocable_v<Callable, Arg, Args...>>>
|
||||
template <typename Callable, typename Arg, typename... Args>
|
||||
requires std::invocable<Callable, Arg, Args...>
|
||||
Notifier(Callable&& f, Arg&& arg, Args&&... args)
|
||||
: Notifier(std::bind(std::forward<Callable>(f), std::forward<Arg>(arg),
|
||||
std::forward<Args>(args)...)) {}
|
||||
@@ -59,6 +58,7 @@ class Notifier {
|
||||
explicit Notifier(int priority, std::function<void()> handler);
|
||||
|
||||
template <typename Callable, typename Arg, typename... Args>
|
||||
requires std::invocable<Callable, Arg, Args...>
|
||||
Notifier(int priority, Callable&& f, Arg&& arg, Args&&... args)
|
||||
: Notifier(priority,
|
||||
std::bind(std::forward<Callable>(f), std::forward<Arg>(arg),
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <networktables/NetworkTable.h>
|
||||
#include <wpi/StringMap.h>
|
||||
#include <wpi/concepts.h>
|
||||
|
||||
#include "frc/Errors.h"
|
||||
|
||||
@@ -62,9 +62,8 @@ class MechanismObject2d {
|
||||
* assignments and call chaining.
|
||||
* @throw if an object with the given name already exists.
|
||||
*/
|
||||
template <typename T, typename... Args,
|
||||
typename =
|
||||
std::enable_if_t<std::is_convertible_v<T*, MechanismObject2d*>>>
|
||||
template <typename T, typename... Args>
|
||||
requires std::convertible_to<T*, MechanismObject2d*>
|
||||
T* Append(std::string_view name, Args&&... args) {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
auto& obj = m_objects[name];
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <string_view>
|
||||
|
||||
#include <wpi/StringMap.h>
|
||||
#include <wpi/concepts.h>
|
||||
|
||||
#include "frc/smartdashboard/SendableChooserBase.h"
|
||||
|
||||
@@ -27,12 +28,9 @@ namespace frc {
|
||||
* @see SmartDashboard
|
||||
*/
|
||||
template <class T>
|
||||
requires std::copy_constructible<T> && std::default_initializable<T>
|
||||
class SendableChooser : public SendableChooserBase {
|
||||
wpi::StringMap<T> m_choices;
|
||||
static_assert(std::is_copy_constructible_v<T>,
|
||||
"T must be copy-constructible!");
|
||||
static_assert(std::is_default_constructible_v<T>,
|
||||
"T must be default-constructible!");
|
||||
|
||||
template <class U>
|
||||
static U _unwrap_smart_ptr(const U& value);
|
||||
|
||||
@@ -18,17 +18,20 @@
|
||||
namespace frc {
|
||||
|
||||
template <class T>
|
||||
requires std::copy_constructible<T> && std::default_initializable<T>
|
||||
void SendableChooser<T>::AddOption(std::string_view name, T object) {
|
||||
m_choices[name] = std::move(object);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
requires std::copy_constructible<T> && std::default_initializable<T>
|
||||
void SendableChooser<T>::SetDefaultOption(std::string_view name, T object) {
|
||||
m_defaultChoice = name;
|
||||
AddOption(name, std::move(object));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
requires std::copy_constructible<T> && std::default_initializable<T>
|
||||
auto SendableChooser<T>::GetSelected()
|
||||
-> decltype(_unwrap_smart_ptr(m_choices[""])) {
|
||||
std::string selected = m_defaultChoice;
|
||||
@@ -46,6 +49,7 @@ auto SendableChooser<T>::GetSelected()
|
||||
}
|
||||
|
||||
template <class T>
|
||||
requires std::copy_constructible<T> && std::default_initializable<T>
|
||||
void SendableChooser<T>::InitSendable(nt::NTSendableBuilder& builder) {
|
||||
builder.SetSmartDashboardType("String Chooser");
|
||||
{
|
||||
@@ -101,18 +105,21 @@ void SendableChooser<T>::InitSendable(nt::NTSendableBuilder& builder) {
|
||||
}
|
||||
|
||||
template <class T>
|
||||
requires std::copy_constructible<T> && std::default_initializable<T>
|
||||
template <class U>
|
||||
U SendableChooser<T>::_unwrap_smart_ptr(const U& value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
requires std::copy_constructible<T> && std::default_initializable<T>
|
||||
template <class U>
|
||||
U* SendableChooser<T>::_unwrap_smart_ptr(const std::unique_ptr<U>& value) {
|
||||
return value.get();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
requires std::copy_constructible<T> && std::default_initializable<T>
|
||||
template <class U>
|
||||
std::weak_ptr<U> SendableChooser<T>::_unwrap_smart_ptr(
|
||||
const std::shared_ptr<U>& value) {
|
||||
|
||||
@@ -42,20 +42,21 @@ public class SwerveDriveKinematics {
|
||||
private Translation2d m_prevCoR = new Translation2d();
|
||||
|
||||
/**
|
||||
* Constructs a swerve drive kinematics object. This takes in a variable number of wheel locations
|
||||
* as Translation2d objects. The order in which you pass in the wheel locations is the same order
|
||||
* that you will receive the module states when performing inverse kinematics. It is also expected
|
||||
* that you pass in the module states in the same order when calling the forward kinematics
|
||||
* methods.
|
||||
* Constructs a swerve drive kinematics object. This takes in a variable number of module
|
||||
* locations as Translation2d objects. The order in which you pass in the module locations is the
|
||||
* same order that you will receive the module states when performing inverse kinematics. It is
|
||||
* also expected that you pass in the module states in the same order when calling the forward
|
||||
* kinematics methods.
|
||||
*
|
||||
* @param wheelsMeters The locations of the wheels relative to the physical center of the robot.
|
||||
* @param moduleTranslationsMeters The locations of the modules relative to the physical center of
|
||||
* the robot.
|
||||
*/
|
||||
public SwerveDriveKinematics(Translation2d... wheelsMeters) {
|
||||
if (wheelsMeters.length < 2) {
|
||||
public SwerveDriveKinematics(Translation2d... moduleTranslationsMeters) {
|
||||
if (moduleTranslationsMeters.length < 2) {
|
||||
throw new IllegalArgumentException("A swerve drive requires at least two modules");
|
||||
}
|
||||
m_numModules = wheelsMeters.length;
|
||||
m_modules = Arrays.copyOf(wheelsMeters, m_numModules);
|
||||
m_numModules = moduleTranslationsMeters.length;
|
||||
m_modules = Arrays.copyOf(moduleTranslationsMeters, m_numModules);
|
||||
m_moduleStates = new SwerveModuleState[m_numModules];
|
||||
Arrays.fill(m_moduleStates, new SwerveModuleState());
|
||||
m_inverseKinematics = new SimpleMatrix(m_numModules * 2, 3);
|
||||
@@ -163,21 +164,21 @@ public class SwerveDriveKinematics {
|
||||
* This method is often used for odometry -- determining the robot's position on the field using
|
||||
* data from the real-world speed and angle of each module on the robot.
|
||||
*
|
||||
* @param wheelStates The state of the modules (as a SwerveModuleState type) as measured from
|
||||
* @param moduleStates The state of the modules (as a SwerveModuleState type) as measured from
|
||||
* respective encoders and gyros. The order of the swerve module states should be same as
|
||||
* passed into the constructor of this class.
|
||||
* @return The resulting chassis speed.
|
||||
*/
|
||||
public ChassisSpeeds toChassisSpeeds(SwerveModuleState... wheelStates) {
|
||||
if (wheelStates.length != m_numModules) {
|
||||
public ChassisSpeeds toChassisSpeeds(SwerveModuleState... moduleStates) {
|
||||
if (moduleStates.length != m_numModules) {
|
||||
throw new IllegalArgumentException(
|
||||
"Number of modules is not consistent with number of wheel locations provided in "
|
||||
"Number of modules is not consistent with number of module locations provided in "
|
||||
+ "constructor");
|
||||
}
|
||||
var moduleStatesMatrix = new SimpleMatrix(m_numModules * 2, 1);
|
||||
|
||||
for (int i = 0; i < m_numModules; i++) {
|
||||
var module = wheelStates[i];
|
||||
var module = moduleStates[i];
|
||||
moduleStatesMatrix.set(i * 2, 0, module.speedMetersPerSecond * module.angle.getCos());
|
||||
moduleStatesMatrix.set(i * 2 + 1, module.speedMetersPerSecond * module.angle.getSin());
|
||||
}
|
||||
@@ -194,21 +195,21 @@ public class SwerveDriveKinematics {
|
||||
* This method is often used for odometry -- determining the robot's position on the field using
|
||||
* data from the real-world speed and angle of each module on the robot.
|
||||
*
|
||||
* @param wheelDeltas The latest change in position of the modules (as a SwerveModulePosition
|
||||
* @param moduleDeltas The latest change in position of the modules (as a SwerveModulePosition
|
||||
* type) as measured from respective encoders and gyros. The order of the swerve module states
|
||||
* should be same as passed into the constructor of this class.
|
||||
* @return The resulting Twist2d.
|
||||
*/
|
||||
public Twist2d toTwist2d(SwerveModulePosition... wheelDeltas) {
|
||||
if (wheelDeltas.length != m_numModules) {
|
||||
public Twist2d toTwist2d(SwerveModulePosition... moduleDeltas) {
|
||||
if (moduleDeltas.length != m_numModules) {
|
||||
throw new IllegalArgumentException(
|
||||
"Number of modules is not consistent with number of wheel locations provided in "
|
||||
"Number of modules is not consistent with number of module locations provided in "
|
||||
+ "constructor");
|
||||
}
|
||||
var moduleDeltaMatrix = new SimpleMatrix(m_numModules * 2, 1);
|
||||
|
||||
for (int i = 0; i < m_numModules; i++) {
|
||||
var module = wheelDeltas[i];
|
||||
var module = moduleDeltas[i];
|
||||
moduleDeltaMatrix.set(i * 2, 0, module.distanceMeters * module.angle.getCos());
|
||||
moduleDeltaMatrix.set(i * 2 + 1, module.distanceMeters * module.angle.getSin());
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <numbers>
|
||||
#include <type_traits>
|
||||
|
||||
#include <wpi/SymbolExports.h>
|
||||
|
||||
@@ -25,12 +26,11 @@ namespace frc {
|
||||
* be infinite.
|
||||
* @return The value after the deadband is applied.
|
||||
*/
|
||||
template <typename T,
|
||||
typename = std::enable_if_t<std::disjunction_v<
|
||||
std::is_floating_point<T>, units::traits::is_unit_t<T>>>>
|
||||
template <typename T>
|
||||
requires std::is_arithmetic_v<T> || units::traits::is_unit_t_v<T>
|
||||
T ApplyDeadband(T value, T deadband, T maxMagnitude = T{1.0}) {
|
||||
T magnitude;
|
||||
if constexpr (std::is_floating_point_v<T>) {
|
||||
if constexpr (std::is_arithmetic_v<T>) {
|
||||
magnitude = std::abs(value);
|
||||
} else {
|
||||
magnitude = units::math::abs(value);
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <random>
|
||||
#include <type_traits>
|
||||
|
||||
#include <wpi/SymbolExports.h>
|
||||
#include <wpi/concepts.h>
|
||||
#include <wpi/deprecated.h>
|
||||
|
||||
#include "Eigen/Eigenvalues"
|
||||
@@ -96,8 +96,7 @@ bool IsStabilizableImpl(const Matrixd<States, States>& A,
|
||||
* of the control inputs from no actuation.
|
||||
* @return State excursion or control effort cost matrix.
|
||||
*/
|
||||
template <typename... Ts, typename = std::enable_if_t<
|
||||
std::conjunction_v<std::is_same<double, Ts>...>>>
|
||||
template <std::same_as<double>... Ts>
|
||||
Matrixd<sizeof...(Ts), sizeof...(Ts)> MakeCostMatrix(Ts... tolerances) {
|
||||
Eigen::DiagonalMatrix<double, sizeof...(Ts)> result;
|
||||
detail::CostMatrixImpl(result.diagonal(), tolerances...);
|
||||
@@ -116,8 +115,7 @@ Matrixd<sizeof...(Ts), sizeof...(Ts)> MakeCostMatrix(Ts... tolerances) {
|
||||
* output measurement.
|
||||
* @return Process noise or measurement noise covariance matrix.
|
||||
*/
|
||||
template <typename... Ts, typename = std::enable_if_t<
|
||||
std::conjunction_v<std::is_same<double, Ts>...>>>
|
||||
template <std::same_as<double>... Ts>
|
||||
Matrixd<sizeof...(Ts), sizeof...(Ts)> MakeCovMatrix(Ts... stdDevs) {
|
||||
Eigen::DiagonalMatrix<double, sizeof...(Ts)> result;
|
||||
detail::CovMatrixImpl(result.diagonal(), stdDevs...);
|
||||
@@ -173,8 +171,7 @@ Matrixd<N, N> MakeCovMatrix(const std::array<double, N>& stdDevs) {
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename... Ts, typename = std::enable_if_t<
|
||||
std::conjunction_v<std::is_same<double, Ts>...>>>
|
||||
template <std::same_as<double>... Ts>
|
||||
Matrixd<sizeof...(Ts), 1> MakeWhiteNoiseVector(Ts... stdDevs) {
|
||||
Matrixd<sizeof...(Ts), 1> result;
|
||||
detail::WhiteNoiseVectorImpl(result, stdDevs...);
|
||||
|
||||
@@ -4,9 +4,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <wpi/concepts.h>
|
||||
|
||||
#include "Eigen/Core"
|
||||
#include "Eigen/SparseCore"
|
||||
@@ -16,12 +15,9 @@
|
||||
* Eigen::SparseCompressedBase<Derived>.
|
||||
*/
|
||||
template <typename Derived, typename CharT>
|
||||
struct fmt::formatter<
|
||||
Derived, CharT,
|
||||
std::enable_if_t<
|
||||
std::is_base_of_v<Eigen::MatrixBase<Derived>, Derived> ||
|
||||
std::is_base_of_v<Eigen::SparseCompressedBase<Derived>, Derived>,
|
||||
void>> {
|
||||
requires std::derived_from<Derived, Eigen::MatrixBase<Derived>> ||
|
||||
std::derived_from<Derived, Eigen::SparseCompressedBase<Derived>>
|
||||
struct fmt::formatter<Derived, CharT> {
|
||||
constexpr auto parse(fmt::format_parse_context& ctx) {
|
||||
return m_underlying.parse(ctx);
|
||||
}
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
|
||||
#include <wpi/SymbolExports.h>
|
||||
#include <wpi/array.h>
|
||||
#include <wpi/concepts.h>
|
||||
|
||||
#include "Eigen/QR"
|
||||
#include "frc/EigenCore.h"
|
||||
@@ -49,23 +49,19 @@ class SwerveDriveKinematics {
|
||||
public:
|
||||
/**
|
||||
* Constructs a swerve drive kinematics object. This takes in a variable
|
||||
* number of wheel locations as Translation2ds. The order in which you pass in
|
||||
* the wheel locations is the same order that you will receive the module
|
||||
* number of module locations as Translation2ds. The order in which you pass
|
||||
* in the module locations is the same order that you will receive the module
|
||||
* states when performing inverse kinematics. It is also expected that you
|
||||
* pass in the module states in the same order when calling the forward
|
||||
* kinematics methods.
|
||||
*
|
||||
* @param wheel The location of the first wheel relative to the physical
|
||||
* center of the robot.
|
||||
* @param wheels The locations of the other wheels relative to the physical
|
||||
* center of the robot.
|
||||
* @param moduleTranslations The locations of the modules relative to the
|
||||
* physical center of the robot.
|
||||
*/
|
||||
template <typename... Wheels>
|
||||
explicit SwerveDriveKinematics(Translation2d wheel, Wheels&&... wheels)
|
||||
: m_modules{wheel, wheels...}, m_moduleStates(wpi::empty_array) {
|
||||
static_assert(sizeof...(wheels) >= 1,
|
||||
"A swerve drive requires at least two modules");
|
||||
|
||||
template <std::convertible_to<Translation2d>... ModuleTranslations>
|
||||
requires(sizeof...(ModuleTranslations) == NumModules)
|
||||
explicit SwerveDriveKinematics(ModuleTranslations&&... moduleTranslations)
|
||||
: m_modules{moduleTranslations...}, m_moduleStates(wpi::empty_array) {
|
||||
for (size_t i = 0; i < NumModules; i++) {
|
||||
// clang-format off
|
||||
m_inverseKinematics.template block<2, 3>(i * 2, 0) <<
|
||||
@@ -81,8 +77,8 @@ class SwerveDriveKinematics {
|
||||
}
|
||||
|
||||
explicit SwerveDriveKinematics(
|
||||
const wpi::array<Translation2d, NumModules>& wheels)
|
||||
: m_modules{wheels}, m_moduleStates(wpi::empty_array) {
|
||||
const wpi::array<Translation2d, NumModules>& modules)
|
||||
: m_modules{modules}, m_moduleStates(wpi::empty_array) {
|
||||
for (size_t i = 0; i < NumModules; i++) {
|
||||
// clang-format off
|
||||
m_inverseKinematics.template block<2, 3>(i * 2, 0) <<
|
||||
@@ -140,17 +136,18 @@ class SwerveDriveKinematics {
|
||||
* the robot's position on the field using data from the real-world speed and
|
||||
* angle of each module on the robot.
|
||||
*
|
||||
* @param wheelStates The state of the modules (as a SwerveModuleState type)
|
||||
* @param moduleStates The state of the modules (as a SwerveModuleState type)
|
||||
* as measured from respective encoders and gyros. The order of the swerve
|
||||
* module states should be same as passed into the constructor of this class.
|
||||
*
|
||||
* @return The resulting chassis speed.
|
||||
*/
|
||||
template <typename... ModuleStates>
|
||||
requires(std::is_same_v<std::remove_reference_t<ModuleStates>,
|
||||
SwerveModuleState> &&
|
||||
...)
|
||||
ChassisSpeeds ToChassisSpeeds(ModuleStates&&... wheelStates) const;
|
||||
template <std::convertible_to<SwerveModuleState>... ModuleStates>
|
||||
requires(sizeof...(ModuleStates) == NumModules)
|
||||
ChassisSpeeds ToChassisSpeeds(ModuleStates&&... moduleStates) const {
|
||||
return this->ToChassisSpeeds(
|
||||
wpi::array<SwerveModuleState, NumModules>{moduleStates...});
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs forward kinematics to return the resulting chassis state from the
|
||||
@@ -174,15 +171,19 @@ class SwerveDriveKinematics {
|
||||
* determining the robot's position on the field using data from the
|
||||
* real-world position delta and angle of each module on the robot.
|
||||
*
|
||||
* @param wheelDeltas The latest change in position of the modules (as a
|
||||
* @param moduleDeltas The latest change in position of the modules (as a
|
||||
* SwerveModulePosition type) as measured from respective encoders and gyros.
|
||||
* The order of the swerve module states should be same as passed into the
|
||||
* constructor of this class.
|
||||
*
|
||||
* @return The resulting Twist2d.
|
||||
*/
|
||||
template <typename... ModuleDeltas>
|
||||
Twist2d ToTwist2d(ModuleDeltas&&... wheelDeltas) const;
|
||||
template <std::convertible_to<SwerveModulePosition>... ModuleDeltas>
|
||||
requires(sizeof...(ModuleDeltas) == NumModules)
|
||||
Twist2d ToTwist2d(ModuleDeltas&&... moduleDeltas) const {
|
||||
return this->ToTwist2d(
|
||||
wpi::array<SwerveModulePosition, NumModules>{moduleDeltas...});
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs forward kinematics to return the resulting Twist2d from the
|
||||
@@ -190,7 +191,7 @@ class SwerveDriveKinematics {
|
||||
* determining the robot's position on the field using data from the
|
||||
* real-world position delta and angle of each module on the robot.
|
||||
*
|
||||
* @param wheelDeltas The latest change in position of the modules (as a
|
||||
* @param moduleDeltas The latest change in position of the modules (as a
|
||||
* SwerveModulePosition type) as measured from respective encoders and gyros.
|
||||
* The order of the swerve module states should be same as passed into the
|
||||
* constructor of this class.
|
||||
@@ -198,7 +199,7 @@ class SwerveDriveKinematics {
|
||||
* @return The resulting Twist2d.
|
||||
*/
|
||||
Twist2d ToTwist2d(
|
||||
wpi::array<SwerveModulePosition, NumModules> wheelDeltas) const;
|
||||
wpi::array<SwerveModulePosition, NumModules> moduleDeltas) const;
|
||||
|
||||
/**
|
||||
* Renormalizes the wheel speeds if any individual speed is above the
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
|
||||
namespace frc {
|
||||
|
||||
template <class... Wheels>
|
||||
SwerveDriveKinematics(Translation2d, Wheels...)
|
||||
-> SwerveDriveKinematics<1 + sizeof...(Wheels)>;
|
||||
template <typename ModuleTranslation, typename... ModuleTranslations>
|
||||
SwerveDriveKinematics(ModuleTranslation, ModuleTranslations...)
|
||||
-> SwerveDriveKinematics<1 + sizeof...(ModuleTranslations)>;
|
||||
|
||||
template <size_t NumModules>
|
||||
wpi::array<SwerveModuleState, NumModules>
|
||||
@@ -64,22 +64,6 @@ SwerveDriveKinematics<NumModules>::ToSwerveModuleStates(
|
||||
return m_moduleStates;
|
||||
}
|
||||
|
||||
template <size_t NumModules>
|
||||
template <typename... ModuleStates>
|
||||
requires(std::is_same_v<std::remove_reference_t<ModuleStates>,
|
||||
SwerveModuleState> &&
|
||||
...)
|
||||
ChassisSpeeds SwerveDriveKinematics<NumModules>::ToChassisSpeeds(
|
||||
ModuleStates&&... wheelStates) const {
|
||||
static_assert(sizeof...(wheelStates) == NumModules,
|
||||
"Number of modules is not consistent with number of wheel "
|
||||
"locations provided in constructor.");
|
||||
|
||||
wpi::array<SwerveModuleState, NumModules> moduleStates{wheelStates...};
|
||||
|
||||
return this->ToChassisSpeeds(moduleStates);
|
||||
}
|
||||
|
||||
template <size_t NumModules>
|
||||
ChassisSpeeds SwerveDriveKinematics<NumModules>::ToChassisSpeeds(
|
||||
const wpi::array<SwerveModuleState, NumModules>& moduleStates) const {
|
||||
@@ -99,19 +83,6 @@ ChassisSpeeds SwerveDriveKinematics<NumModules>::ToChassisSpeeds(
|
||||
units::radians_per_second_t{chassisSpeedsVector(2)}};
|
||||
}
|
||||
|
||||
template <size_t NumModules>
|
||||
template <typename... ModuleDeltas>
|
||||
Twist2d SwerveDriveKinematics<NumModules>::ToTwist2d(
|
||||
ModuleDeltas&&... wheelDeltas) const {
|
||||
static_assert(sizeof...(wheelDeltas) == NumModules,
|
||||
"Number of modules is not consistent with number of wheel "
|
||||
"locations provided in constructor.");
|
||||
|
||||
wpi::array<SwerveModulePosition, NumModules> moduleDeltas{wheelDeltas...};
|
||||
|
||||
return this->ToTwist2d(moduleDeltas);
|
||||
}
|
||||
|
||||
template <size_t NumModules>
|
||||
Twist2d SwerveDriveKinematics<NumModules>::ToTwist2d(
|
||||
wpi::array<SwerveModulePosition, NumModules> moduleDeltas) const {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <stdexcept>
|
||||
|
||||
#include <wpi/SymbolExports.h>
|
||||
#include <wpi/concepts.h>
|
||||
|
||||
#include "frc/system/LinearSystem.h"
|
||||
#include "frc/system/plant/DCMotor.h"
|
||||
@@ -76,9 +77,9 @@ class WPILIB_DLLEXPORT LinearSystemId {
|
||||
* @param kA The acceleration gain, in volts/(unit/sec²).
|
||||
* @throws std::domain_error if kV <= 0 or kA <= 0.
|
||||
*/
|
||||
template <typename Distance, typename = std::enable_if_t<
|
||||
std::is_same_v<units::meter, Distance> ||
|
||||
std::is_same_v<units::radian, Distance>>>
|
||||
template <typename Distance>
|
||||
requires std::same_as<units::meter, Distance> ||
|
||||
std::same_as<units::radian, Distance>
|
||||
static LinearSystem<1, 1, 1> IdentifyVelocitySystem(
|
||||
decltype(1_V / Velocity_t<Distance>(1)) kV,
|
||||
decltype(1_V / Acceleration_t<Distance>(1)) kA) {
|
||||
@@ -117,9 +118,9 @@ class WPILIB_DLLEXPORT LinearSystemId {
|
||||
*
|
||||
* @throws std::domain_error if kV <= 0 or kA <= 0.
|
||||
*/
|
||||
template <typename Distance, typename = std::enable_if_t<
|
||||
std::is_same_v<units::meter, Distance> ||
|
||||
std::is_same_v<units::radian, Distance>>>
|
||||
template <typename Distance>
|
||||
requires std::same_as<units::meter, Distance> ||
|
||||
std::same_as<units::radian, Distance>
|
||||
static LinearSystem<2, 1, 1> IdentifyPositionSystem(
|
||||
decltype(1_V / Velocity_t<Distance>(1)) kV,
|
||||
decltype(1_V / Acceleration_t<Distance>(1)) kA) {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include <wpi/SymbolExports.h>
|
||||
#include <wpi/concepts.h>
|
||||
|
||||
#include "frc/kinematics/DifferentialDriveKinematics.h"
|
||||
#include "frc/kinematics/MecanumDriveKinematics.h"
|
||||
@@ -74,8 +75,7 @@ class WPILIB_DLLEXPORT TrajectoryConfig {
|
||||
* Adds a user-defined constraint to the trajectory.
|
||||
* @param constraint The user-defined constraint.
|
||||
*/
|
||||
template <typename Constraint, typename = std::enable_if_t<std::is_base_of_v<
|
||||
TrajectoryConstraint, Constraint>>>
|
||||
template <std::derived_from<TrajectoryConstraint> Constraint>
|
||||
void AddConstraint(Constraint constraint) {
|
||||
m_constraints.emplace_back(std::make_unique<Constraint>(constraint));
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include <wpi/concepts.h>
|
||||
|
||||
#include "frc/geometry/Rotation2d.h"
|
||||
#include "frc/geometry/Translation2d.h"
|
||||
#include "frc/trajectory/constraint/TrajectoryConstraint.h"
|
||||
@@ -15,8 +17,7 @@ namespace frc {
|
||||
/**
|
||||
* Enforces a particular constraint only within an elliptical region.
|
||||
*/
|
||||
template <typename Constraint, typename = std::enable_if_t<std::is_base_of_v<
|
||||
TrajectoryConstraint, Constraint>>>
|
||||
template <std::derived_from<TrajectoryConstraint> Constraint>
|
||||
class EllipticalRegionConstraint : public TrajectoryConstraint {
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include <wpi/concepts.h>
|
||||
|
||||
#include "frc/geometry/Rotation2d.h"
|
||||
#include "frc/geometry/Translation2d.h"
|
||||
#include "frc/trajectory/constraint/TrajectoryConstraint.h"
|
||||
@@ -14,8 +16,7 @@ namespace frc {
|
||||
/**
|
||||
* Enforces a particular constraint only within a rectangular region.
|
||||
*/
|
||||
template <typename Constraint, typename = std::enable_if_t<std::is_base_of_v<
|
||||
TrajectoryConstraint, Constraint>>>
|
||||
template <std::derived_from<TrajectoryConstraint> Constraint>
|
||||
class RectangularRegionConstraint : public TrajectoryConstraint {
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <wpi/concepts.h>
|
||||
#include <wpi/future.h>
|
||||
#include <wpi/mutex.h>
|
||||
|
||||
@@ -127,7 +128,7 @@ class AsyncFunction<R(T...)> final
|
||||
|
||||
auto loop = m_loop.lock();
|
||||
if (loop->IsClosing()) {
|
||||
if constexpr (std::is_same_v<R, void>) {
|
||||
if constexpr (std::same_as<R, void>) {
|
||||
return m_promises.MakeReadyFuture();
|
||||
} else {
|
||||
return m_promises.MakeReadyFuture({});
|
||||
|
||||
18
wpiutil/src/main/native/include/wpi/DecayedDerivedFrom.h
Normal file
18
wpiutil/src/main/native/include/wpi/DecayedDerivedFrom.h
Normal file
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "wpi/concepts.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
template <class Derived, class Base>
|
||||
concept DecayedDerivedFrom =
|
||||
std::derived_from<std::decay_t<Derived>, std::decay_t<Base>> &&
|
||||
std::convertible_to<std::decay_t<Derived>*, std::decay_t<Base>*>;
|
||||
|
||||
} // namespace wpi
|
||||
@@ -9,6 +9,8 @@
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
#include "wpi/concepts.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
struct empty_array_t {};
|
||||
@@ -26,11 +28,10 @@ class array : public std::array<T, N> {
|
||||
public:
|
||||
constexpr explicit array(empty_array_t) {}
|
||||
|
||||
template <typename... Ts>
|
||||
template <std::convertible_to<T>... Ts>
|
||||
requires(1 + sizeof...(Ts) == N)
|
||||
constexpr array(T arg, Ts&&... args) // NOLINT
|
||||
: std::array<T, N>{std::forward<T>(arg), std::forward<Ts>(args)...} {
|
||||
static_assert(1 + sizeof...(args) == N, "Dimension mismatch");
|
||||
}
|
||||
: std::array<T, N>{std::forward<T>(arg), std::forward<Ts>(args)...} {}
|
||||
|
||||
constexpr array(const array<T, N>&) = default;
|
||||
constexpr array& operator=(const array<T, N>&) = default;
|
||||
@@ -56,33 +57,32 @@ class array : public std::array<T, N> {
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename... Ts>
|
||||
array(T, Ts...) -> array<std::enable_if_t<(std::is_same_v<T, Ts> && ...), T>,
|
||||
1 + sizeof...(Ts)>;
|
||||
template <typename T, std::convertible_to<T>... Ts>
|
||||
array(T, Ts...) -> array<T, 1 + sizeof...(Ts)>;
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
template <size_t I, typename T, size_t N>
|
||||
requires(I < N)
|
||||
constexpr T& get(wpi::array<T, N>& arr) noexcept {
|
||||
static_assert(I < N, "array index is within bounds");
|
||||
return std::get<I>(static_cast<std::array<T, N>>(arr));
|
||||
}
|
||||
|
||||
template <size_t I, typename T, size_t N>
|
||||
requires(I < N)
|
||||
constexpr T&& get(wpi::array<T, N>&& arr) noexcept {
|
||||
static_assert(I < N, "array index is within bounds");
|
||||
return std::move(std::get<I>(arr));
|
||||
}
|
||||
|
||||
template <size_t I, typename T, size_t N>
|
||||
requires(I < N)
|
||||
constexpr const T& get(const wpi::array<T, N>& arr) noexcept {
|
||||
static_assert(I < N, "array index is within bounds");
|
||||
return std::get<I>(static_cast<std::array<T, N>>(arr));
|
||||
}
|
||||
|
||||
template <size_t I, typename T, size_t N>
|
||||
requires(I < N)
|
||||
constexpr const T&& get(const wpi::array<T, N>&& arr) noexcept {
|
||||
static_assert(I < N, "array index is within bounds");
|
||||
return std::move(std::get<I>(arr));
|
||||
}
|
||||
|
||||
@@ -94,8 +94,8 @@ struct tuple_size<wpi::array<T, N>> : public integral_constant<size_t, N> {};
|
||||
|
||||
// Partial specialization for wpi::array
|
||||
template <size_t I, typename T, size_t N>
|
||||
requires(I < N)
|
||||
struct tuple_element<I, wpi::array<T, N>> {
|
||||
static_assert(I < N, "index is out of bounds");
|
||||
using type = T;
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
57
wpiutil/src/main/native/include/wpi/concepts.h
Normal file
57
wpiutil/src/main/native/include/wpi/concepts.h
Normal file
@@ -0,0 +1,57 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <concepts>
|
||||
|
||||
#if defined(__APPLE__) && !defined(__cpp_lib_concepts)
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace std {
|
||||
|
||||
template <typename T, typename... Args>
|
||||
concept constructible_from =
|
||||
is_nothrow_destructible_v<T> && is_constructible_v<T, Args...>;
|
||||
|
||||
template <typename From, typename To>
|
||||
concept convertible_to = is_convertible_v<From, To> &&
|
||||
requires { static_cast<To>(declval<From>()); };
|
||||
|
||||
template <typename T>
|
||||
concept move_constructible = constructible_from<T, T> && convertible_to<T, T>;
|
||||
|
||||
template <typename T>
|
||||
concept copy_constructible =
|
||||
move_constructible<T> && constructible_from<T, T&> &&
|
||||
convertible_to<T&, T> && constructible_from<T, const T&> &&
|
||||
convertible_to<const T&, T> && constructible_from<T, const T> &&
|
||||
convertible_to<const T, T>;
|
||||
|
||||
template <typename T>
|
||||
concept default_initializable =
|
||||
constructible_from<T> && requires { T{}; } && requires { ::new T; };
|
||||
|
||||
template <typename Derived, typename Base>
|
||||
concept derived_from =
|
||||
is_base_of_v<Base, Derived> &&
|
||||
is_convertible_v<const volatile Derived*, const volatile Base*>;
|
||||
|
||||
template <typename T>
|
||||
concept floating_point = is_floating_point_v<T>;
|
||||
|
||||
template <typename T>
|
||||
concept integral = is_integral_v<T>;
|
||||
|
||||
template <typename F, typename... Args>
|
||||
concept invocable = requires(F&& f, Args&&... args) {
|
||||
invoke(forward<F>(f), forward<Args>(args)...);
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
#endif // defined(__APPLE__) && !defined(__cpp_lib_concepts)
|
||||
@@ -11,7 +11,6 @@
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -20,6 +19,7 @@
|
||||
#include "wpi/SmallString.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/StringExtras.h"
|
||||
#include "wpi/concepts.h"
|
||||
#include "wpi/mutex.h"
|
||||
#include "wpi/raw_ostream.h"
|
||||
|
||||
@@ -219,9 +219,8 @@ class JArrayRefInner<C, jbyte> {
|
||||
template <typename C>
|
||||
class JArrayRefInner<C, jlong> {
|
||||
public:
|
||||
template <typename U,
|
||||
typename = std::enable_if_t<sizeof(U) == sizeof(jlong) &&
|
||||
std::is_integral_v<U>>>
|
||||
template <typename U>
|
||||
requires(sizeof(U) == sizeof(jlong) && std::integral<U>)
|
||||
operator std::span<const U>() const { // NOLINT
|
||||
auto arr = static_cast<const C*>(this)->array();
|
||||
if (arr.empty()) {
|
||||
@@ -397,46 +396,38 @@ inline jstring MakeJString(JNIEnv* env, std::string_view str) {
|
||||
// details for MakeJIntArray
|
||||
namespace detail {
|
||||
|
||||
/**
|
||||
* Slow path (get primitive array and set individual elements).
|
||||
*
|
||||
* This is used if the input type is not an integer of the same size (note
|
||||
* signed/unsigned is ignored).
|
||||
*/
|
||||
template <typename T,
|
||||
bool = (std::is_integral<T>::value && sizeof(jint) == sizeof(T))>
|
||||
template <typename T>
|
||||
struct ConvertIntArray {
|
||||
static jintArray ToJava(JNIEnv* env, std::span<const T> arr) {
|
||||
jintArray jarr = env->NewIntArray(arr.size());
|
||||
if (!jarr) {
|
||||
return nullptr;
|
||||
if constexpr (sizeof(T) == sizeof(jint) && std::integral<T>) {
|
||||
// Fast path (use SetIntArrayRegion).
|
||||
jintArray jarr = env->NewIntArray(arr.size());
|
||||
if (!jarr) {
|
||||
return nullptr;
|
||||
}
|
||||
env->SetIntArrayRegion(jarr, 0, arr.size(),
|
||||
reinterpret_cast<const jint*>(arr.data()));
|
||||
return jarr;
|
||||
} else {
|
||||
// Slow path (get primitive array and set individual elements).
|
||||
//
|
||||
// This is used if the input type is not an integer of the same size (note
|
||||
// signed/unsigned is ignored).
|
||||
jintArray jarr = env->NewIntArray(arr.size());
|
||||
if (!jarr) {
|
||||
return nullptr;
|
||||
}
|
||||
jint* elements =
|
||||
static_cast<jint*>(env->GetPrimitiveArrayCritical(jarr, nullptr));
|
||||
if (!elements) {
|
||||
return nullptr;
|
||||
}
|
||||
for (size_t i = 0; i < arr.size(); ++i) {
|
||||
elements[i] = static_cast<jint>(arr[i]);
|
||||
}
|
||||
env->ReleasePrimitiveArrayCritical(jarr, elements, 0);
|
||||
return jarr;
|
||||
}
|
||||
jint* elements =
|
||||
static_cast<jint*>(env->GetPrimitiveArrayCritical(jarr, nullptr));
|
||||
if (!elements) {
|
||||
return nullptr;
|
||||
}
|
||||
for (size_t i = 0; i < arr.size(); ++i) {
|
||||
elements[i] = static_cast<jint>(arr[i]);
|
||||
}
|
||||
env->ReleasePrimitiveArrayCritical(jarr, elements, 0);
|
||||
return jarr;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Fast path (use SetIntArrayRegion).
|
||||
*/
|
||||
template <typename T>
|
||||
struct ConvertIntArray<T, true> {
|
||||
static jintArray ToJava(JNIEnv* env, std::span<const T> arr) {
|
||||
jintArray jarr = env->NewIntArray(arr.size());
|
||||
if (!jarr) {
|
||||
return nullptr;
|
||||
}
|
||||
env->SetIntArrayRegion(jarr, 0, arr.size(),
|
||||
reinterpret_cast<const jint*>(arr.data()));
|
||||
return jarr;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -574,9 +565,9 @@ WPI_JNI_MAKEJARRAY(jdouble, Double)
|
||||
|
||||
#undef WPI_JNI_MAKEJARRAY
|
||||
|
||||
template <class T, typename = std::enable_if_t<
|
||||
sizeof(typename T::value_type) == sizeof(jlong) &&
|
||||
std::is_integral_v<typename T::value_type>>>
|
||||
template <class T>
|
||||
requires(sizeof(typename T::value_type) == sizeof(jlong) &&
|
||||
std::integral<typename T::value_type>)
|
||||
inline jlongArray MakeJLongArray(JNIEnv* env, const T& arr) {
|
||||
jlongArray jarr = env->NewLongArray(arr.size());
|
||||
if (!jarr) {
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "wpi/concepts.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/**
|
||||
@@ -22,11 +24,9 @@ namespace wpi {
|
||||
*/
|
||||
template <typename T, typename Sequence = std::vector<T>,
|
||||
typename Compare = std::less<typename Sequence::value_type>>
|
||||
requires std::same_as<T, typename Sequence::value_type>
|
||||
class priority_queue {
|
||||
public:
|
||||
static_assert(std::is_same_v<T, typename Sequence::value_type>,
|
||||
"value_type must be the same as the underlying container");
|
||||
|
||||
using value_type = typename Sequence::value_type;
|
||||
using reference = typename Sequence::reference;
|
||||
using const_reference = typename Sequence::const_reference;
|
||||
@@ -34,10 +34,9 @@ class priority_queue {
|
||||
using container_type = Sequence;
|
||||
using value_compare = Compare;
|
||||
|
||||
template <typename Seq = Sequence,
|
||||
typename Requires = typename std::enable_if_t<
|
||||
std::is_default_constructible<Compare>{} &&
|
||||
std::is_default_constructible<Seq>{}>>
|
||||
template <typename Seq = Sequence>
|
||||
requires std::default_initializable<Compare> &&
|
||||
std::default_initializable<Seq>
|
||||
priority_queue() {}
|
||||
|
||||
priority_queue(const Compare& comp, const Sequence& c) : c(c), comp(comp) {
|
||||
|
||||
Reference in New Issue
Block a user