diff options
author | Marco Bubke <marco.bubke@qt.io> | 2018-03-26 17:10:17 +0200 |
---|---|---|
committer | Marco Bubke <marco.bubke@qt.io> | 2018-04-04 13:34:20 +0000 |
commit | b6cb22899c1e221397649b635a3e07c191971b93 (patch) | |
tree | 2e02839c647fbc6cd3a2ccf629f4839b67c20f76 /src/libs/utils | |
parent | 0ecd5436148edc2c8f0ffb12a4acb633c525046c (diff) |
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 <ivan.donchevskii@qt.io>
Diffstat (limited to 'src/libs/utils')
-rw-r--r-- | src/libs/utils/smallstring.h | 28 | ||||
-rw-r--r-- | src/libs/utils/smallstringiterator.h | 9 | ||||
-rw-r--r-- | src/libs/utils/smallstringlayout.h | 176 | ||||
-rw-r--r-- | src/libs/utils/smallstringliteral.h | 8 | ||||
-rw-r--r-- | src/libs/utils/smallstringview.h | 6 |
5 files changed, 155 insertions, 72 deletions
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<Size>(); + 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<Category, Type, DistanceType, { return ++pointer_; } + SmallStringIterator operator++(int) noexcept { return pointer_++; @@ -121,16 +122,19 @@ struct SmallStringIterator : public std::iterator<Category, Type, DistanceType, return pointer_; } + constexpr bool operator==(SmallStringIterator other) const noexcept { return pointer_ == other.pointer_; } + constexpr bool operator!=(SmallStringIterator other) const noexcept { return pointer_ != other.pointer_; } + constexpr bool operator<(SmallStringIterator other) const noexcept { return pointer_ < other.pointer_; @@ -141,6 +145,11 @@ struct SmallStringIterator : public std::iterator<Category, Type, DistanceType, return pointer_; } + const Pointer data() const noexcept + { + return pointer_; + } + private: Pointer pointer_ = nullptr; }; diff --git a/src/libs/utils/smallstringlayout.h b/src/libs/utils/smallstringlayout.h index 3a93fe8805..5f1406951e 100644 --- a/src/libs/utils/smallstringlayout.h +++ b/src/libs/utils/smallstringlayout.h @@ -28,113 +28,162 @@ #include <QtGlobal> #include <cstdint> +#include <memory> #include <type_traits> -#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<bool Bool> -struct block_type +template <uint MaximumShortStringDataAreaSize, + typename ControlType = typename std::conditional_t<(MaximumShortStringDataAreaSize < 64), uint8_t, uint16_t>> +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<SizeType>(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<false> { - 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 <uint MaximumShortStringDataAreaSize, - typename BlockType = typename block_type<(MaximumShortStringDataAreaSize < 64)>::type> -struct AllocatedLayout { - struct Data { +template <uint MaximumShortStringDataAreaSize> +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<MaximumShortStringDataAreaSize> control; + Data data; }; -template <uint MaximumShortStringDataAreaSize, - typename BlockType = typename block_type<(MaximumShortStringDataAreaSize < 64)>::type> -struct ReferenceLayout { - struct Data { +template <uint MaximumShortStringDataAreaSize> +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<MaximumShortStringDataAreaSize> control; + Data data; }; -template <uint MaximumShortStringDataAreaSize, - typename BlockType = typename block_type<(MaximumShortStringDataAreaSize < 64)>::type> -struct ShortStringLayout { +template <uint MaximumShortStringDataAreaSize> +struct ShortStringLayout +{ + ControlBlock<MaximumShortStringDataAreaSize> control; char string[MaximumShortStringDataAreaSize]; - BlockType shortStringSize : (sizeof(BlockType) * 8) - 2; - BlockType isReadOnlyReference : 1; - BlockType isReference : 1; }; template <uint MaximumShortStringDataAreaSize> -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<size_type Size, typename std::enable_if_t<Size <= MaximumShortStringDataAreaSize, int> = 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<MaximumShortStringDataAreaSize>{}) -#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<size_type Size, typename std::enable_if_t<!(Size <= MaximumShortStringDataAreaSize), int> = 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<MaximumShortStringDataAreaSize>(); + shortString.string[0] = '\0'; + } + + StringDataLayout &operator=(const StringDataLayout &other) + { + this->shortString = other.shortString; + + return *this; + } + union { AllocatedLayout<MaximumShortStringDataAreaSize> allocated; ReferenceLayout<MaximumShortStringDataAreaSize> 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<Size>::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<typename String, typename Utils::enable_if_has_char_data_pointer<String> = 0> SmallStringView(const String &string) noexcept |