diff --git a/src/libs/utils/smallstring.h b/src/libs/utils/smallstring.h index 602197c9bf6..70ba55272f1 100644 --- a/src/libs/utils/smallstring.h +++ b/src/libs/utils/smallstring.h @@ -63,7 +63,8 @@ namespace Utils { -class SmallString +template +class BasicSmallString { public: using iterator = Internal::SmallStringIterator; @@ -72,25 +73,25 @@ public: using const_reverse_iterator = std::reverse_iterator; using size_type = std::size_t; - SmallString() noexcept - : m_data(Internal::StringDataLayout()) + BasicSmallString() noexcept + : m_data(Internal::StringDataLayout()) { } constexpr - SmallString(const SmallStringLiteral &stringReference) + BasicSmallString(const BasicSmallStringLiteral &stringReference) : m_data(stringReference.m_data) { } - template + template constexpr - SmallString(const char(&string)[Size]) + BasicSmallString(const char(&string)[ArraySize]) : m_data(string) { } - SmallString(const char *string, size_type size, size_type capacity) + BasicSmallString(const char *string, size_type size, size_type capacity) { if (Q_LIKELY(capacity <= shortStringCapacity())) { std::memcpy(m_data.shortString.string, string, size); @@ -110,62 +111,62 @@ public: } } - SmallString(const char *string, size_type size) - : SmallString(string, size, size) + BasicSmallString(const char *string, size_type size) + : BasicSmallString(string, size, size) { } template::value>::type > - SmallString(Type characterPointer) - : SmallString(characterPointer, std::strlen(characterPointer)) + BasicSmallString(Type characterPointer) + : BasicSmallString(characterPointer, std::strlen(characterPointer)) { static_assert(!std::is_array::value, "Input type is array and not char pointer!"); } - SmallString(const QString &qString) - : SmallString(SmallString::fromQString(qString)) + BasicSmallString(const QString &qString) + : BasicSmallString(BasicSmallString::fromQString(qString)) {} template::type, std::string>::value>::type> - SmallString(Type &&string) - : SmallString(string.data(), string.size()) + BasicSmallString(Type &&string) + : BasicSmallString(string.data(), string.size()) {} template::value>::type > - SmallString(BeginIterator begin, EndIterator end) - : SmallString(&(*begin), size_type(end - begin)) + BasicSmallString(BeginIterator begin, EndIterator end) + : BasicSmallString(&(*begin), size_type(end - begin)) { } - ~SmallString() noexcept + ~BasicSmallString() noexcept { if (Q_UNLIKELY(hasAllocatedMemory())) Memory::deallocate(m_data.allocated.data.pointer); } #if !defined(UNIT_TESTS) && !(defined(_MSC_VER) && _MSC_VER < 1900) - SmallString(const SmallString &other) = delete; - SmallString &operator=(const SmallString &other) = delete; + BasicSmallString(const BasicSmallString &other) = delete; + BasicSmallString &operator=(const BasicSmallString &other) = delete; #else - SmallString(const SmallString &string) + BasicSmallString(const BasicSmallString &string) { if (string.isShortString() || string.isReadOnlyReference()) m_data = string.m_data; else - new (this) SmallString{string.data(), string.size()}; + new (this) BasicSmallString{string.data(), string.size()}; } - SmallString &operator=(const SmallString &other) + BasicSmallString &operator=(const BasicSmallString &other) { - SmallString copy = other; + BasicSmallString copy = other; swap(*this, copy); @@ -173,31 +174,31 @@ public: } #endif - SmallString(SmallString &&other) noexcept + BasicSmallString(BasicSmallString &&other) noexcept { m_data = other.m_data; - other.m_data = Internal::StringDataLayout(); + other.m_data = Internal::StringDataLayout(); } - SmallString &operator=(SmallString &&other) noexcept + BasicSmallString &operator=(BasicSmallString &&other) noexcept { swap(*this, other); return *this; } - SmallString clone() const + BasicSmallString clone() const { - SmallString clonedString(m_data); + BasicSmallString clonedString(m_data); if (Q_UNLIKELY(hasAllocatedMemory())) - new (&clonedString) SmallString{m_data.allocated.data.pointer, m_data.allocated.data.size}; + new (&clonedString) BasicSmallString{m_data.allocated.data.pointer, m_data.allocated.data.size}; return clonedString; } friend - void swap(SmallString &first, SmallString &second) + void swap(BasicSmallString &first, BasicSmallString &second) { using std::swap; @@ -230,9 +231,9 @@ public: } static - SmallString fromUtf8(const char *characterPointer) + BasicSmallString fromUtf8(const char *characterPointer) { - return SmallString(characterPointer, std::strlen(characterPointer)); + return BasicSmallString(characterPointer, std::strlen(characterPointer)); } void reserve(size_type newCapacity) @@ -245,7 +246,7 @@ public: } else { const size_type oldSize = size(); - new (this) SmallString(data(), oldSize, newCapacity); + new (this) BasicSmallString(data(), oldSize, newCapacity); } } } @@ -259,8 +260,8 @@ public: void clear() noexcept { - this->~SmallString(); - m_data = Internal::StringDataLayout(); + this->~BasicSmallString(); + m_data = Internal::StringDataLayout(); } char *data() noexcept @@ -319,17 +320,17 @@ public: } static - SmallString fromQString(const QString &qString) + BasicSmallString fromQString(const QString &qString) { const QByteArray &utf8ByteArray = qString.toUtf8(); - return SmallString(utf8ByteArray.constData(), uint(utf8ByteArray.size())); + return BasicSmallString(utf8ByteArray.constData(), uint(utf8ByteArray.size())); } static - SmallString fromQByteArray(const QByteArray &utf8ByteArray) + BasicSmallString fromQByteArray(const QByteArray &utf8ByteArray) { - return SmallString(utf8ByteArray.constData(), uint(utf8ByteArray.size())); + return BasicSmallString(utf8ByteArray.constData(), uint(utf8ByteArray.size())); } bool contains(SmallStringView subStringToSearch) const @@ -426,7 +427,7 @@ public: setSize(newSize); } - SmallString &operator+=(SmallStringView string) + BasicSmallString &operator+=(SmallStringView string) { append(string); @@ -464,7 +465,7 @@ public: constexpr static size_type shortStringCapacity() noexcept { - return SmallStringLiteral::shortStringCapacity(); + return BasicSmallStringLiteral::shortStringCapacity(); } size_type optimalCapacity(const size_type size) @@ -481,16 +482,16 @@ public: } static - SmallString join(std::initializer_list list) + BasicSmallString join(std::initializer_list list) { size_type totalSize = 0; - for (const SmallString &string : list) + for (const BasicSmallString &string : list) totalSize += string.size(); - SmallString joinedString; + BasicSmallString joinedString; joinedString.reserve(totalSize); - for (const SmallString &string : list) + for (const BasicSmallString &string : list) joinedString.append(string); return joinedString; @@ -537,8 +538,105 @@ UNIT_TEST_PUBLIC: return cacheLineBlocks * cacheLineSize; } + template + friend bool operator==(const BasicSmallString& first, const char(&second)[ArraySize]) noexcept + { + return first == SmallStringView(second); + } + + template + friend bool operator==(const char(&first)[ArraySize], const BasicSmallString& second) noexcept + { + return second == first; + } + + template::value>::type + > + friend bool operator==(const BasicSmallString& first, Type second) noexcept + { + return first == SmallStringView(second); + } + + template::value>::type + > + friend bool operator==(Type first, const BasicSmallString& second) noexcept + { + return second == first; + } + + friend bool operator==(const BasicSmallString& first, const BasicSmallString& second) noexcept + { + return first.size() == second.size() + && std::memcmp(first.data(), second.data(), first.size()) == 0; + } + + friend bool operator==(const BasicSmallString& first, const SmallStringView& second) noexcept + { + return first.size() == second.size() + && std::memcmp(first.data(), second.data(), first.size()) == 0; + } + + friend bool operator==(const SmallStringView& first, const BasicSmallString& second) noexcept + { + return second == first; + } + + friend bool operator!=(const BasicSmallString& first, const SmallStringView& second) noexcept + { + return !(first == second); + } + + friend bool operator!=(const SmallStringView& first, const BasicSmallString& second) noexcept + { + return second == first; + } + + friend bool operator!=(const BasicSmallString& first, const BasicSmallString& second) noexcept + { + return !(first == second); + } + + template + friend bool operator!=(const BasicSmallString& first, const char(&second)[ArraySize]) noexcept + { + return !(first == second); + } + + template + friend bool operator!=(const char(&first)[ArraySize], const BasicSmallString& second) noexcept + { + return second != first; + } + + template::value>::type + > + friend bool operator!=(const BasicSmallString& first, Type second) noexcept + { + return !(first == second); + } + + template::value>::type + > + friend bool operator!=(Type first, const BasicSmallString& second) noexcept + { + return second != first; + } + + friend bool operator<(const BasicSmallString& first, const BasicSmallString& second) noexcept + { + size_type minimalSize = std::min(first.size(), second.size()); + + const int comparison = std::memcmp(first.data(), second.data(), minimalSize + 1); + + return comparison < 0; + } + private: - SmallString(Internal::StringDataLayout data) noexcept + BasicSmallString(Internal::StringDataLayout data) noexcept : m_data(data) { } @@ -677,113 +775,9 @@ private: } private: - Internal::StringDataLayout m_data; + Internal::StringDataLayout m_data; }; -template -bool operator==(const SmallString& first, const char(&second)[Size]) noexcept -{ - return first == SmallStringView(second); -} - -template -bool operator==(const char(&first)[Size], const SmallString& second) noexcept -{ - return second == first; -} - -template::value>::type - > -bool operator==(const SmallString& first, Type second) noexcept -{ - return first == SmallStringView(second); -} - -template::value>::type - > -bool operator==(Type first, const SmallString& second) noexcept -{ - return second == first; -} - -inline -bool operator==(const SmallString& first, const SmallString& second) noexcept -{ - return first.size() == second.size() - && std::memcmp(first.data(), second.data(), first.size()) == 0; -} - -inline -bool operator==(const SmallString& first, const SmallStringView& second) noexcept -{ - return first.size() == second.size() - && std::memcmp(first.data(), second.data(), first.size()) == 0; -} - -inline -bool operator==(const SmallStringView& first, const SmallString& second) noexcept -{ - return second == first; -} - -inline -bool operator!=(const SmallString& first, const SmallStringView& second) noexcept -{ - return !(first == second); -} - -inline -bool operator!=(const SmallStringView& first, const SmallString& second) noexcept -{ - return second == first; -} - -inline -bool operator!=(const SmallString& first, const SmallString& second) noexcept -{ - return !(first == second); -} - -template -bool operator!=(const SmallString& first, const char(&second)[Size]) noexcept -{ - return !(first == second); -} - -template -bool operator!=(const char(&first)[Size], const SmallString& second) noexcept -{ - return second != first; -} - -template::value>::type - > -bool operator!=(const SmallString& first, Type second) noexcept -{ - return !(first == second); -} - -template::value>::type - > -bool operator!=(Type first, const SmallString& second) noexcept -{ - return second != first; -} - -inline -bool operator<(const SmallString& first, const SmallString& second) noexcept -{ - SmallString::size_type minimalSize = std::min(first.size(), second.size()); - - const int comparison = std::memcmp(first.data(), second.data(), minimalSize + 1); - - return comparison < 0; -} - template, @@ -813,6 +807,8 @@ std::vector clone(const std::vector &vector) return clonedVector; } +using SmallString = BasicSmallString<31>; + } // namespace Utils #pragma pop_macro("noexcept") diff --git a/src/libs/utils/smallstringlayout.h b/src/libs/utils/smallstringlayout.h index e04b6d3b198..c03bdc4ad80 100644 --- a/src/libs/utils/smallstringlayout.h +++ b/src/libs/utils/smallstringlayout.h @@ -51,41 +51,44 @@ namespace Internal { using size_type = std::size_t; -static const int smallStringLayoutByteSize = 32; -static const int maximumShortStringDataAreaSize = smallStringLayoutByteSize - 1; - +template struct AllocatedLayout { struct Data { char *pointer; size_type size; size_type capacity; } data; - char dummy[maximumShortStringDataAreaSize - sizeof(Data)]; + char dummy[MaximumShortStringDataAreaSize - sizeof(Data)]; std::uint8_t shortStringSize: 6; std::uint8_t isReadOnlyReference : 1; std::uint8_t isReference : 1; }; +template struct ReferenceLayout { struct Data { const char *pointer; size_type size; size_type capacity; } data; - char dummy[maximumShortStringDataAreaSize - sizeof(Data)]; + char dummy[MaximumShortStringDataAreaSize - sizeof(Data)]; std::uint8_t shortStringSize: 6; std::uint8_t isReadOnlyReference : 1; std::uint8_t isReference : 1; }; +template struct ShortStringLayout { - char string[maximumShortStringDataAreaSize]; + char string[MaximumShortStringDataAreaSize]; std::uint8_t shortStringSize: 6; std::uint8_t isReadOnlyReference : 1; std::uint8_t isReference : 1; }; +template struct ALIGNAS_16 StringDataLayout { + static_assert( MaximumShortStringDataAreaSize >= 15, "Size must be greater equal than 15 bytes!"); + static_assert(((MaximumShortStringDataAreaSize + 1) % 16) == 0, "Size + 1 must be dividable by 16!"); StringDataLayout() noexcept = default; constexpr StringDataLayout(const char *string, @@ -101,7 +104,7 @@ struct ALIGNAS_16 StringDataLayout { #endif { #if __cpp_constexpr >= 201304 - if (Size <= maximumShortStringDataAreaSize) { + if (Size <= MaximumShortStringDataAreaSize) { for (size_type i = 0; i < Size; ++i) shortString.string[i] = string[i]; @@ -125,9 +128,9 @@ struct ALIGNAS_16 StringDataLayout { } union { - AllocatedLayout allocated; - ReferenceLayout reference; - ShortStringLayout shortString = ShortStringLayout(); + AllocatedLayout allocated; + ReferenceLayout reference; + ShortStringLayout shortString = ShortStringLayout(); }; }; diff --git a/src/libs/utils/smallstringliteral.h b/src/libs/utils/smallstringliteral.h index a4b505a56b5..fdd720e0b3c 100644 --- a/src/libs/utils/smallstringliteral.h +++ b/src/libs/utils/smallstringliteral.h @@ -41,27 +41,27 @@ namespace Utils { -class SmallString; - -class SmallStringLiteral +template +class BasicSmallStringLiteral { - friend class SmallString; + template + friend class BasicSmallString; public: using const_iterator = Internal::SmallStringIterator; using const_reverse_iterator = std::reverse_iterator; using size_type = std::size_t; - template + template constexpr - SmallStringLiteral(const char(&string)[Size]) noexcept + BasicSmallStringLiteral(const char(&string)[ArraySize]) noexcept : m_data(string) { - static_assert(Size >= 1, "Invalid string literal! Length is zero!"); + static_assert(ArraySize >= 1, "Invalid string literal! Length is zero!"); } constexpr - SmallStringLiteral(const char *string, const size_type size) noexcept + BasicSmallStringLiteral(const char *string, const size_type size) noexcept : m_data(string, size) { } @@ -99,7 +99,7 @@ public: constexpr static size_type shortStringCapacity() noexcept { - return sizeof(Internal::ShortStringLayout) - 2; + return sizeof(Internal::ShortStringLayout) - 2; } bool isShortString() const noexcept @@ -118,14 +118,16 @@ public: } private: - SmallStringLiteral(Internal::StringDataLayout data) noexcept + BasicSmallStringLiteral(Internal::StringDataLayout data) noexcept : m_data(data) { } private: - Internal::StringDataLayout m_data; + Internal::StringDataLayout m_data; }; +using SmallStringLiteral = BasicSmallStringLiteral<31>; + } // namespace Utils #pragma pop_macro("noexcept") diff --git a/src/libs/utils/smallstringvector.h b/src/libs/utils/smallstringvector.h index ca5ba201e52..d1405c3dc5b 100644 --- a/src/libs/utils/smallstringvector.h +++ b/src/libs/utils/smallstringvector.h @@ -40,100 +40,103 @@ namespace Utils { -class SmallStringVector : public std::vector +template +class BasicSmallStringVector : public std::vector> { + using SmallString =BasicSmallString; + using Base = std::vector; public: - SmallStringVector() = default; + BasicSmallStringVector() = default; - SmallStringVector(std::initializer_list list) + BasicSmallStringVector(std::initializer_list list) { - reserve(list.size()); + Base::reserve(list.size()); for (auto &&entry : list) - push_back(entry.clone()); + Base::push_back(entry.clone()); } - explicit SmallStringVector(const QStringList &stringList) + explicit BasicSmallStringVector(const QStringList &stringList) { - reserve(std::size_t(stringList.count())); + std::vector::reserve(std::size_t(stringList.count())); for (const QString &string : stringList) - push_back(Utils::SmallString::fromQString(string)); + Base::push_back(SmallString::fromQString(string)); } - explicit SmallStringVector(const std::vector &stringVector) + explicit BasicSmallStringVector(const std::vector &stringVector) { - reserve(std::size_t(stringVector.size())); + Base::reserve(std::size_t(stringVector.size())); for (const std::string &string : stringVector) - emplace_back(string); + Base::emplace_back(string); } #if !defined(UNIT_TESTS) && !(defined(_MSC_VER) && _MSC_VER < 1900) - SmallStringVector(const SmallStringVector &) = delete; - SmallStringVector &operator=(const SmallStringVector &) = delete; + BasicSmallStringVector(const BasicSmallStringVector &) = delete; + BasicSmallStringVector &operator=(const BasicSmallStringVector &) = delete; #else - SmallStringVector(const SmallStringVector &) = default; - SmallStringVector &operator=(const SmallStringVector &) = default; + BasicSmallStringVector(const BasicSmallStringVector &) = default; + BasicSmallStringVector &operator=(const BasicSmallStringVector &) = default; #endif #if !(defined(_MSC_VER) && _MSC_VER < 1900) - SmallStringVector(SmallStringVector &&) noexcept = default; - SmallStringVector &operator=(SmallStringVector &&) noexcept = default; + BasicSmallStringVector(BasicSmallStringVector &&) noexcept = default; + BasicSmallStringVector &operator=(BasicSmallStringVector &&) noexcept = default; #else - SmallStringVector(SmallStringVector &&other) - : std::vector(std::move(other)) + BasicSmallStringVector(BasicSmallStringVector &&other) + : Base(std::move(other)) { } - SmallStringVector &operator=(SmallStringVector &&other) + BasicSmallStringVector &operator=(BasicSmallStringVector &&other) { - std::vector(std::move(other)); + Base(std::move(other)); return *this; } #endif - Utils::SmallString join(Utils::SmallString &&separator) const + SmallString join(SmallString &&separator) const { - Utils::SmallString joinedString; + SmallString joinedString; - joinedString.reserve(totalByteSize() + separator.size() * std::size_t(size())); + joinedString.reserve(totalByteSize() + separator.size() * std::size_t(Base::size())); - for (auto stringIterator = begin(); stringIterator != end(); ++stringIterator) { + for (auto stringIterator = Base::begin(); stringIterator != Base::end(); ++stringIterator) { joinedString.append(*stringIterator); - if (std::next(stringIterator) != end()) + if (std::next(stringIterator) != Base::end()) joinedString.append(separator); } return joinedString; } - bool contains(const Utils::SmallString &string) const noexcept + bool contains(SmallStringView string) const noexcept { - return std::find(cbegin(), cend(), string) != cend(); + return std::find(Base::begin(), Base::end(), string) != Base::end(); } - bool removeFast(Utils::SmallStringView valueToBeRemoved) + bool removeFast(SmallStringView valueToBeRemoved) { - auto position = std::remove(begin(), end(), valueToBeRemoved); + auto position = std::remove(Base::begin(), Base::end(), valueToBeRemoved); - const bool hasEntry = position != end(); + const bool hasEntry = position != Base::end(); - erase(position, end()); + erase(position, Base::end()); return hasEntry; } - void append(Utils::SmallString &&string) + void append(SmallString &&string) { push_back(std::move(string)); } - SmallStringVector clone() const + BasicSmallStringVector clone() const { - SmallStringVector clonedVector; - clonedVector.reserve(size()); + BasicSmallStringVector clonedVector; + clonedVector.reserve(Base::size()); for (auto &&entry : *this) clonedVector.push_back(entry.clone()); @@ -143,7 +146,7 @@ public: operator std::vector() const { - return std::vector(begin(), end()); + return std::vector(Base::begin(), Base::end()); } private: @@ -158,6 +161,8 @@ private: } }; +using SmallStringVector = BasicSmallStringVector<31>; + } // namespace Utils; #pragma pop_macro("noexcept")