mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
[wpiutil] Replace LLVM StringMap impl with std::map
As string_view operations on std::map<std::string> won't be integrated until C++26, placeholder implementations are used which are less efficient in a couple of situations (e.g. insert with hint).
This commit is contained in:
@@ -130,7 +130,7 @@ void AprilTagDetector::RemoveFamily(std::string_view fam) {
|
||||
apriltag_detector_remove_family(
|
||||
static_cast<apriltag_detector_t*>(m_impl),
|
||||
static_cast<apriltag_family_t*>(it->second));
|
||||
DestroyFamily(it->getKey(), it->second);
|
||||
DestroyFamily(it->first, it->second);
|
||||
m_families.erase(it);
|
||||
}
|
||||
}
|
||||
@@ -158,7 +158,7 @@ void AprilTagDetector::Destroy() {
|
||||
|
||||
void AprilTagDetector::DestroyFamilies() {
|
||||
for (auto&& entry : m_families) {
|
||||
DestroyFamily(entry.getKey(), entry.second);
|
||||
DestroyFamily(entry.first, entry.second);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ static void WorkspaceInit() {
|
||||
}
|
||||
|
||||
for (auto&& root : gContext->storageRoots) {
|
||||
root.getValue()->Apply();
|
||||
root.second->Apply();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ static bool LoadStorageImpl(Context* ctx, std::string_view dir,
|
||||
bool rv = true;
|
||||
for (auto&& root : ctx->storageRoots) {
|
||||
std::string filename;
|
||||
auto rootName = root.getKey();
|
||||
auto& rootName = root.first;
|
||||
if (rootName.empty()) {
|
||||
filename = (fs::path{dir} / fmt::format("{}.json", name)).string();
|
||||
} else {
|
||||
@@ -291,7 +291,7 @@ static bool SaveStorageImpl(Context* ctx, std::string_view dir,
|
||||
if (exiting && wpi::gui::gContext->resetOnExit) {
|
||||
fs::remove(dirPath / fmt::format("{}-window.json", name), ec);
|
||||
for (auto&& root : ctx->storageRoots) {
|
||||
auto rootName = root.getKey();
|
||||
auto& rootName = root.first;
|
||||
if (rootName.empty()) {
|
||||
fs::remove(dirPath / fmt::format("{}.json", name), ec);
|
||||
} else {
|
||||
@@ -304,14 +304,14 @@ static bool SaveStorageImpl(Context* ctx, std::string_view dir,
|
||||
(dirPath / fmt::format("{}-window.json", name)).string());
|
||||
|
||||
for (auto&& root : ctx->storageRoots) {
|
||||
auto rootName = root.getKey();
|
||||
auto& rootName = root.first;
|
||||
std::string filename;
|
||||
if (rootName.empty()) {
|
||||
filename = (dirPath / fmt::format("{}.json", name)).string();
|
||||
} else {
|
||||
filename = (dirPath / fmt::format("{}-{}.json", name, rootName)).string();
|
||||
}
|
||||
if (!SaveStorageRootImpl(ctx, filename, *root.getValue())) {
|
||||
if (!SaveStorageRootImpl(ctx, filename, *root.second)) {
|
||||
rv = false;
|
||||
}
|
||||
}
|
||||
@@ -320,8 +320,7 @@ static bool SaveStorageImpl(Context* ctx, std::string_view dir,
|
||||
|
||||
Context::Context()
|
||||
: sourceNameStorage{storageRoots.insert({"", std::make_unique<Storage>()})
|
||||
.first->getValue()
|
||||
->GetChild("sourceNames")} {
|
||||
.first->second->GetChild("sourceNames")} {
|
||||
storageStack.emplace_back(storageRoots[""].get());
|
||||
|
||||
// override ImGui ini saving
|
||||
|
||||
@@ -112,5 +112,5 @@ DataSource* DataSource::Find(std::string_view id) {
|
||||
if (it == gContext->sources.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return it->getValue();
|
||||
return it->second;
|
||||
}
|
||||
|
||||
@@ -331,7 +331,7 @@ std::vector<std::unique_ptr<Storage>>& Storage::GetChildArray(
|
||||
std::unique_ptr<Storage::Value> Storage::Erase(std::string_view key) {
|
||||
auto it = m_values.find(key);
|
||||
if (it != m_values.end()) {
|
||||
auto rv = std::move(it->getValue());
|
||||
auto rv = std::move(it->second);
|
||||
m_values.erase(it);
|
||||
return rv;
|
||||
}
|
||||
@@ -339,11 +339,9 @@ std::unique_ptr<Storage::Value> Storage::Erase(std::string_view key) {
|
||||
}
|
||||
|
||||
void Storage::EraseChildren() {
|
||||
for (auto&& kv : m_values) {
|
||||
if (kv.getValue()->type == Value::kChild) {
|
||||
m_values.remove(&kv);
|
||||
}
|
||||
}
|
||||
std::erase_if(m_values, [](const auto& kv) {
|
||||
return kv.second->type == Value::kChild;
|
||||
});
|
||||
}
|
||||
|
||||
static bool JsonArrayToStorage(Storage::Value* valuePtr, const wpi::json& jarr,
|
||||
@@ -559,7 +557,7 @@ wpi::json Storage::ToJson() const {
|
||||
wpi::json j = wpi::json::object();
|
||||
for (auto&& kv : m_values) {
|
||||
wpi::json jelem;
|
||||
auto& value = *kv.getValue();
|
||||
auto& value = *kv.second;
|
||||
switch (value.type) {
|
||||
#define CASE(CapsName, LowerName) \
|
||||
case Value::k##CapsName: \
|
||||
@@ -602,7 +600,7 @@ wpi::json Storage::ToJson() const {
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
j.emplace(kv.getKey(), std::move(jelem));
|
||||
j.emplace(kv.first, std::move(jelem));
|
||||
}
|
||||
return j;
|
||||
}
|
||||
@@ -617,7 +615,7 @@ void Storage::Clear() {
|
||||
|
||||
void Storage::ClearValues() {
|
||||
for (auto&& kv : m_values) {
|
||||
auto& value = *kv.getValue();
|
||||
auto& value = *kv.second;
|
||||
switch (value.type) {
|
||||
case Value::kInt:
|
||||
value.intVal = value.intDefault;
|
||||
@@ -703,7 +701,7 @@ void Storage::Apply() {
|
||||
|
||||
void Storage::ApplyChildren() {
|
||||
for (auto&& kv : m_values) {
|
||||
auto& value = *kv.getValue();
|
||||
auto& value = *kv.second;
|
||||
switch (value.type) {
|
||||
case Value::kChild:
|
||||
value.child->Apply();
|
||||
|
||||
@@ -249,8 +249,7 @@ class ChildIterator {
|
||||
public:
|
||||
ChildIterator(IteratorType it, IteratorType end) noexcept
|
||||
: anchor(it), end(end) {
|
||||
while (anchor != end &&
|
||||
anchor->getValue()->type != Storage::Value::kChild) {
|
||||
while (anchor != end && anchor->second->type != Storage::Value::kChild) {
|
||||
++anchor;
|
||||
}
|
||||
}
|
||||
@@ -261,8 +260,7 @@ class ChildIterator {
|
||||
/// increment operator (needed for range-based for)
|
||||
ChildIterator& operator++() {
|
||||
++anchor;
|
||||
while (anchor != end &&
|
||||
anchor->getValue()->type != Storage::Value::kChild) {
|
||||
while (anchor != end && anchor->second->type != Storage::Value::kChild) {
|
||||
++anchor;
|
||||
}
|
||||
return *this;
|
||||
@@ -274,10 +272,10 @@ class ChildIterator {
|
||||
}
|
||||
|
||||
/// return key of the iterator
|
||||
std::string_view key() const { return anchor->getKey(); }
|
||||
std::string_view key() const { return anchor->first; }
|
||||
|
||||
/// return value of the iterator
|
||||
Storage& value() const { return *anchor->getValue()->child; }
|
||||
Storage& value() const { return *anchor->second->child; }
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -317,7 +317,7 @@ HAL_SimDeviceHandle SimDeviceData::GetDeviceHandle(const char* name) {
|
||||
if (it == m_deviceMap.end()) {
|
||||
return 0;
|
||||
}
|
||||
if (auto deviceImpl = it->getValue().lock()) {
|
||||
if (auto deviceImpl = it->second.lock()) {
|
||||
return deviceImpl->handle;
|
||||
} else {
|
||||
return 0;
|
||||
@@ -459,10 +459,10 @@ HAL_SimValueHandle SimDeviceData::GetValueHandle(HAL_SimDeviceHandle device,
|
||||
if (it == deviceImpl->valueMap.end()) {
|
||||
return 0;
|
||||
}
|
||||
if (!it->getValue()) {
|
||||
if (!it->second) {
|
||||
return 0;
|
||||
}
|
||||
return it->getValue()->handle;
|
||||
return it->second->handle;
|
||||
}
|
||||
|
||||
void SimDeviceData::EnumerateValues(HAL_SimDeviceHandle device, void* param,
|
||||
|
||||
@@ -112,8 +112,8 @@ void HALSimWS::Start() {
|
||||
// Print any filters we are using
|
||||
if (m_useMsgFiltering) {
|
||||
wpi::print("WS Message Filters:");
|
||||
for (auto filter : m_msgFilters.keys()) {
|
||||
wpi::print("* \"{}\"\n", filter);
|
||||
for (auto&& filter : m_msgFilters) {
|
||||
wpi::print("* \"{}\"\n", filter.first);
|
||||
}
|
||||
} else {
|
||||
wpi::print("No WS Message Filters specified");
|
||||
|
||||
@@ -54,7 +54,7 @@ void HALSimWSProviderSimDevice::CancelCallbacks() {
|
||||
m_simValueCreatedCbKey = 0;
|
||||
|
||||
for (auto& kv : m_simValueChangedCbKeys) {
|
||||
HALSIM_CancelSimValueChangedCallback(kv.getValue());
|
||||
HALSIM_CancelSimValueChangedCallback(kv.second);
|
||||
}
|
||||
|
||||
m_simValueChangedCbKeys.clear();
|
||||
|
||||
@@ -40,7 +40,7 @@ class ProviderContainer {
|
||||
void ForEach(IterFn fn) {
|
||||
std::shared_lock lock(m_mutex);
|
||||
for (auto& kv : m_providers) {
|
||||
fn(kv.getValue());
|
||||
fn(kv.second);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -123,8 +123,8 @@ void HALSimWeb::Start() {
|
||||
// Print any filters we are using
|
||||
if (m_useMsgFiltering) {
|
||||
wpi::print("WS Message Filters:");
|
||||
for (auto filter : m_msgFilters.keys()) {
|
||||
wpi::print("* \"{}\"\n", filter);
|
||||
for (auto&& filter : m_msgFilters) {
|
||||
wpi::print("* \"{}\"\n", filter.first);
|
||||
}
|
||||
} else {
|
||||
wpi::print("No WS Message Filters specified");
|
||||
|
||||
@@ -90,8 +90,8 @@ static void CopyRawData(wpi::StringMap<MotorData>* dataset) {
|
||||
auto& data = *dataset;
|
||||
// Loads the Raw Data
|
||||
for (auto& it : data) {
|
||||
auto key = it.first();
|
||||
auto& motorData = it.getValue();
|
||||
auto& key = it.first;
|
||||
auto& motorData = it.second;
|
||||
|
||||
if (!wpi::contains(key, "raw")) {
|
||||
data[fmt::format("raw-{}", key)] = motorData;
|
||||
@@ -126,7 +126,7 @@ void AnalysisManager::PrepareGeneralData() {
|
||||
WPI_INFO(m_logger, "{}", "Converting raw data to PreparedData struct.");
|
||||
// Convert data to PreparedData structs
|
||||
for (auto& it : m_data.motorData) {
|
||||
auto key = it.first();
|
||||
auto key = it.first;
|
||||
preparedData[key] = ConvertToPrepared(m_data.motorData[key]);
|
||||
WPI_INFO(m_logger, "SAMPLES {}", preparedData[key].size());
|
||||
}
|
||||
|
||||
@@ -322,8 +322,8 @@ static units::second_t GetMaxStepTime(
|
||||
wpi::StringMap<std::vector<PreparedData>>& data) {
|
||||
auto maxStepTime = 0_s;
|
||||
for (auto& it : data) {
|
||||
auto key = it.first();
|
||||
auto& dataset = it.getValue();
|
||||
auto& key = it.first;
|
||||
auto& dataset = it.second;
|
||||
|
||||
if (IsRaw(key) && wpi::contains(key, "dynamic")) {
|
||||
if (!dataset.empty()) {
|
||||
@@ -351,8 +351,8 @@ void sysid::InitialTrimAndFilter(
|
||||
// Calculate Velocity Threshold if it hasn't been set yet
|
||||
if (settings->velocityThreshold == std::numeric_limits<double>::infinity()) {
|
||||
for (auto& it : preparedData) {
|
||||
auto key = it.first();
|
||||
auto& dataset = it.getValue();
|
||||
auto& key = it.first;
|
||||
auto& dataset = it.second;
|
||||
if (wpi::contains(key, "quasistatic")) {
|
||||
settings->velocityThreshold =
|
||||
std::min(settings->velocityThreshold,
|
||||
@@ -363,8 +363,8 @@ void sysid::InitialTrimAndFilter(
|
||||
}
|
||||
|
||||
for (auto& it : preparedData) {
|
||||
auto key = it.first();
|
||||
auto& dataset = it.getValue();
|
||||
auto& key = it.first;
|
||||
auto& dataset = it.second;
|
||||
|
||||
// Trim quasistatic test data to remove all points where voltage is zero or
|
||||
// velocity < velocity threshold.
|
||||
@@ -424,7 +424,7 @@ void sysid::AccelFilter(wpi::StringMap<std::vector<PreparedData>>* data) {
|
||||
|
||||
// Remove points with acceleration = 0
|
||||
for (auto& it : preparedData) {
|
||||
auto& dataset = it.getValue();
|
||||
auto& dataset = it.second;
|
||||
|
||||
for (size_t i = 0; i < dataset.size(); i++) {
|
||||
if (dataset.at(i).acceleration == 0.0) {
|
||||
@@ -436,7 +436,7 @@ void sysid::AccelFilter(wpi::StringMap<std::vector<PreparedData>>* data) {
|
||||
|
||||
// Confirm there's still data
|
||||
if (std::any_of(preparedData.begin(), preparedData.end(),
|
||||
[](const auto& it) { return it.getValue().empty(); })) {
|
||||
[](const auto& it) { return it.second.empty(); })) {
|
||||
throw sysid::InvalidDataError(
|
||||
"Acceleration filtering has removed all data.");
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ void DataSelector::Display() {
|
||||
TestData data = m_testdataFuture.get();
|
||||
for (auto&& motordata : data.motorData) {
|
||||
m_testdataStats.emplace_back(
|
||||
fmt::format("Test State: {}", motordata.first()));
|
||||
fmt::format("Test State: {}", motordata.first));
|
||||
int i = 0;
|
||||
for (auto&& run : motordata.second.runs) {
|
||||
m_testdataStats.emplace_back(fmt::format(
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <imgui.h>
|
||||
#include <imgui_stdlib.h>
|
||||
#include <portable-file-dialogs.h>
|
||||
#include <wpi/SmallVector.h>
|
||||
#include <wpi/SpanExtras.h>
|
||||
#include <wpi/StringExtras.h>
|
||||
#include <wpi/fs.h>
|
||||
|
||||
@@ -8,8 +8,6 @@ Subject: [PATCH 01/38] Remove StringRef, ArrayRef, and Optional
|
||||
llvm/include/llvm/ADT/SmallSet.h | 2 +-
|
||||
llvm/include/llvm/ADT/SmallString.h | 103 ++++++++++--------
|
||||
llvm/include/llvm/ADT/SmallVector.h | 7 +-
|
||||
llvm/include/llvm/ADT/StringMap.h | 38 +++----
|
||||
llvm/include/llvm/ADT/StringMapEntry.h | 20 ++--
|
||||
llvm/include/llvm/Support/Chrono.h | 10 +-
|
||||
llvm/include/llvm/Support/Compiler.h | 2 +-
|
||||
llvm/include/llvm/Support/ConvertUTF.h | 31 +++---
|
||||
@@ -22,7 +20,6 @@ Subject: [PATCH 01/38] Remove StringRef, ArrayRef, and Optional
|
||||
llvm/lib/Support/ConvertUTFWrapper.cpp | 38 +++----
|
||||
llvm/lib/Support/ErrorHandling.cpp | 13 +--
|
||||
llvm/lib/Support/SmallVector.cpp | 5 +-
|
||||
llvm/lib/Support/StringMap.cpp | 12 +-
|
||||
llvm/lib/Support/raw_ostream.cpp | 25 ++---
|
||||
llvm/lib/Support/xxhash.cpp | 10 +-
|
||||
llvm/unittests/ADT/DenseMapTest.cpp | 29 +----
|
||||
@@ -31,7 +28,6 @@ Subject: [PATCH 01/38] Remove StringRef, ArrayRef, and Optional
|
||||
llvm/unittests/ADT/SmallPtrSetTest.cpp | 1 -
|
||||
llvm/unittests/ADT/SmallStringTest.cpp | 50 ++++-----
|
||||
llvm/unittests/ADT/SmallVectorTest.cpp | 30 +----
|
||||
llvm/unittests/ADT/StringMapTest.cpp | 32 +++---
|
||||
llvm/unittests/Support/ConvertUTFTest.cpp | 41 ++++---
|
||||
llvm/unittests/Support/xxhashTest.cpp | 4 +-
|
||||
30 files changed, 282 insertions(+), 323 deletions(-)
|
||||
@@ -372,230 +368,6 @@ index 09676d792dfebd88e5c8eace666b3ab0044a962e..c96fd0e4956ee6d586f85dc79623de13
|
||||
this->append(A.begin(), A.end());
|
||||
}
|
||||
|
||||
diff --git a/llvm/include/llvm/ADT/StringMap.h b/llvm/include/llvm/ADT/StringMap.h
|
||||
index 466f95254d102e98343290b211f317f749d7692b..34dfbf83c681f4e81a9dadd9382ddca6ef8d6c1d 100644
|
||||
--- a/llvm/include/llvm/ADT/StringMap.h
|
||||
+++ b/llvm/include/llvm/ADT/StringMap.h
|
||||
@@ -60,12 +60,12 @@ protected:
|
||||
/// specified bucket will be non-null. Otherwise, it will be null. In either
|
||||
/// case, the FullHashValue field of the bucket will be set to the hash value
|
||||
/// of the string.
|
||||
- unsigned LookupBucketFor(StringRef Key);
|
||||
+ unsigned LookupBucketFor(std::string_view Key);
|
||||
|
||||
/// FindKey - Look up the bucket that contains the specified key. If it exists
|
||||
/// in the map, return the bucket number of the key. Otherwise return -1.
|
||||
/// This does not modify the map.
|
||||
- int FindKey(StringRef Key) const;
|
||||
+ int FindKey(std::string_view Key) const;
|
||||
|
||||
/// RemoveKey - Remove the specified StringMapEntry from the table, but do not
|
||||
/// delete it. This aborts if the value isn't in the table.
|
||||
@@ -73,7 +73,7 @@ protected:
|
||||
|
||||
/// RemoveKey - Remove the StringMapEntry for the specified key from the
|
||||
/// table, returning it. If the key is not in the table, this returns null.
|
||||
- StringMapEntryBase *RemoveKey(StringRef Key);
|
||||
+ StringMapEntryBase *RemoveKey(std::string_view Key);
|
||||
|
||||
/// Allocate the table with the specified number of buckets and otherwise
|
||||
/// setup the map as empty.
|
||||
@@ -127,7 +127,7 @@ public:
|
||||
: StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))),
|
||||
AllocTy(A) {}
|
||||
|
||||
- StringMap(std::initializer_list<std::pair<StringRef, ValueTy>> List)
|
||||
+ StringMap(std::initializer_list<std::pair<std::string_view, ValueTy>> List)
|
||||
: StringMapImpl(List.size(), static_cast<unsigned>(sizeof(MapEntryTy))) {
|
||||
insert(List);
|
||||
}
|
||||
@@ -215,14 +215,14 @@ public:
|
||||
StringMapKeyIterator<ValueTy>(end()));
|
||||
}
|
||||
|
||||
- iterator find(StringRef Key) {
|
||||
+ iterator find(std::string_view Key) {
|
||||
int Bucket = FindKey(Key);
|
||||
if (Bucket == -1)
|
||||
return end();
|
||||
return iterator(TheTable + Bucket, true);
|
||||
}
|
||||
|
||||
- const_iterator find(StringRef Key) const {
|
||||
+ const_iterator find(std::string_view Key) const {
|
||||
int Bucket = FindKey(Key);
|
||||
if (Bucket == -1)
|
||||
return end();
|
||||
@@ -231,7 +231,7 @@ public:
|
||||
|
||||
/// lookup - Return the entry for the specified key, or a default
|
||||
/// constructed value if no such entry exists.
|
||||
- ValueTy lookup(StringRef Key) const {
|
||||
+ ValueTy lookup(std::string_view Key) const {
|
||||
const_iterator Iter = find(Key);
|
||||
if (Iter != end())
|
||||
return Iter->second;
|
||||
@@ -240,7 +240,7 @@ public:
|
||||
|
||||
/// at - Return the entry for the specified key, or abort if no such
|
||||
/// entry exists.
|
||||
- const ValueTy &at(StringRef Val) const {
|
||||
+ const ValueTy &at(std::string_view Val) const {
|
||||
auto Iter = this->find(std::move(Val));
|
||||
assert(Iter != this->end() && "StringMap::at failed due to a missing key");
|
||||
return Iter->second;
|
||||
@@ -248,13 +248,13 @@ public:
|
||||
|
||||
/// Lookup the ValueTy for the \p Key, or create a default constructed value
|
||||
/// if the key is not in the map.
|
||||
- ValueTy &operator[](StringRef Key) { return try_emplace(Key).first->second; }
|
||||
+ ValueTy &operator[](std::string_view Key) { return try_emplace(Key).first->second; }
|
||||
|
||||
/// contains - Return true if the element is in the map, false otherwise.
|
||||
- bool contains(StringRef Key) const { return find(Key) != end(); }
|
||||
+ bool contains(std::string_view Key) const { return find(Key) != end(); }
|
||||
|
||||
/// count - Return 1 if the element is in the map, 0 otherwise.
|
||||
- size_type count(StringRef Key) const { return contains(Key) ? 1 : 0; }
|
||||
+ size_type count(std::string_view Key) const { return contains(Key) ? 1 : 0; }
|
||||
|
||||
template <typename InputTy>
|
||||
size_type count(const StringMapEntry<InputTy> &MapEntry) const {
|
||||
@@ -304,7 +304,7 @@ public:
|
||||
/// isn't already in the map. The bool component of the returned pair is true
|
||||
/// if and only if the insertion takes place, and the iterator component of
|
||||
/// the pair points to the element with key equivalent to the key of the pair.
|
||||
- std::pair<iterator, bool> insert(std::pair<StringRef, ValueTy> KV) {
|
||||
+ std::pair<iterator, bool> insert(std::pair<std::string_view, ValueTy> KV) {
|
||||
return try_emplace(KV.first, std::move(KV.second));
|
||||
}
|
||||
|
||||
@@ -319,14 +319,14 @@ public:
|
||||
/// Inserts elements from initializer list ilist. If multiple elements in
|
||||
/// the range have keys that compare equivalent, it is unspecified which
|
||||
/// element is inserted
|
||||
- void insert(std::initializer_list<std::pair<StringRef, ValueTy>> List) {
|
||||
+ void insert(std::initializer_list<std::pair<std::string_view, ValueTy>> List) {
|
||||
insert(List.begin(), List.end());
|
||||
}
|
||||
|
||||
/// Inserts an element or assigns to the current element if the key already
|
||||
/// exists. The return type is the same as try_emplace.
|
||||
template <typename V>
|
||||
- std::pair<iterator, bool> insert_or_assign(StringRef Key, V &&Val) {
|
||||
+ std::pair<iterator, bool> insert_or_assign(std::string_view Key, V &&Val) {
|
||||
auto Ret = try_emplace(Key, std::forward<V>(Val));
|
||||
if (!Ret.second)
|
||||
Ret.first->second = std::forward<V>(Val);
|
||||
@@ -338,7 +338,7 @@ public:
|
||||
/// if and only if the insertion takes place, and the iterator component of
|
||||
/// the pair points to the element with key equivalent to the key of the pair.
|
||||
template <typename... ArgsTy>
|
||||
- std::pair<iterator, bool> try_emplace(StringRef Key, ArgsTy &&...Args) {
|
||||
+ std::pair<iterator, bool> try_emplace(std::string_view Key, ArgsTy &&...Args) {
|
||||
unsigned BucketNo = LookupBucketFor(Key);
|
||||
StringMapEntryBase *&Bucket = TheTable[BucketNo];
|
||||
if (Bucket && Bucket != getTombstoneVal())
|
||||
@@ -385,7 +385,7 @@ public:
|
||||
V.Destroy(getAllocator());
|
||||
}
|
||||
|
||||
- bool erase(StringRef Key) {
|
||||
+ bool erase(std::string_view Key) {
|
||||
iterator I = find(Key);
|
||||
if (I == end())
|
||||
return false;
|
||||
@@ -482,17 +482,17 @@ template <typename ValueTy>
|
||||
class StringMapKeyIterator
|
||||
: public iterator_adaptor_base<StringMapKeyIterator<ValueTy>,
|
||||
StringMapConstIterator<ValueTy>,
|
||||
- std::forward_iterator_tag, StringRef> {
|
||||
+ std::forward_iterator_tag, std::string_view> {
|
||||
using base = iterator_adaptor_base<StringMapKeyIterator<ValueTy>,
|
||||
StringMapConstIterator<ValueTy>,
|
||||
- std::forward_iterator_tag, StringRef>;
|
||||
+ std::forward_iterator_tag, std::string_view>;
|
||||
|
||||
public:
|
||||
StringMapKeyIterator() = default;
|
||||
explicit StringMapKeyIterator(StringMapConstIterator<ValueTy> Iter)
|
||||
: base(std::move(Iter)) {}
|
||||
|
||||
- StringRef operator*() const { return this->wrapped()->getKey(); }
|
||||
+ std::string_view operator*() const { return this->wrapped()->getKey(); }
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
diff --git a/llvm/include/llvm/ADT/StringMapEntry.h b/llvm/include/llvm/ADT/StringMapEntry.h
|
||||
index 98b51cc1aebd59eba20076e6d8a4eebc0eebb982..388e81c361642113937f7d5680de73a50635b07d 100644
|
||||
--- a/llvm/include/llvm/ADT/StringMapEntry.h
|
||||
+++ b/llvm/include/llvm/ADT/StringMapEntry.h
|
||||
@@ -16,8 +16,8 @@
|
||||
#ifndef LLVM_ADT_STRINGMAPENTRY_H
|
||||
#define LLVM_ADT_STRINGMAPENTRY_H
|
||||
|
||||
-#include "llvm/ADT/StringRef.h"
|
||||
#include <optional>
|
||||
+#include <string_view>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@@ -36,13 +36,13 @@ protected:
|
||||
/// type-erase the allocator and put it in a source file.
|
||||
template <typename AllocatorTy>
|
||||
static void *allocateWithKey(size_t EntrySize, size_t EntryAlign,
|
||||
- StringRef Key, AllocatorTy &Allocator);
|
||||
+ std::string_view Key, AllocatorTy &Allocator);
|
||||
};
|
||||
|
||||
// Define out-of-line to dissuade inlining.
|
||||
template <typename AllocatorTy>
|
||||
void *StringMapEntryBase::allocateWithKey(size_t EntrySize, size_t EntryAlign,
|
||||
- StringRef Key,
|
||||
+ std::string_view Key,
|
||||
AllocatorTy &Allocator) {
|
||||
size_t KeyLength = Key.size();
|
||||
|
||||
@@ -105,8 +105,8 @@ public:
|
||||
|
||||
using ValueType = ValueTy;
|
||||
|
||||
- StringRef getKey() const {
|
||||
- return StringRef(getKeyData(), this->getKeyLength());
|
||||
+ std::string_view getKey() const {
|
||||
+ return std::string_view(getKeyData(), this->getKeyLength());
|
||||
}
|
||||
|
||||
/// getKeyData - Return the start of the string data that is the key for this
|
||||
@@ -116,15 +116,15 @@ public:
|
||||
return reinterpret_cast<const char *>(this + 1);
|
||||
}
|
||||
|
||||
- StringRef first() const {
|
||||
- return StringRef(getKeyData(), this->getKeyLength());
|
||||
+ std::string_view first() const {
|
||||
+ return std::string_view(getKeyData(), this->getKeyLength());
|
||||
}
|
||||
|
||||
/// Create a StringMapEntry for the specified key construct the value using
|
||||
/// \p InitiVals.
|
||||
template <typename AllocatorTy, typename... InitTy>
|
||||
- static StringMapEntry *create(StringRef key, AllocatorTy &allocator,
|
||||
- InitTy &&...initVals) {
|
||||
+ static StringMapEntry *create(std::string_view key, AllocatorTy &allocator,
|
||||
+ InitTy &&... initVals) {
|
||||
return new (StringMapEntryBase::allocateWithKey(
|
||||
sizeof(StringMapEntry), alignof(StringMapEntry), key, allocator))
|
||||
StringMapEntry(key.size(), std::forward<InitTy>(initVals)...);
|
||||
@@ -167,7 +167,7 @@ struct tuple_size<llvm::StringMapEntry<ValueTy>>
|
||||
|
||||
template <std::size_t I, typename ValueTy>
|
||||
struct tuple_element<I, llvm::StringMapEntry<ValueTy>>
|
||||
- : std::conditional<I == 0, llvm::StringRef, ValueTy> {};
|
||||
+ : std::conditional<I == 0, std::string_view, ValueTy> {};
|
||||
} // namespace std
|
||||
|
||||
#endif // LLVM_ADT_STRINGMAPENTRY_H
|
||||
diff --git a/llvm/include/llvm/Support/Chrono.h b/llvm/include/llvm/Support/Chrono.h
|
||||
index 71859af7c7e4a595140475daf356744f52d14d24..9c9ba7002310eba5113c14957f769702c61f4326 100644
|
||||
--- a/llvm/include/llvm/Support/Chrono.h
|
||||
@@ -1228,63 +1000,6 @@ index b6ce37842040b36fc79770ca0296255f2bb42a1a..4f6fee18b659adcbfd79822832f91417
|
||||
#endif
|
||||
}
|
||||
|
||||
diff --git a/llvm/lib/Support/StringMap.cpp b/llvm/lib/Support/StringMap.cpp
|
||||
index 67c05a87959cf0c243d17646ae2f28f6c9f0d708..7be219323f6d76f32a9a841115f2f146141cdbab 100644
|
||||
--- a/llvm/lib/Support/StringMap.cpp
|
||||
+++ b/llvm/lib/Support/StringMap.cpp
|
||||
@@ -81,7 +81,7 @@ void StringMapImpl::init(unsigned InitSize) {
|
||||
/// specified bucket will be non-null. Otherwise, it will be null. In either
|
||||
/// case, the FullHashValue field of the bucket will be set to the hash value
|
||||
/// of the string.
|
||||
-unsigned StringMapImpl::LookupBucketFor(StringRef Name) {
|
||||
+unsigned StringMapImpl::LookupBucketFor(std::string_view Name) {
|
||||
// Hash table unallocated so far?
|
||||
if (NumBuckets == 0)
|
||||
init(16);
|
||||
@@ -121,7 +121,7 @@ unsigned StringMapImpl::LookupBucketFor(StringRef Name) {
|
||||
// Do the comparison like this because Name isn't necessarily
|
||||
// null-terminated!
|
||||
char *ItemStr = (char *)BucketItem + ItemSize;
|
||||
- if (Name == StringRef(ItemStr, BucketItem->getKeyLength())) {
|
||||
+ if (Name == std::string_view(ItemStr, BucketItem->getKeyLength())) {
|
||||
// We found a match!
|
||||
return BucketNo;
|
||||
}
|
||||
@@ -139,7 +139,7 @@ unsigned StringMapImpl::LookupBucketFor(StringRef Name) {
|
||||
/// FindKey - Look up the bucket that contains the specified key. If it exists
|
||||
/// in the map, return the bucket number of the key. Otherwise return -1.
|
||||
/// This does not modify the map.
|
||||
-int StringMapImpl::FindKey(StringRef Key) const {
|
||||
+int StringMapImpl::FindKey(std::string_view Key) const {
|
||||
if (NumBuckets == 0)
|
||||
return -1; // Really empty table?
|
||||
unsigned FullHashValue = xxh3_64bits(Key);
|
||||
@@ -166,7 +166,7 @@ int StringMapImpl::FindKey(StringRef Key) const {
|
||||
// Do the comparison like this because NameStart isn't necessarily
|
||||
// null-terminated!
|
||||
char *ItemStr = (char *)BucketItem + ItemSize;
|
||||
- if (Key == StringRef(ItemStr, BucketItem->getKeyLength())) {
|
||||
+ if (Key == std::string_view(ItemStr, BucketItem->getKeyLength())) {
|
||||
// We found a match!
|
||||
return BucketNo;
|
||||
}
|
||||
@@ -185,14 +185,14 @@ int StringMapImpl::FindKey(StringRef Key) const {
|
||||
/// delete it. This aborts if the value isn't in the table.
|
||||
void StringMapImpl::RemoveKey(StringMapEntryBase *V) {
|
||||
const char *VStr = (char *)V + ItemSize;
|
||||
- StringMapEntryBase *V2 = RemoveKey(StringRef(VStr, V->getKeyLength()));
|
||||
+ StringMapEntryBase *V2 = RemoveKey(std::string_view(VStr, V->getKeyLength()));
|
||||
(void)V2;
|
||||
assert(V == V2 && "Didn't find key?");
|
||||
}
|
||||
|
||||
/// RemoveKey - Remove the StringMapEntry for the specified key from the
|
||||
/// table, returning it. If the key is not in the table, this returns null.
|
||||
-StringMapEntryBase *StringMapImpl::RemoveKey(StringRef Key) {
|
||||
+StringMapEntryBase *StringMapImpl::RemoveKey(std::string_view Key) {
|
||||
int Bucket = FindKey(Key);
|
||||
if (Bucket == -1)
|
||||
return nullptr;
|
||||
diff --git a/llvm/lib/Support/raw_ostream.cpp b/llvm/lib/Support/raw_ostream.cpp
|
||||
index 3d3a564af51d120786b358b96a3c90e2b7fbf9f3..220d850b9bc69f8fc2fba7cd23629eca487cde23 100644
|
||||
--- a/llvm/lib/Support/raw_ostream.cpp
|
||||
@@ -1746,132 +1461,6 @@ index 137dd43b473068eae34b39edc4b9b8b9633bab95..7029038d18d433cef987bedbfa4fda26
|
||||
{
|
||||
llvm::SmallVector<To> Vector(Array);
|
||||
|
||||
diff --git a/llvm/unittests/ADT/StringMapTest.cpp b/llvm/unittests/ADT/StringMapTest.cpp
|
||||
index f9b138e9a472137139397d9cae76823711594211..7f10b3d7d3a8894b1ab0ac660268d94a8b89e082 100644
|
||||
--- a/llvm/unittests/ADT/StringMapTest.cpp
|
||||
+++ b/llvm/unittests/ADT/StringMapTest.cpp
|
||||
@@ -7,8 +7,6 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
-#include "llvm/ADT/STLExtras.h"
|
||||
-#include "llvm/ADT/Twine.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include <limits>
|
||||
@@ -43,10 +41,10 @@ protected:
|
||||
// Lookup tests
|
||||
EXPECT_FALSE(testMap.contains(testKey));
|
||||
EXPECT_EQ(0u, testMap.count(testKey));
|
||||
- EXPECT_EQ(0u, testMap.count(StringRef(testKeyFirst, testKeyLength)));
|
||||
+ EXPECT_EQ(0u, testMap.count(std::string_view(testKeyFirst, testKeyLength)));
|
||||
EXPECT_EQ(0u, testMap.count(testKeyStr));
|
||||
EXPECT_TRUE(testMap.find(testKey) == testMap.end());
|
||||
- EXPECT_TRUE(testMap.find(StringRef(testKeyFirst, testKeyLength)) ==
|
||||
+ EXPECT_TRUE(testMap.find(std::string_view(testKeyFirst, testKeyLength)) ==
|
||||
testMap.end());
|
||||
EXPECT_TRUE(testMap.find(testKeyStr) == testMap.end());
|
||||
}
|
||||
@@ -67,10 +65,10 @@ protected:
|
||||
// Lookup tests
|
||||
EXPECT_TRUE(testMap.contains(testKey));
|
||||
EXPECT_EQ(1u, testMap.count(testKey));
|
||||
- EXPECT_EQ(1u, testMap.count(StringRef(testKeyFirst, testKeyLength)));
|
||||
+ EXPECT_EQ(1u, testMap.count(std::string_view(testKeyFirst, testKeyLength)));
|
||||
EXPECT_EQ(1u, testMap.count(testKeyStr));
|
||||
EXPECT_TRUE(testMap.find(testKey) == testMap.begin());
|
||||
- EXPECT_TRUE(testMap.find(StringRef(testKeyFirst, testKeyLength)) ==
|
||||
+ EXPECT_TRUE(testMap.find(std::string_view(testKeyFirst, testKeyLength)) ==
|
||||
testMap.begin());
|
||||
EXPECT_TRUE(testMap.find(testKeyStr) == testMap.begin());
|
||||
}
|
||||
@@ -108,10 +106,10 @@ TEST_F(StringMapTest, ConstEmptyMapTest) {
|
||||
|
||||
// Lookup tests
|
||||
EXPECT_EQ(0u, constTestMap.count(testKey));
|
||||
- EXPECT_EQ(0u, constTestMap.count(StringRef(testKeyFirst, testKeyLength)));
|
||||
+ EXPECT_EQ(0u, constTestMap.count(std::string_view(testKeyFirst, testKeyLength)));
|
||||
EXPECT_EQ(0u, constTestMap.count(testKeyStr));
|
||||
EXPECT_TRUE(constTestMap.find(testKey) == constTestMap.end());
|
||||
- EXPECT_TRUE(constTestMap.find(StringRef(testKeyFirst, testKeyLength)) ==
|
||||
+ EXPECT_TRUE(constTestMap.find(std::string_view(testKeyFirst, testKeyLength)) ==
|
||||
constTestMap.end());
|
||||
EXPECT_TRUE(constTestMap.find(testKeyStr) == constTestMap.end());
|
||||
}
|
||||
@@ -251,7 +249,7 @@ TEST_F(StringMapTest, StringMapEntryTest) {
|
||||
MallocAllocator Allocator;
|
||||
StringMap<uint32_t>::value_type *entry =
|
||||
StringMap<uint32_t>::value_type::create(
|
||||
- StringRef(testKeyFirst, testKeyLength), Allocator, 1u);
|
||||
+ std::string_view(testKeyFirst, testKeyLength), Allocator, 1u);
|
||||
EXPECT_STREQ(testKey, entry->first().data());
|
||||
EXPECT_EQ(1u, entry->second);
|
||||
entry->Destroy(Allocator);
|
||||
@@ -261,7 +259,7 @@ TEST_F(StringMapTest, StringMapEntryTest) {
|
||||
TEST_F(StringMapTest, InsertTest) {
|
||||
SCOPED_TRACE("InsertTest");
|
||||
testMap.insert(StringMap<uint32_t>::value_type::create(
|
||||
- StringRef(testKeyFirst, testKeyLength), testMap.getAllocator(), 1u));
|
||||
+ std::string_view(testKeyFirst, testKeyLength), testMap.getAllocator(), 1u));
|
||||
assertSingleItemMap();
|
||||
}
|
||||
|
||||
@@ -330,10 +328,10 @@ TEST_F(StringMapTest, IterMapKeysVector) {
|
||||
Map["C"] = 3;
|
||||
Map["D"] = 3;
|
||||
|
||||
- std::vector<StringRef> Keys{Map.keys().begin(), Map.keys().end()};
|
||||
+ std::vector<std::string_view> Keys{Map.keys().begin(), Map.keys().end()};
|
||||
llvm::sort(Keys);
|
||||
|
||||
- std::vector<StringRef> Expected{{"A", "B", "C", "D"}};
|
||||
+ std::vector<std::string_view> Expected{{"A", "B", "C", "D"}};
|
||||
EXPECT_EQ(Expected, Keys);
|
||||
}
|
||||
|
||||
@@ -347,7 +345,7 @@ TEST_F(StringMapTest, IterMapKeysSmallVector) {
|
||||
auto Keys = to_vector<4>(Map.keys());
|
||||
llvm::sort(Keys);
|
||||
|
||||
- SmallVector<StringRef, 4> Expected = {"A", "B", "C", "D"};
|
||||
+ SmallVector<std::string_view, 4> Expected = {"A", "B", "C", "D"};
|
||||
EXPECT_EQ(Expected, Keys);
|
||||
}
|
||||
|
||||
@@ -389,13 +387,13 @@ private:
|
||||
TEST_F(StringMapTest, MoveOnly) {
|
||||
StringMap<MoveOnly> t;
|
||||
t.insert(std::make_pair("Test", MoveOnly(42)));
|
||||
- StringRef Key = "Test";
|
||||
+ std::string_view Key = "Test";
|
||||
StringMapEntry<MoveOnly>::create(Key, t.getAllocator(), MoveOnly(42))
|
||||
->Destroy(t.getAllocator());
|
||||
}
|
||||
|
||||
TEST_F(StringMapTest, CtorArg) {
|
||||
- StringRef Key = "Test";
|
||||
+ std::string_view Key = "Test";
|
||||
MallocAllocator Allocator;
|
||||
StringMapEntry<MoveOnly>::create(Key, Allocator, Immovable())
|
||||
->Destroy(Allocator);
|
||||
@@ -580,7 +578,7 @@ TEST(StringMapCustomTest, InitialSizeTest) {
|
||||
CountCtorCopyAndMove::Copy = 0;
|
||||
for (int i = 0; i < Size; ++i)
|
||||
Map.insert(std::pair<std::string, CountCtorCopyAndMove>(
|
||||
- std::piecewise_construct, std::forward_as_tuple(Twine(i).str()),
|
||||
+ std::piecewise_construct, std::forward_as_tuple(std::to_string(i)),
|
||||
std::forward_as_tuple(i)));
|
||||
// After the initial move, the map will move the Elts in the Entry.
|
||||
EXPECT_EQ((unsigned)Size * 2, CountCtorCopyAndMove::Move);
|
||||
@@ -649,7 +647,7 @@ TEST(StringMapCustomTest, StringMapEntrySize) {
|
||||
else
|
||||
LargeValue = std::numeric_limits<unsigned>::max() + 1ULL;
|
||||
StringMapEntry<int> LargeEntry(LargeValue);
|
||||
- StringRef Key = LargeEntry.getKey();
|
||||
+ std::string_view Key = LargeEntry.getKey();
|
||||
EXPECT_EQ(LargeValue, Key.size());
|
||||
|
||||
// Test that the entry can hold at least max size_t.
|
||||
diff --git a/llvm/unittests/Support/ConvertUTFTest.cpp b/llvm/unittests/Support/ConvertUTFTest.cpp
|
||||
index 6e75fbae0969ba1bf0a76c4d79a123e405a8dae7..3b07d344f15a555f11ad5f8177a0a65b8a4fa472 100644
|
||||
--- a/llvm/unittests/Support/ConvertUTFTest.cpp
|
||||
|
||||
@@ -8,7 +8,6 @@ Subject: [PATCH 06/38] Explicitly use std::
|
||||
llvm/lib/Support/ErrorHandling.cpp | 2 +-
|
||||
llvm/unittests/ADT/SmallPtrSetTest.cpp | 2 +-
|
||||
llvm/unittests/ADT/SmallSetTest.cpp | 10 +++++-----
|
||||
llvm/unittests/ADT/StringMapTest.cpp | 2 +-
|
||||
5 files changed, 9 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/llvm/include/llvm/ADT/SmallSet.h b/llvm/include/llvm/ADT/SmallSet.h
|
||||
@@ -100,16 +99,3 @@ index b50b368ae663614f050c220432c05b32c201db00..f9d84fa8a42a7feaaffa3aa080e84574
|
||||
EXPECT_EQ(4u, s1.size());
|
||||
EXPECT_EQ("str 0", V[0]);
|
||||
EXPECT_EQ("str 1", V[1]);
|
||||
diff --git a/llvm/unittests/ADT/StringMapTest.cpp b/llvm/unittests/ADT/StringMapTest.cpp
|
||||
index 7f10b3d7d3a8894b1ab0ac660268d94a8b89e082..acd8b566f9c7a6efc2c9204624c01104dd34daf6 100644
|
||||
--- a/llvm/unittests/ADT/StringMapTest.cpp
|
||||
+++ b/llvm/unittests/ADT/StringMapTest.cpp
|
||||
@@ -343,7 +343,7 @@ TEST_F(StringMapTest, IterMapKeysSmallVector) {
|
||||
Map["D"] = 3;
|
||||
|
||||
auto Keys = to_vector<4>(Map.keys());
|
||||
- llvm::sort(Keys);
|
||||
+ std::sort(Keys.begin(), Keys.end());
|
||||
|
||||
SmallVector<std::string_view, 4> Expected = {"A", "B", "C", "D"};
|
||||
EXPECT_EQ(Expected, Keys);
|
||||
|
||||
@@ -4,143 +4,9 @@ Date: Tue, 3 May 2022 22:16:10 -0400
|
||||
Subject: [PATCH 12/38] Extra collections features
|
||||
|
||||
---
|
||||
llvm/include/llvm/ADT/StringMap.h | 103 +++++++++++++++++++++++++++++-
|
||||
llvm/lib/Support/raw_ostream.cpp | 8 +++
|
||||
2 files changed, 110 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/llvm/include/llvm/ADT/StringMap.h b/llvm/include/llvm/ADT/StringMap.h
|
||||
index 34dfbf83c681f4e81a9dadd9382ddca6ef8d6c1d..c133e84f9b2e3a225cdac782c011fadbf07adab2 100644
|
||||
--- a/llvm/include/llvm/ADT/StringMap.h
|
||||
+++ b/llvm/include/llvm/ADT/StringMap.h
|
||||
@@ -42,7 +42,7 @@ protected:
|
||||
|
||||
protected:
|
||||
explicit StringMapImpl(unsigned itemSize) : ItemSize(itemSize) {}
|
||||
- StringMapImpl(StringMapImpl &&RHS)
|
||||
+ StringMapImpl(StringMapImpl &&RHS) noexcept
|
||||
: TheTable(RHS.TheTable), NumBuckets(RHS.NumBuckets),
|
||||
NumItems(RHS.NumItems), NumTombstones(RHS.NumTombstones),
|
||||
ItemSize(RHS.ItemSize) {
|
||||
@@ -432,11 +432,27 @@ public:
|
||||
return Tmp;
|
||||
}
|
||||
|
||||
+ DerivedTy &operator--() { // Predecrement
|
||||
+ --Ptr;
|
||||
+ ReversePastEmptyBuckets();
|
||||
+ return static_cast<DerivedTy &>(*this);
|
||||
+ }
|
||||
+
|
||||
+ DerivedTy operator--(int) { // Post-decrement
|
||||
+ DerivedTy Tmp(Ptr);
|
||||
+ --*this;
|
||||
+ return Tmp;
|
||||
+ }
|
||||
+
|
||||
private:
|
||||
void AdvancePastEmptyBuckets() {
|
||||
while (*Ptr == nullptr || *Ptr == StringMapImpl::getTombstoneVal())
|
||||
++Ptr;
|
||||
}
|
||||
+ void ReversePastEmptyBuckets() {
|
||||
+ while (*Ptr == nullptr || *Ptr == StringMapImpl::getTombstoneVal())
|
||||
+ --Ptr;
|
||||
+ }
|
||||
};
|
||||
|
||||
template <typename ValueTy>
|
||||
@@ -495,6 +511,91 @@ public:
|
||||
std::string_view operator*() const { return this->wrapped()->getKey(); }
|
||||
};
|
||||
|
||||
+template <typename ValueTy>
|
||||
+bool operator==(const StringMap<ValueTy>& lhs, const StringMap<ValueTy>& rhs) {
|
||||
+ // same instance?
|
||||
+ if (&lhs == &rhs) return true;
|
||||
+
|
||||
+ // first check that sizes are identical
|
||||
+ if (lhs.size() != rhs.size()) return false;
|
||||
+
|
||||
+ // copy into vectors and sort by key
|
||||
+ SmallVector<StringMapConstIterator<ValueTy>, 16> lhs_items;
|
||||
+ lhs_items.reserve(lhs.size());
|
||||
+ for (auto i = lhs.begin(), end = lhs.end(); i != end; ++i)
|
||||
+ lhs_items.push_back(i);
|
||||
+ std::sort(lhs_items.begin(), lhs_items.end(),
|
||||
+ [](const StringMapConstIterator<ValueTy>& a,
|
||||
+ const StringMapConstIterator<ValueTy>& b) {
|
||||
+ return a->getKey() < b->getKey();
|
||||
+ });
|
||||
+
|
||||
+ SmallVector<StringMapConstIterator<ValueTy>, 16> rhs_items;
|
||||
+ rhs_items.reserve(rhs.size());
|
||||
+ for (auto i = rhs.begin(), end = rhs.end(); i != end; ++i)
|
||||
+ rhs_items.push_back(i);
|
||||
+ std::sort(rhs_items.begin(), rhs_items.end(),
|
||||
+ [](const StringMapConstIterator<ValueTy>& a,
|
||||
+ const StringMapConstIterator<ValueTy>& b) {
|
||||
+ return a->getKey() < b->getKey();
|
||||
+ });
|
||||
+
|
||||
+ // compare vector keys and values
|
||||
+ for (auto a = lhs_items.begin(), b = rhs_items.begin(),
|
||||
+ aend = lhs_items.end(), bend = rhs_items.end();
|
||||
+ a != aend && b != bend; ++a, ++b) {
|
||||
+ if ((*a)->first() != (*b)->first() || (*a)->second != (*b)->second)
|
||||
+ return false;
|
||||
+ }
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
+template <typename ValueTy>
|
||||
+inline bool operator!=(const StringMap<ValueTy>& lhs,
|
||||
+ const StringMap<ValueTy>& rhs) {
|
||||
+ return !(lhs == rhs);
|
||||
+}
|
||||
+
|
||||
+template <typename ValueTy>
|
||||
+bool operator<(const StringMap<ValueTy>& lhs, const StringMap<ValueTy>& rhs) {
|
||||
+ // same instance?
|
||||
+ if (&lhs == &rhs) return false;
|
||||
+
|
||||
+ // copy into vectors and sort by key
|
||||
+ SmallVector<std::string_view, 16> lhs_keys;
|
||||
+ lhs_keys.reserve(lhs.size());
|
||||
+ for (auto i = lhs.begin(), end = lhs.end(); i != end; ++i)
|
||||
+ lhs_keys.push_back(i->getKey());
|
||||
+ std::sort(lhs_keys.begin(), lhs_keys.end());
|
||||
+
|
||||
+ SmallVector<std::string_view, 16> rhs_keys;
|
||||
+ rhs_keys.reserve(rhs.size());
|
||||
+ for (auto i = rhs.begin(), end = rhs.end(); i != end; ++i)
|
||||
+ rhs_keys.push_back(i->getKey());
|
||||
+ std::sort(rhs_keys.begin(), rhs_keys.end());
|
||||
+
|
||||
+ // use std::vector comparison
|
||||
+ return lhs_keys < rhs_keys;
|
||||
+}
|
||||
+
|
||||
+template <typename ValueTy>
|
||||
+inline bool operator<=(const StringMap<ValueTy>& lhs,
|
||||
+ const StringMap<ValueTy>& rhs) {
|
||||
+ return !(rhs < lhs);
|
||||
+}
|
||||
+
|
||||
+template <typename ValueTy>
|
||||
+inline bool operator>(const StringMap<ValueTy>& lhs,
|
||||
+ const StringMap<ValueTy>& rhs) {
|
||||
+ return !(lhs <= rhs);
|
||||
+}
|
||||
+
|
||||
+template <typename ValueTy>
|
||||
+inline bool operator>=(const StringMap<ValueTy>& lhs,
|
||||
+ const StringMap<ValueTy>& rhs) {
|
||||
+ return !(lhs < rhs);
|
||||
+}
|
||||
+
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_ADT_STRINGMAP_H
|
||||
diff --git a/llvm/lib/Support/raw_ostream.cpp b/llvm/lib/Support/raw_ostream.cpp
|
||||
index 57d3091fd5cc5b416e814f9f33811f0fa7afe9cf..5bec803ccc76ce287b7ff3ea037d5e490a7af20c 100644
|
||||
--- a/llvm/lib/Support/raw_ostream.cpp
|
||||
|
||||
@@ -4,48 +4,15 @@ Date: Sun, 8 May 2022 16:38:11 -0400
|
||||
Subject: [PATCH 16/38] Fixup includes
|
||||
|
||||
---
|
||||
llvm/include/llvm/ADT/StringMap.h | 4 ++++
|
||||
llvm/include/llvm/ADT/StringMapEntry.h | 4 ++++
|
||||
llvm/include/llvm/Support/PointerLikeTypeTraits.h | 1 +
|
||||
llvm/lib/Support/ConvertUTFWrapper.cpp | 1 +
|
||||
llvm/lib/Support/ErrorHandling.cpp | 7 +++----
|
||||
llvm/lib/Support/raw_ostream.cpp | 11 ++++++-----
|
||||
llvm/unittests/ADT/SmallPtrSetTest.cpp | 2 ++
|
||||
llvm/unittests/ADT/SmallVectorTest.cpp | 1 +
|
||||
llvm/unittests/ADT/StringMapTest.cpp | 1 +
|
||||
llvm/unittests/Support/ConvertUTFTest.cpp | 2 ++
|
||||
10 files changed, 25 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/llvm/include/llvm/ADT/StringMap.h b/llvm/include/llvm/ADT/StringMap.h
|
||||
index c133e84f9b2e3a225cdac782c011fadbf07adab2..2173a4159111e7fea70325de82dbfce628ae3ea8 100644
|
||||
--- a/llvm/include/llvm/ADT/StringMap.h
|
||||
+++ b/llvm/include/llvm/ADT/StringMap.h
|
||||
@@ -17,6 +17,10 @@
|
||||
#include "llvm/ADT/StringMapEntry.h"
|
||||
#include "llvm/ADT/iterator.h"
|
||||
#include "llvm/Support/AllocatorBase.h"
|
||||
+#include "llvm/Support/MemAlloc.h"
|
||||
+#include "llvm/Support/SmallVector.h"
|
||||
+#include "llvm/Support/iterator.h"
|
||||
+#include "llvm/Support/iterator_range.h"
|
||||
#include "llvm/Support/PointerLikeTypeTraits.h"
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
diff --git a/llvm/include/llvm/ADT/StringMapEntry.h b/llvm/include/llvm/ADT/StringMapEntry.h
|
||||
index 388e81c361642113937f7d5680de73a50635b07d..011806f5fd89ff738ed805a82b3ddbc6fc9b08ce 100644
|
||||
--- a/llvm/include/llvm/ADT/StringMapEntry.h
|
||||
+++ b/llvm/include/llvm/ADT/StringMapEntry.h
|
||||
@@ -16,6 +16,10 @@
|
||||
#ifndef LLVM_ADT_STRINGMAPENTRY_H
|
||||
#define LLVM_ADT_STRINGMAPENTRY_H
|
||||
|
||||
+#include "wpi/MemAlloc.h"
|
||||
+
|
||||
+#include <cassert>
|
||||
+#include <cstring>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
diff --git a/llvm/include/llvm/Support/PointerLikeTypeTraits.h b/llvm/include/llvm/Support/PointerLikeTypeTraits.h
|
||||
index 1b15f930bd87d97d51824af5e62ea5f222a6b4c9..acadd5e89a1651cfbad67a5b1b0933d1f288d094 100644
|
||||
--- a/llvm/include/llvm/Support/PointerLikeTypeTraits.h
|
||||
@@ -153,18 +120,6 @@ index f8c37820ef9fdfe0af067f5aa8d2297ed15e73bc..5e91f71bc9ac0e499a64dd1591e581d0
|
||||
#include <list>
|
||||
#include <span>
|
||||
#include <stdarg.h>
|
||||
diff --git a/llvm/unittests/ADT/StringMapTest.cpp b/llvm/unittests/ADT/StringMapTest.cpp
|
||||
index acd8b566f9c7a6efc2c9204624c01104dd34daf6..6b6cf564909f329c220eb225f3b7af6c35301029 100644
|
||||
--- a/llvm/unittests/ADT/StringMapTest.cpp
|
||||
+++ b/llvm/unittests/ADT/StringMapTest.cpp
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "gtest/gtest.h"
|
||||
+#include <algorithm>
|
||||
#include <limits>
|
||||
#include <tuple>
|
||||
using namespace llvm;
|
||||
diff --git a/llvm/unittests/Support/ConvertUTFTest.cpp b/llvm/unittests/Support/ConvertUTFTest.cpp
|
||||
index 3b07d344f15a555f11ad5f8177a0a65b8a4fa472..77e70a46d3621ecfaed923d87256184addfda721 100644
|
||||
--- a/llvm/unittests/Support/ConvertUTFTest.cpp
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tyler Veness <calcmogul@gmail.com>
|
||||
Date: Wed, 10 Aug 2022 22:35:00 -0700
|
||||
Subject: [PATCH 27/38] Remove StringMap test for llvm::sort()
|
||||
|
||||
---
|
||||
llvm/unittests/ADT/StringMapTest.cpp | 14 --------------
|
||||
1 file changed, 14 deletions(-)
|
||||
|
||||
diff --git a/llvm/unittests/ADT/StringMapTest.cpp b/llvm/unittests/ADT/StringMapTest.cpp
|
||||
index 6b6cf564909f329c220eb225f3b7af6c35301029..0d83669a580408e925ec6308410ebe7c01b48b12 100644
|
||||
--- a/llvm/unittests/ADT/StringMapTest.cpp
|
||||
+++ b/llvm/unittests/ADT/StringMapTest.cpp
|
||||
@@ -322,20 +322,6 @@ TEST_F(StringMapTest, InsertOrAssignTest) {
|
||||
EXPECT_EQ(0, try1.first->second.copy);
|
||||
}
|
||||
|
||||
-TEST_F(StringMapTest, IterMapKeysVector) {
|
||||
- StringMap<int> Map;
|
||||
- Map["A"] = 1;
|
||||
- Map["B"] = 2;
|
||||
- Map["C"] = 3;
|
||||
- Map["D"] = 3;
|
||||
-
|
||||
- std::vector<std::string_view> Keys{Map.keys().begin(), Map.keys().end()};
|
||||
- llvm::sort(Keys);
|
||||
-
|
||||
- std::vector<std::string_view> Expected{{"A", "B", "C", "D"}};
|
||||
- EXPECT_EQ(Expected, Keys);
|
||||
-}
|
||||
-
|
||||
TEST_F(StringMapTest, IterMapKeysSmallVector) {
|
||||
StringMap<int> Map;
|
||||
Map["A"] = 1;
|
||||
@@ -1,54 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Ryan Blue <ryanzblue@gmail.com>
|
||||
Date: Tue, 24 Sep 2024 23:36:16 -0400
|
||||
Subject: [PATCH 38/38] StringMap: fix structured bindings with move-only types
|
||||
|
||||
---
|
||||
llvm/include/llvm/ADT/StringMapEntry.h | 12 +++++++++++-
|
||||
llvm/unittests/ADT/StringMapTest.cpp | 10 ++++++++++
|
||||
2 files changed, 21 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/llvm/include/llvm/ADT/StringMapEntry.h b/llvm/include/llvm/ADT/StringMapEntry.h
|
||||
index 011806f5fd89ff738ed805a82b3ddbc6fc9b08ce..5b8eeb167c53c7ab15d05b0c71b75cd7f5b496c5 100644
|
||||
--- a/llvm/include/llvm/ADT/StringMapEntry.h
|
||||
+++ b/llvm/include/llvm/ADT/StringMapEntry.h
|
||||
@@ -159,7 +159,17 @@ decltype(auto) get(const StringMapEntry<ValueTy> &E) {
|
||||
if constexpr (Index == 0)
|
||||
return E.first();
|
||||
else
|
||||
- return E.second;
|
||||
+ return (E.second);
|
||||
+}
|
||||
+
|
||||
+// Allow structured bindings on StringMapEntry.
|
||||
+template <std::size_t Index, typename ValueTy>
|
||||
+decltype(auto) get(StringMapEntry<ValueTy> &E) {
|
||||
+ static_assert(Index < 2);
|
||||
+ if constexpr (Index == 0)
|
||||
+ return E.first();
|
||||
+ else
|
||||
+ return (E.second);
|
||||
}
|
||||
|
||||
} // end namespace llvm
|
||||
diff --git a/llvm/unittests/ADT/StringMapTest.cpp b/llvm/unittests/ADT/StringMapTest.cpp
|
||||
index 0d83669a580408e925ec6308410ebe7c01b48b12..f1834bec65afec6be4365e52c4e21aa61cbb1d12 100644
|
||||
--- a/llvm/unittests/ADT/StringMapTest.cpp
|
||||
+++ b/llvm/unittests/ADT/StringMapTest.cpp
|
||||
@@ -526,6 +526,16 @@ TEST_F(StringMapTest, StructuredBindings) {
|
||||
}
|
||||
}
|
||||
|
||||
+TEST_F(StringMapTest, StructuredBindingsMoveOnly) {
|
||||
+ StringMap<MoveOnly> A;
|
||||
+ A.insert(std::make_pair("a", MoveOnly(42)));
|
||||
+
|
||||
+ for (auto &&[Key, Value] : A) {
|
||||
+ EXPECT_EQ("a", Key);
|
||||
+ EXPECT_EQ(42, Value.i);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
namespace {
|
||||
// Simple class that counts how many moves and copy happens when growing a map
|
||||
struct CountCtorCopyAndMove {
|
||||
@@ -49,8 +49,8 @@ void Tracer::PrintEpochs(wpi::raw_ostream& os) {
|
||||
m_lastEpochsPrintTime = now;
|
||||
for (const auto& epoch : m_epochs) {
|
||||
os << fmt::format(
|
||||
"\t{}: {:.6f}s\n", epoch.getKey(),
|
||||
duration_cast<microseconds>(epoch.getValue()).count() / 1.0e6);
|
||||
"\t{}: {:.6f}s\n", epoch.first,
|
||||
duration_cast<microseconds>(epoch.second).count() / 1.0e6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ void ShuffleboardComponentBase::BuildMetadata(
|
||||
if (GetProperties().size() > 0) {
|
||||
auto propTable = metaTable->GetSubTable("Properties");
|
||||
for (auto& entry : GetProperties()) {
|
||||
propTable->GetEntry(entry.first()).SetValue(entry.second);
|
||||
propTable->GetEntry(entry.first).SetValue(entry.second);
|
||||
}
|
||||
}
|
||||
m_metadataDirty = false;
|
||||
|
||||
@@ -51,7 +51,7 @@ void Mechanism2d::InitSendable(nt::NTSendableBuilder& builder) {
|
||||
m_colorPub = m_table->GetStringTopic(kBackgroundColor).Publish();
|
||||
m_colorPub.Set(m_color);
|
||||
for (const auto& entry : m_roots) {
|
||||
const auto& root = entry.getValue().get();
|
||||
root->Update(m_table->GetSubTable(entry.getKey()));
|
||||
const auto& root = entry.second.get();
|
||||
root->Update(m_table->GetSubTable(entry.first));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,7 @@ void MechanismObject2d::Update(std::shared_ptr<nt::NetworkTable> table) {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
m_table = table;
|
||||
UpdateEntries(m_table);
|
||||
for (const wpi::StringMapEntry<std::unique_ptr<MechanismObject2d>>& entry :
|
||||
m_objects) {
|
||||
entry.getValue()->Update(m_table->GetSubTable(entry.getKey()));
|
||||
for (const auto& entry : m_objects) {
|
||||
entry.second->Update(m_table->GetSubTable(entry.first));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ wpi::Sendable* SmartDashboard::GetData(std::string_view key) {
|
||||
if (it == inst.tablesToData.end()) {
|
||||
throw FRC_MakeError(err::SmartDashboardMissingKey, "{}", key);
|
||||
}
|
||||
return wpi::SendableRegistry::GetSendable(it->getValue());
|
||||
return wpi::SendableRegistry::GetSendable(it->second);
|
||||
}
|
||||
|
||||
bool SmartDashboard::PutBoolean(std::string_view keyName, bool value) {
|
||||
@@ -254,6 +254,6 @@ void SmartDashboard::UpdateValues() {
|
||||
inst.listenerExecutor.RunListenerTasks();
|
||||
std::scoped_lock lock(inst.tablesToDataMutex);
|
||||
for (auto& i : inst.tablesToData) {
|
||||
wpi::SendableRegistry::Update(i.getValue());
|
||||
wpi::SendableRegistry::Update(i.second);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ class SendableChooser : public SendableChooserBase {
|
||||
}
|
||||
|
||||
public:
|
||||
using CopyType = decltype(_unwrap_smart_ptr(m_choices.lookup("")));
|
||||
using CopyType = decltype(_unwrap_smart_ptr(m_choices.find("")->second));
|
||||
|
||||
SendableChooser() = default;
|
||||
~SendableChooser() override = default;
|
||||
@@ -105,7 +105,11 @@ class SendableChooser : public SendableChooserBase {
|
||||
if (selected.empty()) {
|
||||
return CopyType{};
|
||||
} else {
|
||||
return _unwrap_smart_ptr(m_choices.lookup(selected));
|
||||
auto it = m_choices.find(selected);
|
||||
if (it == m_choices.end()) {
|
||||
return CopyType{};
|
||||
}
|
||||
return _unwrap_smart_ptr(it->second);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,13 +132,8 @@ class SendableChooser : public SendableChooserBase {
|
||||
[=, this] {
|
||||
std::vector<std::string> keys;
|
||||
for (const auto& choice : m_choices) {
|
||||
keys.emplace_back(choice.first());
|
||||
keys.emplace_back(choice.first);
|
||||
}
|
||||
|
||||
// Unlike std::map, wpi::StringMap elements
|
||||
// are not sorted
|
||||
std::sort(keys.begin(), keys.end());
|
||||
|
||||
return keys;
|
||||
},
|
||||
nullptr);
|
||||
|
||||
@@ -60,7 +60,7 @@ std::string_view MimeTypeFromPath(std::string_view path) {
|
||||
if (dot_pos > 0 && dot_pos != std::string_view::npos) {
|
||||
auto type = mimeTypes.find(wpi::substr(path, dot_pos + 1));
|
||||
if (type != mimeTypes.end()) {
|
||||
return type->getValue();
|
||||
return type->second;
|
||||
}
|
||||
}
|
||||
return defaultType;
|
||||
|
||||
@@ -375,8 +375,8 @@ class HttpRequest {
|
||||
return elem.first;
|
||||
}
|
||||
template <typename T>
|
||||
static std::string_view GetFirst(const StringMapEntry<T>& elem) {
|
||||
return elem.getKey();
|
||||
static std::string_view GetFirst(const std::pair<std::string, T>& elem) {
|
||||
return elem.first;
|
||||
}
|
||||
template <typename T>
|
||||
static std::string_view GetSecond(const T& elem) {
|
||||
|
||||
@@ -83,7 +83,7 @@ void DataLog::StartFile() {
|
||||
|
||||
// Existing start and schema data records
|
||||
for (auto&& entryInfo : m_entries) {
|
||||
AppendStartRecord(entryInfo.second.id, entryInfo.first(),
|
||||
AppendStartRecord(entryInfo.second.id, entryInfo.first,
|
||||
entryInfo.second.type,
|
||||
m_entryIds[entryInfo.second.id].metadata, 0);
|
||||
if (!entryInfo.second.schemaData.empty()) {
|
||||
|
||||
777
wpiutil/src/main/native/include/wpi/StringMap.h
Normal file
777
wpiutil/src/main/native/include/wpi/StringMap.h
Normal file
@@ -0,0 +1,777 @@
|
||||
// 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 <functional>
|
||||
#include <initializer_list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/**
|
||||
* StringMap is a sorted associative container that contains key-value pairs
|
||||
* with unique string keys. Keys are sorted in the same order as std::string's
|
||||
* are compared. Search, removal, and insertion operations have logarithmic
|
||||
* complexity. The underlying implementation is std::map<std::string, T>.
|
||||
*/
|
||||
template <typename T,
|
||||
typename Allocator = std::allocator<std::pair<const std::string, T>>>
|
||||
class StringMap : public std::map<std::string, T, std::less<>, Allocator> {
|
||||
public:
|
||||
using map_type = typename std::map<std::string, T, std::less<>>;
|
||||
using key_type = typename map_type::key_type;
|
||||
using mapped_type = typename map_type::mapped_type;
|
||||
using value_type = typename map_type::value_type;
|
||||
using size_type = typename map_type::size_type;
|
||||
using difference_type = typename map_type::difference_type;
|
||||
using key_compare = typename map_type::key_compare;
|
||||
using allocator_type = typename map_type::allocator_type;
|
||||
using reference = typename map_type::reference;
|
||||
using const_reference = typename map_type::const_reference;
|
||||
using pointer = typename map_type::pointer;
|
||||
using const_pointer = typename map_type::const_pointer;
|
||||
using iterator = typename map_type::iterator;
|
||||
using const_iterator = typename map_type::const_iterator;
|
||||
using reverse_iterator = typename map_type::reverse_iterator;
|
||||
using const_reverse_iterator = typename map_type::const_reverse_iterator;
|
||||
using node_type = typename map_type::node_type;
|
||||
using insert_return_type = typename map_type::insert_return_type;
|
||||
|
||||
/** Constructs an empty container. */
|
||||
StringMap() = default;
|
||||
|
||||
/**
|
||||
* Constructs an empty container.
|
||||
*
|
||||
* @param alloc allocator to use for all memory allocations of this container
|
||||
*/
|
||||
explicit StringMap(const Allocator& alloc) : map_type{alloc} {}
|
||||
|
||||
/**
|
||||
* Constructs the container with the contents of the range [first, last). If
|
||||
* multiple elements in the range have keys that compare equivalent, it is
|
||||
* unspecified which element is inserted. If [first, last) is not a valid
|
||||
* range, the behavior is undefined.
|
||||
*
|
||||
* @param first start of the range to copy the elements from
|
||||
* @param last end of the range to copy the elements from
|
||||
* @param alloc allocator to use for all memory allocations of this container
|
||||
*/
|
||||
template <typename InputIt>
|
||||
StringMap(InputIt first, InputIt last, const Allocator& alloc = Allocator())
|
||||
: map_type{first, last, alloc} {}
|
||||
|
||||
/** Copy constructor. */
|
||||
StringMap(const StringMap&) = default;
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
*
|
||||
* @param other another container to be used as source to initialize the
|
||||
* elements of the container with
|
||||
* @param alloc allocator to use for all memory allocations of this container
|
||||
*/
|
||||
StringMap(const StringMap& other, const Allocator& alloc)
|
||||
: map_type{other, alloc} {}
|
||||
|
||||
/** Move constructor. */
|
||||
StringMap(StringMap&&) = default;
|
||||
|
||||
/**
|
||||
* Move constructor.
|
||||
*
|
||||
* @param other another container to be used as source to initialize the
|
||||
* elements of the container with
|
||||
* @param alloc allocator to use for all memory allocations of this container
|
||||
*/
|
||||
StringMap(StringMap&& other, const Allocator& alloc)
|
||||
: map_type{other, alloc} {}
|
||||
|
||||
/**
|
||||
* Initializer-list constructor. Construct the container with the contents of
|
||||
* the initializer list init. If multiple elements in the range have keys
|
||||
* that compare equal, it is unspecified which element is inserted.
|
||||
*
|
||||
* @param init initializer list to initialize the elements of the container
|
||||
* with
|
||||
* @param alloc allocator to use for all memory allocations of this container
|
||||
*/
|
||||
StringMap(std::initializer_list<value_type> init,
|
||||
const Allocator& alloc = Allocator())
|
||||
: map_type{init, alloc} {}
|
||||
|
||||
/** Copy assignment operator. */
|
||||
StringMap& operator=(const StringMap&) = default;
|
||||
|
||||
/** Move assignment operator. */
|
||||
StringMap& operator=(StringMap&&) noexcept(
|
||||
std::allocator_traits<Allocator>::is_always_equal::value &&
|
||||
std::is_nothrow_move_assignable<std::less<>>::value) = default;
|
||||
|
||||
/**
|
||||
* Replaces the contents with those identified by initializer list ilist.
|
||||
*
|
||||
* @param ilist initializer list to use as data source
|
||||
*/
|
||||
StringMap& operator=(std::initializer_list<value_type> ilist) {
|
||||
map_type::operator=(ilist);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the mapped value of the element with the specified
|
||||
* key. If no such element exists, an exception of type std::out_of_range is
|
||||
* thrown.
|
||||
*
|
||||
* @param key the key of the element to find
|
||||
* @return A reference to the mapped value of the requested element.
|
||||
*/
|
||||
T& at(const std::string& key) { return map_type::at(key); }
|
||||
|
||||
/**
|
||||
* Returns a reference to the mapped value of the element with the specified
|
||||
* key. If no such element exists, an exception of type std::out_of_range is
|
||||
* thrown.
|
||||
*
|
||||
* @param key the key of the element to find
|
||||
* @return A reference to the mapped value of the requested element.
|
||||
*/
|
||||
const T& at(const std::string& key) const { return map_type::at(key); }
|
||||
|
||||
/**
|
||||
* Returns a reference to the mapped value of the element with the specified
|
||||
* key. If no such element exists, an exception of type std::out_of_range is
|
||||
* thrown.
|
||||
*
|
||||
* @param key the key of the element to find
|
||||
* @return A reference to the mapped value of the requested element.
|
||||
*/
|
||||
T& at(const char* key) { return at(std::string_view{key}); }
|
||||
|
||||
/**
|
||||
* Returns a reference to the mapped value of the element with the specified
|
||||
* key. If no such element exists, an exception of type std::out_of_range is
|
||||
* thrown.
|
||||
*
|
||||
* @param key the key of the element to find
|
||||
* @return A reference to the mapped value of the requested element.
|
||||
*/
|
||||
const T& at(const char* key) const { return at(std::string_view{key}); }
|
||||
|
||||
/**
|
||||
* Returns a reference to the mapped value of the element with the specified
|
||||
* key. If no such element exists, an exception of type std::out_of_range is
|
||||
* thrown.
|
||||
*
|
||||
* @param key the key of the element to find
|
||||
* @return A reference to the mapped value of the requested element.
|
||||
*/
|
||||
T& at(std::string_view key) {
|
||||
#ifdef __cpp_lib_associative_heterogeneous_insertion
|
||||
return map_type::at(key);
|
||||
#else
|
||||
auto it = find(key);
|
||||
if (it == this->end()) {
|
||||
throw std::out_of_range{std::string{key}};
|
||||
}
|
||||
return it->second;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the mapped value of the element with the specified
|
||||
* key. If no such element exists, an exception of type std::out_of_range is
|
||||
* thrown.
|
||||
*
|
||||
* @param key the key of the element to find
|
||||
* @return A reference to the mapped value of the requested element.
|
||||
*/
|
||||
const T& at(std::string_view key) const {
|
||||
#ifdef __cpp_lib_associative_heterogeneous_insertion
|
||||
return map_type::at(key);
|
||||
#else
|
||||
auto it = find(key);
|
||||
if (it == this->end()) {
|
||||
throw std::out_of_range{std::string{key}};
|
||||
}
|
||||
return it->second;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the value that is mapped to a key, performing an
|
||||
* insertion if such a key does not exist.
|
||||
*
|
||||
* @param key the key of the element to find
|
||||
* @return A reference to the mapped value of the new element if no element
|
||||
* with key key existed. Otherwise, a reference to the mapped value
|
||||
* of the existing element whose key is equal to key.
|
||||
*/
|
||||
T& operator[](const std::string& key) { return map_type::operator[](key); }
|
||||
|
||||
/**
|
||||
* Returns a reference to the value that is mapped to a key, performing an
|
||||
* insertion if such a key does not exist.
|
||||
*
|
||||
* @param key the key of the element to find
|
||||
* @return A reference to the mapped value of the new element if no element
|
||||
* with key key existed. Otherwise, a reference to the mapped value
|
||||
* of the existing element whose key is equal to key.
|
||||
*/
|
||||
T& operator[](std::string&& key) {
|
||||
return map_type::operator[](std::move(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the value that is mapped to a key, performing an
|
||||
* insertion if such a key does not exist.
|
||||
*
|
||||
* @param key the key of the element to find
|
||||
* @return A reference to the mapped value of the new element if no element
|
||||
* with key key existed. Otherwise, a reference to the mapped value
|
||||
* of the existing element whose key is equal to key.
|
||||
*/
|
||||
T& operator[](const char* key) { return operator[](std::string_view{key}); }
|
||||
|
||||
/**
|
||||
* Returns a reference to the value that is mapped to a key, performing an
|
||||
* insertion if such a key does not exist.
|
||||
*
|
||||
* @param key the key of the element to find
|
||||
* @return A reference to the mapped value of the new element if no element
|
||||
* with key key existed. Otherwise, a reference to the mapped value
|
||||
* of the existing element whose key is equal to key.
|
||||
*/
|
||||
T& operator[](std::string_view key) { return try_emplace(key).first->second; }
|
||||
|
||||
/**
|
||||
* If a key equal to key already exists in the container, assigns obj to the
|
||||
* mapped type corresponding to that key. If the key does not exist, inserts
|
||||
* the value as if by calling insert().
|
||||
*
|
||||
* @param key the key used both to look up and to insert if not found
|
||||
* @param obj the value to insert or assign
|
||||
* @return The bool component is true if the insertion took place and false if
|
||||
* the assignment took place. The iterator component is pointing at
|
||||
* the element that was inserted or updated.
|
||||
*/
|
||||
template <typename M>
|
||||
std::pair<iterator, bool> insert_or_assign(std::string&& key, M&& obj) {
|
||||
return map_type::insert_or_assign(std::move(key), std::forward<M>(obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* If a key equal to key already exists in the container, assigns obj to the
|
||||
* mapped type corresponding to that key. If the key does not exist, inserts
|
||||
* the value as if by calling insert().
|
||||
*
|
||||
* @param key the key used both to look up and to insert if not found
|
||||
* @param obj the value to insert or assign
|
||||
* @return The bool component is true if the insertion took place and false if
|
||||
* the assignment took place. The iterator component is pointing at
|
||||
* the element that was inserted or updated.
|
||||
*/
|
||||
template <typename M>
|
||||
std::pair<iterator, bool> insert_or_assign(const char* key, M&& obj) {
|
||||
return insert_or_assign(std::string_view{key}, std::forward<M>(obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* If a key equal to key already exists in the container, assigns obj to the
|
||||
* mapped type corresponding to that key. If the key does not exist, inserts
|
||||
* the value as if by calling insert().
|
||||
*
|
||||
* @param key the key used both to look up and to insert if not found
|
||||
* @param obj the value to insert or assign
|
||||
* @return The bool component is true if the insertion took place and false if
|
||||
* the assignment took place. The iterator component is pointing at
|
||||
* the element that was inserted or updated.
|
||||
*/
|
||||
template <typename M>
|
||||
std::pair<iterator, bool> insert_or_assign(std::string_view key, M&& obj) {
|
||||
#ifdef __cpp_lib_associative_heterogeneous_insertion
|
||||
return map_type::insert_or_assign(key, std::forward<M>(obj));
|
||||
#else
|
||||
auto it = lower_bound(key);
|
||||
if (it != this->end() && it->first == key) {
|
||||
it->second = std::forward<M>(obj);
|
||||
return {it, false};
|
||||
} else {
|
||||
return {this->insert(it, {std::string{key}, std::forward<M>(obj)}), true};
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* If a key equal to key already exists in the container, assigns obj to the
|
||||
* mapped type corresponding to that key. If the key does not exist, inserts
|
||||
* the value as if by calling insert().
|
||||
*
|
||||
* @param hint iterator to the position before which the new element will be
|
||||
* inserted
|
||||
* @param key the key used both to look up and to insert if not found
|
||||
* @param obj the value to insert or assign
|
||||
* @return Iterator pointing at the element that was inserted or updated.
|
||||
*/
|
||||
template <typename M>
|
||||
iterator insert_or_assign(const_iterator hint, std::string&& key, M&& obj) {
|
||||
return map_type::insert_or_assign(hint, std::move(key),
|
||||
std::forward<M>(obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* If a key equal to key already exists in the container, assigns obj to the
|
||||
* mapped type corresponding to that key. If the key does not exist, inserts
|
||||
* the value as if by calling insert().
|
||||
*
|
||||
* @param hint iterator to the position before which the new element will be
|
||||
* inserted
|
||||
* @param key the key used both to look up and to insert if not found
|
||||
* @param obj the value to insert or assign
|
||||
* @return Iterator pointing at the element that was inserted or updated.
|
||||
*/
|
||||
template <typename M>
|
||||
iterator insert_or_assign(const_iterator hint, const char* key, M&& obj) {
|
||||
return insert_or_assign(hint, std::string_view{key}, std::forward<M>(obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* If a key equal to key already exists in the container, assigns obj to the
|
||||
* mapped type corresponding to that key. If the key does not exist, inserts
|
||||
* the value as if by calling insert().
|
||||
*
|
||||
* @param hint iterator to the position before which the new element will be
|
||||
* inserted
|
||||
* @param key the key used both to look up and to insert if not found
|
||||
* @param obj the value to insert or assign
|
||||
* @return Iterator pointing at the element that was inserted or updated.
|
||||
*/
|
||||
template <typename M>
|
||||
iterator insert_or_assign(const_iterator hint, std::string_view key,
|
||||
M&& obj) {
|
||||
#ifdef __cpp_lib_associative_heterogeneous_insertion
|
||||
return map_type::insert_or_assign(hint, key, std::forward<M>(obj));
|
||||
#else
|
||||
return map_type::insert_or_assign(hint, std::string{key},
|
||||
std::forward<M>(obj));
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a new element into the container constructed in-place with the
|
||||
* given args, if there is no element with the key in the container.
|
||||
*
|
||||
* No iterators or references are invalidated.
|
||||
*
|
||||
* @param key the key used both to look up and to insert if not found
|
||||
* @param args arguments to forward to the constructor of the element
|
||||
* @return A pair consisting of an interator to the inserted element (or to
|
||||
* the element that prevented the insertion) and a bool value set to
|
||||
* true if and only if the insertion took place.
|
||||
*/
|
||||
template <typename... Args>
|
||||
std::pair<iterator, bool> emplace(std::string&& key, Args&&... args) {
|
||||
return map_type::emplace(std::move(key), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a new element into the container constructed in-place with the
|
||||
* given args, if there is no element with the key in the container.
|
||||
*
|
||||
* No iterators or references are invalidated.
|
||||
*
|
||||
* @param key the key used both to look up and to insert if not found
|
||||
* @param args arguments to forward to the constructor of the element
|
||||
* @return A pair consisting of an interator to the inserted element (or to
|
||||
* the element that prevented the insertion) and a bool value set to
|
||||
* true if and only if the insertion took place.
|
||||
*/
|
||||
template <typename... Args>
|
||||
std::pair<iterator, bool> emplace(const char* key, Args&&... args) {
|
||||
return emplace(std::string_view{key}, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a new element into the container constructed in-place with the
|
||||
* given args, if there is no element with the key in the container.
|
||||
*
|
||||
* No iterators or references are invalidated.
|
||||
*
|
||||
* @param key the key used both to look up and to insert if not found
|
||||
* @param args arguments to forward to the constructor of the element
|
||||
* @return A pair consisting of an interator to the inserted element (or to
|
||||
* the element that prevented the insertion) and a bool value set to
|
||||
* true if and only if the insertion took place.
|
||||
*/
|
||||
template <typename... Args>
|
||||
std::pair<iterator, bool> emplace(std::string_view key, Args&&... args) {
|
||||
return try_emplace(key, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* If a key equal to key already exists in the container, does nothing.
|
||||
* Otherwise, inserts a new element into the container with key key and value
|
||||
* constructed with args.
|
||||
*
|
||||
* @param key the key used both to look up and to insert if not found
|
||||
* @param args arguments to forward to the constructor of the element
|
||||
* @return A pair consisting of an interator to the inserted element (or to
|
||||
* the element that prevented the insertion) and a bool value set to
|
||||
* true if and only if the insertion took place.
|
||||
*/
|
||||
template <typename... Args>
|
||||
std::pair<iterator, bool> try_emplace(std::string&& key, Args&&... args) {
|
||||
return map_type::try_emplace(std::move(key), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* If a key equal to key already exists in the container, does nothing.
|
||||
* Otherwise, inserts a new element into the container with key key and value
|
||||
* constructed with args.
|
||||
*
|
||||
* @param key the key used both to look up and to insert if not found
|
||||
* @param args arguments to forward to the constructor of the element
|
||||
* @return A pair consisting of an interator to the inserted element (or to
|
||||
* the element that prevented the insertion) and a bool value set to
|
||||
* true if and only if the insertion took place.
|
||||
*/
|
||||
template <typename... Args>
|
||||
std::pair<iterator, bool> try_emplace(const char* key, Args&&... args) {
|
||||
return try_emplace(std::string_view{key}, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* If a key equal to key already exists in the container, does nothing.
|
||||
* Otherwise, inserts a new element into the container with key key and value
|
||||
* constructed with args.
|
||||
*
|
||||
* @param key the key used both to look up and to insert if not found
|
||||
* @param args arguments to forward to the constructor of the element
|
||||
* @return A pair consisting of an interator to the inserted element (or to
|
||||
* the element that prevented the insertion) and a bool value set to
|
||||
* true if and only if the insertion took place.
|
||||
*/
|
||||
template <typename... Args>
|
||||
std::pair<iterator, bool> try_emplace(std::string_view key, Args&&... args) {
|
||||
#ifdef __cpp_lib_associative_heterogeneous_insertion
|
||||
return map_type::try_emplace(key, std::forward<Args>(args)...);
|
||||
#else
|
||||
auto it = lower_bound(key);
|
||||
if (it != this->end() && it->first == key) {
|
||||
return {it, false};
|
||||
} else {
|
||||
return {try_emplace(it, key, std::forward<Args>(args)...), true};
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* If a key equal to key already exists in the container, does nothing.
|
||||
* Otherwise, inserts a new element into the container with key key and value
|
||||
* constructed with args.
|
||||
*
|
||||
* @param hint iterator to the position before which the new element will be
|
||||
* inserted
|
||||
* @param key the key used both to look up and to insert if not found
|
||||
* @param args arguments to forward to the constructor of the element
|
||||
* @return An interator to the inserted element, or to the element that
|
||||
* prevented the insertion.
|
||||
*/
|
||||
template <typename... Args>
|
||||
iterator try_emplace(const_iterator hint, std::string&& key, Args&&... args) {
|
||||
return map_type::try_emplace(hint, std::move(key),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* If a key equal to key already exists in the container, does nothing.
|
||||
* Otherwise, inserts a new element into the container with key key and value
|
||||
* constructed with args.
|
||||
*
|
||||
* @param hint iterator to the position before which the new element will be
|
||||
* inserted
|
||||
* @param key the key used both to look up and to insert if not found
|
||||
* @param args arguments to forward to the constructor of the element
|
||||
* @return An interator to the inserted element, or to the element that
|
||||
* prevented the insertion.
|
||||
*/
|
||||
template <typename... Args>
|
||||
iterator try_emplace(const_iterator hint, const char* key, Args&&... args) {
|
||||
return try_emplace(hint, std::string_view{key},
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* If a key equal to key already exists in the container, does nothing.
|
||||
* Otherwise, inserts a new element into the container with key key and value
|
||||
* constructed with args.
|
||||
*
|
||||
* @param hint iterator to the position before which the new element will be
|
||||
* inserted
|
||||
* @param key the key used both to look up and to insert if not found
|
||||
* @param args arguments to forward to the constructor of the element
|
||||
* @return An interator to the inserted element, or to the element that
|
||||
* prevented the insertion.
|
||||
*/
|
||||
template <typename... Args>
|
||||
iterator try_emplace(const_iterator hint, std::string_view key,
|
||||
Args&&... args) {
|
||||
#ifdef __cpp_lib_associative_heterogeneous_insertion
|
||||
return map_type::try_emplace(hint, key, std::forward<Args>(args)...);
|
||||
#else
|
||||
return map_type::try_emplace(hint, std::string{key},
|
||||
std::forward<Args>(args)...);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the element at pos.
|
||||
*
|
||||
* @param pos iterator to the element to remove
|
||||
* @return Iterator following the removed element.
|
||||
*/
|
||||
iterator erase(iterator pos) { return map_type::erase(pos); }
|
||||
|
||||
/**
|
||||
* Removes the element at pos.
|
||||
*
|
||||
* @param pos iterator to the element to remove
|
||||
* @return Iterator following the removed element.
|
||||
*/
|
||||
iterator erase(const_iterator pos) { return map_type::erase(pos); }
|
||||
|
||||
/**
|
||||
* Removes the elements in the range [first, last), which must be a valid
|
||||
* range in this.
|
||||
*
|
||||
* @param first Start of the range of elements to remove
|
||||
* @param last End of the range of elements to remove
|
||||
* @return Iterator following the last removed element.
|
||||
*/
|
||||
iterator erase(iterator first, iterator last) {
|
||||
return map_type::erase(first, last);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the elements in the range [first, last), which must be a valid
|
||||
* range in this.
|
||||
*
|
||||
* @param first Start of the range of elements to remove
|
||||
* @param last End of the range of elements to remove
|
||||
* @return Iterator following the last removed element.
|
||||
*/
|
||||
iterator erase(const_iterator first, const_iterator last) {
|
||||
return map_type::erase(first, last);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the element (if one exists) with the key equal to key.
|
||||
*
|
||||
* @param key key value of the elements to remove
|
||||
* @return Number of elements removed (0 or 1).
|
||||
*/
|
||||
size_type erase(std::string_view key) {
|
||||
#ifdef __cpp_lib_associative_heterogeneous_erasure
|
||||
return map_type::erase(key);
|
||||
#else
|
||||
auto it = find(key);
|
||||
if (it == this->end()) {
|
||||
return 0;
|
||||
}
|
||||
this->erase(it);
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Exchanges the contents of the container with those of other. Does not
|
||||
* invoke any move, copy, or swap operations on individual elements.
|
||||
*
|
||||
* All iterators and references remain valid. The end() iterator is
|
||||
* invalidated.
|
||||
*
|
||||
* @param other container to exchange the contents with
|
||||
*/
|
||||
void swap(StringMap& other) noexcept(
|
||||
std::allocator_traits<Allocator>::is_always_equal::value &&
|
||||
std::is_nothrow_swappable<std::less<>>::value) {
|
||||
map_type::swap(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlinks the node that contains the element pointed to by position and
|
||||
* returns a node handle that owns it.
|
||||
*
|
||||
* @param position a valid iterator into this container
|
||||
* @return A node handle that owns the extracted element
|
||||
*/
|
||||
node_type extract(const_iterator position) {
|
||||
return map_type::extract(position);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the container has an element with key equal to key, unlinks the node
|
||||
* that contains that element from the container and returns a node handle
|
||||
* that owns it. Otherwise, returns an empty node handle.
|
||||
*
|
||||
* @param key a key to identify the node to be extracted
|
||||
* @return A node handle that owns the extracted element, or empty node handle
|
||||
* in case the element is not found.
|
||||
*/
|
||||
node_type extract(std::string_view key) {
|
||||
#ifdef __cpp_lib_associative_heterogeneous_insertion
|
||||
return map_type::extract(key);
|
||||
#else
|
||||
auto it = find(key);
|
||||
if (it == this->end()) {
|
||||
return {};
|
||||
}
|
||||
return extract(it);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of elements with key that equals the specified argument.
|
||||
*
|
||||
* @param key key value of the elements to count
|
||||
* @return Number of elements with key that equals key (either 0 or 1).
|
||||
*/
|
||||
size_type count(std::string_view key) const { return map_type::count(key); }
|
||||
|
||||
/**
|
||||
* Finds an element with key equal to key.
|
||||
*
|
||||
* @param key key value of the element to search for
|
||||
* @return An iterator to the requested element. If no such element is found,
|
||||
* past-the-end (see end()) iterator is returned.
|
||||
*/
|
||||
iterator find(std::string_view key) { return map_type::find(key); }
|
||||
|
||||
/**
|
||||
* Finds an element with key equal to key.
|
||||
*
|
||||
* @param key key value of the element to search for
|
||||
* @return An iterator to the requested element. If no such element is found,
|
||||
* past-the-end (see end()) iterator is returned.
|
||||
*/
|
||||
const_iterator find(std::string_view key) const {
|
||||
return map_type::find(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there is an element with key equal to key in the container.
|
||||
*
|
||||
* @param key key value of the element to search for
|
||||
* @return true if there is such an element, otherwise false
|
||||
*/
|
||||
bool contains(std::string_view key) const { return map_type::contains(key); }
|
||||
|
||||
/**
|
||||
* Returns a range containing all elements with the given key in the
|
||||
* container. The range is defined by two iterators, one pointing to the
|
||||
* first element that is not less than key and another pointing to the first
|
||||
* element greater than key. Alternatively, the first iterator may be
|
||||
* obtained with lower_bound(), and the second with upper_bound().
|
||||
*
|
||||
* @param key key value to compare the elements to
|
||||
* @return std::pair containing a pair of iterators defining the wanted range:
|
||||
* the first pointing to the first element that is not less than key
|
||||
* and the second pointing to the first element greater than key. If
|
||||
* there are no elements not less than key, past-the-end (see end())
|
||||
* iterator is returned as the first element. Similarly if there are
|
||||
* no elements greater than key, past-the-end iterator is returned as
|
||||
* the second element.
|
||||
*/
|
||||
std::pair<iterator, iterator> equal_range(std::string_view key) {
|
||||
return map_type::equal_range(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a range containing all elements with the given key in the
|
||||
* container. The range is defined by two iterators, one pointing to the
|
||||
* first element that is not less than key and another pointing to the first
|
||||
* element greater than key. Alternatively, the first iterator may be
|
||||
* obtained with lower_bound(), and the second with upper_bound().
|
||||
*
|
||||
* @param key key value to compare the elements to
|
||||
* @return std::pair containing a pair of iterators defining the wanted range:
|
||||
* the first pointing to the first element that is not less than key
|
||||
* and the second pointing to the first element greater than key. If
|
||||
* there are no elements not less than key, past-the-end (see end())
|
||||
* iterator is returned as the first element. Similarly if there are
|
||||
* no elements greater than key, past-the-end iterator is returned as
|
||||
* the second element.
|
||||
*/
|
||||
std::pair<const_iterator, const_iterator> equal_range(
|
||||
std::string_view key) const {
|
||||
return map_type::equal_range(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator pointing to the first element that is not less than
|
||||
* (i.e. greater or equal to) key.
|
||||
*
|
||||
* @param key key value to compare the elements to
|
||||
* @return Iterator pointing to the first element that is not less than key.
|
||||
* If no such element is found, a past-the-end iterator (see end()) is
|
||||
* returned.
|
||||
*/
|
||||
iterator lower_bound(std::string_view key) {
|
||||
return map_type::lower_bound(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator pointing to the first element that is not less than
|
||||
* (i.e. greater or equal to) key.
|
||||
*
|
||||
* @param key key value to compare the elements to
|
||||
* @return Iterator pointing to the first element that is not less than key.
|
||||
* If no such element is found, a past-the-end iterator (see end()) is
|
||||
* returned.
|
||||
*/
|
||||
const_iterator lower_bound(std::string_view key) const {
|
||||
return map_type::lower_bound(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an interator pointing to the first element that is greater than
|
||||
* key.
|
||||
*
|
||||
* @param key key value to compare the elements to
|
||||
* @return Iterator pointing to the first element that is greater than key.
|
||||
* If no such element is found, past-the-end (see end()) iterator is
|
||||
* returned.
|
||||
*/
|
||||
iterator upper_bound(std::string_view key) {
|
||||
return map_type::upper_bound(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an interator pointing to the first element that is greater than
|
||||
* key.
|
||||
*
|
||||
* @param key key value to compare the elements to
|
||||
* @return Iterator pointing to the first element that is greater than key.
|
||||
* If no such element is found, past-the-end (see end()) iterator is
|
||||
* returned.
|
||||
*/
|
||||
const_iterator upper_bound(std::string_view key) const {
|
||||
return map_type::upper_bound(key);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
namespace std {
|
||||
template <typename T>
|
||||
inline void swap(wpi::StringMap<T>& lhs, wpi::StringMap<T>& rhs) {
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
} // namespace std
|
||||
@@ -1,259 +0,0 @@
|
||||
//===--- StringMap.cpp - String Hash table map implementation -------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the StringMap class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/StringMap.h"
|
||||
#include "wpi/MathExtras.h"
|
||||
#include "wpi/ReverseIteration.h"
|
||||
#include "wpi/xxhash.h"
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
/// Returns the number of buckets to allocate to ensure that the DenseMap can
|
||||
/// accommodate \p NumEntries without need to grow().
|
||||
static inline unsigned getMinBucketToReserveForEntries(unsigned NumEntries) {
|
||||
// Ensure that "NumEntries * 4 < NumBuckets * 3"
|
||||
if (NumEntries == 0)
|
||||
return 0;
|
||||
// +1 is required because of the strict equality.
|
||||
// For example if NumEntries is 48, we need to return 401.
|
||||
return NextPowerOf2(NumEntries * 4 / 3 + 1);
|
||||
}
|
||||
|
||||
static inline StringMapEntryBase **createTable(unsigned NewNumBuckets) {
|
||||
auto **Table = static_cast<StringMapEntryBase **>(safe_calloc(
|
||||
NewNumBuckets + 1, sizeof(StringMapEntryBase **) + sizeof(unsigned)));
|
||||
|
||||
// Allocate one extra bucket, set it to look filled so the iterators stop at
|
||||
// end.
|
||||
Table[NewNumBuckets] = (StringMapEntryBase *)2;
|
||||
return Table;
|
||||
}
|
||||
|
||||
static inline unsigned *getHashTable(StringMapEntryBase **TheTable,
|
||||
unsigned NumBuckets) {
|
||||
return reinterpret_cast<unsigned *>(TheTable + NumBuckets + 1);
|
||||
}
|
||||
|
||||
StringMapImpl::StringMapImpl(unsigned InitSize, unsigned itemSize) {
|
||||
ItemSize = itemSize;
|
||||
|
||||
// If a size is specified, initialize the table with that many buckets.
|
||||
if (InitSize) {
|
||||
// The table will grow when the number of entries reach 3/4 of the number of
|
||||
// buckets. To guarantee that "InitSize" number of entries can be inserted
|
||||
// in the table without growing, we allocate just what is needed here.
|
||||
init(getMinBucketToReserveForEntries(InitSize));
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, initialize it with zero buckets to avoid the allocation.
|
||||
TheTable = nullptr;
|
||||
NumBuckets = 0;
|
||||
NumItems = 0;
|
||||
NumTombstones = 0;
|
||||
}
|
||||
|
||||
void StringMapImpl::init(unsigned InitSize) {
|
||||
assert((InitSize & (InitSize - 1)) == 0 &&
|
||||
"Init Size must be a power of 2 or zero!");
|
||||
|
||||
unsigned NewNumBuckets = InitSize ? InitSize : 16;
|
||||
NumItems = 0;
|
||||
NumTombstones = 0;
|
||||
|
||||
TheTable = createTable(NewNumBuckets);
|
||||
|
||||
// Set the member only if TheTable was successfully allocated
|
||||
NumBuckets = NewNumBuckets;
|
||||
}
|
||||
|
||||
/// LookupBucketFor - Look up the bucket that the specified string should end
|
||||
/// up in. If it already exists as a key in the map, the Item pointer for the
|
||||
/// specified bucket will be non-null. Otherwise, it will be null. In either
|
||||
/// case, the FullHashValue field of the bucket will be set to the hash value
|
||||
/// of the string.
|
||||
unsigned StringMapImpl::LookupBucketFor(std::string_view Name) {
|
||||
// Hash table unallocated so far?
|
||||
if (NumBuckets == 0)
|
||||
init(16);
|
||||
unsigned FullHashValue = xxh3_64bits(Name);
|
||||
if (shouldReverseIterate())
|
||||
FullHashValue = ~FullHashValue;
|
||||
unsigned BucketNo = FullHashValue & (NumBuckets - 1);
|
||||
unsigned *HashTable = getHashTable(TheTable, NumBuckets);
|
||||
|
||||
unsigned ProbeAmt = 1;
|
||||
int FirstTombstone = -1;
|
||||
while (true) {
|
||||
StringMapEntryBase *BucketItem = TheTable[BucketNo];
|
||||
// If we found an empty bucket, this key isn't in the table yet, return it.
|
||||
if (LLVM_LIKELY(!BucketItem)) {
|
||||
// If we found a tombstone, we want to reuse the tombstone instead of an
|
||||
// empty bucket. This reduces probing.
|
||||
if (FirstTombstone != -1) {
|
||||
HashTable[FirstTombstone] = FullHashValue;
|
||||
return FirstTombstone;
|
||||
}
|
||||
|
||||
HashTable[BucketNo] = FullHashValue;
|
||||
return BucketNo;
|
||||
}
|
||||
|
||||
if (BucketItem == getTombstoneVal()) {
|
||||
// Skip over tombstones. However, remember the first one we see.
|
||||
if (FirstTombstone == -1)
|
||||
FirstTombstone = BucketNo;
|
||||
} else if (LLVM_LIKELY(HashTable[BucketNo] == FullHashValue)) {
|
||||
// If the full hash value matches, check deeply for a match. The common
|
||||
// case here is that we are only looking at the buckets (for item info
|
||||
// being non-null and for the full hash value) not at the items. This
|
||||
// is important for cache locality.
|
||||
|
||||
// Do the comparison like this because Name isn't necessarily
|
||||
// null-terminated!
|
||||
char *ItemStr = (char *)BucketItem + ItemSize;
|
||||
if (Name == std::string_view(ItemStr, BucketItem->getKeyLength())) {
|
||||
// We found a match!
|
||||
return BucketNo;
|
||||
}
|
||||
}
|
||||
|
||||
// Okay, we didn't find the item. Probe to the next bucket.
|
||||
BucketNo = (BucketNo + ProbeAmt) & (NumBuckets - 1);
|
||||
|
||||
// Use quadratic probing, it has fewer clumping artifacts than linear
|
||||
// probing and has good cache behavior in the common case.
|
||||
++ProbeAmt;
|
||||
}
|
||||
}
|
||||
|
||||
/// FindKey - Look up the bucket that contains the specified key. If it exists
|
||||
/// in the map, return the bucket number of the key. Otherwise return -1.
|
||||
/// This does not modify the map.
|
||||
int StringMapImpl::FindKey(std::string_view Key) const {
|
||||
if (NumBuckets == 0)
|
||||
return -1; // Really empty table?
|
||||
unsigned FullHashValue = xxh3_64bits(Key);
|
||||
if (shouldReverseIterate())
|
||||
FullHashValue = ~FullHashValue;
|
||||
unsigned BucketNo = FullHashValue & (NumBuckets - 1);
|
||||
unsigned *HashTable = getHashTable(TheTable, NumBuckets);
|
||||
|
||||
unsigned ProbeAmt = 1;
|
||||
while (true) {
|
||||
StringMapEntryBase *BucketItem = TheTable[BucketNo];
|
||||
// If we found an empty bucket, this key isn't in the table yet, return.
|
||||
if (LLVM_LIKELY(!BucketItem))
|
||||
return -1;
|
||||
|
||||
if (BucketItem == getTombstoneVal()) {
|
||||
// Ignore tombstones.
|
||||
} else if (LLVM_LIKELY(HashTable[BucketNo] == FullHashValue)) {
|
||||
// If the full hash value matches, check deeply for a match. The common
|
||||
// case here is that we are only looking at the buckets (for item info
|
||||
// being non-null and for the full hash value) not at the items. This
|
||||
// is important for cache locality.
|
||||
|
||||
// Do the comparison like this because NameStart isn't necessarily
|
||||
// null-terminated!
|
||||
char *ItemStr = (char *)BucketItem + ItemSize;
|
||||
if (Key == std::string_view(ItemStr, BucketItem->getKeyLength())) {
|
||||
// We found a match!
|
||||
return BucketNo;
|
||||
}
|
||||
}
|
||||
|
||||
// Okay, we didn't find the item. Probe to the next bucket.
|
||||
BucketNo = (BucketNo + ProbeAmt) & (NumBuckets - 1);
|
||||
|
||||
// Use quadratic probing, it has fewer clumping artifacts than linear
|
||||
// probing and has good cache behavior in the common case.
|
||||
++ProbeAmt;
|
||||
}
|
||||
}
|
||||
|
||||
/// RemoveKey - Remove the specified StringMapEntry from the table, but do not
|
||||
/// delete it. This aborts if the value isn't in the table.
|
||||
void StringMapImpl::RemoveKey(StringMapEntryBase *V) {
|
||||
const char *VStr = (char *)V + ItemSize;
|
||||
StringMapEntryBase *V2 = RemoveKey(std::string_view(VStr, V->getKeyLength()));
|
||||
(void)V2;
|
||||
assert(V == V2 && "Didn't find key?");
|
||||
}
|
||||
|
||||
/// RemoveKey - Remove the StringMapEntry for the specified key from the
|
||||
/// table, returning it. If the key is not in the table, this returns null.
|
||||
StringMapEntryBase *StringMapImpl::RemoveKey(std::string_view Key) {
|
||||
int Bucket = FindKey(Key);
|
||||
if (Bucket == -1)
|
||||
return nullptr;
|
||||
|
||||
StringMapEntryBase *Result = TheTable[Bucket];
|
||||
TheTable[Bucket] = getTombstoneVal();
|
||||
--NumItems;
|
||||
++NumTombstones;
|
||||
assert(NumItems + NumTombstones <= NumBuckets);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// RehashTable - Grow the table, redistributing values into the buckets with
|
||||
/// the appropriate mod-of-hashtable-size.
|
||||
unsigned StringMapImpl::RehashTable(unsigned BucketNo) {
|
||||
unsigned NewSize;
|
||||
// If the hash table is now more than 3/4 full, or if fewer than 1/8 of
|
||||
// the buckets are empty (meaning that many are filled with tombstones),
|
||||
// grow/rehash the table.
|
||||
if (LLVM_UNLIKELY(NumItems * 4 > NumBuckets * 3)) {
|
||||
NewSize = NumBuckets * 2;
|
||||
} else if (LLVM_UNLIKELY(NumBuckets - (NumItems + NumTombstones) <=
|
||||
NumBuckets / 8)) {
|
||||
NewSize = NumBuckets;
|
||||
} else {
|
||||
return BucketNo;
|
||||
}
|
||||
|
||||
unsigned NewBucketNo = BucketNo;
|
||||
auto **NewTableArray = createTable(NewSize);
|
||||
unsigned *NewHashArray = getHashTable(NewTableArray, NewSize);
|
||||
unsigned *HashTable = getHashTable(TheTable, NumBuckets);
|
||||
|
||||
// Rehash all the items into their new buckets. Luckily :) we already have
|
||||
// the hash values available, so we don't have to rehash any strings.
|
||||
for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
|
||||
StringMapEntryBase *Bucket = TheTable[I];
|
||||
if (Bucket && Bucket != getTombstoneVal()) {
|
||||
// If the bucket is not available, probe for a spot.
|
||||
unsigned FullHash = HashTable[I];
|
||||
unsigned NewBucket = FullHash & (NewSize - 1);
|
||||
if (NewTableArray[NewBucket]) {
|
||||
unsigned ProbeSize = 1;
|
||||
do {
|
||||
NewBucket = (NewBucket + ProbeSize++) & (NewSize - 1);
|
||||
} while (NewTableArray[NewBucket]);
|
||||
}
|
||||
|
||||
// Finally found a slot. Fill it in.
|
||||
NewTableArray[NewBucket] = Bucket;
|
||||
NewHashArray[NewBucket] = FullHash;
|
||||
if (I == BucketNo)
|
||||
NewBucketNo = NewBucket;
|
||||
}
|
||||
}
|
||||
|
||||
free(TheTable);
|
||||
|
||||
TheTable = NewTableArray;
|
||||
NumBuckets = NewSize;
|
||||
NumTombstones = 0;
|
||||
return NewBucketNo;
|
||||
}
|
||||
@@ -1,605 +0,0 @@
|
||||
//===- StringMap.h - String Hash table map interface ------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// This file defines the StringMap class.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_STRINGMAP_H
|
||||
#define WPIUTIL_WPI_STRINGMAP_H
|
||||
|
||||
#include "wpi/StringMapEntry.h"
|
||||
#include "wpi/iterator.h"
|
||||
#include "wpi/AllocatorBase.h"
|
||||
#include "wpi/MemAlloc.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/iterator.h"
|
||||
#include "wpi/iterator_range.h"
|
||||
#include "wpi/PointerLikeTypeTraits.h"
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
template <typename ValueTy> class StringMapConstIterator;
|
||||
template <typename ValueTy> class StringMapIterator;
|
||||
template <typename ValueTy> class StringMapKeyIterator;
|
||||
|
||||
/// StringMapImpl - This is the base class of StringMap that is shared among
|
||||
/// all of its instantiations.
|
||||
class StringMapImpl {
|
||||
protected:
|
||||
// Array of NumBuckets pointers to entries, null pointers are holes.
|
||||
// TheTable[NumBuckets] contains a sentinel value for easy iteration. Followed
|
||||
// by an array of the actual hash values as unsigned integers.
|
||||
StringMapEntryBase **TheTable = nullptr;
|
||||
unsigned NumBuckets = 0;
|
||||
unsigned NumItems = 0;
|
||||
unsigned NumTombstones = 0;
|
||||
unsigned ItemSize;
|
||||
|
||||
protected:
|
||||
explicit StringMapImpl(unsigned itemSize) : ItemSize(itemSize) {}
|
||||
StringMapImpl(StringMapImpl &&RHS) noexcept
|
||||
: TheTable(RHS.TheTable), NumBuckets(RHS.NumBuckets),
|
||||
NumItems(RHS.NumItems), NumTombstones(RHS.NumTombstones),
|
||||
ItemSize(RHS.ItemSize) {
|
||||
RHS.TheTable = nullptr;
|
||||
RHS.NumBuckets = 0;
|
||||
RHS.NumItems = 0;
|
||||
RHS.NumTombstones = 0;
|
||||
}
|
||||
|
||||
StringMapImpl(unsigned InitSize, unsigned ItemSize);
|
||||
unsigned RehashTable(unsigned BucketNo = 0);
|
||||
|
||||
/// LookupBucketFor - Look up the bucket that the specified string should end
|
||||
/// up in. If it already exists as a key in the map, the Item pointer for the
|
||||
/// specified bucket will be non-null. Otherwise, it will be null. In either
|
||||
/// case, the FullHashValue field of the bucket will be set to the hash value
|
||||
/// of the string.
|
||||
unsigned LookupBucketFor(std::string_view Key);
|
||||
|
||||
/// FindKey - Look up the bucket that contains the specified key. If it exists
|
||||
/// in the map, return the bucket number of the key. Otherwise return -1.
|
||||
/// This does not modify the map.
|
||||
int FindKey(std::string_view Key) const;
|
||||
|
||||
/// RemoveKey - Remove the specified StringMapEntry from the table, but do not
|
||||
/// delete it. This aborts if the value isn't in the table.
|
||||
void RemoveKey(StringMapEntryBase *V);
|
||||
|
||||
/// RemoveKey - Remove the StringMapEntry for the specified key from the
|
||||
/// table, returning it. If the key is not in the table, this returns null.
|
||||
StringMapEntryBase *RemoveKey(std::string_view Key);
|
||||
|
||||
/// Allocate the table with the specified number of buckets and otherwise
|
||||
/// setup the map as empty.
|
||||
void init(unsigned Size);
|
||||
|
||||
public:
|
||||
static constexpr uintptr_t TombstoneIntVal =
|
||||
static_cast<uintptr_t>(-1)
|
||||
<< PointerLikeTypeTraits<StringMapEntryBase *>::NumLowBitsAvailable;
|
||||
|
||||
static StringMapEntryBase *getTombstoneVal() {
|
||||
return reinterpret_cast<StringMapEntryBase *>(TombstoneIntVal);
|
||||
}
|
||||
|
||||
unsigned getNumBuckets() const { return NumBuckets; }
|
||||
unsigned getNumItems() const { return NumItems; }
|
||||
|
||||
bool empty() const { return NumItems == 0; }
|
||||
unsigned size() const { return NumItems; }
|
||||
|
||||
void swap(StringMapImpl &Other) {
|
||||
std::swap(TheTable, Other.TheTable);
|
||||
std::swap(NumBuckets, Other.NumBuckets);
|
||||
std::swap(NumItems, Other.NumItems);
|
||||
std::swap(NumTombstones, Other.NumTombstones);
|
||||
}
|
||||
};
|
||||
|
||||
/// StringMap - This is an unconventional map that is specialized for handling
|
||||
/// keys that are "strings", which are basically ranges of bytes. This does some
|
||||
/// funky memory allocation and hashing things to make it extremely efficient,
|
||||
/// storing the string data *after* the value in the map.
|
||||
template <typename ValueTy, typename AllocatorTy = MallocAllocator>
|
||||
class LLVM_ALLOCATORHOLDER_EMPTYBASE StringMap
|
||||
: public StringMapImpl,
|
||||
private detail::AllocatorHolder<AllocatorTy> {
|
||||
using AllocTy = detail::AllocatorHolder<AllocatorTy>;
|
||||
|
||||
public:
|
||||
using MapEntryTy = StringMapEntry<ValueTy>;
|
||||
|
||||
StringMap() : StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))) {}
|
||||
|
||||
explicit StringMap(unsigned InitialSize)
|
||||
: StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))) {}
|
||||
|
||||
explicit StringMap(AllocatorTy A)
|
||||
: StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))), AllocTy(A) {}
|
||||
|
||||
StringMap(unsigned InitialSize, AllocatorTy A)
|
||||
: StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))),
|
||||
AllocTy(A) {}
|
||||
|
||||
StringMap(std::initializer_list<std::pair<std::string_view, ValueTy>> List)
|
||||
: StringMapImpl(List.size(), static_cast<unsigned>(sizeof(MapEntryTy))) {
|
||||
insert(List);
|
||||
}
|
||||
|
||||
StringMap(StringMap &&RHS)
|
||||
: StringMapImpl(std::move(RHS)), AllocTy(std::move(RHS.getAllocator())) {}
|
||||
|
||||
StringMap(const StringMap &RHS)
|
||||
: StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))),
|
||||
AllocTy(RHS.getAllocator()) {
|
||||
if (RHS.empty())
|
||||
return;
|
||||
|
||||
// Allocate TheTable of the same size as RHS's TheTable, and set the
|
||||
// sentinel appropriately (and NumBuckets).
|
||||
init(RHS.NumBuckets);
|
||||
unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1),
|
||||
*RHSHashTable = (unsigned *)(RHS.TheTable + NumBuckets + 1);
|
||||
|
||||
NumItems = RHS.NumItems;
|
||||
NumTombstones = RHS.NumTombstones;
|
||||
for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
|
||||
StringMapEntryBase *Bucket = RHS.TheTable[I];
|
||||
if (!Bucket || Bucket == getTombstoneVal()) {
|
||||
TheTable[I] = Bucket;
|
||||
continue;
|
||||
}
|
||||
|
||||
TheTable[I] = MapEntryTy::create(
|
||||
static_cast<MapEntryTy *>(Bucket)->getKey(), getAllocator(),
|
||||
static_cast<MapEntryTy *>(Bucket)->getValue());
|
||||
HashTable[I] = RHSHashTable[I];
|
||||
}
|
||||
|
||||
// Note that here we've copied everything from the RHS into this object,
|
||||
// tombstones included. We could, instead, have re-probed for each key to
|
||||
// instantiate this new object without any tombstone buckets. The
|
||||
// assumption here is that items are rarely deleted from most StringMaps,
|
||||
// and so tombstones are rare, so the cost of re-probing for all inputs is
|
||||
// not worthwhile.
|
||||
}
|
||||
|
||||
StringMap &operator=(StringMap RHS) {
|
||||
StringMapImpl::swap(RHS);
|
||||
std::swap(getAllocator(), RHS.getAllocator());
|
||||
return *this;
|
||||
}
|
||||
|
||||
~StringMap() {
|
||||
// Delete all the elements in the map, but don't reset the elements
|
||||
// to default values. This is a copy of clear(), but avoids unnecessary
|
||||
// work not required in the destructor.
|
||||
if (!empty()) {
|
||||
for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
|
||||
StringMapEntryBase *Bucket = TheTable[I];
|
||||
if (Bucket && Bucket != getTombstoneVal()) {
|
||||
static_cast<MapEntryTy *>(Bucket)->Destroy(getAllocator());
|
||||
}
|
||||
}
|
||||
}
|
||||
free(TheTable);
|
||||
}
|
||||
|
||||
using AllocTy::getAllocator;
|
||||
|
||||
using key_type = const char *;
|
||||
using mapped_type = ValueTy;
|
||||
using value_type = StringMapEntry<ValueTy>;
|
||||
using size_type = size_t;
|
||||
|
||||
using const_iterator = StringMapConstIterator<ValueTy>;
|
||||
using iterator = StringMapIterator<ValueTy>;
|
||||
|
||||
iterator begin() { return iterator(TheTable, NumBuckets == 0); }
|
||||
iterator end() { return iterator(TheTable + NumBuckets, true); }
|
||||
const_iterator begin() const {
|
||||
return const_iterator(TheTable, NumBuckets == 0);
|
||||
}
|
||||
const_iterator end() const {
|
||||
return const_iterator(TheTable + NumBuckets, true);
|
||||
}
|
||||
|
||||
iterator_range<StringMapKeyIterator<ValueTy>> keys() const {
|
||||
return make_range(StringMapKeyIterator<ValueTy>(begin()),
|
||||
StringMapKeyIterator<ValueTy>(end()));
|
||||
}
|
||||
|
||||
iterator find(std::string_view Key) {
|
||||
int Bucket = FindKey(Key);
|
||||
if (Bucket == -1)
|
||||
return end();
|
||||
return iterator(TheTable + Bucket, true);
|
||||
}
|
||||
|
||||
const_iterator find(std::string_view Key) const {
|
||||
int Bucket = FindKey(Key);
|
||||
if (Bucket == -1)
|
||||
return end();
|
||||
return const_iterator(TheTable + Bucket, true);
|
||||
}
|
||||
|
||||
/// lookup - Return the entry for the specified key, or a default
|
||||
/// constructed value if no such entry exists.
|
||||
ValueTy lookup(std::string_view Key) const {
|
||||
const_iterator Iter = find(Key);
|
||||
if (Iter != end())
|
||||
return Iter->second;
|
||||
return ValueTy();
|
||||
}
|
||||
|
||||
/// at - Return the entry for the specified key, or abort if no such
|
||||
/// entry exists.
|
||||
const ValueTy &at(std::string_view Val) const {
|
||||
auto Iter = this->find(std::move(Val));
|
||||
assert(Iter != this->end() && "StringMap::at failed due to a missing key");
|
||||
return Iter->second;
|
||||
}
|
||||
|
||||
/// Lookup the ValueTy for the \p Key, or create a default constructed value
|
||||
/// if the key is not in the map.
|
||||
ValueTy &operator[](std::string_view Key) { return try_emplace(Key).first->second; }
|
||||
|
||||
/// contains - Return true if the element is in the map, false otherwise.
|
||||
bool contains(std::string_view Key) const { return find(Key) != end(); }
|
||||
|
||||
/// count - Return 1 if the element is in the map, 0 otherwise.
|
||||
size_type count(std::string_view Key) const { return contains(Key) ? 1 : 0; }
|
||||
|
||||
template <typename InputTy>
|
||||
size_type count(const StringMapEntry<InputTy> &MapEntry) const {
|
||||
return count(MapEntry.getKey());
|
||||
}
|
||||
|
||||
/// equal - check whether both of the containers are equal.
|
||||
bool operator==(const StringMap &RHS) const {
|
||||
if (size() != RHS.size())
|
||||
return false;
|
||||
|
||||
for (const auto &KeyValue : *this) {
|
||||
auto FindInRHS = RHS.find(KeyValue.getKey());
|
||||
|
||||
if (FindInRHS == RHS.end())
|
||||
return false;
|
||||
|
||||
if (!(KeyValue.getValue() == FindInRHS->getValue()))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator!=(const StringMap &RHS) const { return !(*this == RHS); }
|
||||
|
||||
/// insert - Insert the specified key/value pair into the map. If the key
|
||||
/// already exists in the map, return false and ignore the request, otherwise
|
||||
/// insert it and return true.
|
||||
bool insert(MapEntryTy *KeyValue) {
|
||||
unsigned BucketNo = LookupBucketFor(KeyValue->getKey());
|
||||
StringMapEntryBase *&Bucket = TheTable[BucketNo];
|
||||
if (Bucket && Bucket != getTombstoneVal())
|
||||
return false; // Already exists in map.
|
||||
|
||||
if (Bucket == getTombstoneVal())
|
||||
--NumTombstones;
|
||||
Bucket = KeyValue;
|
||||
++NumItems;
|
||||
assert(NumItems + NumTombstones <= NumBuckets);
|
||||
|
||||
RehashTable();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// insert - Inserts the specified key/value pair into the map if the key
|
||||
/// isn't already in the map. The bool component of the returned pair is true
|
||||
/// if and only if the insertion takes place, and the iterator component of
|
||||
/// the pair points to the element with key equivalent to the key of the pair.
|
||||
std::pair<iterator, bool> insert(std::pair<std::string_view, ValueTy> KV) {
|
||||
return try_emplace(KV.first, std::move(KV.second));
|
||||
}
|
||||
|
||||
/// Inserts elements from range [first, last). If multiple elements in the
|
||||
/// range have keys that compare equivalent, it is unspecified which element
|
||||
/// is inserted .
|
||||
template <typename InputIt> void insert(InputIt First, InputIt Last) {
|
||||
for (InputIt It = First; It != Last; ++It)
|
||||
insert(*It);
|
||||
}
|
||||
|
||||
/// Inserts elements from initializer list ilist. If multiple elements in
|
||||
/// the range have keys that compare equivalent, it is unspecified which
|
||||
/// element is inserted
|
||||
void insert(std::initializer_list<std::pair<std::string_view, ValueTy>> List) {
|
||||
insert(List.begin(), List.end());
|
||||
}
|
||||
|
||||
/// Inserts an element or assigns to the current element if the key already
|
||||
/// exists. The return type is the same as try_emplace.
|
||||
template <typename V>
|
||||
std::pair<iterator, bool> insert_or_assign(std::string_view Key, V &&Val) {
|
||||
auto Ret = try_emplace(Key, std::forward<V>(Val));
|
||||
if (!Ret.second)
|
||||
Ret.first->second = std::forward<V>(Val);
|
||||
return Ret;
|
||||
}
|
||||
|
||||
/// Emplace a new element for the specified key into the map if the key isn't
|
||||
/// already in the map. The bool component of the returned pair is true
|
||||
/// if and only if the insertion takes place, and the iterator component of
|
||||
/// the pair points to the element with key equivalent to the key of the pair.
|
||||
template <typename... ArgsTy>
|
||||
std::pair<iterator, bool> try_emplace(std::string_view Key, ArgsTy &&...Args) {
|
||||
unsigned BucketNo = LookupBucketFor(Key);
|
||||
StringMapEntryBase *&Bucket = TheTable[BucketNo];
|
||||
if (Bucket && Bucket != getTombstoneVal())
|
||||
return std::make_pair(iterator(TheTable + BucketNo, false),
|
||||
false); // Already exists in map.
|
||||
|
||||
if (Bucket == getTombstoneVal())
|
||||
--NumTombstones;
|
||||
Bucket =
|
||||
MapEntryTy::create(Key, getAllocator(), std::forward<ArgsTy>(Args)...);
|
||||
++NumItems;
|
||||
assert(NumItems + NumTombstones <= NumBuckets);
|
||||
|
||||
BucketNo = RehashTable(BucketNo);
|
||||
return std::make_pair(iterator(TheTable + BucketNo, false), true);
|
||||
}
|
||||
|
||||
// clear - Empties out the StringMap
|
||||
void clear() {
|
||||
if (empty())
|
||||
return;
|
||||
|
||||
// Zap all values, resetting the keys back to non-present (not tombstone),
|
||||
// which is safe because we're removing all elements.
|
||||
for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
|
||||
StringMapEntryBase *&Bucket = TheTable[I];
|
||||
if (Bucket && Bucket != getTombstoneVal()) {
|
||||
static_cast<MapEntryTy *>(Bucket)->Destroy(getAllocator());
|
||||
}
|
||||
Bucket = nullptr;
|
||||
}
|
||||
|
||||
NumItems = 0;
|
||||
NumTombstones = 0;
|
||||
}
|
||||
|
||||
/// remove - Remove the specified key/value pair from the map, but do not
|
||||
/// erase it. This aborts if the key is not in the map.
|
||||
void remove(MapEntryTy *KeyValue) { RemoveKey(KeyValue); }
|
||||
|
||||
void erase(iterator I) {
|
||||
MapEntryTy &V = *I;
|
||||
remove(&V);
|
||||
V.Destroy(getAllocator());
|
||||
}
|
||||
|
||||
bool erase(std::string_view Key) {
|
||||
iterator I = find(Key);
|
||||
if (I == end())
|
||||
return false;
|
||||
erase(I);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename DerivedTy, typename ValueTy>
|
||||
class StringMapIterBase
|
||||
: public iterator_facade_base<DerivedTy, std::forward_iterator_tag,
|
||||
ValueTy> {
|
||||
protected:
|
||||
StringMapEntryBase **Ptr = nullptr;
|
||||
|
||||
public:
|
||||
StringMapIterBase() = default;
|
||||
|
||||
explicit StringMapIterBase(StringMapEntryBase **Bucket,
|
||||
bool NoAdvance = false)
|
||||
: Ptr(Bucket) {
|
||||
if (!NoAdvance)
|
||||
AdvancePastEmptyBuckets();
|
||||
}
|
||||
|
||||
DerivedTy &operator=(const DerivedTy &Other) {
|
||||
Ptr = Other.Ptr;
|
||||
return static_cast<DerivedTy &>(*this);
|
||||
}
|
||||
|
||||
friend bool operator==(const DerivedTy &LHS, const DerivedTy &RHS) {
|
||||
return LHS.Ptr == RHS.Ptr;
|
||||
}
|
||||
|
||||
DerivedTy &operator++() { // Preincrement
|
||||
++Ptr;
|
||||
AdvancePastEmptyBuckets();
|
||||
return static_cast<DerivedTy &>(*this);
|
||||
}
|
||||
|
||||
DerivedTy operator++(int) { // Post-increment
|
||||
DerivedTy Tmp(Ptr);
|
||||
++*this;
|
||||
return Tmp;
|
||||
}
|
||||
|
||||
DerivedTy &operator--() { // Predecrement
|
||||
--Ptr;
|
||||
ReversePastEmptyBuckets();
|
||||
return static_cast<DerivedTy &>(*this);
|
||||
}
|
||||
|
||||
DerivedTy operator--(int) { // Post-decrement
|
||||
DerivedTy Tmp(Ptr);
|
||||
--*this;
|
||||
return Tmp;
|
||||
}
|
||||
|
||||
private:
|
||||
void AdvancePastEmptyBuckets() {
|
||||
while (*Ptr == nullptr || *Ptr == StringMapImpl::getTombstoneVal())
|
||||
++Ptr;
|
||||
}
|
||||
void ReversePastEmptyBuckets() {
|
||||
while (*Ptr == nullptr || *Ptr == StringMapImpl::getTombstoneVal())
|
||||
--Ptr;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ValueTy>
|
||||
class StringMapConstIterator
|
||||
: public StringMapIterBase<StringMapConstIterator<ValueTy>,
|
||||
const StringMapEntry<ValueTy>> {
|
||||
using base = StringMapIterBase<StringMapConstIterator<ValueTy>,
|
||||
const StringMapEntry<ValueTy>>;
|
||||
|
||||
public:
|
||||
StringMapConstIterator() = default;
|
||||
explicit StringMapConstIterator(StringMapEntryBase **Bucket,
|
||||
bool NoAdvance = false)
|
||||
: base(Bucket, NoAdvance) {}
|
||||
|
||||
const StringMapEntry<ValueTy> &operator*() const {
|
||||
return *static_cast<const StringMapEntry<ValueTy> *>(*this->Ptr);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ValueTy>
|
||||
class StringMapIterator : public StringMapIterBase<StringMapIterator<ValueTy>,
|
||||
StringMapEntry<ValueTy>> {
|
||||
using base =
|
||||
StringMapIterBase<StringMapIterator<ValueTy>, StringMapEntry<ValueTy>>;
|
||||
|
||||
public:
|
||||
StringMapIterator() = default;
|
||||
explicit StringMapIterator(StringMapEntryBase **Bucket,
|
||||
bool NoAdvance = false)
|
||||
: base(Bucket, NoAdvance) {}
|
||||
|
||||
StringMapEntry<ValueTy> &operator*() const {
|
||||
return *static_cast<StringMapEntry<ValueTy> *>(*this->Ptr);
|
||||
}
|
||||
|
||||
operator StringMapConstIterator<ValueTy>() const {
|
||||
return StringMapConstIterator<ValueTy>(this->Ptr, true);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ValueTy>
|
||||
class StringMapKeyIterator
|
||||
: public iterator_adaptor_base<StringMapKeyIterator<ValueTy>,
|
||||
StringMapConstIterator<ValueTy>,
|
||||
std::forward_iterator_tag, std::string_view> {
|
||||
using base = iterator_adaptor_base<StringMapKeyIterator<ValueTy>,
|
||||
StringMapConstIterator<ValueTy>,
|
||||
std::forward_iterator_tag, std::string_view>;
|
||||
|
||||
public:
|
||||
StringMapKeyIterator() = default;
|
||||
explicit StringMapKeyIterator(StringMapConstIterator<ValueTy> Iter)
|
||||
: base(std::move(Iter)) {}
|
||||
|
||||
std::string_view operator*() const { return this->wrapped()->getKey(); }
|
||||
};
|
||||
|
||||
template <typename ValueTy>
|
||||
bool operator==(const StringMap<ValueTy>& lhs, const StringMap<ValueTy>& rhs) {
|
||||
// same instance?
|
||||
if (&lhs == &rhs) return true;
|
||||
|
||||
// first check that sizes are identical
|
||||
if (lhs.size() != rhs.size()) return false;
|
||||
|
||||
// copy into vectors and sort by key
|
||||
SmallVector<StringMapConstIterator<ValueTy>, 16> lhs_items;
|
||||
lhs_items.reserve(lhs.size());
|
||||
for (auto i = lhs.begin(), end = lhs.end(); i != end; ++i)
|
||||
lhs_items.push_back(i);
|
||||
std::sort(lhs_items.begin(), lhs_items.end(),
|
||||
[](const StringMapConstIterator<ValueTy>& a,
|
||||
const StringMapConstIterator<ValueTy>& b) {
|
||||
return a->getKey() < b->getKey();
|
||||
});
|
||||
|
||||
SmallVector<StringMapConstIterator<ValueTy>, 16> rhs_items;
|
||||
rhs_items.reserve(rhs.size());
|
||||
for (auto i = rhs.begin(), end = rhs.end(); i != end; ++i)
|
||||
rhs_items.push_back(i);
|
||||
std::sort(rhs_items.begin(), rhs_items.end(),
|
||||
[](const StringMapConstIterator<ValueTy>& a,
|
||||
const StringMapConstIterator<ValueTy>& b) {
|
||||
return a->getKey() < b->getKey();
|
||||
});
|
||||
|
||||
// compare vector keys and values
|
||||
for (auto a = lhs_items.begin(), b = rhs_items.begin(),
|
||||
aend = lhs_items.end(), bend = rhs_items.end();
|
||||
a != aend && b != bend; ++a, ++b) {
|
||||
if ((*a)->first() != (*b)->first() || (*a)->second != (*b)->second)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename ValueTy>
|
||||
inline bool operator!=(const StringMap<ValueTy>& lhs,
|
||||
const StringMap<ValueTy>& rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template <typename ValueTy>
|
||||
bool operator<(const StringMap<ValueTy>& lhs, const StringMap<ValueTy>& rhs) {
|
||||
// same instance?
|
||||
if (&lhs == &rhs) return false;
|
||||
|
||||
// copy into vectors and sort by key
|
||||
SmallVector<std::string_view, 16> lhs_keys;
|
||||
lhs_keys.reserve(lhs.size());
|
||||
for (auto i = lhs.begin(), end = lhs.end(); i != end; ++i)
|
||||
lhs_keys.push_back(i->getKey());
|
||||
std::sort(lhs_keys.begin(), lhs_keys.end());
|
||||
|
||||
SmallVector<std::string_view, 16> rhs_keys;
|
||||
rhs_keys.reserve(rhs.size());
|
||||
for (auto i = rhs.begin(), end = rhs.end(); i != end; ++i)
|
||||
rhs_keys.push_back(i->getKey());
|
||||
std::sort(rhs_keys.begin(), rhs_keys.end());
|
||||
|
||||
// use std::vector comparison
|
||||
return lhs_keys < rhs_keys;
|
||||
}
|
||||
|
||||
template <typename ValueTy>
|
||||
inline bool operator<=(const StringMap<ValueTy>& lhs,
|
||||
const StringMap<ValueTy>& rhs) {
|
||||
return !(rhs < lhs);
|
||||
}
|
||||
|
||||
template <typename ValueTy>
|
||||
inline bool operator>(const StringMap<ValueTy>& lhs,
|
||||
const StringMap<ValueTy>& rhs) {
|
||||
return !(lhs <= rhs);
|
||||
}
|
||||
|
||||
template <typename ValueTy>
|
||||
inline bool operator>=(const StringMap<ValueTy>& lhs,
|
||||
const StringMap<ValueTy>& rhs) {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_STRINGMAP_H
|
||||
@@ -1,187 +0,0 @@
|
||||
//===- StringMapEntry.h - String Hash table map interface -------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// This file defines the StringMapEntry class - it is intended to be a low
|
||||
/// dependency implementation detail of StringMap that is more suitable for
|
||||
/// inclusion in public headers than StringMap.h itself is.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_STRINGMAPENTRY_H
|
||||
#define WPIUTIL_WPI_STRINGMAPENTRY_H
|
||||
|
||||
#include "wpi/MemAlloc.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// StringMapEntryBase - Shared base class of StringMapEntry instances.
|
||||
class StringMapEntryBase {
|
||||
size_t keyLength;
|
||||
|
||||
public:
|
||||
explicit StringMapEntryBase(size_t keyLength) : keyLength(keyLength) {}
|
||||
|
||||
size_t getKeyLength() const { return keyLength; }
|
||||
|
||||
protected:
|
||||
/// Helper to tail-allocate \p Key. It'd be nice to generalize this so it
|
||||
/// could be reused elsewhere, maybe even taking an wpi::function_ref to
|
||||
/// type-erase the allocator and put it in a source file.
|
||||
template <typename AllocatorTy>
|
||||
static void *allocateWithKey(size_t EntrySize, size_t EntryAlign,
|
||||
std::string_view Key, AllocatorTy &Allocator);
|
||||
};
|
||||
|
||||
// Define out-of-line to dissuade inlining.
|
||||
template <typename AllocatorTy>
|
||||
void *StringMapEntryBase::allocateWithKey(size_t EntrySize, size_t EntryAlign,
|
||||
std::string_view Key,
|
||||
AllocatorTy &Allocator) {
|
||||
size_t KeyLength = Key.size();
|
||||
|
||||
// Allocate a new item with space for the string at the end and a null
|
||||
// terminator.
|
||||
size_t AllocSize = EntrySize + KeyLength + 1;
|
||||
void *Allocation = Allocator.Allocate(AllocSize, EntryAlign);
|
||||
assert(Allocation && "Unhandled out-of-memory");
|
||||
|
||||
// Copy the string information.
|
||||
char *Buffer = reinterpret_cast<char *>(Allocation) + EntrySize;
|
||||
if (KeyLength > 0)
|
||||
::memcpy(Buffer, Key.data(), KeyLength);
|
||||
Buffer[KeyLength] = 0; // Null terminate for convenience of clients.
|
||||
return Allocation;
|
||||
}
|
||||
|
||||
/// StringMapEntryStorage - Holds the value in a StringMapEntry.
|
||||
///
|
||||
/// Factored out into a separate base class to make it easier to specialize.
|
||||
/// This is primarily intended to support StringSet, which doesn't need a value
|
||||
/// stored at all.
|
||||
template <typename ValueTy>
|
||||
class StringMapEntryStorage : public StringMapEntryBase {
|
||||
public:
|
||||
ValueTy second;
|
||||
|
||||
explicit StringMapEntryStorage(size_t keyLength)
|
||||
: StringMapEntryBase(keyLength), second() {}
|
||||
template <typename... InitTy>
|
||||
StringMapEntryStorage(size_t keyLength, InitTy &&...initVals)
|
||||
: StringMapEntryBase(keyLength),
|
||||
second(std::forward<InitTy>(initVals)...) {}
|
||||
StringMapEntryStorage(StringMapEntryStorage &e) = delete;
|
||||
|
||||
const ValueTy &getValue() const { return second; }
|
||||
ValueTy &getValue() { return second; }
|
||||
|
||||
void setValue(const ValueTy &V) { second = V; }
|
||||
};
|
||||
|
||||
template <>
|
||||
class StringMapEntryStorage<std::nullopt_t> : public StringMapEntryBase {
|
||||
public:
|
||||
explicit StringMapEntryStorage(size_t keyLength,
|
||||
std::nullopt_t = std::nullopt)
|
||||
: StringMapEntryBase(keyLength) {}
|
||||
StringMapEntryStorage(StringMapEntryStorage &entry) = delete;
|
||||
|
||||
std::nullopt_t getValue() const { return std::nullopt; }
|
||||
};
|
||||
|
||||
/// StringMapEntry - This is used to represent one value that is inserted into
|
||||
/// a StringMap. It contains the Value itself and the key: the string length
|
||||
/// and data.
|
||||
template <typename ValueTy>
|
||||
class StringMapEntry final : public StringMapEntryStorage<ValueTy> {
|
||||
public:
|
||||
using StringMapEntryStorage<ValueTy>::StringMapEntryStorage;
|
||||
|
||||
using ValueType = ValueTy;
|
||||
|
||||
std::string_view getKey() const {
|
||||
return std::string_view(getKeyData(), this->getKeyLength());
|
||||
}
|
||||
|
||||
/// getKeyData - Return the start of the string data that is the key for this
|
||||
/// value. The string data is always stored immediately after the
|
||||
/// StringMapEntry object.
|
||||
const char *getKeyData() const {
|
||||
return reinterpret_cast<const char *>(this + 1);
|
||||
}
|
||||
|
||||
std::string_view first() const {
|
||||
return std::string_view(getKeyData(), this->getKeyLength());
|
||||
}
|
||||
|
||||
/// Create a StringMapEntry for the specified key construct the value using
|
||||
/// \p InitiVals.
|
||||
template <typename AllocatorTy, typename... InitTy>
|
||||
static StringMapEntry *create(std::string_view key, AllocatorTy &allocator,
|
||||
InitTy &&... initVals) {
|
||||
return new (StringMapEntryBase::allocateWithKey(
|
||||
sizeof(StringMapEntry), alignof(StringMapEntry), key, allocator))
|
||||
StringMapEntry(key.size(), std::forward<InitTy>(initVals)...);
|
||||
}
|
||||
|
||||
/// GetStringMapEntryFromKeyData - Given key data that is known to be embedded
|
||||
/// into a StringMapEntry, return the StringMapEntry itself.
|
||||
static StringMapEntry &GetStringMapEntryFromKeyData(const char *keyData) {
|
||||
char *ptr = const_cast<char *>(keyData) - sizeof(StringMapEntry<ValueTy>);
|
||||
return *reinterpret_cast<StringMapEntry *>(ptr);
|
||||
}
|
||||
|
||||
/// Destroy - Destroy this StringMapEntry, releasing memory back to the
|
||||
/// specified allocator.
|
||||
template <typename AllocatorTy> void Destroy(AllocatorTy &allocator) {
|
||||
// Free memory referenced by the item.
|
||||
size_t AllocSize = sizeof(StringMapEntry) + this->getKeyLength() + 1;
|
||||
this->~StringMapEntry();
|
||||
allocator.Deallocate(static_cast<void *>(this), AllocSize,
|
||||
alignof(StringMapEntry));
|
||||
}
|
||||
};
|
||||
|
||||
// Allow structured bindings on StringMapEntry.
|
||||
template <std::size_t Index, typename ValueTy>
|
||||
decltype(auto) get(const StringMapEntry<ValueTy> &E) {
|
||||
static_assert(Index < 2);
|
||||
if constexpr (Index == 0)
|
||||
return E.first();
|
||||
else
|
||||
return (E.second);
|
||||
}
|
||||
|
||||
// Allow structured bindings on StringMapEntry.
|
||||
template <std::size_t Index, typename ValueTy>
|
||||
decltype(auto) get(StringMapEntry<ValueTy> &E) {
|
||||
static_assert(Index < 2);
|
||||
if constexpr (Index == 0)
|
||||
return E.first();
|
||||
else
|
||||
return (E.second);
|
||||
}
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
namespace std {
|
||||
template <typename ValueTy>
|
||||
struct tuple_size<wpi::StringMapEntry<ValueTy>>
|
||||
: std::integral_constant<std::size_t, 2> {};
|
||||
|
||||
template <std::size_t I, typename ValueTy>
|
||||
struct tuple_element<I, wpi::StringMapEntry<ValueTy>>
|
||||
: std::conditional<I == 0, std::string_view, ValueTy> {};
|
||||
} // namespace std
|
||||
|
||||
#endif // WPIUTIL_WPI_STRINGMAPENTRY_H
|
||||
@@ -1,3 +1,7 @@
|
||||
// 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.
|
||||
|
||||
//===- llvm/unittest/ADT/StringMapMap.cpp - StringMap unit tests ----------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
@@ -6,27 +10,26 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/StringMap.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include "wpi/StringMap.h" // NOLINT(build/include_order)
|
||||
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
namespace {
|
||||
|
||||
static_assert(sizeof(StringMap<uint32_t>) <
|
||||
sizeof(StringMap<uint32_t, MallocAllocator &>),
|
||||
"Ensure empty base optimization happens with default allocator");
|
||||
|
||||
// Test fixture
|
||||
class StringMapTest : public testing::Test {
|
||||
protected:
|
||||
protected:
|
||||
StringMap<uint32_t> testMap;
|
||||
|
||||
static const char testKey[];
|
||||
static const uint32_t testValue;
|
||||
static const char *testKeyFirst;
|
||||
static const char* testKeyFirst;
|
||||
static size_t testKeyLength;
|
||||
static const std::string testKeyStr;
|
||||
|
||||
@@ -57,7 +60,7 @@ protected:
|
||||
|
||||
// Iterator tests
|
||||
StringMap<uint32_t>::iterator it = testMap.begin();
|
||||
EXPECT_STREQ(testKey, it->first().data());
|
||||
EXPECT_STREQ(testKey, it->first.data());
|
||||
EXPECT_EQ(testValue, it->second);
|
||||
++it;
|
||||
EXPECT_TRUE(it == testMap.end());
|
||||
@@ -76,26 +79,28 @@ protected:
|
||||
|
||||
const char StringMapTest::testKey[] = "key";
|
||||
const uint32_t StringMapTest::testValue = 1u;
|
||||
const char *StringMapTest::testKeyFirst = testKey;
|
||||
const char* StringMapTest::testKeyFirst = testKey;
|
||||
size_t StringMapTest::testKeyLength = sizeof(testKey) - 1;
|
||||
const std::string StringMapTest::testKeyStr(testKey);
|
||||
|
||||
struct CountCopyAndMove {
|
||||
CountCopyAndMove() = default;
|
||||
CountCopyAndMove(const CountCopyAndMove &) { copy = 1; }
|
||||
CountCopyAndMove(CountCopyAndMove &&) { move = 1; }
|
||||
void operator=(const CountCopyAndMove &) { ++copy; }
|
||||
void operator=(CountCopyAndMove &&) { ++move; }
|
||||
CountCopyAndMove(const CountCopyAndMove&) { copy = 1; }
|
||||
CountCopyAndMove(CountCopyAndMove&&) { move = 1; }
|
||||
void operator=(const CountCopyAndMove&) { ++copy; }
|
||||
void operator=(CountCopyAndMove&&) { ++move; }
|
||||
int copy = 0;
|
||||
int move = 0;
|
||||
};
|
||||
|
||||
// Empty map tests.
|
||||
TEST_F(StringMapTest, EmptyMapTest) { assertEmptyMap(); }
|
||||
TEST_F(StringMapTest, EmptyMap) {
|
||||
assertEmptyMap();
|
||||
}
|
||||
|
||||
// Constant map tests.
|
||||
TEST_F(StringMapTest, ConstEmptyMapTest) {
|
||||
const StringMap<uint32_t> &constTestMap = testMap;
|
||||
TEST_F(StringMapTest, ConstEmptyMap) {
|
||||
const StringMap<uint32_t>& constTestMap = testMap;
|
||||
|
||||
// Size tests
|
||||
EXPECT_EQ(0u, constTestMap.size());
|
||||
@@ -106,11 +111,12 @@ TEST_F(StringMapTest, ConstEmptyMapTest) {
|
||||
|
||||
// Lookup tests
|
||||
EXPECT_EQ(0u, constTestMap.count(testKey));
|
||||
EXPECT_EQ(0u, constTestMap.count(std::string_view(testKeyFirst, testKeyLength)));
|
||||
EXPECT_EQ(0u,
|
||||
constTestMap.count(std::string_view(testKeyFirst, testKeyLength)));
|
||||
EXPECT_EQ(0u, constTestMap.count(testKeyStr));
|
||||
EXPECT_TRUE(constTestMap.find(testKey) == constTestMap.end());
|
||||
EXPECT_TRUE(constTestMap.find(std::string_view(testKeyFirst, testKeyLength)) ==
|
||||
constTestMap.end());
|
||||
EXPECT_TRUE(constTestMap.find(std::string_view(
|
||||
testKeyFirst, testKeyLength)) == constTestMap.end());
|
||||
EXPECT_TRUE(constTestMap.find(testKeyStr) == constTestMap.end());
|
||||
}
|
||||
|
||||
@@ -122,63 +128,41 @@ TEST_F(StringMapTest, InitializerListCtor) {
|
||||
}
|
||||
|
||||
// A map with a single entry.
|
||||
TEST_F(StringMapTest, SingleEntryMapTest) {
|
||||
TEST_F(StringMapTest, SingleEntryMap) {
|
||||
testMap[testKey] = testValue;
|
||||
assertSingleItemMap();
|
||||
}
|
||||
|
||||
// Test clear() method.
|
||||
TEST_F(StringMapTest, ClearTest) {
|
||||
TEST_F(StringMapTest, Clear) {
|
||||
testMap[testKey] = testValue;
|
||||
testMap.clear();
|
||||
assertEmptyMap();
|
||||
}
|
||||
|
||||
// Test erase(iterator) method.
|
||||
TEST_F(StringMapTest, EraseIteratorTest) {
|
||||
TEST_F(StringMapTest, EraseIterator) {
|
||||
testMap[testKey] = testValue;
|
||||
testMap.erase(testMap.begin());
|
||||
assertEmptyMap();
|
||||
}
|
||||
|
||||
// Test erase(value) method.
|
||||
TEST_F(StringMapTest, EraseValueTest) {
|
||||
TEST_F(StringMapTest, EraseValue) {
|
||||
testMap[testKey] = testValue;
|
||||
testMap.erase(testKey);
|
||||
assertEmptyMap();
|
||||
}
|
||||
|
||||
// Test inserting two values and erasing one.
|
||||
TEST_F(StringMapTest, InsertAndEraseTest) {
|
||||
TEST_F(StringMapTest, InsertAndErase) {
|
||||
testMap[testKey] = testValue;
|
||||
testMap["otherKey"] = 2;
|
||||
testMap.erase("otherKey");
|
||||
assertSingleItemMap();
|
||||
}
|
||||
|
||||
TEST_F(StringMapTest, SmallFullMapTest) {
|
||||
// StringMap has a tricky corner case when the map is small (<8 buckets) and
|
||||
// it fills up through a balanced pattern of inserts and erases. This can
|
||||
// lead to inf-loops in some cases (PR13148) so we test it explicitly here.
|
||||
wpi::StringMap<int> Map(2);
|
||||
|
||||
Map["eins"] = 1;
|
||||
Map["zwei"] = 2;
|
||||
Map["drei"] = 3;
|
||||
Map.erase("drei");
|
||||
Map.erase("eins");
|
||||
Map["veir"] = 4;
|
||||
Map["funf"] = 5;
|
||||
|
||||
EXPECT_EQ(3u, Map.size());
|
||||
EXPECT_EQ(0, Map.lookup("eins"));
|
||||
EXPECT_EQ(2, Map.lookup("zwei"));
|
||||
EXPECT_EQ(0, Map.lookup("drei"));
|
||||
EXPECT_EQ(4, Map.lookup("veir"));
|
||||
EXPECT_EQ(5, Map.lookup("funf"));
|
||||
}
|
||||
|
||||
TEST_F(StringMapTest, CopyCtorTest) {
|
||||
TEST_F(StringMapTest, SmallFullMap) {
|
||||
wpi::StringMap<int> Map;
|
||||
|
||||
Map["eins"] = 1;
|
||||
@@ -190,22 +174,41 @@ TEST_F(StringMapTest, CopyCtorTest) {
|
||||
Map["funf"] = 5;
|
||||
|
||||
EXPECT_EQ(3u, Map.size());
|
||||
EXPECT_EQ(0, Map.lookup("eins"));
|
||||
EXPECT_EQ(2, Map.lookup("zwei"));
|
||||
EXPECT_EQ(0, Map.lookup("drei"));
|
||||
EXPECT_EQ(4, Map.lookup("veir"));
|
||||
EXPECT_EQ(5, Map.lookup("funf"));
|
||||
EXPECT_FALSE(Map.contains("eins"));
|
||||
EXPECT_EQ(2, Map["zwei"]);
|
||||
EXPECT_FALSE(Map.contains("drei"));
|
||||
EXPECT_EQ(4, Map["veir"]);
|
||||
EXPECT_EQ(5, Map["funf"]);
|
||||
}
|
||||
|
||||
TEST_F(StringMapTest, CopyCtor) {
|
||||
wpi::StringMap<int> Map;
|
||||
|
||||
Map["eins"] = 1;
|
||||
Map["zwei"] = 2;
|
||||
Map["drei"] = 3;
|
||||
Map.erase("drei");
|
||||
Map.erase("eins");
|
||||
Map["veir"] = 4;
|
||||
Map["funf"] = 5;
|
||||
|
||||
EXPECT_EQ(3u, Map.size());
|
||||
EXPECT_FALSE(Map.contains("eins"));
|
||||
EXPECT_EQ(2, Map["zwei"]);
|
||||
EXPECT_FALSE(Map.contains("drei"));
|
||||
EXPECT_EQ(4, Map["veir"]);
|
||||
EXPECT_EQ(5, Map["funf"]);
|
||||
|
||||
wpi::StringMap<int> Map2(Map);
|
||||
EXPECT_EQ(3u, Map2.size());
|
||||
EXPECT_EQ(0, Map2.lookup("eins"));
|
||||
EXPECT_EQ(2, Map2.lookup("zwei"));
|
||||
EXPECT_EQ(0, Map2.lookup("drei"));
|
||||
EXPECT_EQ(4, Map2.lookup("veir"));
|
||||
EXPECT_EQ(5, Map2.lookup("funf"));
|
||||
EXPECT_FALSE(Map2.contains("eins"));
|
||||
EXPECT_EQ(2, Map2["zwei"]);
|
||||
EXPECT_FALSE(Map2.contains("drei"));
|
||||
EXPECT_EQ(4, Map2["veir"]);
|
||||
EXPECT_EQ(5, Map2["funf"]);
|
||||
}
|
||||
|
||||
TEST_F(StringMapTest, AtTest) {
|
||||
TEST_F(StringMapTest, At) {
|
||||
wpi::StringMap<int> Map;
|
||||
|
||||
// keys both found and not found on non-empty map
|
||||
@@ -218,7 +221,7 @@ TEST_F(StringMapTest, AtTest) {
|
||||
}
|
||||
|
||||
// A more complex iteration test.
|
||||
TEST_F(StringMapTest, IterationTest) {
|
||||
TEST_F(StringMapTest, Iteration) {
|
||||
bool visited[100];
|
||||
|
||||
// Insert 100 numbers into the map
|
||||
@@ -234,7 +237,7 @@ TEST_F(StringMapTest, IterationTest) {
|
||||
++it) {
|
||||
std::stringstream ss;
|
||||
ss << "key_" << it->second;
|
||||
ASSERT_STREQ(ss.str().c_str(), it->first().data());
|
||||
ASSERT_STREQ(ss.str().c_str(), it->first.data());
|
||||
visited[it->second] = true;
|
||||
}
|
||||
|
||||
@@ -244,34 +247,23 @@ TEST_F(StringMapTest, IterationTest) {
|
||||
}
|
||||
}
|
||||
|
||||
// Test StringMapEntry::Create() method.
|
||||
TEST_F(StringMapTest, StringMapEntryTest) {
|
||||
MallocAllocator Allocator;
|
||||
StringMap<uint32_t>::value_type *entry =
|
||||
StringMap<uint32_t>::value_type::create(
|
||||
std::string_view(testKeyFirst, testKeyLength), Allocator, 1u);
|
||||
EXPECT_STREQ(testKey, entry->first().data());
|
||||
EXPECT_EQ(1u, entry->second);
|
||||
entry->Destroy(Allocator);
|
||||
}
|
||||
|
||||
// Test insert() method.
|
||||
TEST_F(StringMapTest, InsertTest) {
|
||||
TEST_F(StringMapTest, Insert) {
|
||||
SCOPED_TRACE("InsertTest");
|
||||
testMap.insert(StringMap<uint32_t>::value_type::create(
|
||||
std::string_view(testKeyFirst, testKeyLength), testMap.getAllocator(), 1u));
|
||||
testMap.insert(
|
||||
std::make_pair(std::string_view(testKeyFirst, testKeyLength), 1u));
|
||||
assertSingleItemMap();
|
||||
}
|
||||
|
||||
// Test insert(pair<K, V>) method
|
||||
TEST_F(StringMapTest, InsertPairTest) {
|
||||
TEST_F(StringMapTest, InsertPair) {
|
||||
bool Inserted;
|
||||
StringMap<uint32_t>::iterator NewIt;
|
||||
std::tie(NewIt, Inserted) =
|
||||
testMap.insert(std::make_pair(testKeyFirst, testValue));
|
||||
EXPECT_EQ(1u, testMap.size());
|
||||
EXPECT_EQ(testValue, testMap[testKeyFirst]);
|
||||
EXPECT_EQ(testKeyFirst, NewIt->first());
|
||||
EXPECT_EQ(testKeyFirst, NewIt->first);
|
||||
EXPECT_EQ(testValue, NewIt->second);
|
||||
EXPECT_TRUE(Inserted);
|
||||
|
||||
@@ -284,28 +276,12 @@ TEST_F(StringMapTest, InsertPairTest) {
|
||||
EXPECT_EQ(NewIt, ExistingIt);
|
||||
}
|
||||
|
||||
// Test insert(pair<K, V>) method when rehashing occurs
|
||||
TEST_F(StringMapTest, InsertRehashingPairTest) {
|
||||
// Check that the correct iterator is returned when the inserted element is
|
||||
// moved to a different bucket during internal rehashing. This depends on
|
||||
// the particular key, and the implementation of StringMap and HashString.
|
||||
// Changes to those might result in this test not actually checking that.
|
||||
StringMap<uint32_t> t(0);
|
||||
EXPECT_EQ(0u, t.getNumBuckets());
|
||||
|
||||
StringMap<uint32_t>::iterator It =
|
||||
t.insert(std::make_pair("abcdef", 42)).first;
|
||||
EXPECT_EQ(16u, t.getNumBuckets());
|
||||
EXPECT_EQ("abcdef", It->first());
|
||||
EXPECT_EQ(42u, It->second);
|
||||
}
|
||||
|
||||
TEST_F(StringMapTest, InsertOrAssignTest) {
|
||||
TEST_F(StringMapTest, InsertOrAssign) {
|
||||
struct A : CountCopyAndMove {
|
||||
A(int v) : v(v) {}
|
||||
explicit A(int v) : v(v) {}
|
||||
int v;
|
||||
};
|
||||
StringMap<A> t(0);
|
||||
StringMap<A> t;
|
||||
|
||||
auto try1 = t.insert_or_assign("A", A(1));
|
||||
EXPECT_TRUE(try1.second);
|
||||
@@ -321,23 +297,9 @@ TEST_F(StringMapTest, InsertOrAssignTest) {
|
||||
EXPECT_EQ(0, try1.first->second.copy);
|
||||
}
|
||||
|
||||
TEST_F(StringMapTest, IterMapKeysSmallVector) {
|
||||
StringMap<int> Map;
|
||||
Map["A"] = 1;
|
||||
Map["B"] = 2;
|
||||
Map["C"] = 3;
|
||||
Map["D"] = 3;
|
||||
|
||||
auto Keys = to_vector<4>(Map.keys());
|
||||
std::sort(Keys.begin(), Keys.end());
|
||||
|
||||
SmallVector<std::string_view, 4> Expected = {"A", "B", "C", "D"};
|
||||
EXPECT_EQ(Expected, Keys);
|
||||
}
|
||||
|
||||
// Create a non-default constructable value
|
||||
struct StringMapTestStruct {
|
||||
StringMapTestStruct(int i) : i(i) {}
|
||||
explicit StringMapTestStruct(int i) : i(i) {}
|
||||
StringMapTestStruct() = delete;
|
||||
int i;
|
||||
};
|
||||
@@ -352,39 +314,24 @@ TEST_F(StringMapTest, NonDefaultConstructable) {
|
||||
|
||||
struct Immovable {
|
||||
Immovable() {}
|
||||
Immovable(Immovable &&) = delete; // will disable the other special members
|
||||
Immovable(Immovable&&) = delete; // will disable the other special members
|
||||
};
|
||||
|
||||
struct MoveOnly {
|
||||
int i;
|
||||
MoveOnly(int i) : i(i) {}
|
||||
MoveOnly(const Immovable &) : i(0) {}
|
||||
MoveOnly(MoveOnly &&RHS) : i(RHS.i) {}
|
||||
MoveOnly &operator=(MoveOnly &&RHS) {
|
||||
explicit MoveOnly(int i) : i(i) {}
|
||||
explicit MoveOnly(const Immovable&) : i(0) {}
|
||||
MoveOnly(MoveOnly&& RHS) : i(RHS.i) {}
|
||||
MoveOnly& operator=(MoveOnly&& RHS) {
|
||||
i = RHS.i;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
MoveOnly(const MoveOnly &) = delete;
|
||||
MoveOnly &operator=(const MoveOnly &) = delete;
|
||||
private:
|
||||
MoveOnly(const MoveOnly&) = delete;
|
||||
MoveOnly& operator=(const MoveOnly&) = delete;
|
||||
};
|
||||
|
||||
TEST_F(StringMapTest, MoveOnly) {
|
||||
StringMap<MoveOnly> t;
|
||||
t.insert(std::make_pair("Test", MoveOnly(42)));
|
||||
std::string_view Key = "Test";
|
||||
StringMapEntry<MoveOnly>::create(Key, t.getAllocator(), MoveOnly(42))
|
||||
->Destroy(t.getAllocator());
|
||||
}
|
||||
|
||||
TEST_F(StringMapTest, CtorArg) {
|
||||
std::string_view Key = "Test";
|
||||
MallocAllocator Allocator;
|
||||
StringMapEntry<MoveOnly>::create(Key, Allocator, Immovable())
|
||||
->Destroy(Allocator);
|
||||
}
|
||||
|
||||
TEST_F(StringMapTest, MoveConstruct) {
|
||||
StringMap<int> A;
|
||||
A["x"] = 42;
|
||||
@@ -412,7 +359,7 @@ TEST_F(StringMapTest, EqualEmpty) {
|
||||
StringMap<int> B;
|
||||
ASSERT_TRUE(A == B);
|
||||
ASSERT_FALSE(A != B);
|
||||
ASSERT_TRUE(A == A); // self check
|
||||
ASSERT_TRUE(A == A); // self check
|
||||
}
|
||||
|
||||
TEST_F(StringMapTest, EqualWithValues) {
|
||||
@@ -432,7 +379,7 @@ TEST_F(StringMapTest, EqualWithValues) {
|
||||
ASSERT_TRUE(B == A);
|
||||
ASSERT_FALSE(A != B);
|
||||
ASSERT_FALSE(B != A);
|
||||
ASSERT_TRUE(A == A); // self check
|
||||
ASSERT_TRUE(A == A); // self check
|
||||
}
|
||||
|
||||
TEST_F(StringMapTest, NotEqualMissingKeys) {
|
||||
@@ -472,21 +419,21 @@ TEST_F(StringMapTest, NotEqualWithDifferentValues) {
|
||||
}
|
||||
|
||||
struct Countable {
|
||||
int &InstanceCount;
|
||||
int& InstanceCount;
|
||||
int Number;
|
||||
Countable(int Number, int &InstanceCount)
|
||||
Countable(int Number, int& InstanceCount)
|
||||
: InstanceCount(InstanceCount), Number(Number) {
|
||||
++InstanceCount;
|
||||
}
|
||||
Countable(Countable &&C) : InstanceCount(C.InstanceCount), Number(C.Number) {
|
||||
Countable(Countable&& C) : InstanceCount(C.InstanceCount), Number(C.Number) {
|
||||
++InstanceCount;
|
||||
C.Number = -1;
|
||||
}
|
||||
Countable(const Countable &C)
|
||||
Countable(const Countable& C)
|
||||
: InstanceCount(C.InstanceCount), Number(C.Number) {
|
||||
++InstanceCount;
|
||||
}
|
||||
Countable &operator=(Countable C) {
|
||||
Countable& operator=(Countable C) {
|
||||
Number = C.Number;
|
||||
return *this;
|
||||
}
|
||||
@@ -519,7 +466,7 @@ TEST_F(StringMapTest, StructuredBindings) {
|
||||
StringMap<int> A;
|
||||
A["a"] = 42;
|
||||
|
||||
for (auto &[Key, Value] : A) {
|
||||
for (auto& [Key, Value] : A) {
|
||||
EXPECT_EQ("a", Key);
|
||||
EXPECT_EQ(42, Value);
|
||||
}
|
||||
@@ -529,7 +476,7 @@ TEST_F(StringMapTest, StructuredBindingsMoveOnly) {
|
||||
StringMap<MoveOnly> A;
|
||||
A.insert(std::make_pair("a", MoveOnly(42)));
|
||||
|
||||
for (auto &&[Key, Value] : A) {
|
||||
for (auto&& [Key, Value] : A) {
|
||||
EXPECT_EQ("a", Key);
|
||||
EXPECT_EQ(42, Value.i);
|
||||
}
|
||||
@@ -542,16 +489,16 @@ struct CountCtorCopyAndMove {
|
||||
static unsigned Move;
|
||||
static unsigned Copy;
|
||||
int Data = 0;
|
||||
CountCtorCopyAndMove(int Data) : Data(Data) { Ctor++; }
|
||||
explicit CountCtorCopyAndMove(int Data) : Data(Data) { Ctor++; }
|
||||
CountCtorCopyAndMove() { Ctor++; }
|
||||
|
||||
CountCtorCopyAndMove(const CountCtorCopyAndMove &) { Copy++; }
|
||||
CountCtorCopyAndMove &operator=(const CountCtorCopyAndMove &) {
|
||||
CountCtorCopyAndMove(const CountCtorCopyAndMove&) { Copy++; }
|
||||
CountCtorCopyAndMove& operator=(const CountCtorCopyAndMove&) {
|
||||
Copy++;
|
||||
return *this;
|
||||
}
|
||||
CountCtorCopyAndMove(CountCtorCopyAndMove &&) { Move++; }
|
||||
CountCtorCopyAndMove &operator=(const CountCtorCopyAndMove &&) {
|
||||
CountCtorCopyAndMove(CountCtorCopyAndMove&&) { Move++; }
|
||||
CountCtorCopyAndMove& operator=(const CountCtorCopyAndMove&&) {
|
||||
Move++;
|
||||
return *this;
|
||||
}
|
||||
@@ -560,30 +507,7 @@ unsigned CountCtorCopyAndMove::Copy = 0;
|
||||
unsigned CountCtorCopyAndMove::Move = 0;
|
||||
unsigned CountCtorCopyAndMove::Ctor = 0;
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// Make sure creating the map with an initial size of N actually gives us enough
|
||||
// buckets to insert N items without increasing allocation size.
|
||||
TEST(StringMapCustomTest, InitialSizeTest) {
|
||||
// 1 is an "edge value", 32 is an arbitrary power of two, and 67 is an
|
||||
// arbitrary prime, picked without any good reason.
|
||||
for (auto Size : {1, 32, 67}) {
|
||||
StringMap<CountCtorCopyAndMove> Map(Size);
|
||||
auto NumBuckets = Map.getNumBuckets();
|
||||
CountCtorCopyAndMove::Move = 0;
|
||||
CountCtorCopyAndMove::Copy = 0;
|
||||
for (int i = 0; i < Size; ++i)
|
||||
Map.insert(std::pair<std::string, CountCtorCopyAndMove>(
|
||||
std::piecewise_construct, std::forward_as_tuple(std::to_string(i)),
|
||||
std::forward_as_tuple(i)));
|
||||
// After the initial move, the map will move the Elts in the Entry.
|
||||
EXPECT_EQ((unsigned)Size * 2, CountCtorCopyAndMove::Move);
|
||||
// We copy once the pair from the Elts vector
|
||||
EXPECT_EQ(0u, CountCtorCopyAndMove::Copy);
|
||||
// Check that the map didn't grow
|
||||
EXPECT_EQ(Map.getNumBuckets(), NumBuckets);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST(StringMapCustomTest, BracketOperatorCtor) {
|
||||
StringMap<CountCtorCopyAndMove> Map;
|
||||
@@ -600,57 +524,18 @@ namespace {
|
||||
struct NonMoveableNonCopyableType {
|
||||
int Data = 0;
|
||||
NonMoveableNonCopyableType() = default;
|
||||
NonMoveableNonCopyableType(int Data) : Data(Data) {}
|
||||
NonMoveableNonCopyableType(const NonMoveableNonCopyableType &) = delete;
|
||||
NonMoveableNonCopyableType(NonMoveableNonCopyableType &&) = delete;
|
||||
explicit NonMoveableNonCopyableType(int Data) : Data(Data) {}
|
||||
NonMoveableNonCopyableType(const NonMoveableNonCopyableType&) = delete;
|
||||
NonMoveableNonCopyableType(NonMoveableNonCopyableType&&) = delete;
|
||||
};
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
// Test that we can "emplace" an element in the map without involving map/move
|
||||
TEST(StringMapCustomTest, EmplaceTest) {
|
||||
TEST(StringMapCustomTest, Emplace) {
|
||||
StringMap<NonMoveableNonCopyableType> Map;
|
||||
Map.try_emplace("abcd", 42);
|
||||
EXPECT_EQ(1u, Map.count("abcd"));
|
||||
EXPECT_EQ(42, Map["abcd"].Data);
|
||||
}
|
||||
|
||||
// Test that StringMapEntryBase can handle size_t wide sizes.
|
||||
TEST(StringMapCustomTest, StringMapEntryBaseSize) {
|
||||
size_t LargeValue;
|
||||
|
||||
// Test that the entry can represent max-unsigned.
|
||||
if (sizeof(size_t) <= sizeof(unsigned))
|
||||
LargeValue = std::numeric_limits<unsigned>::max();
|
||||
else
|
||||
LargeValue = std::numeric_limits<unsigned>::max() + 1ULL;
|
||||
StringMapEntryBase LargeBase(LargeValue);
|
||||
EXPECT_EQ(LargeValue, LargeBase.getKeyLength());
|
||||
|
||||
// Test that the entry can hold at least max size_t.
|
||||
LargeValue = std::numeric_limits<size_t>::max();
|
||||
StringMapEntryBase LargerBase(LargeValue);
|
||||
LargeValue = std::numeric_limits<size_t>::max();
|
||||
EXPECT_EQ(LargeValue, LargerBase.getKeyLength());
|
||||
}
|
||||
|
||||
// Test that StringMapEntry can handle size_t wide sizes.
|
||||
TEST(StringMapCustomTest, StringMapEntrySize) {
|
||||
size_t LargeValue;
|
||||
|
||||
// Test that the entry can represent max-unsigned.
|
||||
if (sizeof(size_t) <= sizeof(unsigned))
|
||||
LargeValue = std::numeric_limits<unsigned>::max();
|
||||
else
|
||||
LargeValue = std::numeric_limits<unsigned>::max() + 1ULL;
|
||||
StringMapEntry<int> LargeEntry(LargeValue);
|
||||
std::string_view Key = LargeEntry.getKey();
|
||||
EXPECT_EQ(LargeValue, Key.size());
|
||||
|
||||
// Test that the entry can hold at least max size_t.
|
||||
LargeValue = std::numeric_limits<size_t>::max();
|
||||
StringMapEntry<int> LargerEntry(LargeValue);
|
||||
Key = LargerEntry.getKey();
|
||||
EXPECT_EQ(LargeValue, Key.size());
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
||||
} // namespace
|
||||
Reference in New Issue
Block a user