From c70b8c71eea3599eed514fac90d77217003a171b Mon Sep 17 00:00:00 2001 From: "Duncan P. N. Exon Smith" Date: Thu, 28 Jan 2021 15:43:04 -0800 Subject: [PATCH] ADT: Sink the guts of StringMapEntry::Create into StringMapEntryBase Sink the interesting parts of StringMapEntry::Create into a new function StringMapEntryBase::allocateWithKey that's only templated on the allocator, taking the entry size and alignment as parameters. As dblaikie pointed out in the review, it'd be interesting as a follow-up to make this more generic and maybe sink at least some of it into a source file; I haven't done that yet myself, but I left behind an encouraging comment. Differential Revision: https://reviews.llvm.org/D95654 --- include/llvm/ADT/StringMapEntry.h | 52 +++++++++++++++++++------------ 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/include/llvm/ADT/StringMapEntry.h b/include/llvm/ADT/StringMapEntry.h index ea3aad6f1cb..079143d5051 100644 --- a/include/llvm/ADT/StringMapEntry.h +++ b/include/llvm/ADT/StringMapEntry.h @@ -27,8 +27,37 @@ 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 + static void *allocateWithKey(size_t EntrySize, size_t EntryAlign, + StringRef Key, AllocatorTy &Allocator); }; +// Define out-of-line to dissuade inlining. +template +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(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. @@ -90,26 +119,9 @@ public: template static StringMapEntry *Create(StringRef key, AllocatorTy &allocator, InitTy &&... initVals) { - size_t keyLength = key.size(); - - // Allocate a new item with space for the string at the end and a null - // terminator. - size_t allocSize = sizeof(StringMapEntry) + keyLength + 1; - size_t alignment = alignof(StringMapEntry); - - StringMapEntry *newItem = - static_cast(allocator.Allocate(allocSize, alignment)); - assert(newItem && "Unhandled out-of-memory"); - - // Construct the value. - new (newItem) StringMapEntry(keyLength, std::forward(initVals)...); - - // Copy the string information. - char *strBuffer = const_cast(newItem->getKeyData()); - if (keyLength > 0) - memcpy(strBuffer, key.data(), keyLength); - strBuffer[keyLength] = 0; // Null terminate for convenience of clients. - return newItem; + return new (StringMapEntryBase::allocateWithKey( + sizeof(StringMapEntry), alignof(StringMapEntry), key, allocator)) + StringMapEntry(key.size(), std::forward(initVals)...); } /// GetStringMapEntryFromKeyData - Given key data that is known to be embedded