Utils: Add SmallString

SmallString is a very simple utf8 string class. It's purpose is performance.
It uses a short string opimization which provides 31 bytes of heap free
memory to save a 30 bytes long string plus null terminator. If the string
gets larger heap is allocated. The grow strategy is 1.5 to improve reuse
of allocated memory.

It uses optionally constexpr to provide string literals.

Change-Id: I7757fb51abfeca200d074cbfce2f1d99edc0ecb0
Reviewed-by: Tobias Hunger <tobias.hunger@theqtcompany.com>
This commit is contained in:
Marco Bubke
2016-02-17 16:05:41 +01:00
parent 7984e928d1
commit 1eb0c94f81
12 changed files with 3086 additions and 2 deletions

View File

@@ -0,0 +1,833 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "utils_global.h"
#include "smallstringliteral.h"
#include "smallstringiterator.h"
#include "smallstringview.h"
#include "smallstringmemory.h"
#include <QByteArray>
#include <QDataStream>
#include <QDebug>
#include <QString>
#include <algorithm>
#include <cstdlib>
#include <climits>
#include <cstring>
#include <iosfwd>
#include <utility>
#pragma push_macro("constexpr")
#ifndef __cpp_constexpr
#define constexpr
#endif
#pragma push_macro("noexcept")
#ifndef __cpp_noexcept
#define noexcept
#endif
#ifdef UNIT_TESTS
#define UNIT_TEST_PUBLIC public
#else
#define UNIT_TEST_PUBLIC private
#endif
namespace Utils {
class SmallString
{
public:
using iterator = Internal::SmallStringIterator<std::random_access_iterator_tag, char>;
using const_iterator = Internal::SmallStringIterator<std::random_access_iterator_tag, const char>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using size_type = std::size_t;
SmallString() noexcept
: m_data(Internal::StringDataLayout())
{
}
constexpr
SmallString(const SmallStringLiteral &stringReference)
: m_data(stringReference.m_data)
{
}
template<size_type Size>
constexpr
SmallString(const char(&string)[Size])
: m_data(string)
{
}
SmallString(const char *string, size_type size, size_type capacity)
{
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.hasAllocated = false;
m_data.shortString.isReference = false;
} else {
m_data.allocated.data.pointer = Memory::allocate(capacity + 1);
std::memcpy(m_data.allocated.data.pointer, string, size);
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.hasAllocated = true;
m_data.allocated.isReference = false;
}
}
SmallString(const char *string, size_type size)
: SmallString(string, size, size)
{
}
SmallString(const QString &qString)
: SmallString(SmallString::fromQString(qString))
{}
~SmallString() 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;
#else
SmallString(const SmallString &string)
{
if (string.isShortString() || string.isReference())
m_data = string.m_data;
else
new (this) SmallString{string.data(), string.size()};
}
SmallString &operator=(const SmallString &other)
{
SmallString copy = other;
swap(*this, copy);
return *this;
}
#endif
SmallString(SmallString &&other) noexcept
{
m_data = other.m_data;
other.m_data = Internal::StringDataLayout();
}
SmallString &operator=(SmallString &&other) noexcept
{
swap(*this, other);
return *this;
}
SmallString clone() const
{
SmallString clonedString(m_data);
if (Q_UNLIKELY(hasAllocatedMemory()))
new (&clonedString) SmallString{m_data.allocated.data.pointer, m_data.allocated.data.size};
return clonedString;
}
friend
void swap(SmallString &first, SmallString &second)
{
using std::swap;
swap(first.m_data, second.m_data);
}
char &operator[](size_type index)
{
return at(index);
}
const char &operator[](size_type index) const
{
return at(index);
}
QByteArray toQByteArray() const noexcept
{
return QByteArray(data(), int(size()));
}
QString toQString() const
{
return QString::fromUtf8(data(), int(size()));
}
operator SmallStringView() const
{
return SmallStringView(data(), size());
}
operator QString() const
{
return toQString();
}
static
SmallString fromUtf8(const char *characterPointer)
{
return SmallString(characterPointer, std::strlen(characterPointer));
}
void reserve(size_type newCapacity)
{
if (fitsNotInCapacity(newCapacity)) {
if (Q_UNLIKELY(hasAllocatedMemory())) {
m_data.allocated.data.pointer = Memory::reallocate(m_data.allocated.data.pointer,
newCapacity + 1);
m_data.allocated.data.capacity = newCapacity;
} else {
const size_type oldSize = size();
new (this) SmallString(data(), oldSize, newCapacity);
}
}
}
void resize(size_type newSize)
{
reserve(newSize);
setSize(newSize);
at(newSize) = 0;
}
void clear() noexcept
{
this->~SmallString();
m_data = Internal::StringDataLayout();
}
char *data() noexcept
{
return Q_LIKELY(isShortString()) ? m_data.shortString.string : m_data.allocated.data.pointer;
}
const char *data() const noexcept
{
return Q_LIKELY(isShortString()) ? m_data.shortString.string : m_data.allocated.data.pointer;
}
const char *constData() const noexcept
{
return data();
}
iterator begin() noexcept
{
return data();
}
iterator end() noexcept
{
return data() + size();
}
reverse_iterator rbegin() noexcept
{
return reverse_iterator(end() - 1l);
}
reverse_iterator rend() noexcept
{
return reverse_iterator(begin() - 1l);
}
const_iterator begin() const noexcept
{
return constData();
}
const_iterator end() const noexcept
{
return data() + size();
}
const_iterator cbegin() const noexcept
{
return begin();
}
const_iterator cend() const noexcept
{
return end();
}
static
SmallString fromQString(const QString &qString)
{
const QByteArray &utf8ByteArray = qString.toUtf8();
return SmallString(utf8ByteArray.constData(), uint(utf8ByteArray.size()));
}
static
SmallString fromQByteArray(const QByteArray &utf8ByteArray)
{
return SmallString(utf8ByteArray.constData(), uint(utf8ByteArray.size()));
}
bool contains(SmallStringView subStringToSearch) const
{
auto found = std::search(begin(),
end(),
subStringToSearch.begin(),
subStringToSearch.end());
return found != end();
}
bool contains(char characterToSearch) const
{
auto found = std::strchr(data(), characterToSearch);
return found != nullptr;
}
bool startsWith(SmallStringView subStringToSearch) const noexcept
{
if (size() >= subStringToSearch.size())
return !std::memcmp(data(), subStringToSearch.data(), subStringToSearch.size());
return false;
}
bool startsWith(char characterToSearch) const noexcept
{
return data()[0] == characterToSearch;
}
bool endsWith(SmallStringView subStringToSearch) const noexcept
{
if (size() >= subStringToSearch.size()) {
const int comparison = std::memcmp(end().data() - subStringToSearch.size(),
subStringToSearch.data(),
subStringToSearch.size());
return comparison == 0;
}
return false;
}
bool endsWith(char character) const noexcept
{
return at(size() - 1) == character;
}
size_type size() const noexcept
{
if (!isShortString())
return m_data.allocated.data.size;
return m_data.shortString.shortStringSize;
}
size_type capacity() const noexcept
{
if (!isShortString())
return m_data.allocated.data.capacity;
return shortStringCapacity();
}
bool isEmpty() const noexcept
{
return size() == 0;
}
bool hasContent() const noexcept
{
return size() != 0;
}
SmallStringView mid(size_type position) const noexcept
{
return SmallStringView(data() + position, size() - position);
}
SmallStringView mid(size_type position, size_type length) const noexcept
{
return SmallStringView(data() + position, length);
}
void append(SmallStringView string) noexcept
{
size_type oldSize = size();
size_type newSize = oldSize + string.size();
reserve(optimalCapacity(newSize));
std::memcpy(data() + oldSize, string.data(), string.size());
at(newSize) = 0;
setSize(newSize);
}
void replace(SmallStringView fromText, SmallStringView toText)
{
if (toText.size() == fromText.size())
replaceEqualSized(fromText, toText);
else if (toText.size() < fromText.size())
replaceSmallerSized(fromText, toText);
else
replaceLargerSized(fromText, toText);
}
void replace(size_type position, size_type length, SmallStringView replacementText)
{
size_type newSize = size() - length + replacementText.size();
reserve(optimalCapacity(newSize));
auto replaceStart = begin() + position;
auto replaceEnd = replaceStart + length;
auto replacementEnd = replaceStart + replacementText.size();
size_type tailSize = size_type(end() - replaceEnd + 1);
std::memmove(replacementEnd.data(),
replaceEnd.data(), tailSize);
std::memcpy(replaceStart.data(), replacementText.data(), replacementText.size());
setSize(newSize);
}
constexpr static
size_type shortStringCapacity() noexcept
{
return SmallStringLiteral::shortStringCapacity();
}
size_type optimalCapacity(const size_type size)
{
if (fitsNotInCapacity(size))
return optimalHeapCapacity(size + 1) - 1;
return size;
}
size_type shortStringSize() const
{
return m_data.shortString.shortStringSize;
}
static
SmallString join(std::initializer_list<SmallString> list)
{
size_type totalSize = 0;
for (const SmallString &string : list)
totalSize += string.size();
SmallString joinedString;
joinedString.reserve(totalSize);
for (const SmallString &string : list)
joinedString.append(string);
return joinedString;
}
UNIT_TEST_PUBLIC:
bool isShortString() const noexcept
{
return !m_data.shortString.hasAllocated;
}
bool isReference() const noexcept
{
return m_data.shortString.isReference;
}
bool hasAllocatedMemory() const noexcept
{
return !isShortString() && !isReference();
}
bool fitsNotInCapacity(size_type capacity) const noexcept
{
return (isShortString() && capacity > shortStringCapacity())
|| (!isShortString() && capacity > m_data.allocated.data.capacity);
}
static
size_type optimalHeapCapacity(const size_type size)
{
const size_type cacheLineSize = 64;
const auto divisionByCacheLineSize = std::div(int64_t(size), int64_t(cacheLineSize));
size_type cacheLineBlocks = size_type(divisionByCacheLineSize.quot);
const size_type supplement = divisionByCacheLineSize.rem ? 1 : 0;
cacheLineBlocks += supplement;
int exponent;
const double significand = std::frexp(cacheLineBlocks, &exponent);
const double factorOneDotFiveSignificant = std::ceil(significand * 4.) / 4.;
cacheLineBlocks = size_type(std::ldexp(factorOneDotFiveSignificant, exponent));
return cacheLineBlocks * cacheLineSize;
}
private:
constexpr
SmallString(Internal::StringDataLayout data) noexcept
: m_data(data)
{
}
char &at(size_type index)
{
return *(data() + index);
}
const char &at(size_type index) const
{
return *(data() + index);
}
void replaceEqualSized(SmallStringView fromText, SmallStringView toText)
{
reserve(size());
auto start = begin();
auto found = std::search(start,
end(),
fromText.begin(),
fromText.end());
while (found != end()) {
start = found + toText.size();
std::memcpy(found.data(), toText.data(), toText.size());
found = std::search(start,
end(),
fromText.begin(),
fromText.end());
}
}
void replaceSmallerSized(SmallStringView fromText, SmallStringView toText)
{
size_type newSize = size();
reserve(newSize);
auto start = begin();
auto found = std::search(start,
end(),
fromText.begin(),
fromText.end());
size_type sizeDifference = 0;
while (found != end()) {
start = found + fromText.size();
auto nextFound = std::search(start,
end(),
fromText.begin(),
fromText.end());
auto replacedTextEndPosition = found + fromText.size();
auto replacementTextEndPosition = found + toText.size() - sizeDifference;
auto replacementTextStartPosition = found - sizeDifference;
std::memmove(replacementTextEndPosition.data(),
replacedTextEndPosition.data(),
nextFound - start);
std::memcpy(replacementTextStartPosition.data(), toText.data(), toText.size());
sizeDifference += fromText.size() - toText.size();
found = nextFound;
}
newSize -= sizeDifference;
setSize(newSize);
*end() = 0;
}
iterator replaceLargerSizedRecursive(size_type startIndex,
SmallStringView fromText,
SmallStringView toText,
size_type sizeDifference)
{
auto found = std::search(begin() + startIndex,
end(),
fromText.begin(),
fromText.end());
auto foundIndex = found - begin();
if (found != end()) {
startIndex = foundIndex + fromText.size();
size_type newSizeDifference = sizeDifference + toText.size() - fromText.size();
auto nextFound = replaceLargerSizedRecursive(startIndex,
fromText,
toText,
newSizeDifference);
found = begin() + foundIndex;
auto start = begin() + startIndex;
auto replacedTextEndPosition = found + fromText.size();
auto replacementTextEndPosition = found + fromText.size() + newSizeDifference;
auto replacementTextStartPosition = found + sizeDifference;
std::memmove(replacementTextEndPosition.data(),
replacedTextEndPosition.data(),
nextFound - start);
std::memcpy(replacementTextStartPosition.data(), toText.data(), toText.size());
} else {
size_type newSize = size() + sizeDifference;
reserve(optimalCapacity(newSize));
setSize(newSize);
found = end();
*end() = 0;
}
return found;
}
void replaceLargerSized(SmallStringView fromText, SmallStringView toText)
{
size_type sizeDifference = 0;
size_type startIndex = 0;
replaceLargerSizedRecursive(startIndex, fromText, toText, sizeDifference);
}
void setSize(size_type size)
{
if (isShortString())
m_data.shortString.shortStringSize = uchar(size);
else
m_data.allocated.data.size = size;
}
private:
Internal::StringDataLayout m_data;
};
template<SmallString::size_type Size>
bool operator==(const SmallString& first, const char(&second)[Size]) noexcept
{
return first == SmallStringView(second);
}
template<SmallString::size_type Size>
bool operator==(const char(&first)[Size], const SmallString& second) noexcept
{
return second == first;
}
template<typename Type,
typename = typename std::enable_if<std::is_pointer<Type>::value>::type
>
bool operator==(const SmallString& first, Type second) noexcept
{
return first == SmallStringView(second);
}
template<typename Type,
typename = typename std::enable_if<std::is_pointer<Type>::value>::type
>
bool operator==(Type first, const SmallString& second) noexcept
{
return second == first;
}
inline
bool operator==(const SmallString& first, const SmallString& second) noexcept
{
if (Q_LIKELY(first.size() != second.size()))
return false;
const int comparison = std::memcmp(first.data(), second.data(), first.size());
return comparison == 0;
}
inline
bool operator==(const SmallString& first, const SmallStringView& second) noexcept
{
if (Q_LIKELY(first.size() != second.size()))
return false;
const int comparison = std::memcmp(first.data(), second.data(), first.size());
return comparison == 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<SmallString::size_type Size>
bool operator!=(const SmallString& first, const char(&second)[Size]) noexcept
{
return !(first == second);
}
template<SmallString::size_type Size>
bool operator!=(const char(&first)[Size], const SmallString& second) noexcept
{
return second != first;
}
template<typename Type,
typename = typename std::enable_if<std::is_pointer<Type>::value>::type
>
bool operator!=(const SmallString& first, Type second) noexcept
{
return !(first == second);
}
template<typename Type,
typename = typename std::enable_if<std::is_pointer<Type>::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;
}
inline
QDataStream &operator<<(QDataStream &out, const SmallString &string)
{
if (string.isEmpty())
out << quint32(0);
else
out.writeBytes(string.data(), qint32(string.size()));
return out;
}
inline
QDataStream &operator>>(QDataStream &in, SmallString &string)
{
quint32 size;
in >> size;
if (size > 0 ) {
string.resize(size);
char *data = string.data();
in.readRawData(data, size);
}
return in;
}
inline
QDebug &operator<<(QDebug &debug, const SmallString &string)
{
debug.nospace() << "\"" << string.data() << "\"";
return debug;
}
inline
std::ostream &operator<<(std::ostream &stream, const SmallString &string)
{
return stream << string.data();
}
inline
void PrintTo(const SmallString &string, ::std::ostream *os)
{
*os << "'" << string.data() << "'";
}
} // namespace Utils
namespace std {
template<> struct hash<Utils::SmallString>
{
using argument_type = Utils::SmallString;
using result_type = uint;
result_type operator()(const argument_type& string) const
{
return qHashBits(string.data(), string.size());
}
};
} // namespace std
#pragma pop_macro("noexcept")
#pragma pop_macro("constexpr")

View File

@@ -0,0 +1,155 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <cstddef>
#include <iterator>
#pragma push_macro("noexcept")
#ifndef __cpp_noexcept
#define noexcept
#endif
namespace Utils {
namespace Internal {
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>
{
SmallStringIterator() noexcept = default;
SmallStringIterator(Pointer ptr) : pointer_(ptr) noexcept
{
}
SmallStringIterator operator++() noexcept
{
return ++pointer_;
}
SmallStringIterator operator++(int) noexcept
{
return pointer_++;
}
SmallStringIterator operator--() noexcept
{
return --pointer_;
}
SmallStringIterator operator--(int) noexcept
{
return pointer_--;
}
SmallStringIterator operator+(DistanceType difference) const noexcept
{
return pointer_ + difference;
}
SmallStringIterator operator-(DistanceType difference) const noexcept
{
return pointer_ - difference;
}
SmallStringIterator operator+(std::size_t difference) const noexcept
{
return pointer_ + difference;
}
SmallStringIterator operator-(std::size_t difference) const noexcept
{
return pointer_ - difference;
}
DistanceType operator-(SmallStringIterator other) const noexcept
{
return pointer_ - other.data();
}
SmallStringIterator operator+=(DistanceType difference) noexcept
{
return pointer_ += difference;
}
SmallStringIterator operator-=(DistanceType difference) noexcept
{
return pointer_ -= difference;
}
Reference operator*() noexcept
{
return *pointer_;
}
const Reference operator*() const noexcept
{
return *pointer_;
}
Pointer operator->() noexcept
{
return pointer_;
}
const Pointer operator->() const noexcept
{
return pointer_;
}
bool operator==(SmallStringIterator other) const noexcept
{
return pointer_ == other.pointer_;
}
bool operator!=(SmallStringIterator other) const noexcept
{
return pointer_ != other.pointer_;
}
bool operator<(SmallStringIterator other) const noexcept
{
return pointer_ < other.pointer_;
}
Pointer data() noexcept
{
return pointer_;
}
private:
Pointer pointer_ = nullptr;
};
} // namespace Internal
} // namespace Utils
#pragma pop_macro("noexcept")

View File

@@ -0,0 +1,140 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <QtGlobal>
#include <cstdint>
#pragma push_macro("constexpr")
#ifndef __cpp_constexpr
#define constexpr
#endif
#pragma push_macro("noexcept")
#ifndef __cpp_noexcept
#define noexcept
#endif
#ifdef __cpp_alignas
#define ALIGNAS_16 alignas(16)
#else
#define ALIGNAS_16
#endif
namespace Utils {
namespace Internal {
using size_type = std::size_t;
static const int smallStringLayoutByteSize = 32;
static const int maximumShortStringDataAreaSize = smallStringLayoutByteSize - 1;
struct AllocatedLayout {
struct Data {
char *pointer;
size_type size;
size_type capacity;
} data;
char dummy[maximumShortStringDataAreaSize - sizeof(Data)];
std::uint8_t isReference : 1;
std::uint8_t shortStringSize: 6;
std::uint8_t hasAllocated : 1;
};
struct ReferenceLayout {
struct Data {
const char *pointer;
size_type size;
size_type capacity;
} data;
char dummy[maximumShortStringDataAreaSize - sizeof(Data)];
std::uint8_t shortStringSize: 6;
std::uint8_t isReference : 1;
std::uint8_t hasAllocated : 1;
};
struct ShortStringLayout {
char string[maximumShortStringDataAreaSize];
std::uint8_t shortStringSize: 6;
std::uint8_t isReference : 1;
std::uint8_t hasAllocated : 1;
};
struct ALIGNAS_16 StringDataLayout {
StringDataLayout() noexcept = default;
constexpr StringDataLayout(const char *string,
size_type size) noexcept
: reference({{string, size, 0}, {}, 0, true, true})
{
}
template<size_type Size>
constexpr StringDataLayout(const char(&string)[Size]) noexcept
#if __cpp_constexpr < 201304
: reference({{string, Size - 1, 0}, {}, 0, true, true})
#endif
{
#if __cpp_constexpr >= 201304
if (Size <= maximumShortStringDataAreaSize) {
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.hasAllocated = false;
shortString.isReference = false;
} else {
reference.data.pointer = string;
reference.data.size = Size - 1;
reference.data.capacity = 0;
reference.shortStringSize = 0;
reference.hasAllocated = true;
reference.isReference = true;
}
#endif
}
union {
AllocatedLayout allocated;
ReferenceLayout reference;
ShortStringLayout shortString = {};
};
};
} // namespace Internal
} // namespace Utils
#pragma pop_macro("noexcept")
#pragma pop_macro("constexpr")

View File

@@ -0,0 +1,137 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "smallstringiterator.h"
#include "smallstringlayout.h"
#include "smallstringview.h"
#pragma push_macro("constexpr")
#ifndef __cpp_constexpr
#define constexpr
#endif
#pragma push_macro("noexcept")
#ifndef __cpp_noexcept
#define noexcept
#endif
namespace Utils {
class SmallString;
class SmallStringLiteral
{
friend class SmallString;
public:
using const_iterator = Internal::SmallStringIterator<std::random_access_iterator_tag, const char>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using size_type = std::size_t;
template<size_type Size>
constexpr
SmallStringLiteral(const char(&string)[Size]) noexcept
: m_data(string)
{
static_assert(Size >= 1, "Invalid string literal! Length is zero!");
}
constexpr
SmallStringLiteral(const char *string, const size_type size) noexcept
: m_data(string, size)
{
}
constexpr
const char *data() const
{
return Q_LIKELY(isShortString()) ? m_data.shortString.string : m_data.allocated.data.pointer;
}
constexpr
size_type size() const
{
return Q_LIKELY(isShortString()) ? m_data.shortString.shortStringSize : m_data.allocated.data.size;
}
const_iterator begin() const noexcept
{
return data();
}
const_iterator end() const noexcept
{
return data() + size();
}
const_reverse_iterator rbegin() const noexcept
{
return const_reverse_iterator(end() - 1l);
}
const_reverse_iterator rend() const noexcept
{
return const_reverse_iterator(begin() - 1l);
}
constexpr static
size_type shortStringCapacity() noexcept
{
return sizeof(Internal::ShortStringLayout) - 2;
}
constexpr
bool isShortString() const noexcept
{
return !m_data.shortString.hasAllocated;
}
constexpr
bool isReference() const noexcept
{
return m_data.shortString.isReference;
}
operator SmallStringView() const
{
return SmallStringView(data(), size());
}
private:
constexpr SmallStringLiteral(Internal::StringDataLayout data) noexcept
: m_data(data)
{
}
private:
Internal::StringDataLayout m_data;
};
} // namespace Utils
#pragma pop_macro("noexcept")
#pragma pop_macro("constexpr")

View File

@@ -0,0 +1,69 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <cstring>
#include <memory>
namespace Utils {
namespace Memory {
inline char *allocate(std::size_t size)
{
#ifdef WIN32
return static_cast<char*>(_aligned_malloc(size, 64));
#else
return static_cast<char*>(std::malloc(size));
#endif
}
inline void deallocate(char *memory)
{
#ifdef WIN32
_aligned_free(memory);
#else
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfree-nonheap-object"
std::free(memory);
#pragma GCC diagnostic pop
#endif
#endif
}
inline char *reallocate(char *oldMemory, std::size_t newSize)
{
#ifdef WIN32
return static_cast<char*>(_aligned_realloc(oldMemory, newSize, 64));
#else
return static_cast<char*>(std::realloc(oldMemory, newSize));
#endif
}
} // namespace Memory
} // namespace Utils

View File

@@ -0,0 +1,255 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "utils_global.h"
#include "smallstring.h"
#include <vector>
#pragma push_macro("noexcept")
#ifndef __cpp_noexcept
#define noexcept
#endif
namespace Utils {
class SmallStringVector : public std::vector<Utils::SmallString>
{
public:
SmallStringVector() = default;
SmallStringVector(std::initializer_list<Utils::SmallString> list)
{
reserve(list.size());
for (auto &&entry : list)
push_back(entry.clone());
}
explicit SmallStringVector(const QStringList &stringList)
{
reserve(std::size_t(stringList.count()));
for (const QString &string : stringList)
push_back(Utils::SmallString::fromQString(string));
}
#if !defined(UNIT_TESTS) && !(defined(_MSC_VER) && _MSC_VER < 1900)
SmallStringVector(const SmallStringVector &) = delete;
SmallStringVector &operator=(const SmallStringVector &) = delete;
#else
SmallStringVector(const SmallStringVector &) = default;
SmallStringVector &operator=(const SmallStringVector &) = default;
#endif
#if !(defined(_MSC_VER) && _MSC_VER < 1900)
SmallStringVector(SmallStringVector &&) noexcept = default;
SmallStringVector &operator=(SmallStringVector &&) noexcept = default;
#else
SmallStringVector(SmallStringVector &&other)
: std::vector<Utils::SmallString>(std::move(other))
{
}
SmallStringVector &operator=(SmallStringVector &&other)
{
std::vector<Utils::SmallString>(std::move(other));
return *this;
}
#endif
Utils::SmallString join(Utils::SmallString &&separator) const
{
Utils::SmallString joinedString;
joinedString.reserve(totalByteSize() + separator.size() * std::size_t(size()));
for (auto stringIterator = begin(); stringIterator != end(); ++stringIterator) {
joinedString.append(*stringIterator);
if (std::next(stringIterator) != end())
joinedString.append(separator);
}
return joinedString;
}
bool contains(const Utils::SmallString &string) const noexcept
{
return std::find(cbegin(), cend(), string) != cend();
}
bool removeFast(Utils::SmallStringView valueToBeRemoved)
{
auto position = std::remove(begin(), end(), valueToBeRemoved);
const bool hasEntry = position != end();
erase(position, end());
return hasEntry;
}
void append(Utils::SmallString &&string)
{
push_back(std::move(string));
}
SmallStringVector clone() const
{
SmallStringVector clonedVector;
clonedVector.reserve(size());
for (auto &&entry : *this)
clonedVector.push_back(entry.clone());
return clonedVector;
}
private:
std::size_t totalByteSize() const
{
std::size_t totalSize = 0;
for (auto &&string : *this)
totalSize += string.size();
return totalSize;
}
};
template <typename Type>
std::vector<Type> clone(const std::vector<Type> &vector)
{
std::vector<Type> clonedVector;
clonedVector.reserve(vector.size());
for (auto &&entry : vector)
clonedVector.push_back(entry.clone());
return clonedVector;
}
inline QDataStream &operator<<(QDataStream &out, const SmallStringVector &stringVector)
{
out << quint64(stringVector.size());
for (auto &&string : stringVector)
out << string;
return out;
}
inline QDataStream &operator>>(QDataStream &in, SmallStringVector &stringVector)
{
stringVector.clear();
quint64 size;
in >> size;
stringVector.reserve(size);
for (quint64 i = 0; i < size; ++i) {
SmallString string;
in >> string;
stringVector.push_back(std::move(string));
}
return in;
}
inline QDebug operator<<(QDebug debug, const SmallStringVector &stringVector)
{
debug << "StringVector(" << stringVector.join(Utils::SmallString(", ")).constData() << ")";
return debug;
}
inline void PrintTo(const SmallStringVector &textVector, ::std::ostream* os)
{
*os << "StringVector(" << textVector.join(Utils::SmallString(", ")).constData() << ")";
}
} // namespace Utils;
namespace std {
template<typename Type>
QDataStream &operator<<(QDataStream &out, const vector<Type> &vector)
{
out << quint64(vector.size());
for (auto &&entry : vector)
out << entry;
return out;
}
template<typename Type>
QDataStream &operator>>(QDataStream &in, vector<Type> &vector)
{
vector.clear();
quint64 size;
in >> size;
vector.reserve(size);
for (quint64 i = 0; i < size; ++i) {
Type entry;
in >> entry;
vector.push_back(move(entry));
}
return in;
}
} // namespace std
QT_BEGIN_NAMESPACE
template<typename Type>
QDebug &operator<<(QDebug &debug, const std::vector<Type> &vector)
{
debug.noquote() << "[";
for (auto &&entry : vector)
debug.noquote() << entry << ", ";
debug.noquote() << "]";
return debug;
}
QT_END_NAMESPACE
#pragma pop_macro("noexcept")

View File

@@ -0,0 +1,140 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "smallstringiterator.h"
#include <QtGlobal>
#include <cstring>
#pragma push_macro("constexpr")
#ifndef __cpp_constexpr
#define constexpr
#endif
#pragma push_macro("noexcept")
#ifndef __cpp_noexcept
#define noexcept
#endif
namespace Utils {
class SmallStringView
{
public:
using const_iterator = Internal::SmallStringIterator<std::random_access_iterator_tag, const char>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using size_type = std::size_t;
template<size_type Size>
constexpr
SmallStringView(const char(&string)[Size]) noexcept
: m_pointer(string),
m_size(Size - 1)
{
static_assert(Size >= 1, "Invalid string literal! Length is zero!");
}
template<typename Type,
typename = typename std::enable_if<std::is_pointer<Type>::value>::type
>
SmallStringView(Type characterPointer) noexcept
: m_pointer(characterPointer),
m_size(std::strlen(characterPointer))
{
static_assert(!std::is_array<Type>::value, "Input type is array and not char pointer!");
}
constexpr
SmallStringView(const char *const string, const size_type size) noexcept
: m_pointer(string),
m_size(size)
{
}
static
SmallStringView fromUtf8(const char *const characterPointer)
{
return SmallStringView(characterPointer, std::strlen(characterPointer));
}
constexpr
const char *data() const
{
return m_pointer;
}
constexpr
size_type size() const
{
return m_size;
}
const_iterator begin() const noexcept
{
return data();
}
const_iterator end() const noexcept
{
return data() + size();
}
const_reverse_iterator rbegin() const noexcept
{
return const_reverse_iterator(end() - 1l);
}
const_reverse_iterator rend() const noexcept
{
return const_reverse_iterator(begin() - 1l);
}
private:
const char *m_pointer;
size_type m_size;
};
inline
bool operator==(const SmallStringView& first, const SmallStringView& second) noexcept
{
if (Q_LIKELY(first.size() != second.size()))
return false;
return !std::memcmp(first.data(), second.data(), first.size());
}
inline
bool operator!=(const SmallStringView& first, const SmallStringView& second) noexcept
{
return !(first == second);
}
} // namespace Utils
#pragma pop_macro("noexcept")
#pragma pop_macro("constexpr")

View File

@@ -211,7 +211,13 @@ HEADERS += \
$$PWD/port.h \
$$PWD/functiontraits.h \
$$PWD/mapreduce.h \
$$PWD/declarationmacros.h
$$PWD/declarationmacros.h \
$$PWD/smallstring.h \
$$PWD/smallstringiterator.h \
$$PWD/smallstringliteral.h \
$$PWD/smallstringmemory.h \
$$PWD/smallstringvector.h \
$$PWD/smallstringlayout.h
FORMS += $$PWD/filewizardpage.ui \
$$PWD/projectintropage.ui \

View File

@@ -184,6 +184,11 @@ QtcLibrary {
"shellcommandpage.h",
"sleep.cpp",
"sleep.h",
"smallstring.h",
"smallstringiterator.h",
"smallstringliteral.h",
"smallstringmemory.h",
"smallstringvector.h",
"statuslabel.cpp",
"statuslabel.h",
"stringutils.cpp",

View File

@@ -0,0 +1,359 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms and
** conditions see http://www.qt.io/terms-conditions. For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include <benchmark/benchmark.h>
#include <QByteArray>
#include <utils/smallstringvector.h>
#ifndef __cpp_constexpr
#define constexpr
#endif
namespace {
Utils::SmallStringView createText(int size)
{
auto text = new char[size + 1];
std::fill(text, text + size, 'x');
text[size] = 0;
return Utils::SmallStringView(text, size);
}
void CreateSmallStringLiteral(benchmark::State& state) {
while (state.KeepRunning())
constexpr auto string = Utils::SmallStringLiteral("very very very long long long text");
}
BENCHMARK(CreateSmallStringLiteral);
void CreateNullSmallString(benchmark::State& state) {
while (state.KeepRunning())
auto string = Utils::SmallString();
}
BENCHMARK(CreateNullSmallString);
void CreateSmallStringFromLiteral(benchmark::State& state) {
while (state.KeepRunning())
auto string = Utils::SmallString("very very very long long long text");
}
BENCHMARK(CreateSmallStringFromLiteral);
void CreateSmallString(benchmark::State& state) {
auto text = createText(state.range_x());
while (state.KeepRunning())
auto string = Utils::SmallString(text.data(), state.range_x());
}
BENCHMARK(CreateSmallString)->Range(0, 1024);
void CreateQByteArray(benchmark::State& state) {
auto text = createText(state.range_x());
while (state.KeepRunning())
QByteArray foo(text.data(), state.range_x());
}
BENCHMARK(CreateQByteArray)->Range(0, 1024);
void CreateQString(benchmark::State& state) {
auto text = createText(state.range_x());
while (state.KeepRunning())
auto string = QString::fromUtf8(text.data(), state.range_x());
}
BENCHMARK(CreateQString)->Range(0, 1024);
void SmallStringAppend(benchmark::State& state) {
auto text = createText(state.range_y());
while (state.KeepRunning()) {
auto string = Utils::SmallString();
for (int i = 0; i < state.range_x(); ++i)
string.append(text);
}
}
BENCHMARK(SmallStringAppend)->RangePair(1, 64, 1, 4096);
void QByteArrayAppend(benchmark::State& state) {
auto text = createText(state.range_y());
while (state.KeepRunning()) {
auto string = QByteArray();
for (int i = 0; i < state.range_x(); ++i)
string.append(text.data(), text.size());
}
}
BENCHMARK(QByteArrayAppend)->RangePair(1, 64, 1, 4096);
void CompareCString(benchmark::State& state) {
Utils::SmallString text("myFunctionIsQuiteLong");
while (state.KeepRunning())
benchmark::DoNotOptimize(text == "staticMetaObject");
}
BENCHMARK(CompareCString);
void CompareString(benchmark::State& state) {
Utils::SmallString text("myFunctionIsQuiteLong");
while (state.KeepRunning())
benchmark::DoNotOptimize(text == Utils::SmallString("staticMetaObject"));
}
BENCHMARK(CompareString);
void CompareStringView(benchmark::State& state) {
Utils::SmallString text("myFunctionIsQuiteLong");
while (state.KeepRunning())
benchmark::DoNotOptimize(text == Utils::SmallStringView("staticMetaObject"));
}
BENCHMARK(CompareStringView);
void CompareCStringPointer(benchmark::State& state) {
Utils::SmallString text("myFunctionIsQuiteLong");
const char *cStringText = "staticMetaObject";
while (state.KeepRunning())
benchmark::DoNotOptimize(text == cStringText);
}
BENCHMARK(CompareCStringPointer);
void StartsWith(benchmark::State& state) {
Utils::SmallString text("myFunctionIsQuiteLong");
while (state.KeepRunning())
benchmark::DoNotOptimize(text.startsWith("qt_"));
}
BENCHMARK(StartsWith);
void ShortSize(benchmark::State& state) {
Utils::SmallString text("myFunctionIsQuiteLong");
while (state.KeepRunning())
benchmark::DoNotOptimize(text.size());
}
BENCHMARK(ShortSize);
void LongSize(benchmark::State& state) {
Utils::SmallString text("myFunctionIsQuiteLong");
while (state.KeepRunning())
benchmark::DoNotOptimize(text.size());
}
BENCHMARK(LongSize);
void Size(benchmark::State& state) {
Utils::SmallString text("myFunctionIsMUCHMUCHMUCHMUCHMUCHLonger");
while (state.KeepRunning())
benchmark::DoNotOptimize(text.size());
}
BENCHMARK(LongSize);
void generateRandomString(char *data, const int length)
{
static const char alphaNumericData[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
for (int i = 0; i < length; ++i) {
data[i] = alphaNumericData[std::rand() % (sizeof(alphaNumericData) - 1)];
}
}
uint entryCount=100000;
QByteArray generateRandomQByteArray()
{
QByteArray text;
text.resize(20);
generateRandomString(text.data(), text.size());
return text;
}
void Collection_CreateQByteArrays(benchmark::State& state)
{
while (state.KeepRunning()) {
QVector<QByteArray> values;
values.reserve(entryCount);
for (int i = 0; i < entryCount; i++)
values.append(generateRandomQByteArray());
}
}
BENCHMARK(Collection_CreateQByteArrays);
void Collection_SortQByteArrays(benchmark::State& state)
{
while (state.KeepRunning()) {
state.PauseTiming();
QVector<QByteArray> values;
values.reserve(entryCount);
for (int i = 0; i < entryCount; i++)
values.append(generateRandomQByteArray());
state.ResumeTiming();
std::sort(values.begin(), values.end());
}
}
BENCHMARK(Collection_SortQByteArrays);
void Collection_FilterQByteArrays(benchmark::State& state)
{
while (state.KeepRunning()) {
state.PauseTiming();
QVector<QByteArray> values;
values.reserve(entryCount);
QVector<QByteArray> filteredValues;
filteredValues.reserve(entryCount);
for (int i = 0; i < entryCount; i++)
values.append(generateRandomQByteArray());
auto startsWithA = [] (const QByteArray &byteArray) {
return byteArray.startsWith('a');
};
state.ResumeTiming();
std::copy_if(std::make_move_iterator(values.begin()),
std::make_move_iterator(values.end()),
std::back_inserter(filteredValues),
startsWithA);
}
}
BENCHMARK(Collection_FilterQByteArrays);
Utils::SmallString generateRandomSmallString(int size = 20)
{
Utils::SmallString text;
text.resize(size);
generateRandomString(text.data(), text.size());
return text;
}
void Collection_CreateSmallStrings(benchmark::State& state)
{
while (state.KeepRunning()) {
Utils::SmallStringVector values;
values.reserve(entryCount);
for (int i = 0; i < entryCount; i++)
values.push_back(generateRandomSmallString());
}
}
BENCHMARK(Collection_CreateSmallStrings);
void Collection_SortSmallStrings(benchmark::State& state)
{
while (state.KeepRunning()) {
state.PauseTiming();
Utils::SmallStringVector values;
values.reserve(entryCount);
for (int i = 0; i < entryCount; i++)
values.push_back(generateRandomSmallString());
state.ResumeTiming();
std::sort(values.begin(), values.end());
}
}
BENCHMARK(Collection_SortSmallStrings);
void Collection_FilterSmallStrings(benchmark::State& state)
{
while (state.KeepRunning()) {
state.PauseTiming();
Utils::SmallStringVector values;
values.reserve(entryCount);
Utils::SmallStringVector filteredValues;
filteredValues.reserve(entryCount);
for (int i = 0; i < entryCount; i++)
values.push_back(generateRandomSmallString());
auto startsWithA = [] (const Utils::SmallString &byteArray) {
return byteArray.startsWith('a');
};
state.ResumeTiming();
std::copy_if(std::make_move_iterator(values.begin()),
std::make_move_iterator(values.end()),
std::back_inserter(filteredValues),
startsWithA);
}
}
BENCHMARK(Collection_FilterSmallStrings);
void IterateOver(benchmark::State& state) {
Utils::SmallString text = generateRandomSmallString(30);
auto begin = std::next(text.begin(), state.range_x());
auto end = std::next(text.begin(), state.range_y());
while (state.KeepRunning()) {
std::for_each(begin, end, [] (char x) {
benchmark::DoNotOptimize(x);
});
}
}
BENCHMARK(IterateOver)->ArgPair(0, 8)
->ArgPair(8, 16)
->ArgPair(16, 24)
->ArgPair(24, 31)
->ArgPair(0, 8)
->ArgPair(0, 16)
->ArgPair(0, 24)
->ArgPair(0, 31);
//void StringLiteralSize(benchmark::State& state) {
// constexpr Utils::SmallStringLiteral text("myFunctionIsQuiteLong");
// while (state.KeepRunning()) {
// constexpr auto size = text.size(); // internal compile error
// benchmark::DoNotOptimize(size);
// }
//}
//BENCHMARK(StringLiteralSize);
}

View File

@@ -0,0 +1,979 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "gtest/gtest.h"
#include "gmock/gmock-matchers.h"
#include "gtest-qt-printing.h"
#include <QString>
#include <utils/smallstringvector.h>
#include <utils/smallstring.h>
#ifndef __cpp_constexpr
#define constexpr
#endif
using namespace ::testing;
using Utils::SmallString;
using Utils::SmallStringLiteral;
using Utils::SmallStringView;
TEST(SmallString, BasicStringEqual)
{
ASSERT_THAT(SmallString("text"), Eq(SmallString("text")));
}
TEST(SmallString, BasicSmallStringUnequal)
{
ASSERT_THAT(SmallString("text"), Ne(SmallString("other text")));
}
TEST(SmallString, NullSmallStringIsEqualToEmptySmallString)
{
ASSERT_THAT(SmallString(), Eq(SmallString("")));
}
TEST(SmallString, ShortSmallStringLiteralIsShortSmallString)
{
constexpr SmallStringLiteral shortText("short string");
#if __cpp_constexpr >= 201304
ASSERT_TRUE(shortText.isShortString());
#else
ASSERT_TRUE(shortText.isReference());
#endif
}
TEST(SmallString, ShortSmallStringIsShortSmallString)
{
SmallString shortText("short string");
#if __cpp_constexpr >= 201304
ASSERT_TRUE(shortText.isShortString());
#else
ASSERT_TRUE(shortText.isReference());
#endif
}
TEST(SmallString, ShortSmallStringIsReference)
{
SmallString longText("very very very very very long text");
ASSERT_TRUE(longText.isReference());
}
TEST(SmallString, ShortSmallStringIsNotReference)
{
const char *shortCSmallString = "short string";
auto shortText = SmallString::fromUtf8(shortCSmallString);
ASSERT_FALSE(shortText.isReference());
}
TEST(SmallString, MaximumShortSmallString)
{
SmallString maximumShortText("very very very very short text", 30);
ASSERT_THAT(maximumShortText.constData(), StrEq("very very very very short text"));
}
TEST(SmallString, LongConstExpressionSmallStringIsReference)
{
SmallString longText("very very very very very very very very very very very long string");
ASSERT_TRUE(longText.isReference());
}
TEST(SmallString, CloneShortSmallString)
{
SmallString shortText("short string");
auto clonedText = shortText.clone();
ASSERT_THAT(clonedText, Eq("short string"));
}
TEST(SmallString, CloneLongSmallString)
{
SmallString longText = SmallString::fromUtf8("very very very very very very very very very very very long string");
auto clonedText = longText.clone();
ASSERT_THAT(clonedText, Eq("very very very very very very very very very very very long string"));
}
TEST(SmallString, ClonedLongSmallStringDataPointerIsDifferent)
{
SmallString longText = SmallString::fromUtf8("very very very very very very very very very very very long string");
auto clonedText = longText.clone();
ASSERT_THAT(clonedText.data(), Ne(longText.data()));
}
TEST(SmallString, CopyShortConstExpressionSmallStringIsShortSmallString)
{
SmallString shortText("short string");
auto shortTextCopy = shortText;
#if __cpp_constexpr >= 201304
ASSERT_TRUE(shortTextCopy.isShortString());
#else
ASSERT_TRUE(shortTextCopy.isReference());
#endif
}
TEST(SmallString, CopyLongConstExpressionSmallStringIsLongSmallString)
{
SmallString longText("very very very very very very very very very very very long string");
auto longTextCopy = longText;
ASSERT_FALSE(longTextCopy.isShortString());
}
TEST(SmallString, SmallStringFromCharacterArrayIsReference)
{
const char longCString[] = "very very very very very very very very very very very long string";
SmallString longString(longCString);
ASSERT_TRUE(longString.isReference());
}
TEST(SmallString, SmallStringFromCharacterPointerIsNotReference)
{
const char *longCString = "very very very very very very very very very very very long string";
SmallString longString = SmallString::fromUtf8(longCString);
ASSERT_FALSE(longString.isReference());
}
TEST(SmallString, CopyStringFromReference)
{
SmallString longText("very very very very very very very very very very very long string");
SmallString longTextCopy;
longTextCopy = longText;
ASSERT_TRUE(longTextCopy.isReference());
}
TEST(SmallString, SmallStringLiteralShortSmallStringDataAccess)
{
SmallStringLiteral literalText("very very very very very very very very very very very long string");
ASSERT_THAT(literalText.data(), StrEq("very very very very very very very very very very very long string"));
}
TEST(SmallString, SmallStringLiteralLongSmallStringDataAccess)
{
SmallStringLiteral literalText("short string");
ASSERT_THAT(literalText.data(), StrEq("short string"));
}
TEST(SmallString, ReferenceDataAccess)
{
SmallString literalText("short string");
ASSERT_THAT(literalText.constData(), StrEq("short string"));
}
TEST(SmallString, ShortDataAccess)
{
const char *shortCString = "short string";
auto shortText = SmallString::fromUtf8(shortCString);
ASSERT_THAT(shortText.constData(), StrEq("short string"));
}
TEST(SmallString, LongDataAccess)
{
const char *longCString = "very very very very very very very very very very very long string";
auto longText = SmallString::fromUtf8(longCString);
ASSERT_THAT(longText.constData(), StrEq(longCString));
}
TEST(SmallString, LongSmallStringHasShortSmallStringSizeZero)
{
auto longText = SmallString::fromUtf8("very very very very very very very very very very very long string");
ASSERT_THAT(longText.shortStringSize(), 0);
}
TEST(SmallString, BeginIsEqualEndForEmptySmallString)
{
SmallString text;
ASSERT_THAT(text.begin(), Eq(text.end()));
}
TEST(SmallString, BeginIsNotEqualEndForNonEmptySmallString)
{
SmallString text("x");
ASSERT_THAT(text.begin(), Ne(text.end()));
}
TEST(SmallString, BeginPlusOneIsEqualEndForSmallStringWidthSizeOne)
{
SmallString text("x");
auto beginPlusOne = text.begin() + 1l;
ASSERT_THAT(beginPlusOne, Eq(text.end()));
}
TEST(SmallString, RBeginIsEqualREndForEmptySmallString)
{
SmallString text;
ASSERT_THAT(text.rbegin(), Eq(text.rend()));
}
TEST(SmallString, RBeginIsNotEqualREndForNonEmptySmallString)
{
SmallString text("x");
ASSERT_THAT(text.rbegin(), Ne(text.rend()));
}
TEST(SmallString, RBeginPlusOneIsEqualREndForSmallStringWidthSizeOne)
{
SmallString text("x");
auto beginPlusOne = text.rbegin() + 1l;
ASSERT_THAT(beginPlusOne, Eq(text.rend()));
}
TEST(SmallString, ToQString)
{
SmallString text("short string");
auto qStringText = text;
ASSERT_THAT(qStringText, QStringLiteral("short string"));
}
TEST(SmallString, FromQString)
{
QString qStringText = QStringLiteral("short string");
auto text = SmallString::fromQString(qStringText);
ASSERT_THAT(text, SmallString("short string"));
}
TEST(SmallString, FromQByteArray)
{
QByteArray qByteArray = QByteArrayLiteral("short string");
auto text = SmallString::fromQByteArray(qByteArray);
ASSERT_THAT(text, SmallString("short string"));
}
TEST(SmallString, MidOneParameter)
{
SmallString text("some text");
auto midString = text.mid(5);
ASSERT_THAT(midString, Eq(SmallString("text")));
}
TEST(SmallString, MidTwoParameter)
{
SmallString text("some text and more");
auto midString = text.mid(5, 4);
ASSERT_THAT(midString, Eq(SmallString("text")));
}
TEST(SmallString, SizeOfEmptyStringl)
{
SmallString emptyString;
auto size = emptyString.size();
ASSERT_THAT(size, 0);
}
TEST(SmallString, SizeShortSmallStringLiteral)
{
SmallStringLiteral shortText("text");
auto size = shortText.size();
ASSERT_THAT(size, 4);
}
TEST(SmallString, SizeLongSmallStringLiteral)
{
auto longText = SmallStringLiteral("very very very very very very very very very very very long string");
auto size = longText.size();
ASSERT_THAT(size, 66);
}
TEST(SmallString, SizeReference)
{
SmallString shortText("text");
auto size = shortText.size();
ASSERT_THAT(size, 4);
}
TEST(SmallString, SizeShortSmallString)
{
SmallString shortText("text", 4);
auto size = shortText.size();
ASSERT_THAT(size, 4);
}
TEST(SmallString, SizeLongSmallString)
{
auto longText = SmallString::fromUtf8("very very very very very very very very very very very long string");
auto size = longText.size();
ASSERT_THAT(size, 66);
}
TEST(SmallString, CapacityReference)
{
SmallString shortText("very very very very very very very long string");
auto capacity = shortText.capacity();
ASSERT_THAT(capacity, 0);
}
TEST(SmallString, CapacityShortSmallString)
{
SmallString shortText("text", 4);
auto capacity = shortText.capacity();
ASSERT_THAT(capacity, 30);
}
TEST(SmallString, CapacityLongSmallString)
{
auto longText = SmallString::fromUtf8("very very very very very very very very very very very long string");
auto capacity = longText.capacity();
ASSERT_THAT(capacity, 66);
}
TEST(SmallString, FitsNotInCapacityBecauseNullSmallStringIsAShortSmallString)
{
SmallString text;
ASSERT_FALSE(text.fitsNotInCapacity(30));
}
TEST(SmallString, FitsNotInCapacityBecauseItIsReference)
{
SmallString text("very very very very very very very long string");
ASSERT_TRUE(text.fitsNotInCapacity(1));
}
TEST(SmallString, FitsInShortSmallStringCapacity)
{
SmallString text("text", 4);
ASSERT_FALSE(text.fitsNotInCapacity(30));
}
TEST(SmallString, FitsInNotShortSmallStringCapacity)
{
SmallString text("text", 4);
ASSERT_TRUE(text.fitsNotInCapacity(31));
}
TEST(SmallString, FitsInLongSmallStringCapacity)
{
SmallString text = SmallString::fromUtf8("very very very very very very long string");
ASSERT_FALSE(text.fitsNotInCapacity(33)) << text.capacity();
}
TEST(SmallString, FitsNotInLongSmallStringCapacity)
{
SmallString text = SmallString::fromUtf8("very very very very very very long string");
ASSERT_TRUE(text.fitsNotInCapacity(65)) << text.capacity();
}
TEST(SmallString, AppendNullSmallString)
{
SmallString text("text");
text.append(SmallString());
ASSERT_THAT(text, SmallString("text"));
}
TEST(SmallString, AppendEmptySmallString)
{
SmallString text("text");
text.append(SmallString(""));
ASSERT_THAT(text, SmallString("text"));
}
TEST(SmallString, AppendShortSmallString)
{
SmallString text("some ");
text.append(SmallString("text"));
ASSERT_THAT(text, SmallString("some text"));
}
TEST(SmallString, AppendLongSmallString)
{
SmallString longText("some very very very very very very very very very very very long string");
longText.append(SmallString(" text"));
ASSERT_THAT(longText, SmallString("some very very very very very very very very very very very long string text"));
}
TEST(SmallString, ToByteArray)
{
SmallString text("some text");
ASSERT_THAT(text.toQByteArray(), QByteArrayLiteral("some text"));
}
TEST(SmallString, Contains)
{
SmallString text("some text");
ASSERT_TRUE(text.contains(SmallString("text")));
ASSERT_TRUE(text.contains("text"));
ASSERT_TRUE(text.contains('x'));
}
TEST(SmallString, NotContains)
{
SmallString text("some text");
ASSERT_FALSE(text.contains(SmallString("textTwo")));
ASSERT_FALSE(text.contains("foo"));
ASSERT_FALSE(text.contains('q'));
}
TEST(SmallString, EqualSmallStringOperator)
{
ASSERT_TRUE(SmallString() == SmallString(""));
ASSERT_FALSE(SmallString() == SmallString("text"));
ASSERT_TRUE(SmallString("text") == SmallString("text"));
ASSERT_FALSE(SmallString("text") == SmallString("text2"));
}
TEST(SmallString, EqualCStringArrayOperator)
{
ASSERT_TRUE(SmallString() == "");
ASSERT_FALSE(SmallString() == "text");
ASSERT_TRUE(SmallString("text") == "text");
ASSERT_FALSE(SmallString("text") == "text2");
}
TEST(SmallString, EqualCStringPointerOperator)
{
ASSERT_TRUE(SmallString("text") == SmallString("text").data());
ASSERT_FALSE(SmallString("text") == SmallString("text2").data());
}
TEST(SmallString, EqualSmallStringViewOperator)
{
ASSERT_TRUE(SmallString("text") == SmallStringView("text"));
ASSERT_FALSE(SmallString("text") == SmallStringView("text2"));
}
TEST(SmallString, EqualSmallStringViewsOperator)
{
ASSERT_TRUE(SmallStringView("text") == SmallStringView("text"));
ASSERT_FALSE(SmallStringView("text") == SmallStringView("text2"));
}
TEST(SmallString, UnequalOperator)
{
ASSERT_FALSE(SmallString("text") != SmallString("text"));
ASSERT_TRUE(SmallString("text") != SmallString("text2"));
}
TEST(SmallString, UnequalCStringArrayOperator)
{
ASSERT_FALSE(SmallString("text") != "text");
ASSERT_TRUE(SmallString("text") != "text2");
}
TEST(SmallString, UnequalCStringPointerOperator)
{
ASSERT_FALSE(SmallString("text") != SmallString("text").data());
ASSERT_TRUE(SmallString("text") != SmallString("text2").data());
}
TEST(SmallString, UnequalSmallStringViewArrayOperator)
{
ASSERT_FALSE(SmallString("text") != SmallStringView("text"));
ASSERT_TRUE(SmallString("text") != SmallStringView("text2"));
}
TEST(SmallString, UnequalSmallStringViewsArrayOperator)
{
ASSERT_FALSE(SmallStringView("text") != SmallStringView("text"));
ASSERT_TRUE(SmallStringView("text") != SmallStringView("text2"));
}
TEST(SmallString, SmallerOperator)
{
ASSERT_TRUE(SmallString() < SmallString("text"));
ASSERT_TRUE(SmallString("some") < SmallString("text"));
ASSERT_TRUE(SmallString("text") < SmallString("texta"));
ASSERT_FALSE(SmallString("texta") < SmallString("text"));
ASSERT_FALSE(SmallString("text") < SmallString("some"));
ASSERT_FALSE(SmallString("text") < SmallString("text"));
}
TEST(SmallString, IsEmpty)
{
ASSERT_FALSE(SmallString("text").isEmpty());
ASSERT_TRUE(SmallString("").isEmpty());
ASSERT_TRUE(SmallString().isEmpty());
}
TEST(SmallString, HasContent)
{
ASSERT_TRUE(SmallString("text").hasContent());
ASSERT_FALSE(SmallString("").hasContent());
ASSERT_FALSE(SmallString().hasContent());
}
TEST(SmallString, Clear)
{
SmallString text("text");
text.clear();
ASSERT_TRUE(text.isEmpty());
}
TEST(SmallString, ReplaceWithEqualSizedText)
{
SmallString text("here is some text");
text.replace("some", "much");
ASSERT_THAT(text, SmallString("here is much text"));
}
TEST(SmallString, ReplaceWithEqualSizedTextOnEmptyText)
{
SmallString text;
text.replace("some", "much");
ASSERT_THAT(text, SmallString());
}
TEST(SmallString, ReplaceWithShorterText)
{
SmallString text("here is some text");
text.replace("some", "any");
ASSERT_THAT(text, SmallString("here is any text"));
}
TEST(SmallString, ReplaceWithShorterTextOnEmptyText)
{
SmallString text;
text.replace("some", "any");
ASSERT_THAT(text, SmallString());
}
TEST(SmallString, ReplaceWithLongerText)
{
SmallString text("here is some text");
text.replace("some", "much more");
ASSERT_THAT(text, SmallString("here is much more text"));
}
TEST(SmallString, ReplaceWithLongerTextOnEmptyText)
{
SmallString text;
text.replace("some", "much more");
ASSERT_THAT(text, SmallString());
}
TEST(SmallString, ReplaceShortSmallStringWithLongerText)
{
SmallString text = SmallString::fromUtf8("here is some text");
text.replace("some", "much more");
ASSERT_THAT(text, SmallString("here is much more text"));
}
TEST(SmallString, ReplaceLongSmallStringWithLongerText)
{
SmallString text = SmallString::fromUtf8("some very very very very very very very very very very very long string");
text.replace("some", "much more");
ASSERT_THAT(text, Eq(SmallString("much more very very very very very very very very very very very long string")));
}
TEST(SmallString, MultipleReplaceSmallStringWithLongerText)
{
SmallString text = SmallString("here is some text with some longer text");
text.replace("some", "much more");
ASSERT_THAT(text, SmallString("here is much more text with much more longer text"));
}
TEST(SmallString, MultipleReplaceSmallStringWithShorterText)
{
SmallString text = SmallString("here is some text with some longer text");
text.replace("some", "a");
ASSERT_THAT(text, SmallString("here is a text with a longer text"));
}
TEST(SmallString, DontReplaceReplacedText)
{
SmallString text("here is some foo text");
text.replace("foo", "foofoo");
ASSERT_THAT(text, SmallString("here is some foofoo text"));
}
TEST(SmallString, StartsWith)
{
SmallString text("$column");
ASSERT_TRUE(text.startsWith("$column"));
ASSERT_TRUE(text.startsWith("$col"));
ASSERT_FALSE(text.startsWith("col"));
ASSERT_TRUE(text.startsWith('$'));
ASSERT_FALSE(text.startsWith('@'));
}
TEST(SmallString, EndsWith)
{
SmallString text("/my/path");
ASSERT_TRUE(text.endsWith("/my/path"));
ASSERT_TRUE(text.endsWith("path"));
ASSERT_FALSE(text.endsWith("paths"));
ASSERT_TRUE(text.endsWith('h'));
ASSERT_FALSE(text.endsWith('x'));
}
TEST(SmallString, EndsWithSmallString)
{
SmallString text("/my/path");
ASSERT_TRUE(text.endsWith(SmallString("path")));
ASSERT_TRUE(text.endsWith('h'));
}
TEST(SmallString, ReserveSmallerThanReference)
{
SmallString text("text");
text.reserve(2);
ASSERT_THAT(text.capacity(), 30);
}
TEST(SmallString, ReserveBiggerThanReference)
{
SmallString text("text");
text.reserve(10);
ASSERT_THAT(text.capacity(), 30);
}
TEST(SmallString, ReserveMuchBiggerThanReference)
{
SmallString text("text");
text.reserve(100);
ASSERT_THAT(text.capacity(), 100);
}
TEST(SmallString, ReserveSmallerThanShortSmallString)
{
SmallString text = SmallString::fromUtf8("text");
text.reserve(10);
ASSERT_THAT(text.capacity(), 30);
}
TEST(SmallString, ReserveBiggerThanShortSmallString)
{
SmallString text = SmallString::fromUtf8("text");
text.reserve(100);
ASSERT_THAT(text.capacity(), 100);
}
TEST(SmallString, ReserveBiggerThanLongSmallString)
{
SmallString text = SmallString::fromUtf8("some very very very very very very very very very very very long string");
text.reserve(100);
ASSERT_THAT(text.capacity(), 100);
}
TEST(SmallString, OptimalHeapCacheLineForSize)
{
ASSERT_THAT(SmallString::optimalHeapCapacity(64), 64);
ASSERT_THAT(SmallString::optimalHeapCapacity(65), 128);
ASSERT_THAT(SmallString::optimalHeapCapacity(127), 128);
ASSERT_THAT(SmallString::optimalHeapCapacity(128), 128);
ASSERT_THAT(SmallString::optimalHeapCapacity(129), 192);
ASSERT_THAT(SmallString::optimalHeapCapacity(191), 192);
ASSERT_THAT(SmallString::optimalHeapCapacity(193), 256);
ASSERT_THAT(SmallString::optimalHeapCapacity(255), 256);
ASSERT_THAT(SmallString::optimalHeapCapacity(257), 384);
ASSERT_THAT(SmallString::optimalHeapCapacity(257), 384);
ASSERT_THAT(SmallString::optimalHeapCapacity(383), 384);
ASSERT_THAT(SmallString::optimalHeapCapacity(385), 512);
ASSERT_THAT(SmallString::optimalHeapCapacity(4095), 4096);
ASSERT_THAT(SmallString::optimalHeapCapacity(4096), 4096);
ASSERT_THAT(SmallString::optimalHeapCapacity(4097), 6144);
}
TEST(SmallString, OptimalCapacityForSize)
{
SmallString text;
ASSERT_THAT(text.optimalCapacity(0), 0);
ASSERT_THAT(text.optimalCapacity(30), 30);
ASSERT_THAT(text.optimalCapacity(31), 63);
ASSERT_THAT(text.optimalCapacity(63), 63);
ASSERT_THAT(text.optimalCapacity(64), 127);
ASSERT_THAT(text.optimalCapacity(128), 191);
}
TEST(SmallString, DataStreamData)
{
SmallString inputText("foo");
QByteArray byteArray;
QDataStream out(&byteArray, QIODevice::ReadWrite);
out << inputText;
ASSERT_TRUE(byteArray.endsWith("foo"));
}
TEST(SmallString, ReadDataStreamSize)
{
SmallString outputText("foo");
QByteArray byteArray;
quint32 size;
{
QDataStream out(&byteArray, QIODevice::WriteOnly);
out << outputText;
}
QDataStream in(&byteArray, QIODevice::ReadOnly);
in >> size;
ASSERT_THAT(size, 3);
}
TEST(SmallString, ReadDataStreamData)
{
SmallString outputText("foo");
QByteArray byteArray;
SmallString outputString;
{
QDataStream out(&byteArray, QIODevice::WriteOnly);
out << outputText;
}
QDataStream in(&byteArray, QIODevice::ReadOnly);
in >> outputString;
ASSERT_THAT(outputString, SmallString("foo"));
}
TEST(SmallString, ShortSmallStringCopyConstuctor)
{
SmallString text("text");
auto copy = text;
ASSERT_THAT(copy, text);
}
TEST(SmallString, LongSmallStringCopyConstuctor)
{
SmallString text("this is a very very very very long text");
auto copy = text;
ASSERT_THAT(copy, text);
}
TEST(SmallString, ShortSmallStringMoveConstuctor)
{
SmallString text("text");
auto copy = std::move(text);
ASSERT_TRUE(text.isEmpty());
ASSERT_THAT(copy, SmallString("text"));
}
TEST(SmallString, LongSmallStringMoveConstuctor)
{
SmallString text("this is a very very very very long text");
auto copy = std::move(text);
ASSERT_TRUE(text.isEmpty());
ASSERT_THAT(copy, SmallString("this is a very very very very long text"));
}
TEST(SmallString, ShortSmallStringCopyAssignment)
{
SmallString text("text");
SmallString copy("more text");
copy = text;
ASSERT_THAT(copy, text);
}
TEST(SmallString, LongSmallStringCopyAssignment)
{
SmallString text("this is a very very very very long text");
SmallString copy("more text");
copy = text;
ASSERT_THAT(copy, text);
}
TEST(SmallString, LongSmallStringCopySelfAssignment)
{
SmallString text("this is a very very very very long text");
text = text;
ASSERT_THAT(text, SmallString("this is a very very very very long text"));
}
TEST(SmallString, ShortSmallStringMoveAssignment)
{
SmallString text("text");
SmallString copy("more text");
copy = std::move(text);
ASSERT_THAT(text, SmallString("more text"));
ASSERT_THAT(copy, SmallString("text"));
}
TEST(SmallString, LongSmallStringMoveAssignment)
{
SmallString text("this is a very very very very long text");
SmallString copy("more text");
copy = std::move(text);
ASSERT_THAT(text, SmallString("more text"));
ASSERT_THAT(copy, SmallString("this is a very very very very long text"));
}
TEST(SmallString, ReplaceByPositionShorterWithLongerText)
{
SmallString text("this is a very very very very long text");
text.replace(8, 1, "some");
ASSERT_THAT(text, SmallString("this is some very very very very long text"));
}
TEST(SmallString, ReplaceByPositionLongerWithShortText)
{
SmallString text("this is some very very very very long text");
text.replace(8, 4, "a");
ASSERT_THAT(text, SmallString("this is a very very very very long text"));
}
TEST(SmallString, ReplaceByPositionEqualSizedTexts)
{
SmallString text("this is very very very very very long text");
text.replace(33, 4, "much");
ASSERT_THAT(text, SmallString("this is very very very very very much text"));
}

View File

@@ -64,7 +64,13 @@ SOURCES += \
highlightingmarksreportertest.cpp \
chunksreportedmonitor.cpp \
unsavedfiletest.cpp \
clangisdiagnosticrelatedtolocationtest.cpp
clangisdiagnosticrelatedtolocationtest.cpp \
smallstringtest.cpp
exists($$GOOGLEBENCHMARK_DIR) {
SOURCES += \
smallstringbenchmark.cpp
}
HEADERS += \
gtest-qt-printing.h \