diff --git a/src/libs/utils/smallstring.h b/src/libs/utils/smallstring.h index 60de005dbc8..0d8ba6ae706 100644 --- a/src/libs/utils/smallstring.h +++ b/src/libs/utils/smallstring.h @@ -63,7 +63,7 @@ namespace Utils { template -class BasicSmallString +class alignas(16) BasicSmallString { public: using const_iterator = Internal::SmallStringIterator; @@ -97,14 +97,14 @@ public: BasicSmallString(const char *string, size_type size, size_type capacity) { if (Q_LIKELY(capacity <= shortStringCapacity())) { - std::char_traits::copy(m_data.shortString.string, string, size); - m_data.shortString.string[size] = 0; - m_data.shortString.control.setShortStringSize(size); - m_data.shortString.control.setIsShortString(true); - m_data.shortString.control.setIsReadOnlyReference(false); + std::char_traits::copy(m_data.shortString, string, size); + m_data.shortString[size] = 0; + m_data.control.setShortStringSize(size); + m_data.control.setIsShortString(true); + m_data.control.setIsReadOnlyReference(false); } else { - m_data.allocated.data.pointer = Memory::allocate(capacity + 1); - std::char_traits::copy(m_data.allocated.data.pointer, string, size); + m_data.reference.pointer = Memory::allocate(capacity + 1); + std::char_traits::copy(m_data.reference.pointer, string, size); initializeLongString(size, capacity); } } @@ -167,7 +167,7 @@ public: ~BasicSmallString() noexcept { if (Q_UNLIKELY(hasAllocatedMemory())) - Memory::deallocate(m_data.allocated.data.pointer); + Memory::deallocate(m_data.reference.pointer); } BasicSmallString(const BasicSmallString &other) @@ -182,7 +182,7 @@ public: { if (Q_LIKELY(this != &other)) { if (Q_UNLIKELY(hasAllocatedMemory())) - Memory::deallocate(m_data.allocated.data.pointer); + Memory::deallocate(m_data.reference.pointer); if (Q_LIKELY(other.isShortString() || other.isReadOnlyReference())) m_data = other.m_data; @@ -203,7 +203,7 @@ public: { if (Q_LIKELY(this != &other)) { if (Q_UNLIKELY(hasAllocatedMemory())) - Memory::deallocate(m_data.allocated.data.pointer); + Memory::deallocate(m_data.reference.pointer); m_data = std::move(other.m_data); other.m_data.reset(); @@ -218,9 +218,9 @@ public: BasicSmallString clonedString(m_data); if (Q_UNLIKELY(hasAllocatedMemory())) - new (&clonedString) BasicSmallString{m_data.allocated.data.pointer, - m_data.allocated.data.size, - m_data.allocated.data.capacity}; + new (&clonedString) BasicSmallString{m_data.reference.pointer, + m_data.reference.size, + m_data.reference.capacity}; return clonedString; } @@ -274,11 +274,11 @@ public: { if (fitsNotInCapacity(newCapacity)) { if (Q_UNLIKELY(hasAllocatedMemory())) { - m_data.allocated.data.pointer = Memory::reallocate(m_data.allocated.data.pointer, - newCapacity + 1); - m_data.allocated.data.capacity = newCapacity; + m_data.reference.pointer = Memory::reallocate(m_data.reference.pointer, + newCapacity + 1); + m_data.reference.capacity = newCapacity; } else if (newCapacity <= shortStringCapacity()) { - new (this) BasicSmallString{m_data.allocated.data.pointer, m_data.allocated.data.size}; + new (this) BasicSmallString{m_data.reference.pointer, m_data.reference.size}; } else { const size_type oldSize = size(); newCapacity = std::max(newCapacity, oldSize); @@ -286,7 +286,7 @@ public: char *newData = Memory::allocate(newCapacity + 1); std::char_traits::copy(newData, oldData, oldSize); - m_data.allocated.data.pointer = newData; + m_data.reference.pointer = newData; initializeLongString(oldSize, newCapacity); } } @@ -307,12 +307,12 @@ public: char *data() noexcept { - return Q_LIKELY(isShortString()) ? m_data.shortString.string : m_data.allocated.data.pointer; + return Q_LIKELY(isShortString()) ? m_data.shortString : m_data.reference.pointer; } const char *data() const noexcept { - return Q_LIKELY(isShortString()) ? m_data.shortString.string : m_data.allocated.data.pointer; + return Q_LIKELY(isShortString()) ? m_data.shortString : m_data.reference.pointer; } const char *constData() const noexcept @@ -442,15 +442,15 @@ public: size_type size() const noexcept { if (!isShortString()) - return m_data.allocated.data.size; + return m_data.reference.size; - return m_data.shortString.control.shortStringSize(); + return m_data.control.shortStringSize(); } size_type capacity() const noexcept { if (!isShortString()) - return m_data.allocated.data.capacity; + return m_data.reference.capacity; return shortStringCapacity(); } @@ -603,11 +603,7 @@ public: return size; } - constexpr - size_type shortStringSize() const - { - return m_data.shortString.control.shortStringSize(); - } + constexpr size_type shortStringSize() const { return m_data.control.shortStringSize(); } static BasicSmallString join(std::initializer_list list) @@ -721,13 +717,13 @@ unittest_public: constexpr bool isShortString() const noexcept { - return m_data.shortString.control.isShortString(); + return m_data.control.isShortString(); } constexpr bool isReadOnlyReference() const noexcept { - return m_data.shortString.control.isReadOnlyReference(); + return m_data.control.isReadOnlyReference(); } constexpr @@ -739,7 +735,7 @@ unittest_public: bool fitsNotInCapacity(size_type capacity) const noexcept { return (isShortString() && capacity > shortStringCapacity()) - || (!isShortString() && capacity > m_data.allocated.data.capacity); + || (!isShortString() && capacity > m_data.reference.capacity); } static @@ -802,12 +798,12 @@ private: constexpr void initializeLongString(size_type size, size_type capacity) { - m_data.allocated.data.pointer[size] = 0; - m_data.allocated.data.size = size; - m_data.allocated.data.capacity = capacity; - m_data.shortString.control.setShortStringSize(0); - m_data.shortString.control.setIsReference(true); - m_data.shortString.control.setIsReadOnlyReference(false); + m_data.reference.pointer[size] = 0; + m_data.reference.size = size; + m_data.reference.capacity = capacity; + m_data.control.setShortStringSize(0); + m_data.control.setIsReference(true); + m_data.control.setIsReadOnlyReference(false); } char &at(size_type index) @@ -945,9 +941,9 @@ private: void setSize(size_type size) { if (isShortString()) - m_data.shortString.control.setShortStringSize(size); + m_data.control.setShortStringSize(size); else - m_data.allocated.data.size = size; + m_data.reference.size = size; } private: diff --git a/src/libs/utils/smallstringlayout.h b/src/libs/utils/smallstringlayout.h index 7d6190528ef..c1de97e109f 100644 --- a/src/libs/utils/smallstringlayout.h +++ b/src/libs/utils/smallstringlayout.h @@ -96,56 +96,17 @@ private: ControlType m_isReference : 1; }; -template -struct alignas(16) AllocatedLayout -{ - struct Data - { +struct ReferenceLayout +{ union { + const char *constPointer; char *pointer; - size_type size; - size_type capacity; }; - - ControlBlock control; - Data data; -}; - -template -struct alignas(16) ReferenceLayout -{ - constexpr ReferenceLayout() noexcept = default; - constexpr ReferenceLayout(const char *stringPointer, - size_type size, - size_type capacity) noexcept - : control(0, true, true), - data{stringPointer, size, capacity} - {} - - struct Data - { - const char *pointer; - size_type size; - size_type capacity; - }; - - ControlBlock control; - Data data; -}; - -template -struct alignas(16) ShortStringLayout -{ - constexpr ShortStringLayout( - typename ControlBlock::SizeType shortStringSize) noexcept - : control(shortStringSize, false, false) - {} - - ControlBlock control; - char string[MaximumShortStringDataAreaSize]; + size_type size; + size_type capacity; }; template -struct StringDataLayout +struct alignas(16) StringDataLayout { static_assert(MaximumShortStringDataAreaSize >= 15, "Size must be greater equal than 15 bytes!"); static_assert(MaximumShortStringDataAreaSize < 32, "Size must be less than 32 bytes!"); @@ -156,17 +117,19 @@ struct StringDataLayout StringDataLayout() noexcept { reset(); } constexpr StringDataLayout(const char *string, size_type size) noexcept - : reference(string, size, 0) + : control{0, true, true} + , reference{{string}, size, 0} {} template constexpr StringDataLayout(const char (&string)[Size]) noexcept { if constexpr (Size <= MaximumShortStringDataAreaSize) { - shortString = {Size - 1}; + control = {Size - 1, false, false}; for (size_type i = 0; i < Size; ++i) - shortString.string[i] = string[i]; + shortString[i] = string[i]; } else { + control = {0, true, true}; reference = {string, Size - 1, 0}; } } @@ -178,20 +141,27 @@ struct StringDataLayout constexpr void reset() { - shortString.control = ControlBlock(); - shortString.string[0] = '\0'; + control = ControlBlock(); + shortString[0] = '\0'; } +#pragma pack(push) +#pragma pack(1) + ControlBlock control; union { - AllocatedLayout allocated; - ReferenceLayout reference; - ShortStringLayout shortString; + char shortString[MaximumShortStringDataAreaSize]; + struct + { + char dummy[sizeof(void *) - sizeof(ControlBlock)]; + ReferenceLayout reference; + }; }; +#pragma pack(pop) }; template -struct StringDataLayout= 32>> +struct alignas(16) StringDataLayout= 32>> { static_assert(MaximumShortStringDataAreaSize > 31, "Size must be greater than 31 bytes!"); static_assert(MaximumShortStringDataAreaSize < 64 @@ -203,17 +173,19 @@ struct StringDataLayout constexpr StringDataLayout(const char (&string)[Size]) noexcept { if constexpr (Size <= MaximumShortStringDataAreaSize) { - shortString = {Size - 1}; + control = {Size - 1, false, false}; for (size_type i = 0; i < Size; ++i) - shortString.string[i] = string[i]; + shortString[i] = string[i]; } else { + control = {0, true, true}; reference = {string, Size - 1, 0}; } } @@ -223,11 +195,9 @@ struct StringDataLayout); - auto shortStringLayoutSize = other.shortString.control.stringSize() + controlBlockSize; - constexpr auto referenceLayoutSize = sizeof(ReferenceLayout); - std::memcpy(&shortString, - &other.shortString, - std::max(shortStringLayoutSize, referenceLayoutSize)); + auto shortStringLayoutSize = other.control.stringSize() + controlBlockSize; + constexpr auto referenceLayoutSize = sizeof(ReferenceLayout); + std::memcpy(this, &other, std::max(shortStringLayoutSize, referenceLayoutSize)); return *this; } @@ -239,15 +209,22 @@ struct StringDataLayout(); - shortString.string[0] = '\0'; + control = ControlBlock(); + shortString[0] = '\0'; } +#pragma pack(push) +#pragma pack(1) + ControlBlock control; union { - AllocatedLayout allocated; - ReferenceLayout reference; - ShortStringLayout shortString; + char shortString[MaximumShortStringDataAreaSize]; + struct + { + char dummy[sizeof(void *) - sizeof(ControlBlock)]; + ReferenceLayout reference; + }; }; +#pragma pack(pop) }; } // namespace Internal diff --git a/src/libs/utils/smallstringliteral.h b/src/libs/utils/smallstringliteral.h index cf0c4953fb8..c29a7cf8f85 100644 --- a/src/libs/utils/smallstringliteral.h +++ b/src/libs/utils/smallstringliteral.h @@ -58,12 +58,12 @@ public: const char *data() const noexcept { - return Q_LIKELY(isShortString()) ? m_data.shortString.string : m_data.allocated.data.pointer; + return Q_LIKELY(isShortString()) ? m_data.shortString : m_data.reference.constPointer; } size_type size() const noexcept { - return Q_LIKELY(isShortString()) ? m_data.shortString.control.shortStringSize() : m_data.allocated.data.size; + return Q_LIKELY(isShortString()) ? m_data.control.shortStringSize() : m_data.reference.size; } constexpr @@ -94,16 +94,12 @@ public: return Internal::StringDataLayout::shortStringCapacity(); } - constexpr - bool isShortString() const noexcept - { - return m_data.shortString.control.isShortString(); - } + constexpr bool isShortString() const noexcept { return m_data.control.isShortString(); } constexpr bool isReadOnlyReference() const noexcept { - return m_data.shortString.control.isReadOnlyReference(); + return m_data.control.isReadOnlyReference(); } constexpr