Commit a0c69c51 authored by Marco Bubke's avatar Marco Bubke

Utils: Fix long small string

We used only 6 bit to save the short size but for SmallString with a size
over 64 it is not enough. So we have now to use a uint16 instead of a
uint8 if the size if over 64.

Change-Id: I53558e492b6cb40b739b23a8af83d192a2e11bd2
Reviewed-by: Tim Jenssen's avatarTim Jenssen <tim.jenssen@qt.io>
parent 729c5353
......@@ -55,7 +55,7 @@ namespace Utils {
template <uint Size>
class BasicSmallString;
using SmallString = BasicSmallString<31>;
using PathString = BasicSmallString<191>;
using PathString = BasicSmallString<190>;
}
namespace ClangBackEnd {
......
......@@ -65,6 +65,11 @@ public:
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using size_type = std::size_t;
static_assert(Size < 64
? sizeof(Internal::StringDataLayout<Size>) == Size + 1
: sizeof(Internal::StringDataLayout<Size>) == Size + 2,
"Size is wrong");
BasicSmallString() noexcept
: m_data(Internal::StringDataLayout<Size>())
{
......@@ -498,7 +503,7 @@ public:
constexpr static
size_type shortStringCapacity() noexcept
{
return BasicSmallStringLiteral<Size>::shortStringCapacity();
return Internal::StringDataLayout<Size>::shortStringCapacity();
}
size_type optimalCapacity(const size_type size)
......@@ -897,6 +902,6 @@ std::vector<Type> clone(const std::vector<Type> &vector)
}
using SmallString = BasicSmallString<31>;
using PathString = BasicSmallString<191>;
using PathString = BasicSmallString<190>;
} // namespace Utils
......@@ -28,6 +28,7 @@
#include <QtGlobal>
#include <cstdint>
#include <type_traits>
#ifdef Q_CC_MSVC
# define ALIGNAS_16
......@@ -41,7 +42,19 @@ namespace Internal {
using size_type = std::size_t;
template <uint MaximumShortStringDataAreaSize>
template<bool Bool>
struct block_type
{
using type = uint8_t;
};
template<>
struct block_type<false> {
using type = uint16_t;
};
template <uint MaximumShortStringDataAreaSize,
typename BlockType = typename block_type<(MaximumShortStringDataAreaSize < 64)>::type>
struct AllocatedLayout {
struct Data {
char *pointer;
......@@ -49,12 +62,13 @@ struct AllocatedLayout {
size_type capacity;
} data;
char dummy[MaximumShortStringDataAreaSize - sizeof(Data)];
std::uint8_t shortStringSize: 6;
std::uint8_t isReadOnlyReference : 1;
std::uint8_t isReference : 1;
BlockType shortStringSize : (sizeof(BlockType) * 8) - 2;
BlockType isReadOnlyReference : 1;
BlockType isReference : 1;
};
template <uint MaximumShortStringDataAreaSize>
template <uint MaximumShortStringDataAreaSize,
typename BlockType = typename block_type<(MaximumShortStringDataAreaSize < 64)>::type>
struct ReferenceLayout {
struct Data {
const char *pointer;
......@@ -62,23 +76,28 @@ struct ReferenceLayout {
size_type capacity;
} data;
char dummy[MaximumShortStringDataAreaSize - sizeof(Data)];
std::uint8_t shortStringSize: 6;
std::uint8_t isReadOnlyReference : 1;
std::uint8_t isReference : 1;
BlockType shortStringSize : (sizeof(BlockType) * 8) - 2;
BlockType isReadOnlyReference : 1;
BlockType isReference : 1;
};
template <uint MaximumShortStringDataAreaSize>
template <uint MaximumShortStringDataAreaSize,
typename BlockType = typename block_type<(MaximumShortStringDataAreaSize < 64)>::type>
struct ShortStringLayout {
char string[MaximumShortStringDataAreaSize];
std::uint8_t shortStringSize: 6;
std::uint8_t isReadOnlyReference : 1;
std::uint8_t isReference : 1;
BlockType shortStringSize : (sizeof(BlockType) * 8) - 2;
BlockType isReadOnlyReference : 1;
BlockType isReference : 1;
};
template <uint MaximumShortStringDataAreaSize>
struct ALIGNAS_16 StringDataLayout {
static_assert( MaximumShortStringDataAreaSize >= 15, "Size must be greater equal than 15 bytes!");
static_assert(((MaximumShortStringDataAreaSize + 1) % 16) == 0, "Size + 1 must be dividable by 16!");
static_assert(MaximumShortStringDataAreaSize < 64
? ((MaximumShortStringDataAreaSize + 1) % 16) == 0
: ((MaximumShortStringDataAreaSize + 2) % 16) == 0,
"Size + 1 must be dividable by 16 if under 64 and Size + 2 must be dividable by 16 if over 64!");
StringDataLayout() noexcept = default;
constexpr StringDataLayout(const char *string,
......@@ -117,6 +136,14 @@ struct ALIGNAS_16 StringDataLayout {
#endif
}
constexpr static
size_type shortStringCapacity() noexcept
{
return MaximumShortStringDataAreaSize < 64
? MaximumShortStringDataAreaSize - 1
: MaximumShortStringDataAreaSize - 2;
}
union {
AllocatedLayout<MaximumShortStringDataAreaSize> allocated;
ReferenceLayout<MaximumShortStringDataAreaSize> reference;
......
......@@ -89,7 +89,7 @@ public:
constexpr static
size_type shortStringCapacity() noexcept
{
return sizeof(Internal::ShortStringLayout<Size>) - 2;
return Internal::StringDataLayout<Size>::shortStringCapacity();
}
bool isShortString() const noexcept
......
......@@ -154,5 +154,5 @@ private:
};
using SmallStringVector = BasicSmallStringVector<31>;
using PathStringVector = BasicSmallStringVector<191>;
using PathStringVector = BasicSmallStringVector<190>;
} // namespace Utils;
......@@ -44,7 +44,7 @@ namespace Utils {
template <uint Size>
class BasicSmallString;
using SmallString = BasicSmallString<31>;
using PathString = BasicSmallString<191>;
using PathString = BasicSmallString<190>;
}
namespace ClangBackEnd {
......
......@@ -33,6 +33,7 @@
using namespace ::testing;
using Utils::PathString;
using Utils::SmallString;
using Utils::SmallStringLiteral;
using Utils::SmallStringView;
......@@ -445,6 +446,15 @@ TEST(SmallString, SizeShortSmallString)
ASSERT_THAT(size, 4);
}
TEST(SmallString, SizeShortPathString)
{
SmallString shortPath("very very very very very very very very very very very long path which fits in the short memory");
auto size = shortPath.size();
ASSERT_THAT(size, 95);
}
TEST(SmallString, SizeLongSmallString)
{
auto longText = SmallString::fromUtf8("very very very very very very very very very very very long string");
......
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