From b6cb22899c1e221397649b635a3e07c191971b93 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Mon, 26 Mar 2018 17:10:17 +0200 Subject: Utils: Improve SmallString The small string control block moved to the beginning, so it is more cache local. The control block is cleanup too, so it should be easier to read. The alignment is removed because it is creating to big holes. Change-Id: I401aeb9d55455cbaa5e722dd8192e54b525ddc40 Reviewed-by: Ivan Donchevskii --- src/libs/utils/smallstring.h | 28 +++--- src/libs/utils/smallstringiterator.h | 9 ++ src/libs/utils/smallstringlayout.h | 176 +++++++++++++++++++++++------------ src/libs/utils/smallstringliteral.h | 8 +- src/libs/utils/smallstringview.h | 6 ++ 5 files changed, 155 insertions(+), 72 deletions(-) (limited to 'src/libs/utils') diff --git a/src/libs/utils/smallstring.h b/src/libs/utils/smallstring.h index b945a0f2fe..e8827c3f7b 100644 --- a/src/libs/utils/smallstring.h +++ b/src/libs/utils/smallstring.h @@ -93,9 +93,9 @@ public: if (Q_LIKELY(capacity <= shortStringCapacity())) { std::memcpy(m_data.shortString.string, string, size); m_data.shortString.string[size] = 0; - m_data.shortString.shortStringSize = uchar(size); - m_data.shortString.isReference = false; - m_data.shortString.isReadOnlyReference = false; + m_data.shortString.control.setShortStringSize(size); + m_data.shortString.control.setIsShortString(true); + m_data.shortString.control.setIsReadOnlyReference(false); } else { m_data.allocated.data.pointer = Memory::allocate(capacity + 1); std::memcpy(m_data.allocated.data.pointer, string, size); @@ -178,7 +178,7 @@ public: BasicSmallString(BasicSmallString &&other) noexcept : m_data(other.m_data) { - other.m_data = Internal::StringDataLayout(); + other.m_data.reset(); } BasicSmallString &operator=(BasicSmallString &&other) noexcept @@ -413,7 +413,7 @@ public: if (!isShortString()) return m_data.allocated.data.size; - return m_data.shortString.shortStringSize; + return m_data.shortString.control.shortStringSize(); } size_type capacity() const noexcept @@ -532,9 +532,10 @@ public: return size; } + constexpr size_type shortStringSize() const { - return m_data.shortString.shortStringSize; + return m_data.shortString.control.shortStringSize(); } static @@ -628,16 +629,19 @@ public: } unittest_public: + constexpr bool isShortString() const noexcept { - return !m_data.shortString.isReference; + return m_data.shortString.control.isShortString(); } + constexpr bool isReadOnlyReference() const noexcept { - return m_data.shortString.isReadOnlyReference; + return m_data.shortString.control.isReadOnlyReference(); } + constexpr bool hasAllocatedMemory() const noexcept { return !isShortString() && !isReadOnlyReference(); @@ -712,9 +716,9 @@ private: m_data.allocated.data.pointer[size] = 0; m_data.allocated.data.size = size; m_data.allocated.data.capacity = capacity; - m_data.allocated.shortStringSize = 0; - m_data.allocated.isReference = true; - m_data.allocated.isReadOnlyReference = false; + m_data.shortString.control.setShortStringSize(0); + m_data.shortString.control.setIsReference(true); + m_data.shortString.control.setIsReadOnlyReference(false); } char &at(size_type index) @@ -852,7 +856,7 @@ private: void setSize(size_type size) { if (isShortString()) - m_data.shortString.shortStringSize = uchar(size); + m_data.shortString.control.setShortStringSize(size); else m_data.allocated.data.size = size; } diff --git a/src/libs/utils/smallstringiterator.h b/src/libs/utils/smallstringiterator.h index 1217e4bd2b..82836d78c4 100644 --- a/src/libs/utils/smallstringiterator.h +++ b/src/libs/utils/smallstringiterator.h @@ -51,6 +51,7 @@ struct SmallStringIterator : public std::iterator #include +#include #include -#if defined(Q_CC_MSVC) && !defined(_WIN64) -# define ALIGNAS_16 -#else -# define ALIGNAS_16 alignas(16) -#endif - namespace Utils { namespace Internal { using size_type = std::size_t; -template -struct block_type +template > +struct ControlBlock { - using type = uint8_t; -}; + using SizeType = ControlType; + constexpr ControlBlock() noexcept = default; + constexpr ControlBlock(ControlType shortStringSize, bool isReadOnlyReference, bool isReference) noexcept + : m_shortStringSize(shortStringSize), + m_isReadOnlyReference(isReadOnlyReference), + m_isReference(isReference) + {} + + void setShortStringSize(size_type size) + { + m_shortStringSize = static_cast(size); + } + + size_type shortStringSize() const + { + return m_shortStringSize; + } + + void setIsReadOnlyReference(bool isReadOnlyReference) + { + m_isReadOnlyReference = isReadOnlyReference; + } + + void setIsReference(bool isReference) + { + m_isReference = isReference; + } -template<> -struct block_type { - using type = uint16_t; + void setIsShortString(bool isShortString) + { + m_isReference = !isShortString; + } + + constexpr + SizeType stringSize() const + { + return m_shortStringSize; + } + + constexpr + bool isReadOnlyReference() const + { + return m_isReadOnlyReference; + } + + constexpr + bool isReference() const + { + return m_isReference; + } + + constexpr + bool isShortString() const + { + return !m_isReference; + } + +private: + ControlType m_shortStringSize : (sizeof(ControlType) * 8) - 2; + ControlType m_isReadOnlyReference : 1; + ControlType m_isReference : 1; }; -template ::type> -struct AllocatedLayout { - struct Data { +template +struct AllocatedLayout +{ + struct Data + { char *pointer; size_type size; size_type capacity; - } data; - char dummy[MaximumShortStringDataAreaSize - sizeof(Data)]; - BlockType shortStringSize : (sizeof(BlockType) * 8) - 2; - BlockType isReadOnlyReference : 1; - BlockType isReference : 1; + }; + + ControlBlock control; + Data data; }; -template ::type> -struct ReferenceLayout { - struct Data { +template +struct 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; - } data; - char dummy[MaximumShortStringDataAreaSize - sizeof(Data)]; - BlockType shortStringSize : (sizeof(BlockType) * 8) - 2; - BlockType isReadOnlyReference : 1; - BlockType isReference : 1; + }; + + ControlBlock control; + Data data; }; -template ::type> -struct ShortStringLayout { +template +struct ShortStringLayout +{ + ControlBlock control; char string[MaximumShortStringDataAreaSize]; - BlockType shortStringSize : (sizeof(BlockType) * 8) - 2; - BlockType isReadOnlyReference : 1; - BlockType isReference : 1; }; template -struct ALIGNAS_16 StringDataLayout { +struct StringDataLayout { static_assert(MaximumShortStringDataAreaSize >= 15, "Size must be greater equal than 15 bytes!"); static_assert(MaximumShortStringDataAreaSize < 64 ? ((MaximumShortStringDataAreaSize + 1) % 16) == 0 : ((MaximumShortStringDataAreaSize + 2) % 16) == 0, "Size + 1 must be dividable by 16 if under 64 and Size + 2 must be dividable by 16 if over 64!"); - constexpr StringDataLayout() noexcept = default; + constexpr + StringDataLayout() noexcept + { + reset(); + } constexpr StringDataLayout(const char *string, size_type size) noexcept - : reference({{string, size, 0}, {}, 0, true, true}) + : reference(string, size, 0) { } template = 0> - constexpr StringDataLayout(const char(&string)[Size]) noexcept -#if __cpp_constexpr < 201304 - : reference({{string, Size - 1, 0}, {}, 0, true, true}) -#else + StringDataLayout(const char(&string)[Size]) noexcept : shortString(ShortStringLayout{}) -#endif { -#if __cpp_constexpr >= 201304 for (size_type i = 0; i < Size; ++i) shortString.string[i] = string[i]; -#if defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Woverflow" - shortString.shortStringSize = std::uint8_t(Size) - 1; -#pragma GCC diagnostic pop -#endif - shortString.isReference = false; - shortString.isReadOnlyReference = false; - -#endif + shortString.control.setShortStringSize(Size - 1); + shortString.control.setIsShortString(true); + shortString.control.setIsReadOnlyReference(false); } template = 1> constexpr StringDataLayout(const char(&string)[Size]) noexcept - : reference({{string, Size - 1, 0}, {}, 0, true, true}) + : reference(string, Size - 1, 0) { } @@ -144,6 +193,19 @@ struct ALIGNAS_16 StringDataLayout { return MaximumShortStringDataAreaSize - 1; } + void reset() + { + shortString.control = ControlBlock(); + shortString.string[0] = '\0'; + } + + StringDataLayout &operator=(const StringDataLayout &other) + { + this->shortString = other.shortString; + + return *this; + } + union { AllocatedLayout allocated; ReferenceLayout reference; diff --git a/src/libs/utils/smallstringliteral.h b/src/libs/utils/smallstringliteral.h index eedcf45d13..cf0c4953fb 100644 --- a/src/libs/utils/smallstringliteral.h +++ b/src/libs/utils/smallstringliteral.h @@ -63,7 +63,7 @@ public: size_type size() const noexcept { - return Q_LIKELY(isShortString()) ? m_data.shortString.shortStringSize : m_data.allocated.data.size; + return Q_LIKELY(isShortString()) ? m_data.shortString.control.shortStringSize() : m_data.allocated.data.size; } constexpr @@ -94,14 +94,16 @@ public: return Internal::StringDataLayout::shortStringCapacity(); } + constexpr bool isShortString() const noexcept { - return !m_data.shortString.isReference; + return m_data.shortString.control.isShortString(); } + constexpr bool isReadOnlyReference() const noexcept { - return m_data.shortString.isReadOnlyReference; + return m_data.shortString.control.isReadOnlyReference(); } constexpr diff --git a/src/libs/utils/smallstringview.h b/src/libs/utils/smallstringview.h index 4932a85cb4..0d8600e5de 100644 --- a/src/libs/utils/smallstringview.h +++ b/src/libs/utils/smallstringview.h @@ -79,6 +79,12 @@ public: { } + SmallStringView(const const_iterator begin, const const_iterator end) noexcept + : m_pointer(begin.data()), + m_size(std::size_t(end - begin)) + { + } + template = 0> SmallStringView(const String &string) noexcept -- cgit v1.2.3