| //===- 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 LLVM_ADT_STRINGMAPENTRY_H | |
| #define LLVM_ADT_STRINGMAPENTRY_H | |
| #include "llvm/ADT/StringRef.h" | |
| #include <optional> | |
| namespace llvm { | |
| /// 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 llvm::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, | |
| StringRef Key, AllocatorTy &Allocator); | |
| }; | |
| // Define out-of-line to dissuade inlining. | |
| template <typename AllocatorTy> | |
| void *StringMapEntryBase::allocateWithKey(size_t EntrySize, size_t EntryAlign, | |
| StringRef 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; | |
| StringRef getKey() const { | |
| return StringRef(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); | |
| } | |
| StringRef first() const { | |
| return StringRef(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) { | |
| 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; | |
| } | |
| } // end namespace llvm | |
| namespace std { | |
| template <typename ValueTy> | |
| struct tuple_size<llvm::StringMapEntry<ValueTy>> | |
| : std::integral_constant<std::size_t, 2> {}; | |
| template <std::size_t I, typename ValueTy> | |
| struct tuple_element<I, llvm::StringMapEntry<ValueTy>> | |
| : std::conditional<I == 0, llvm::StringRef, ValueTy> {}; | |
| } // namespace std | |
| #endif // LLVM_ADT_STRINGMAPENTRY_H |