Commit 9b4afa01 authored by Marco Bubke's avatar Marco Bubke

Utils: Improve and fix operators in SmallString

Change-Id: I51f4e647cbd3ada0c3a86d16f40fd8044acead33
Reviewed-by: Tim Jenssen's avatarTim Jenssen <tim.jenssen@qt.io>
parent c02df443
......@@ -506,45 +506,14 @@ public:
return joinedString;
}
unitttest_public:
bool isShortString() const noexcept
{
return !m_data.shortString.isReference;
}
bool isReadOnlyReference() const noexcept
char &operator[](std::size_t index)
{
return m_data.shortString.isReadOnlyReference;
}
bool hasAllocatedMemory() const noexcept
{
return !isShortString() && !isReadOnlyReference();
}
bool fitsNotInCapacity(size_type capacity) const noexcept
{
return (isShortString() && capacity > shortStringCapacity())
|| (!isShortString() && capacity > m_data.allocated.data.capacity);
return *(data() + index);
}
static
size_type optimalHeapCapacity(const size_type size)
char operator[](std::size_t index) const
{
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;
return *(data() + index);
}
template<size_type ArraySize>
......@@ -575,12 +544,6 @@ unitttest_public:
return second == first;
}
friend bool operator==(const BasicSmallString& first, const BasicSmallString& second) noexcept
{
return first.size() == second.size()
&& std::memcmp(first.data(), second.data(), first.size()) == 0;
}
friend bool operator==(const BasicSmallString& first, const SmallStringView& second) noexcept
{
return first.size() == second.size()
......@@ -635,17 +598,17 @@ unitttest_public:
return second != first;
}
friend bool operator<(const BasicSmallString& first, const BasicSmallString& second) noexcept
friend bool operator<(const BasicSmallString& first, SmallStringView second) noexcept
{
if (first.size() != second.size())
return first.size() < second.size();
const int comparison = std::memcmp(first.data(), second.data(), first.size() + 1);
const int comparison = std::memcmp(first.data(), second.data(), first.size());
return comparison < 0;
}
friend bool operator<(const BasicSmallString& first, SmallStringView second) noexcept
friend bool operator<(SmallStringView first, const BasicSmallString& second) noexcept
{
if (first.size() != second.size())
return first.size() < second.size();
......@@ -655,14 +618,45 @@ unitttest_public:
return comparison < 0;
}
friend bool operator<(SmallStringView first, const BasicSmallString& second) noexcept
unitttest_public:
bool isShortString() const noexcept
{
if (first.size() != second.size())
return first.size() < second.size();
return !m_data.shortString.isReference;
}
const int comparison = std::memcmp(first.data(), second.data(), first.size());
bool isReadOnlyReference() const noexcept
{
return m_data.shortString.isReadOnlyReference;
}
return comparison < 0;
bool hasAllocatedMemory() const noexcept
{
return !isShortString() && !isReadOnlyReference();
}
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:
......@@ -818,6 +812,37 @@ private:
Internal::StringDataLayout<Size> m_data;
};
template<template<uint> class String, uint Size>
using isSameString = std::is_same<std::remove_reference_t<std::remove_cv_t<String<Size>>>,
BasicSmallString<Size>>;
template<template<uint> class String,
uint SizeOne,
uint SizeTwo,
typename = std::enable_if_t<isSameString<String, SizeOne>::value
|| isSameString<String, SizeTwo>::value>>
bool operator==(const String<SizeOne> &first, const String<SizeTwo> &second) noexcept
{
return first.size() == second.size()
&& std::memcmp(first.data(), second.data(), first.size()) == 0;
}
template<template<uint> class String,
uint SizeOne,
uint SizeTwo,
typename = std::enable_if_t<isSameString<String, SizeOne>::value
|| isSameString<String, SizeTwo>::value>>
bool operator<(const String<SizeOne> &first, const String<SizeTwo> &second) noexcept
{
if (first.size() != second.size())
return first.size() < second.size();
const int comparison = std::memcmp(first.data(), second.data(), first.size() + 1);
return comparison < 0;
}
template<typename Key,
typename Value,
typename Hash = std::hash<Key>,
......
......@@ -601,6 +601,14 @@ TEST(SmallString, EqualSmallStringOperator)
ASSERT_FALSE(SmallString("text") == SmallString("text2"));
}
TEST(SmallString, EqualSmallStringOperatorWithDifferenceClassSizes)
{
ASSERT_TRUE(SmallString() == PathString(""));
ASSERT_FALSE(SmallString() == PathString("text"));
ASSERT_TRUE(SmallString("text") == PathString("text"));
ASSERT_FALSE(SmallString("text") == PathString("text2"));
}
TEST(SmallString, EqualCStringArrayOperator)
{
ASSERT_TRUE(SmallString() == "");
......@@ -687,6 +695,16 @@ TEST(SmallString, SmallerOperatorWithStringViewLeft)
ASSERT_FALSE(SmallStringView("text") < SmallString("text"));
}
TEST(SmallString, SmallerOperatorForDifferenceClassSizes)
{
ASSERT_TRUE(SmallString() < PathString("text"));
ASSERT_TRUE(SmallString("some") < PathString("text"));
ASSERT_TRUE(SmallString("text") < PathString("texta"));
ASSERT_FALSE(SmallString("texta") < PathString("text"));
ASSERT_FALSE(SmallString("text") < PathString("some"));
ASSERT_FALSE(SmallString("text") < PathString("text"));
}
TEST(SmallString, IsEmpty)
{
ASSERT_FALSE(SmallString("text").isEmpty());
......@@ -1129,3 +1147,42 @@ TEST(SmallString, CompareTextWithDifferentLineEndings)
ASSERT_THAT(unixText, convertedText);
}
TEST(SmallString, ConstSubscriptOperator)
{
const SmallString text = {"some text"};
auto &&sign = text[5];
ASSERT_THAT(sign, 't');
}
TEST(SmallString, NonConstSubscriptOperator)
{
SmallString text = {"some text"};
auto &&sign = text[5];
ASSERT_THAT(sign, 't');
}
TEST(SmallString, ManipulateConstSubscriptOperator)
{
const SmallString text = {"some text"};
auto &&sign = text[5];
sign = 'q';
ASSERT_THAT(text, SmallString{"some text"});
}
TEST(SmallString, ManipulateNonConstSubscriptOperator)
{
char rawText[] = "some text";
SmallString text{rawText};
auto &&sign = text[5];
sign = 'q';
ASSERT_THAT(text, SmallString{"some qext"});
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment