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
BasicSmallString(const char(&string)[ArraySize])
: m_data(string)
{
}
{}
BasicSmallString(const char *string, size_type size, size_type capacity)
{
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.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);
std::char_traits<char>::copy(m_data.allocated.data.pointer, string, size);
initializeLongString(size, capacity);
}
}
explicit BasicSmallString(SmallStringView stringView)
: BasicSmallString(stringView.data(), stringView.size(), stringView.size())
{
}
{}
BasicSmallString(const char *string, size_type size)
: BasicSmallString(string, size, size)
{
}
template<typename Type,
typename = std::enable_if_t<std::is_pointer<Type>::value>
>
template<typename Type, typename = std::enable_if_t<std::is_pointer<Type>::value>>
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!");
}
@@ -253,7 +249,7 @@ public:
static
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)
@@ -271,7 +267,7 @@ public:
const char *oldData = data();
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;
initializeLongString(oldSize, newCapacity);
}
@@ -380,7 +376,7 @@ public:
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;
}
@@ -388,7 +384,9 @@ public:
bool startsWith(SmallStringView subStringToSearch) const noexcept
{
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;
}
@@ -401,7 +399,8 @@ public:
bool endsWith(SmallStringView subStringToSearch) const noexcept
{
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.size());
return comparison == 0;
@@ -462,7 +461,7 @@ public:
size_type newSize = oldSize + string.size();
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;
setSize(newSize);
}
@@ -724,7 +723,7 @@ private:
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.size = size;
@@ -757,7 +756,7 @@ private:
while (found != end()) {
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,
end(),

View File

@@ -25,6 +25,18 @@
#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;
namespace Utils {
@@ -35,9 +47,4 @@ class BasicSmallString;
using SmallString = BasicSmallString<31>;
using PathString = BasicSmallString<190>;
inline
int compare(SmallStringView first, SmallStringView second) noexcept;
inline
int reverseCompare(SmallStringView first, SmallStringView second) noexcept;
} // namespace Utils

View File

@@ -32,123 +32,94 @@ namespace Utils {
namespace Internal {
template <class Category,
template<class Category,
class Type,
typename DistanceType = ptrdiff_t,
typename Pointer = Type*,
typename Reference = Type&>
struct SmallStringIterator : public std::iterator<Category, Type, DistanceType, Pointer, Reference>
typename Pointer = Type *,
typename Reference = Type &>
struct SmallStringIterator
{
constexpr
SmallStringIterator() noexcept = default;
using iterator_category = Category;
using value_type = Type;
using difference_type = DistanceType;
using pointer = Pointer;
using reference = Reference;
constexpr
SmallStringIterator(Pointer ptr) noexcept : pointer_(ptr)
{
}
constexpr SmallStringIterator() noexcept = default;
SmallStringIterator operator++() noexcept
{
return ++pointer_;
}
constexpr SmallStringIterator(Pointer ptr) noexcept
: pointer_(ptr)
{}
SmallStringIterator operator++(int) noexcept
{
return pointer_++;
}
constexpr SmallStringIterator operator++() noexcept { return ++pointer_; }
SmallStringIterator operator--() noexcept
{
return --pointer_;
}
constexpr SmallStringIterator operator++(int) noexcept { return pointer_++; }
SmallStringIterator operator--(int) noexcept
{
return pointer_--;
}
constexpr SmallStringIterator operator--() noexcept { 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;
}
SmallStringIterator operator-(DistanceType difference) const noexcept
constexpr SmallStringIterator operator-(DistanceType difference) const noexcept
{
return pointer_ - difference;
}
SmallStringIterator operator+(std::size_t difference) const noexcept
constexpr SmallStringIterator operator+(std::size_t difference) const noexcept
{
return pointer_ + difference;
}
SmallStringIterator operator-(std::size_t difference) const noexcept
constexpr SmallStringIterator operator-(std::size_t difference) const noexcept
{
return pointer_ - difference;
}
DistanceType operator-(SmallStringIterator other) const noexcept
constexpr DistanceType operator-(SmallStringIterator other) const noexcept
{
return pointer_ - other.data();
}
SmallStringIterator operator+=(DistanceType difference) noexcept
constexpr SmallStringIterator operator+=(DistanceType difference) noexcept
{
return pointer_ += difference;
}
SmallStringIterator operator-=(DistanceType difference) noexcept
constexpr SmallStringIterator operator-=(DistanceType difference) noexcept
{
return pointer_ -= difference;
}
Reference operator*() noexcept
{
return *pointer_;
}
constexpr Reference operator*() noexcept { return *pointer_; }
const Reference operator*() const noexcept
{
return *pointer_;
}
const Reference operator*() const noexcept { return *pointer_; }
Pointer operator->() noexcept
{
return pointer_;
}
constexpr Pointer operator->() noexcept { return pointer_; }
const Pointer operator->() const noexcept
{
return pointer_;
}
constexpr const Pointer operator->() const noexcept { return pointer_; }
constexpr
bool operator==(SmallStringIterator other) const noexcept
constexpr bool operator==(SmallStringIterator other) const noexcept
{
return pointer_ == other.pointer_;
}
constexpr
bool operator!=(SmallStringIterator other) const noexcept
constexpr bool operator!=(SmallStringIterator other) const noexcept
{
return pointer_ != other.pointer_;
}
constexpr
bool operator<(SmallStringIterator other) const noexcept
constexpr bool operator<(SmallStringIterator other) const noexcept
{
return pointer_ < other.pointer_;
}
Pointer data() noexcept
{
return pointer_;
}
constexpr Pointer data() noexcept { return pointer_; }
const Pointer data() const noexcept
{
return pointer_;
}
constexpr const Pointer data() const noexcept { return pointer_; }
private:
Pointer pointer_ = nullptr;

View File

@@ -49,30 +49,21 @@ struct ControlBlock
m_isReference(isReference)
{}
void setShortStringSize(size_type size)
constexpr void setShortStringSize(size_type size)
{
m_shortStringSize = static_cast<SizeType>(size);
}
size_type shortStringSize() const
{
return m_shortStringSize;
}
constexpr size_type shortStringSize() const { return m_shortStringSize; }
void setIsReadOnlyReference(bool isReadOnlyReference)
constexpr void setIsReadOnlyReference(bool isReadOnlyReference)
{
m_isReadOnlyReference = isReadOnlyReference;
}
void setIsReference(bool isReference)
{
m_isReference = isReference;
}
constexpr void setIsReference(bool isReference) { m_isReference = isReference; }
void setIsShortString(bool isShortString)
{
m_isReference = !isShortString;
}
constexpr void setIsShortString(bool isShortString) { m_isReference = !isShortString; }
constexpr
SizeType stringSize() const
@@ -168,7 +159,7 @@ struct StringDataLayout {
template<size_type Size,
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>{})
{
for (size_type i = 0; i < Size; ++i)

View File

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