mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Implement a trie data structure. Specifically, implement
a ternary tree with a fixed-length per-node inline key buffer. I plan to use this for metadata path caches, where it's useful to be able to quickly find the most-derived point along a path that you've already cached, but it should be useful for other things in the compiler as well, like function-with-argument-label lookups and possibly code completion. This is quite a bit more space-efficient (and somewhat faster) than doing scans after a lower_bound on a std::map<std::string, T>. I haven't implemented balancing yet, and I don't need delete at all for metadata paths, so I don't plan to work on that. Swift SVN r32453
This commit is contained in:
184
unittests/Basic/PrefixMapTest.cpp
Normal file
184
unittests/Basic/PrefixMapTest.cpp
Normal file
@@ -0,0 +1,184 @@
|
||||
#include "swift/Basic/PrefixMap.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
using namespace swift;
|
||||
|
||||
static ArrayRef<char> asArray(StringRef str) {
|
||||
return ArrayRef<char>(str.begin(), str.end());
|
||||
}
|
||||
static StringRef asString(ArrayRef<char> str) {
|
||||
return StringRef(str.begin(), str.size());
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct Tester {
|
||||
std::map<std::string, int> StdMap;
|
||||
PrefixMap<char, int> PreMap;
|
||||
|
||||
Tester() {
|
||||
assert(PreMap.empty());
|
||||
}
|
||||
|
||||
// Performs an insert operation and tests that the result matches what
|
||||
// we get from the std::map.
|
||||
void insert(StringRef key, int value) {
|
||||
auto stdmapResult = StdMap.insert({key, value});
|
||||
auto premapResult = PreMap.insert(asArray(key), value);
|
||||
|
||||
// Whether or not we modified the map should be the same in both
|
||||
// implementations.
|
||||
EXPECT_EQ(stdmapResult.second, premapResult.second);
|
||||
|
||||
// If we did insert a new entry, the value at the handle should
|
||||
// reflect the value we inserted.
|
||||
if (premapResult.second) {
|
||||
EXPECT_EQ(value, *premapResult.first);
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that the result of a findPrefix matches what we expect from
|
||||
// the std::map.
|
||||
void find(StringRef key) {
|
||||
auto stdmapResult = StdMap.lower_bound(key);
|
||||
while (stdmapResult == StdMap.end() ||
|
||||
!key.startswith(stdmapResult->first)) {
|
||||
if (stdmapResult == StdMap.begin()) {
|
||||
stdmapResult = StdMap.end();
|
||||
break;
|
||||
}
|
||||
--stdmapResult;
|
||||
}
|
||||
bool hasStdmapEntry = (stdmapResult != StdMap.end());
|
||||
|
||||
auto premapResult = PreMap.findPrefix(asArray(key));
|
||||
|
||||
EXPECT_EQ(hasStdmapEntry, bool(premapResult.first));
|
||||
if (!hasStdmapEntry) return;
|
||||
|
||||
assert(key.startswith(stdmapResult->first));
|
||||
auto stdmapValue = stdmapResult->second;
|
||||
EXPECT_EQ(stdmapValue, *premapResult.first);
|
||||
EXPECT_EQ(key.begin() + stdmapResult->first.size(), premapResult.second);
|
||||
}
|
||||
|
||||
// Perform a clear operation. Tests that that actually clears out the map.
|
||||
void clear() {
|
||||
StdMap.clear();
|
||||
PreMap.clear();
|
||||
EXPECT_TRUE(PreMap.empty());
|
||||
EXPECT_EQ(0U, PreMap.size());
|
||||
}
|
||||
|
||||
// Validate the map. Primarily tests iteration.
|
||||
void validate() {
|
||||
EXPECT_EQ(StdMap.empty(), PreMap.empty());
|
||||
EXPECT_EQ(StdMap.size(), PreMap.size());
|
||||
|
||||
auto si = StdMap.begin(), se = StdMap.end();
|
||||
auto pi = PreMap.begin(), pe = PreMap.end();
|
||||
while (true) {
|
||||
if (si == se) {
|
||||
EXPECT_TRUE(pi == pe);
|
||||
return;
|
||||
}
|
||||
EXPECT_TRUE(pi != pe);
|
||||
|
||||
EXPECT_EQ(si->second, (*pi).getValue());
|
||||
|
||||
llvm::SmallString<128> buffer;
|
||||
EXPECT_EQ(StringRef(si->first), asString((*pi).getKey(buffer)));
|
||||
|
||||
++si;
|
||||
++pi;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
TEST(PrefixMapTest, Insert) {
|
||||
PrefixMap<char, int> map;
|
||||
map.insert(asArray("abcdefghi"), 5);
|
||||
EXPECT_FALSE(bool(map.findPrefix(asArray("abcdefg")).first));
|
||||
|
||||
ArrayRef<char> abcdefghij = asArray("abcdefghij");
|
||||
auto abcdefghijHandle = map.findPrefix(abcdefghij);
|
||||
EXPECT_TRUE(bool(abcdefghijHandle.first));
|
||||
EXPECT_EQ(5, *abcdefghijHandle.first);
|
||||
EXPECT_EQ(abcdefghij.data() + 9, abcdefghijHandle.second);
|
||||
}
|
||||
|
||||
TEST(PrefixMapTest, Test1) {
|
||||
Tester tester;
|
||||
tester.find("");
|
||||
tester.validate();
|
||||
tester.insert("", 22096);
|
||||
tester.validate();
|
||||
tester.insert("", 20154);
|
||||
tester.validate();
|
||||
tester.insert("aezvs", 21441);
|
||||
tester.validate();
|
||||
tester.insert("aezvs", 838);
|
||||
tester.validate();
|
||||
tester.insert("aezvs", 16768);
|
||||
tester.validate();
|
||||
tester.validate();
|
||||
tester.find("aezvsrmoll");
|
||||
tester.validate();
|
||||
tester.insert("aezvsrmoll", 5842);
|
||||
tester.validate();
|
||||
tester.find("aezvsrmoll");
|
||||
tester.validate();
|
||||
}
|
||||
|
||||
TEST(PrefixMapTest, Test2) {
|
||||
Tester tester;
|
||||
tester.find("");
|
||||
tester.validate();
|
||||
tester.insert("", 22096);
|
||||
tester.validate();
|
||||
tester.insert("", 20154);
|
||||
tester.validate();
|
||||
tester.insert("aezvs", 21441);
|
||||
tester.validate();
|
||||
tester.insert("aezvs", 838);
|
||||
tester.validate();
|
||||
tester.insert("aezvs", 16768);
|
||||
tester.validate();
|
||||
tester.clear();
|
||||
tester.validate();
|
||||
tester.find("aezvsrmoll");
|
||||
tester.validate();
|
||||
tester.insert("aezvsrmoll", 5842);
|
||||
tester.validate();
|
||||
tester.find("aezvsrmoll");
|
||||
tester.validate();
|
||||
}
|
||||
|
||||
TEST(PrefixMapTest, Test3) {
|
||||
Tester tester;
|
||||
tester.insert("wbuqbtaprrpooqteftzdhjd", 11861);
|
||||
tester.insert("wbuqbtaprrpooqteftzdhjd", 18531);
|
||||
tester.find("wbuqbtaprrpooqteftzdhjdqkemtcl");
|
||||
}
|
||||
|
||||
TEST(PrefixMapTest, Test4) {
|
||||
Tester tester;
|
||||
tester.find("");
|
||||
tester.validate();
|
||||
tester.find("l");
|
||||
tester.validate();
|
||||
tester.insert("l", 5943);
|
||||
tester.validate();
|
||||
tester.find("l");
|
||||
tester.validate();
|
||||
tester.insert("l", 8632);
|
||||
tester.validate();
|
||||
tester.find("zguowwnctgmkg");
|
||||
}
|
||||
Reference in New Issue
Block a user