Utils: Modernize SmallString

Use more C++ api and constexpr. With C++ 17 we can use even more.

Change-Id: I33934cd7e087c311bf98501442df848bdb108279
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Marco Bubke
2020-05-22 19:05:45 +02:00
parent 64cbffe959
commit 0b3d03121f
5 changed files with 118 additions and 165 deletions

View File

@@ -90,39 +90,35 @@ public:
constexpr constexpr
BasicSmallString(const char(&string)[ArraySize]) BasicSmallString(const char(&string)[ArraySize])
: m_data(string) : m_data(string)
{ {}
}
BasicSmallString(const char *string, size_type size, size_type capacity) BasicSmallString(const char *string, size_type size, size_type capacity)
{ {
if (Q_LIKELY(capacity <= shortStringCapacity())) { if (Q_LIKELY(capacity <= shortStringCapacity())) {
std::memcpy(m_data.shortString.string, string, size); std::char_traits<char>::copy(m_data.shortString.string, string, size);
m_data.shortString.string[size] = 0; m_data.shortString.string[size] = 0;
m_data.shortString.control.setShortStringSize(size); m_data.shortString.control.setShortStringSize(size);
m_data.shortString.control.setIsShortString(true); m_data.shortString.control.setIsShortString(true);
m_data.shortString.control.setIsReadOnlyReference(false); m_data.shortString.control.setIsReadOnlyReference(false);
} else { } else {
m_data.allocated.data.pointer = Memory::allocate(capacity + 1); m_data.allocated.data.pointer = Memory::allocate(capacity + 1);
std::memcpy(m_data.allocated.data.pointer, string, size); std::char_traits<char>::copy(m_data.allocated.data.pointer, string, size);
initializeLongString(size, capacity); initializeLongString(size, capacity);
} }
} }
explicit BasicSmallString(SmallStringView stringView) explicit BasicSmallString(SmallStringView stringView)
: BasicSmallString(stringView.data(), stringView.size(), stringView.size()) : BasicSmallString(stringView.data(), stringView.size(), stringView.size())
{ {}
}
BasicSmallString(const char *string, size_type size) BasicSmallString(const char *string, size_type size)
: BasicSmallString(string, size, size) : BasicSmallString(string, size, size)
{ {
} }
template<typename Type, template<typename Type, typename = std::enable_if_t<std::is_pointer<Type>::value>>
typename = std::enable_if_t<std::is_pointer<Type>::value>
>
BasicSmallString(Type characterPointer) BasicSmallString(Type characterPointer)
: BasicSmallString(characterPointer, std::strlen(characterPointer)) : BasicSmallString(characterPointer, std::char_traits<char>::length(characterPointer))
{ {
static_assert(!std::is_array<Type>::value, "Input type is array and not char pointer!"); static_assert(!std::is_array<Type>::value, "Input type is array and not char pointer!");
} }
@@ -253,7 +249,7 @@ public:
static static
BasicSmallString fromUtf8(const char *characterPointer) BasicSmallString fromUtf8(const char *characterPointer)
{ {
return BasicSmallString(characterPointer, std::strlen(characterPointer)); return BasicSmallString(characterPointer, std::char_traits<char>::length(characterPointer));
} }
void reserve(size_type newCapacity) void reserve(size_type newCapacity)
@@ -271,7 +267,7 @@ public:
const char *oldData = data(); const char *oldData = data();
char *newData = Memory::allocate(newCapacity + 1); char *newData = Memory::allocate(newCapacity + 1);
std::memcpy(newData, oldData, oldSize); std::char_traits<char>::copy(newData, oldData, oldSize);
m_data.allocated.data.pointer = newData; m_data.allocated.data.pointer = newData;
initializeLongString(oldSize, newCapacity); initializeLongString(oldSize, newCapacity);
} }
@@ -380,7 +376,7 @@ public:
bool contains(char characterToSearch) const bool contains(char characterToSearch) const
{ {
auto found = std::memchr(data(), characterToSearch, size()); auto found = std::char_traits<char>::find(data(), size(), characterToSearch);
return found != nullptr; return found != nullptr;
} }
@@ -388,7 +384,9 @@ public:
bool startsWith(SmallStringView subStringToSearch) const noexcept bool startsWith(SmallStringView subStringToSearch) const noexcept
{ {
if (size() >= subStringToSearch.size()) if (size() >= subStringToSearch.size())
return !std::memcmp(data(), subStringToSearch.data(), subStringToSearch.size()); return !std::char_traits<char>::compare(data(),
subStringToSearch.data(),
subStringToSearch.size());
return false; return false;
} }
@@ -401,7 +399,8 @@ public:
bool endsWith(SmallStringView subStringToSearch) const noexcept bool endsWith(SmallStringView subStringToSearch) const noexcept
{ {
if (size() >= subStringToSearch.size()) { if (size() >= subStringToSearch.size()) {
const int comparison = std::memcmp(end().data() - subStringToSearch.size(), const int comparison = std::char_traits<char>::compare(end().data()
- subStringToSearch.size(),
subStringToSearch.data(), subStringToSearch.data(),
subStringToSearch.size()); subStringToSearch.size());
return comparison == 0; return comparison == 0;
@@ -462,7 +461,7 @@ public:
size_type newSize = oldSize + string.size(); size_type newSize = oldSize + string.size();
reserve(optimalCapacity(newSize)); reserve(optimalCapacity(newSize));
std::memcpy(data() + oldSize, string.data(), string.size()); std::char_traits<char>::copy(data() + oldSize, string.data(), string.size());
at(newSize) = 0; at(newSize) = 0;
setSize(newSize); setSize(newSize);
} }
@@ -724,7 +723,7 @@ private:
at(size) = 0; at(size) = 0;
} }
void initializeLongString(size_type size, size_type capacity) constexpr void initializeLongString(size_type size, size_type capacity)
{ {
m_data.allocated.data.pointer[size] = 0; m_data.allocated.data.pointer[size] = 0;
m_data.allocated.data.size = size; m_data.allocated.data.size = size;
@@ -757,7 +756,7 @@ private:
while (found != end()) { while (found != end()) {
start = found + toText.size(); start = found + toText.size();
std::memcpy(found.data(), toText.data(), toText.size()); std::char_traits<char>::copy(found.data(), toText.data(), toText.size());
found = std::search(start, found = std::search(start,
end(), end(),

View File

@@ -25,6 +25,18 @@
#pragma once #pragma once
#if __cplusplus >= 201703L
#define constexpr17 constexpr
#else
#define constexpr17 inline
#endif
#if __cplusplus >= 202002L
#define constexpr20 constexpr
#else
#define constexpr20 inline
#endif
using uint = unsigned int; using uint = unsigned int;
namespace Utils { namespace Utils {
@@ -35,9 +47,4 @@ class BasicSmallString;
using SmallString = BasicSmallString<31>; using SmallString = BasicSmallString<31>;
using PathString = BasicSmallString<190>; using PathString = BasicSmallString<190>;
inline
int compare(SmallStringView first, SmallStringView second) noexcept;
inline
int reverseCompare(SmallStringView first, SmallStringView second) noexcept;
} // namespace Utils } // namespace Utils

View File

@@ -37,118 +37,89 @@ template <class Category,
typename DistanceType = ptrdiff_t, typename DistanceType = ptrdiff_t,
typename Pointer = Type *, typename Pointer = Type *,
typename Reference = Type &> typename Reference = Type &>
struct SmallStringIterator : public std::iterator<Category, Type, DistanceType, Pointer, Reference> struct SmallStringIterator
{ {
constexpr using iterator_category = Category;
SmallStringIterator() noexcept = default; using value_type = Type;
using difference_type = DistanceType;
using pointer = Pointer;
using reference = Reference;
constexpr constexpr SmallStringIterator() noexcept = default;
SmallStringIterator(Pointer ptr) noexcept : pointer_(ptr)
{
}
SmallStringIterator operator++() noexcept constexpr SmallStringIterator(Pointer ptr) noexcept
{ : pointer_(ptr)
return ++pointer_; {}
}
SmallStringIterator operator++(int) noexcept constexpr SmallStringIterator operator++() noexcept { return ++pointer_; }
{
return pointer_++;
}
SmallStringIterator operator--() noexcept constexpr SmallStringIterator operator++(int) noexcept { return pointer_++; }
{
return --pointer_;
}
SmallStringIterator operator--(int) noexcept constexpr SmallStringIterator operator--() noexcept { return --pointer_; }
{
return pointer_--;
}
SmallStringIterator operator+(DistanceType difference) const noexcept constexpr SmallStringIterator operator--(int) noexcept { return pointer_--; }
constexpr SmallStringIterator operator+(DistanceType difference) const noexcept
{ {
return pointer_ + difference; return pointer_ + difference;
} }
SmallStringIterator operator-(DistanceType difference) const noexcept constexpr SmallStringIterator operator-(DistanceType difference) const noexcept
{ {
return pointer_ - difference; return pointer_ - difference;
} }
SmallStringIterator operator+(std::size_t difference) const noexcept constexpr SmallStringIterator operator+(std::size_t difference) const noexcept
{ {
return pointer_ + difference; return pointer_ + difference;
} }
SmallStringIterator operator-(std::size_t difference) const noexcept constexpr SmallStringIterator operator-(std::size_t difference) const noexcept
{ {
return pointer_ - difference; return pointer_ - difference;
} }
DistanceType operator-(SmallStringIterator other) const noexcept constexpr DistanceType operator-(SmallStringIterator other) const noexcept
{ {
return pointer_ - other.data(); return pointer_ - other.data();
} }
SmallStringIterator operator+=(DistanceType difference) noexcept constexpr SmallStringIterator operator+=(DistanceType difference) noexcept
{ {
return pointer_ += difference; return pointer_ += difference;
} }
SmallStringIterator operator-=(DistanceType difference) noexcept constexpr SmallStringIterator operator-=(DistanceType difference) noexcept
{ {
return pointer_ -= difference; return pointer_ -= difference;
} }
Reference operator*() noexcept constexpr Reference operator*() noexcept { return *pointer_; }
{
return *pointer_;
}
const Reference operator*() const noexcept const Reference operator*() const noexcept { return *pointer_; }
{
return *pointer_;
}
Pointer operator->() noexcept constexpr Pointer operator->() noexcept { return pointer_; }
{
return pointer_;
}
const Pointer operator->() const noexcept constexpr const Pointer operator->() const noexcept { return pointer_; }
{
return pointer_;
}
constexpr constexpr bool operator==(SmallStringIterator other) const noexcept
bool operator==(SmallStringIterator other) const noexcept
{ {
return pointer_ == other.pointer_; return pointer_ == other.pointer_;
} }
constexpr constexpr bool operator!=(SmallStringIterator other) const noexcept
bool operator!=(SmallStringIterator other) const noexcept
{ {
return pointer_ != other.pointer_; return pointer_ != other.pointer_;
} }
constexpr constexpr bool operator<(SmallStringIterator other) const noexcept
bool operator<(SmallStringIterator other) const noexcept
{ {
return pointer_ < other.pointer_; return pointer_ < other.pointer_;
} }
Pointer data() noexcept constexpr Pointer data() noexcept { return pointer_; }
{
return pointer_;
}
const Pointer data() const noexcept constexpr const Pointer data() const noexcept { return pointer_; }
{
return pointer_;
}
private: private:
Pointer pointer_ = nullptr; Pointer pointer_ = nullptr;

View File

@@ -49,30 +49,21 @@ struct ControlBlock
m_isReference(isReference) m_isReference(isReference)
{} {}
void setShortStringSize(size_type size) constexpr void setShortStringSize(size_type size)
{ {
m_shortStringSize = static_cast<SizeType>(size); m_shortStringSize = static_cast<SizeType>(size);
} }
size_type shortStringSize() const constexpr size_type shortStringSize() const { return m_shortStringSize; }
{
return m_shortStringSize;
}
void setIsReadOnlyReference(bool isReadOnlyReference) constexpr void setIsReadOnlyReference(bool isReadOnlyReference)
{ {
m_isReadOnlyReference = isReadOnlyReference; m_isReadOnlyReference = isReadOnlyReference;
} }
void setIsReference(bool isReference) constexpr void setIsReference(bool isReference) { m_isReference = isReference; }
{
m_isReference = isReference;
}
void setIsShortString(bool isShortString) constexpr void setIsShortString(bool isShortString) { m_isReference = !isShortString; }
{
m_isReference = !isShortString;
}
constexpr constexpr
SizeType stringSize() const SizeType stringSize() const
@@ -168,7 +159,7 @@ struct StringDataLayout {
template<size_type Size, template<size_type Size,
typename std::enable_if_t<Size <= MaximumShortStringDataAreaSize, int> = 0> typename std::enable_if_t<Size <= MaximumShortStringDataAreaSize, int> = 0>
StringDataLayout(const char(&string)[Size]) noexcept constexpr StringDataLayout(const char (&string)[Size]) noexcept
: shortString(ShortStringLayout<MaximumShortStringDataAreaSize>{}) : shortString(ShortStringLayout<MaximumShortStringDataAreaSize>{})
{ {
for (size_type i = 0; i < Size; ++i) for (size_type i = 0; i < Size; ++i)

View File

@@ -25,6 +25,7 @@
#pragma once #pragma once
#include "smallstringfwd.h"
#include "smallstringiterator.h" #include "smallstringiterator.h"
#include <QString> #include <QString>
@@ -53,36 +54,32 @@ public:
constexpr SmallStringView() = default; constexpr SmallStringView() = default;
SmallStringView(const char *characterPointer) noexcept constexpr17 SmallStringView(const char *characterPointer) noexcept
: m_pointer(characterPointer) : m_pointer(characterPointer)
, m_size(std::strlen(characterPointer)) , m_size(std::char_traits<char>::length(characterPointer))
{
}
constexpr
SmallStringView(const char *const string, const size_type size) noexcept
: m_pointer(string),
m_size(size)
{
}
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
: m_pointer(string.data()),
m_size(string.size())
{} {}
static constexpr SmallStringView(const char *const string, const size_type size) noexcept
SmallStringView fromUtf8(const char *const characterPointer) : m_pointer(string)
, m_size(size)
{ {
return SmallStringView(characterPointer, std::strlen(characterPointer)); }
constexpr 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>
constexpr SmallStringView(const String &string) noexcept
: m_pointer(string.data())
, m_size(string.size())
{}
static constexpr17 SmallStringView fromUtf8(const char *const characterPointer)
{
return SmallStringView(characterPointer);
} }
constexpr constexpr
@@ -133,93 +130,85 @@ public:
return data() + size(); return data() + size();
} }
const_reverse_iterator rbegin() const noexcept constexpr17 const_reverse_iterator rbegin() const noexcept
{ {
return const_reverse_iterator(end()); return const_reverse_iterator(end());
} }
const_reverse_iterator rend() const noexcept constexpr17 const_reverse_iterator rend() const noexcept
{ {
return const_reverse_iterator(begin()); return const_reverse_iterator(begin());
} }
operator std::string() const constexpr20 operator std::string() const { return std::string(data(), size()); }
{
return std::string(data(), size());
}
explicit operator QString() const explicit operator QString() const
{ {
return QString::fromUtf8(data(), int(size())); return QString::fromUtf8(data(), int(size()));
} }
bool startsWith(SmallStringView subStringToSearch) const noexcept constexpr17 bool startsWith(SmallStringView subStringToSearch) const noexcept
{ {
if (size() >= subStringToSearch.size()) if (size() >= subStringToSearch.size())
return !std::memcmp(m_pointer, subStringToSearch.data(), subStringToSearch.size()); return !std::char_traits<char>::compare(m_pointer,
subStringToSearch.data(),
subStringToSearch.size());
return false; return false;
} }
bool startsWith(char characterToSearch) const noexcept constexpr bool startsWith(char characterToSearch) const noexcept
{ {
return m_pointer[0] == characterToSearch; return m_pointer[0] == characterToSearch;
} }
char back() const { return m_pointer[m_size - 1]; } constexpr char back() const { return m_pointer[m_size - 1]; }
char operator[](std::size_t index) { return m_pointer[index]; } constexpr char operator[](std::size_t index) { return m_pointer[index]; }
private: private:
const char *m_pointer = ""; const char *m_pointer = "";
size_type m_size = 0; size_type m_size = 0;
}; };
inline constexpr17 bool operator==(SmallStringView first, SmallStringView second) noexcept
bool operator==(SmallStringView first, SmallStringView second) noexcept
{ {
return first.size() == second.size() && std::memcmp(first.data(), second.data(), first.size()) == 0; return first.size() == second.size()
&& std::char_traits<char>::compare(first.data(), second.data(), first.size()) == 0;
} }
inline constexpr17 bool operator!=(SmallStringView first, SmallStringView second) noexcept
bool operator!=(SmallStringView first, SmallStringView second) noexcept
{ {
return !(first == second); return !(first == second);
} }
inline constexpr17 int compare(SmallStringView first, SmallStringView second) noexcept
int compare(SmallStringView first, SmallStringView second) noexcept
{ {
int sizeDifference = int(first.size() - second.size()); int sizeDifference = int(first.size() - second.size());
if (sizeDifference == 0) if (sizeDifference == 0)
return std::memcmp(first.data(), second.data(), first.size()); return std::char_traits<char>::compare(first.data(), second.data(), first.size());
return sizeDifference; return sizeDifference;
} }
inline constexpr17 bool operator<(SmallStringView first, SmallStringView second) noexcept
bool operator<(SmallStringView first, SmallStringView second) noexcept
{ {
return compare(first, second) < 0; return compare(first, second) < 0;
} }
inline constexpr17 bool operator>(SmallStringView first, SmallStringView second) noexcept
bool operator>(SmallStringView first, SmallStringView second) noexcept
{ {
return second < first; return second < first;
} }
namespace Internal { namespace Internal {
inline constexpr int reverse_memcmp(const char *first, const char *second, size_t n)
int reverse_memcmp(const char *first, const char *second, size_t n)
{ {
const char *currentFirst = first + n - 1; const char *currentFirst = first + n - 1;
const char *currentSecond = second + n - 1; const char *currentSecond = second + n - 1;
while (n > 0) while (n > 0) {
{
// If the current characters differ, return an appropriately signed // If the current characters differ, return an appropriately signed
// value; otherwise, keep searching backwards // value; otherwise, keep searching backwards
int difference = *currentFirst - *currentSecond; int difference = *currentFirst - *currentSecond;
@@ -233,10 +222,9 @@ int reverse_memcmp(const char *first, const char *second, size_t n)
return 0; return 0;
} }
} } // namespace Internal
inline constexpr int reverseCompare(SmallStringView first, SmallStringView second) noexcept
int reverseCompare(SmallStringView first, SmallStringView second) noexcept
{ {
int sizeDifference = int(first.size() - second.size()); int sizeDifference = int(first.size() - second.size());
@@ -248,10 +236,7 @@ int reverseCompare(SmallStringView first, SmallStringView second) noexcept
} // namespace Utils } // namespace Utils
#ifdef __cpp_user_defined_literals
inline
constexpr Utils::SmallStringView operator""_sv(const char *const string, size_t size) constexpr Utils::SmallStringView operator""_sv(const char *const string, size_t size)
{ {
return Utils::SmallStringView(string, size); return Utils::SmallStringView(string, size);
} }
#endif