mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-07-05 03:21:42 +00:00
NetworkTable: Add key utility functions. (#256)
- BasenameKey - NormalizeKey - GetHierarchy
This commit is contained in:
@@ -7,7 +7,9 @@
|
||||
|
||||
package edu.wpi.first.networktables;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -28,6 +30,93 @@ public final class NetworkTable {
|
||||
private final String pathWithSep;
|
||||
private final NetworkTableInstance inst;
|
||||
|
||||
/**
|
||||
* Gets the "base name" of a key. For example, "/foo/bar" becomes "bar".
|
||||
* If the key has a trailing slash, returns an empty string.
|
||||
* @param key key
|
||||
* @return base name
|
||||
*/
|
||||
public static String basenameKey(String key) {
|
||||
final int slash = key.lastIndexOf(PATH_SEPARATOR);
|
||||
if (slash == -1) {
|
||||
return key;
|
||||
}
|
||||
return key.substring(slash + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes an network table key to contain no consecutive slashes and
|
||||
* optionally start with a leading slash. For example:
|
||||
*
|
||||
* <pre><code>
|
||||
* normalizeKey("/foo/bar", true) == "/foo/bar"
|
||||
* normalizeKey("foo/bar", true) == "/foo/bar"
|
||||
* normalizeKey("/foo/bar", false) == "foo/bar"
|
||||
* normalizeKey("foo//bar", false) == "foo/bar"
|
||||
* </code></pre>
|
||||
*
|
||||
* @param key the key to normalize
|
||||
* @param withLeadingSlash whether or not the normalized key should begin
|
||||
* with a leading slash
|
||||
* @return normalized key
|
||||
*/
|
||||
public static String normalizeKey(String key, boolean withLeadingSlash) {
|
||||
String normalized;
|
||||
if (withLeadingSlash) {
|
||||
normalized = PATH_SEPARATOR + key;
|
||||
} else {
|
||||
normalized = key;
|
||||
}
|
||||
normalized = normalized.replaceAll(PATH_SEPARATOR + "{2,}", String.valueOf(PATH_SEPARATOR));
|
||||
|
||||
if (!withLeadingSlash && normalized.charAt(0) == PATH_SEPARATOR) {
|
||||
// remove leading slash, if present
|
||||
normalized = normalized.substring(1);
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes a network table key to start with exactly one leading slash
|
||||
* ("/") and contain no consecutive slashes. For example,
|
||||
* {@code "//foo/bar/"} becomes {@code "/foo/bar/"} and
|
||||
* {@code "///a/b/c"} becomes {@code "/a/b/c"}.
|
||||
*
|
||||
* <p>This is equivalent to {@code normalizeKey(key, true)}
|
||||
*
|
||||
* @param key the key to normalize
|
||||
* @return normalized key
|
||||
*/
|
||||
public static String normalizeKey(String key) {
|
||||
return normalizeKey(key, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of the names of all the super tables of a given key. For
|
||||
* example, the key "/foo/bar/baz" has a hierarchy of "/", "/foo",
|
||||
* "/foo/bar", and "/foo/bar/baz".
|
||||
* @param key the key
|
||||
* @return List of super tables
|
||||
*/
|
||||
public static List<String> getHierarchy(String key) {
|
||||
final String normal = normalizeKey(key, true);
|
||||
List<String> hierarchy = new ArrayList<>();
|
||||
if (normal.length() == 1) {
|
||||
hierarchy.add(normal);
|
||||
return hierarchy;
|
||||
}
|
||||
for (int i = 1; ; i = normal.indexOf(PATH_SEPARATOR, i + 1)) {
|
||||
if (i == -1) {
|
||||
// add the full key
|
||||
hierarchy.add(normal);
|
||||
break;
|
||||
} else {
|
||||
hierarchy.add(normal.substring(0, i));
|
||||
}
|
||||
}
|
||||
return hierarchy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor. Use NetworkTableInstance.getTable() or getSubTable() instead.
|
||||
*/
|
||||
|
||||
@@ -22,6 +22,56 @@ bool NetworkTable::s_enable_ds = true;
|
||||
bool NetworkTable::s_running = false;
|
||||
unsigned int NetworkTable::s_port = NT_DEFAULT_PORT;
|
||||
|
||||
StringRef NetworkTable::BasenameKey(StringRef key) {
|
||||
size_t slash = key.rfind(PATH_SEPARATOR_CHAR);
|
||||
if (slash == StringRef::npos) return key;
|
||||
return key.substr(slash + 1);
|
||||
}
|
||||
|
||||
std::string NetworkTable::NormalizeKey(StringRef key, bool withLeadingSlash) {
|
||||
llvm::SmallString<128> buf;
|
||||
return NormalizeKey(key, buf, withLeadingSlash);
|
||||
}
|
||||
|
||||
StringRef NetworkTable::NormalizeKey(StringRef key,
|
||||
llvm::SmallVectorImpl<char>& buf,
|
||||
bool withLeadingSlash) {
|
||||
buf.clear();
|
||||
if (withLeadingSlash) buf.push_back(PATH_SEPARATOR_CHAR);
|
||||
// for each path element, add it with a slash following
|
||||
llvm::SmallVector<StringRef, 16> parts;
|
||||
key.split(parts, PATH_SEPARATOR_CHAR, -1, false);
|
||||
for (auto i = parts.begin(); i != parts.end(); ++i) {
|
||||
buf.append(i->begin(), i->end());
|
||||
buf.push_back(PATH_SEPARATOR_CHAR);
|
||||
}
|
||||
// remove trailing slash if the input key didn't have one
|
||||
if (!key.empty() && key.back() != PATH_SEPARATOR_CHAR) buf.pop_back();
|
||||
return StringRef(buf.data(), buf.size());
|
||||
}
|
||||
|
||||
std::vector<std::string> NetworkTable::GetHierarchy(StringRef key) {
|
||||
std::vector<std::string> hierarchy;
|
||||
hierarchy.emplace_back(1, PATH_SEPARATOR_CHAR);
|
||||
// for each path element, add it to the end of what we built previously
|
||||
llvm::SmallString<128> path;
|
||||
llvm::SmallVector<StringRef, 16> parts;
|
||||
key.split(parts, PATH_SEPARATOR_CHAR, -1, false);
|
||||
if (!parts.empty()) {
|
||||
for (auto i = parts.begin(); i != parts.end(); ++i) {
|
||||
path += PATH_SEPARATOR_CHAR;
|
||||
path += *i;
|
||||
hierarchy.emplace_back(path.str());
|
||||
}
|
||||
// handle trailing slash
|
||||
if (key.back() == PATH_SEPARATOR_CHAR) {
|
||||
path += PATH_SEPARATOR_CHAR;
|
||||
hierarchy.emplace_back(path.str());
|
||||
}
|
||||
}
|
||||
return hierarchy;
|
||||
}
|
||||
|
||||
void NetworkTable::Initialize() {
|
||||
if (s_running) Shutdown();
|
||||
auto inst = NetworkTableInstance::GetDefault();
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#include "llvm/ArrayRef.h"
|
||||
#include "llvm/StringMap.h"
|
||||
#include "networktables/NetworkTableEntry.h"
|
||||
#include "networktables/TableEntryListener.h"
|
||||
@@ -54,6 +55,44 @@ class NetworkTable final : public ITable {
|
||||
friend class NetworkTableInstance;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Gets the "base name" of a key. For example, "/foo/bar" becomes "bar".
|
||||
* If the key has a trailing slash, returns an empty string.
|
||||
* @param key key
|
||||
* @return base name
|
||||
*/
|
||||
static StringRef BasenameKey(StringRef key);
|
||||
|
||||
/**
|
||||
* Normalizes an network table key to contain no consecutive slashes and
|
||||
* optionally start with a leading slash. For example:
|
||||
*
|
||||
* <pre><code>
|
||||
* normalizeKey("/foo/bar", true) == "/foo/bar"
|
||||
* normalizeKey("foo/bar", true) == "/foo/bar"
|
||||
* normalizeKey("/foo/bar", false) == "foo/bar"
|
||||
* normalizeKey("foo//bar", false) == "foo/bar"
|
||||
* </code></pre>
|
||||
*
|
||||
* @param key the key to normalize
|
||||
* @param withLeadingSlash whether or not the normalized key should begin
|
||||
* with a leading slash
|
||||
* @return normalized key
|
||||
*/
|
||||
static std::string NormalizeKey(StringRef key, bool withLeadingSlash = true);
|
||||
|
||||
static StringRef NormalizeKey(StringRef key, llvm::SmallVectorImpl<char>& buf,
|
||||
bool withLeadingSlash = true);
|
||||
|
||||
/**
|
||||
* Gets a list of the names of all the super tables of a given key. For
|
||||
* example, the key "/foo/bar/baz" has a hierarchy of "/", "/foo",
|
||||
* "/foo/bar", and "/foo/bar/baz".
|
||||
* @param key the key
|
||||
* @return List of super tables
|
||||
*/
|
||||
static std::vector<std::string> GetHierarchy(StringRef key);
|
||||
|
||||
/**
|
||||
* Constructor. Use NetworkTableInstance::GetTable() or GetSubTable()
|
||||
* instead.
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
package edu.wpi.first.networktables;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class NetworkTableTest extends TestCase {
|
||||
|
||||
public void testBasenameKey() {
|
||||
assertEquals("simple", NetworkTable.basenameKey("simple"));
|
||||
assertEquals("simple", NetworkTable.basenameKey("one/two/many/simple"));
|
||||
assertEquals("simple",
|
||||
NetworkTable.basenameKey("//////an/////awful/key////simple"));
|
||||
}
|
||||
|
||||
public void testNormalizeKeySlash() {
|
||||
assertEquals("/", NetworkTable.normalizeKey("///"));
|
||||
assertEquals("/no/normal/req", NetworkTable.normalizeKey("/no/normal/req"));
|
||||
assertEquals("/no/leading/slash",
|
||||
NetworkTable.normalizeKey("no/leading/slash"));
|
||||
assertEquals(
|
||||
"/what/an/awful/key/",
|
||||
NetworkTable.normalizeKey("//////what////an/awful/////key///"));
|
||||
}
|
||||
|
||||
public void testNormalizeKeyNoSlash() {
|
||||
assertEquals("a", NetworkTable.normalizeKey("a", false));
|
||||
assertEquals("a", NetworkTable.normalizeKey("///a", false));
|
||||
assertEquals("leading/slash",
|
||||
NetworkTable.normalizeKey("/leading/slash", false));
|
||||
assertEquals("no/leading/slash",
|
||||
NetworkTable.normalizeKey("no/leading/slash", false));
|
||||
assertEquals(
|
||||
"what/an/awful/key/",
|
||||
NetworkTable.normalizeKey("//////what////an/awful/////key///", false));
|
||||
}
|
||||
|
||||
public void testGetHierarchyEmpty() {
|
||||
List<String> expected = new ArrayList<>();
|
||||
expected.add("/");
|
||||
assertEquals(expected, NetworkTable.getHierarchy(""));
|
||||
}
|
||||
|
||||
public void testGetHierarchyRoot() {
|
||||
List<String> expected = new ArrayList<>();
|
||||
expected.add("/");
|
||||
assertEquals(expected, NetworkTable.getHierarchy("/"));
|
||||
}
|
||||
|
||||
public void testGetHierarchyNormal() {
|
||||
List<String> expected = new ArrayList<>();
|
||||
expected.add("/");
|
||||
expected.add("/foo");
|
||||
expected.add("/foo/bar");
|
||||
expected.add("/foo/bar/baz");
|
||||
assertEquals(expected, NetworkTable.getHierarchy("/foo/bar/baz"));
|
||||
}
|
||||
|
||||
public void testGetHierarchyTrailingSlash() {
|
||||
List<String> expected = new ArrayList<>();
|
||||
expected.add("/");
|
||||
expected.add("/foo");
|
||||
expected.add("/foo/bar");
|
||||
expected.add("/foo/bar/");
|
||||
assertEquals(expected, NetworkTable.getHierarchy("/foo/bar/"));
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,54 @@
|
||||
|
||||
class NetworkTableTest : public ::testing::Test {};
|
||||
|
||||
TEST_F(NetworkTableTest, BasenameKey) {
|
||||
EXPECT_EQ("simple", NetworkTable::BasenameKey("simple"));
|
||||
EXPECT_EQ("simple", NetworkTable::BasenameKey("one/two/many/simple"));
|
||||
EXPECT_EQ("simple",
|
||||
NetworkTable::BasenameKey("//////an/////awful/key////simple"));
|
||||
}
|
||||
|
||||
TEST_F(NetworkTableTest, NormalizeKeySlash) {
|
||||
EXPECT_EQ("/", NetworkTable::NormalizeKey("///"));
|
||||
EXPECT_EQ("/no/normal/req", NetworkTable::NormalizeKey("/no/normal/req"));
|
||||
EXPECT_EQ("/no/leading/slash",
|
||||
NetworkTable::NormalizeKey("no/leading/slash"));
|
||||
EXPECT_EQ("/what/an/awful/key/",
|
||||
NetworkTable::NormalizeKey("//////what////an/awful/////key///"));
|
||||
}
|
||||
|
||||
TEST_F(NetworkTableTest, NormalizeKeyNoSlash) {
|
||||
EXPECT_EQ("a", NetworkTable::NormalizeKey("a", false));
|
||||
EXPECT_EQ("a", NetworkTable::NormalizeKey("///a", false));
|
||||
EXPECT_EQ("leading/slash",
|
||||
NetworkTable::NormalizeKey("/leading/slash", false));
|
||||
EXPECT_EQ("no/leading/slash",
|
||||
NetworkTable::NormalizeKey("no/leading/slash", false));
|
||||
EXPECT_EQ(
|
||||
"what/an/awful/key/",
|
||||
NetworkTable::NormalizeKey("//////what////an/awful/////key///", false));
|
||||
}
|
||||
|
||||
TEST_F(NetworkTableTest, GetHierarchyEmpty) {
|
||||
std::vector<std::string> expected{"/"};
|
||||
ASSERT_EQ(expected, NetworkTable::GetHierarchy(""));
|
||||
}
|
||||
|
||||
TEST_F(NetworkTableTest, GetHierarchyRoot) {
|
||||
std::vector<std::string> expected{"/"};
|
||||
ASSERT_EQ(expected, NetworkTable::GetHierarchy("/"));
|
||||
}
|
||||
|
||||
TEST_F(NetworkTableTest, GetHierarchyNormal) {
|
||||
std::vector<std::string> expected{"/", "/foo", "/foo/bar", "/foo/bar/baz"};
|
||||
ASSERT_EQ(expected, NetworkTable::GetHierarchy("/foo/bar/baz"));
|
||||
}
|
||||
|
||||
TEST_F(NetworkTableTest, GetHierarchyTrailingSlash) {
|
||||
std::vector<std::string> expected{"/", "/foo", "/foo/bar", "/foo/bar/"};
|
||||
ASSERT_EQ(expected, NetworkTable::GetHierarchy("/foo/bar/"));
|
||||
}
|
||||
|
||||
TEST_F(NetworkTableTest, ContainsKey) {
|
||||
auto inst = nt::NetworkTableInstance::Create();
|
||||
auto nt = inst.GetTable("containskey");
|
||||
|
||||
Reference in New Issue
Block a user