Fix String::Data::reserve on big endian platforms, and document String::Data

reserve was not ensuring the capacity would be pair, which is needed
on big endian machines, as we use its least significant bit to flag
short string optimizations. On little endian the bit we use is the
8th most significant (the least significant bit of the last byte),
so we were not hitting any problems.

Fixes #828
This commit is contained in:
Maxime Coste 2016-09-28 19:03:26 +01:00
parent 1b9eb2c6ba
commit e701254b02
2 changed files with 15 additions and 0 deletions

View File

@ -17,6 +17,7 @@ String::Data::Data(const char* data, size_t size, size_t capacity)
if (capacity & 1) if (capacity & 1)
++capacity; ++capacity;
kak_assert(capacity < Long::max_capacity);
l.ptr = Alloc{}.allocate(capacity+1); l.ptr = Alloc{}.allocate(capacity+1);
l.size = size; l.size = size;
l.capacity = capacity; l.capacity = capacity;
@ -71,6 +72,10 @@ void String::Data::reserve(size_t new_capacity)
if (is_long()) if (is_long())
new_capacity = std::max(l.capacity * 2, new_capacity); new_capacity = std::max(l.capacity * 2, new_capacity);
if (new_capacity & 1)
++new_capacity;
kak_assert(new_capacity < Long::max_capacity);
char* new_ptr = Alloc{}.allocate(new_capacity+1); char* new_ptr = Alloc{}.allocate(new_capacity+1);
if (copy) if (copy)
{ {

View File

@ -130,12 +130,22 @@ public:
static const String ms_empty; static const String ms_empty;
static constexpr const char* option_type_name = "str"; static constexpr const char* option_type_name = "str";
// String data storage using small string optimization.
//
// the LSB of the last byte is used to flag if we are using the small buffer
// or an allocated one. On big endian systems that means the allocated
// capacity must be pair, on little endian systems that means the allocated
// capacity cannot use its most significant byte, so we effectively limit
// capacity to 2^24 on 32bit arch, and 2^60 on 64.
union Data union Data
{ {
using Alloc = Allocator<char, MemoryDomain::String>; using Alloc = Allocator<char, MemoryDomain::String>;
struct Long struct Long
{ {
static constexpr size_t max_capacity =
(size_t)1 << 8 * (sizeof(size_t) - 1);
char* ptr; char* ptr;
size_t size; size_t size;
size_t capacity; size_t capacity;