Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[wpiutil C++] Add remove_prefix() and remove_suffix() #6118

Merged
merged 15 commits into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions glass/src/libnt/native/cpp/NTField2D.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ void NTField2DModel::Update() {
for (auto&& event : m_poller.ReadQueue()) {
if (auto info = event.GetTopicInfo()) {
// handle publish/unpublish
auto name = wpi::drop_front(info->name, m_path.size());
auto name = wpi::remove_prefix(info->name, m_path);
if (name.empty() || name[0] == '.') {
continue;
}
Expand Down Expand Up @@ -198,7 +198,7 @@ void NTField2DModel::ForEachFieldObject(
func) {
for (auto&& obj : m_objects) {
if (obj->Exists()) {
func(*obj, wpi::drop_front(obj->GetName(), m_path.size()));
func(*obj, wpi::remove_prefix(obj->GetName(), m_path));
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions glass/src/libnt/native/cpp/NTMechanism2D.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ NTMechanism2DModel::~NTMechanism2DModel() = default;
void NTMechanism2DModel::Update() {
for (auto&& event : m_poller.ReadQueue()) {
if (auto info = event.GetTopicInfo()) {
auto name = wpi::drop_front(info->name, m_path.size());
auto name = wpi::remove_prefix(info->name, m_path);
if (name.empty() || name[0] == '.') {
continue;
}
Expand Down Expand Up @@ -307,7 +307,7 @@ void NTMechanism2DModel::Update() {
}
} else {
auto fullName = nt::Topic{valueData->topic}.GetName();
auto name = wpi::drop_front(fullName, m_path.size());
auto name = wpi::remove_prefix(fullName, m_path);
if (name.empty() || name[0] == '.') {
continue;
}
Expand Down
35 changes: 20 additions & 15 deletions glass/src/libnt/native/cpp/NetworkTables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -726,10 +726,10 @@ void NetworkTablesModel::ValueSource::UpdateFromValue(
UpdateMsgpackValueSource(model, this, r, name, value.last_change());
mpack_reader_destroy(&r);
} else if (wpi::starts_with(typeStr, "struct:")) {
auto structName = wpi::drop_front(typeStr, 7);
auto structName = wpi::remove_prefix(typeStr, "struct:");
bool isArray = structName.ends_with("[]");
if (isArray) {
structName = wpi::drop_back(structName, 2);
structName = wpi::remove_suffix(structName, "[]");
}
auto desc = model.m_structDb.Find(structName);
if (desc && desc->IsValid()) {
Expand Down Expand Up @@ -761,7 +761,7 @@ void NetworkTablesModel::ValueSource::UpdateFromValue(
valueChildren.clear();
}
} else if (wpi::starts_with(typeStr, "proto:")) {
auto msg = model.m_protoDb.Find(wpi::drop_front(typeStr, 6));
auto msg = model.m_protoDb.Find(wpi::remove_prefix(typeStr, "proto:"));
if (msg) {
msg->Clear();
auto raw = value.GetRaw();
Expand Down Expand Up @@ -807,12 +807,14 @@ void NetworkTablesModel::Update() {
} else if (info->name == "$serversub") {
m_server.subscribers.clear();
} else if (wpi::starts_with(info->name, "$clientpub$")) {
auto it = m_clients.find(wpi::drop_front(info->name, 11));
auto it =
m_clients.find(wpi::remove_prefix(info->name, "$clientpub$"));
if (it != m_clients.end()) {
it->second.publishers.clear();
}
} else if (wpi::starts_with(info->name, "$clientsub$")) {
auto it = m_clients.find(wpi::drop_front(info->name, 11));
auto it =
m_clients.find(wpi::remove_prefix(info->name, "$clientsub$"));
if (it != m_clients.end()) {
it->second.subscribers.clear();
}
Expand Down Expand Up @@ -853,12 +855,14 @@ void NetworkTablesModel::Update() {
} else if (entry->info.name == "$serversub") {
m_server.UpdateSubscribers(entry->value.GetRaw());
} else if (wpi::starts_with(entry->info.name, "$clientpub$")) {
auto it = m_clients.find(wpi::drop_front(entry->info.name, 11));
auto it = m_clients.find(
wpi::remove_prefix(entry->info.name, "$clientpub$"));
if (it != m_clients.end()) {
it->second.UpdatePublishers(entry->value.GetRaw());
}
} else if (wpi::starts_with(entry->info.name, "$clientsub$")) {
auto it = m_clients.find(wpi::drop_front(entry->info.name, 11));
auto it = m_clients.find(
wpi::remove_prefix(entry->info.name, "$clientsub$"));
if (it != m_clients.end()) {
it->second.UpdateSubscribers(entry->value.GetRaw());
}
Expand All @@ -867,7 +871,8 @@ void NetworkTablesModel::Update() {
wpi::starts_with(entry->info.name, "/.schema/struct:") &&
entry->info.type_str == "structschema") {
// struct schema handling
auto typeStr = wpi::drop_front(entry->info.name, 16);
auto typeStr =
wpi::remove_prefix(entry->info.name, "/.schema/struct:");
std::string_view schema{
reinterpret_cast<const char*>(entry->value.GetRaw().data()),
entry->value.GetRaw().size()};
Expand All @@ -886,9 +891,8 @@ void NetworkTablesModel::Update() {
if (!wpi::starts_with(ts, "struct:")) {
continue;
}
ts = wpi::drop_front(ts, 7);
if (ts == typeStr || (wpi::ends_with(ts, "[]") &&
wpi::drop_back(ts, 2) == typeStr)) {
ts = wpi::remove_prefix(ts, "struct:");
if (wpi::remove_suffix(ts, "[]") == typeStr) {
entryPair.second->UpdateFromValue(*this);
}
}
Expand All @@ -897,7 +901,8 @@ void NetworkTablesModel::Update() {
wpi::starts_with(entry->info.name, "/.schema/proto:") &&
entry->info.type_str == "proto:FileDescriptorProto") {
// protobuf descriptor handling
auto filename = wpi::drop_front(entry->info.name, 15);
auto filename =
wpi::remove_prefix(entry->info.name, "/.schema/proto:");
if (!m_protoDb.Add(filename, entry->value.GetRaw())) {
fmt::print("could not decode protobuf '{}' filename '{}'\n",
entry->info.name, filename);
Expand Down Expand Up @@ -1079,17 +1084,17 @@ void NetworkTablesModel::UpdateClients(std::span<const uint8_t> data) {

static bool GetHeadingTypeString(std::string_view* ts) {
if (wpi::starts_with(*ts, "proto:")) {
*ts = wpi::drop_front(*ts, 6);
*ts = wpi::remove_prefix(*ts, "proto:");
auto lastdot = ts->rfind('.');
if (lastdot != std::string_view::npos) {
*ts = wpi::substr(*ts, lastdot + 1);
}
if (wpi::starts_with(*ts, "Protobuf")) {
*ts = wpi::drop_front(*ts, 8);
*ts = wpi::remove_prefix(*ts, "Protobuf");
}
return true;
} else if (wpi::starts_with(*ts, "struct:")) {
*ts = wpi::drop_front(*ts, 7);
*ts = wpi::remove_prefix(*ts, "struct:");
return true;
}
return false;
Expand Down
5 changes: 3 additions & 2 deletions glass/src/libnt/native/cpp/NetworkTablesProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ void NetworkTablesProvider::Update() {
}

auto topicName = nt::GetTopicName(valueData->topic);
auto tableName = wpi::drop_back(topicName, 6);
auto tableName = wpi::remove_prefix(topicName, "/.type");

GetOrCreateView(builderIt->second, nt::Topic{valueData->topic},
tableName);
Expand Down Expand Up @@ -198,7 +198,8 @@ void NetworkTablesProvider::Show(ViewEntry* entry, Window* window) {
}
if (wpi::starts_with(entry->name, "/SmartDashboard/")) {
window->SetDefaultName(
fmt::format("{} (SmartDashboard)", wpi::drop_front(entry->name, 16)));
fmt::format("{} (SmartDashboard)",
wpi::remove_prefix(entry->name, "/SmartDashboard/")));
}
entry->window = window;

Expand Down
7 changes: 3 additions & 4 deletions ntcore/src/main/native/cpp/LocalStorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,9 @@ int LocalStorage::DataLoggerData::Start(TopicData* topic, int64_t time) {
} else if (typeStr == "int[]") {
typeStr = "int64[]";
}
return log.Start(fmt::format("{}{}", logPrefix,
wpi::drop_front(topic->name, prefix.size())),
typeStr, DataLoggerEntry::MakeMetadata(topic->propertiesStr),
time);
return log.Start(
fmt::format("{}{}", logPrefix, wpi::remove_prefix(topic->name, prefix)),
typeStr, DataLoggerEntry::MakeMetadata(topic->propertiesStr), time);
}

void LocalStorage::DataLoggerEntry::Append(const Value& v) {
Expand Down
2 changes: 1 addition & 1 deletion ntcore/src/main/native/cpp/NetworkServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ void NetworkServer::ServerConnection4::ProcessWsUpgrade() {
std::string_view name;
bool err = false;
if (wpi::starts_with(path, "/nt/")) {
name = wpi::UnescapeURI(wpi::drop_front(path, 4), nameBuf, &err);
name = wpi::UnescapeURI(wpi::remove_prefix(path, "/nt/"), nameBuf, &err);
}
if (err || name.empty()) {
INFO("invalid path '{}' (from {}), must match /nt/[clientId], closing",
Expand Down
3 changes: 1 addition & 2 deletions ntcore/src/main/native/cpp/net/WireDecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,6 @@ bool nt::net::WireDecodeBinary(std::span<const uint8_t>* in, int64_t* outId,
outValue->SetServerTime(time);
outValue->SetTime(time == 0 ? 0 : time + localTimeOffset);
// update input range
*in = wpi::drop_front(*in,
in->size() - mpack_reader_remaining(&reader, nullptr));
*in = wpi::take_back(*in, mpack_reader_remaining(&reader, nullptr));
return true;
}
Original file line number Diff line number Diff line change
Expand Up @@ -170,13 +170,13 @@ void HALSimHttpConnection::ProcessRequest() {
// convert to fs native representation
fs::path nativePath;
if (wpi::starts_with(path, "/user/")) {
nativePath =
fs::path{m_server->GetWebrootSys()} /
fs::path{wpi::drop_front(path, 6), fs::path::format::generic_format};
nativePath = fs::path{m_server->GetWebrootSys()} /
fs::path{wpi::remove_prefix(path, "/user/"),
fs::path::format::generic_format};
} else {
nativePath =
fs::path{m_server->GetWebrootSys()} /
fs::path{wpi::drop_front(path, 1), fs::path::format::generic_format};
fs::path{wpi::drop_front(path), fs::path::format::generic_format};
}

if (fs::is_directory(nativePath)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ bool wpi::detail::ConsumeSignedInteger(
}

// Get the positive part of the value.
std::string_view str2 = wpi::drop_front(str, 1);
std::string_view str2 = wpi::drop_front(str);
if (wpi::detail::ConsumeUnsignedInteger(str2, radix, ullVal) ||
// Reject values so large they'd overflow as negative signed, but allow
// "-0". This negates the unsigned so that the negative isn't undefined
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,30 @@ inline bool contains_lower(std::string_view str, const char* other) noexcept {
return find_lower(str, other) != std::string_view::npos;
}

/**
* Return a string_view equal to @p str but with @p prefix removed if the string
* starts with the prefix. If the string does not start with the prefix, return
* a copy of the string.
*/
constexpr std::string_view remove_prefix(std::string_view str, std::string_view prefix) noexcept {
if (str.starts_with(prefix)) {
str.remove_prefix(prefix.size());
}
return str;
}

/**
* Return a string_view equal to @p str but with @p suffix removed if the
* string ends with the suffix. If the string does not end with the suffix,
* return a copy of the string.
*/
constexpr std::string_view remove_suffix(std::string_view str, std::string_view suffix) noexcept {
if (str.ends_with(suffix)) {
str.remove_suffix(suffix.size());
}
return str;
}

/**
* Return a string_view equal to @p str but with the first @p n elements
* dropped.
Expand Down
36 changes: 36 additions & 0 deletions wpiutil/src/test/native/cpp/StringExtrasTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// 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.

#include <gtest/gtest.h>

#include "wpi/StringExtras.h"

TEST(StringExtrasTest, RemovePrefix) {
std::string_view original = "wpilib";
std::string_view modified = wpi::remove_prefix(original, "wpi");
EXPECT_EQ(original, "wpilib");
EXPECT_EQ(modified, "lib");
}

TEST(StringExtrasTest, RemoveSuffix) {
std::string_view original = "wpilib";
EXPECT_TRUE(original.ends_with("lib"));
std::string_view modified = wpi::remove_suffix(original, "lib");
EXPECT_EQ(original, "wpilib");
EXPECT_EQ(modified, "wpi");
}

TEST(StringExtrasTest, RemovePrefixNoMatch) {
std::string_view original = "wpilib";
std::string_view modified = wpi::remove_prefix(original, "foo");
EXPECT_EQ(original, "wpilib");
EXPECT_EQ(modified, "wpilib");
}

TEST(StringExtrasTest, RemoveSuffixNoMatch) {
std::string_view original = "wpilib";
std::string_view modified = wpi::remove_suffix(original, "foo");
EXPECT_EQ(original, "wpilib");
EXPECT_EQ(modified, "wpilib");
}
Loading