Implement compact_string with shared storage

This commit is contained in:
Arseny Kapoulkine
2015-05-01 22:47:53 -07:00
parent 3915f7b144
commit e4c539a869

View File

@@ -892,14 +892,14 @@ PUGI__NS_BEGIN
uint16_t _data;
};
template <int header_offset> class compact_string_fat
template <int header_offset, int base_offset> class compact_string
{
public:
compact_string_fat(): _data0(0), _data1(0), _data2(0)
compact_string(): _data(0)
{
}
void operator=(const compact_string_fat& rhs)
void operator=(const compact_string& rhs)
{
*this = rhs + 0;
}
@@ -913,50 +913,59 @@ PUGI__NS_BEGIN
if (PUGI__UNLIKELY(page->compact_string_base == 0))
page->compact_string_base = value;
uint16_t* base = reinterpret_cast<uint16_t*>(reinterpret_cast<char*>(this) - base_offset);
ptrdiff_t offset = value - page->compact_string_base;
if (PUGI__UNLIKELY(static_cast<uintptr_t>(offset) >= 16777213))
if (*base == 0)
*base = static_cast<uint16_t>(offset >> 7) + 1;
ptrdiff_t remainder = offset - ((*base - 1) << 7);
if (PUGI__UNLIKELY(static_cast<uintptr_t>(remainder) >= 254 || *base == 0))
{
compact_set_value<header_offset>(this, value);
offset = 16777214;
_data = 255;
}
else
{
_data = static_cast<unsigned char>(remainder + 1);
}
_data0 = static_cast<unsigned char>(offset + 1);
_data1 = static_cast<unsigned char>((offset + 1) >> 8);
_data2 = static_cast<unsigned char>((offset + 1) >> 16);
}
else
{
_data0 = 0;
_data1 = 0;
_data2 = 0;
_data = 0;
}
}
operator char_t*() const
{
unsigned int data = _data0 + (_data1 << 8) + (_data2 << 16);
if (data)
if (_data)
{
xml_memory_page* page = compact_get_page(this, header_offset);
if (data < 16777215)
return page->compact_string_base + (data - 1);
else
if (PUGI__UNLIKELY(_data == 255))
{
return compact_get_value<header_offset, char_t>(this);
}
else
{
xml_memory_page* page = compact_get_page(this, header_offset);
const uint16_t* base = reinterpret_cast<const uint16_t*>(reinterpret_cast<const char*>(this) - base_offset);
assert(*base);
ptrdiff_t offset = ((*base - 1) << 7) + (_data - 1);
return page->compact_string_base + offset;
}
}
else
return 0;
}
private:
unsigned char _data0;
unsigned char _data1;
unsigned char _data2;
unsigned char _data;
};
PUGI__NS_END
#endif
@@ -965,17 +974,19 @@ namespace pugi
{
struct xml_attribute_struct
{
xml_attribute_struct(impl::xml_memory_page* page): header(page, 0)
xml_attribute_struct(impl::xml_memory_page* page): header(page, 0), namevalue_base(0)
{
PUGI__STATIC_ASSERT(sizeof(xml_attribute_struct) == 12);
}
impl::compact_header header;
unsigned char padding;
unsigned char padding[3];
impl::compact_string_fat<4> name;
impl::compact_string_fat<7> value;
uint16_t namevalue_base;
impl::compact_string<8, 2> name;
impl::compact_string<9, 3> value;
impl::compact_pointer<xml_attribute_struct, 10> prev_attribute_c;
impl::compact_pointer<xml_attribute_struct, 11, 0> next_attribute;
@@ -983,17 +994,19 @@ namespace pugi
struct xml_node_struct
{
xml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(page, type - 1)
xml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(page, type - 1), namevalue_base(0)
{
PUGI__STATIC_ASSERT(sizeof(xml_node_struct) == 16);
}
impl::compact_header header;
unsigned char padding;
unsigned char padding[3];
impl::compact_string_fat<4> name;
impl::compact_string_fat<7> value;
uint16_t namevalue_base;
impl::compact_string<8, 2> name;
impl::compact_string<9, 3> value;
impl::compact_pointer_parent<xml_node_struct, 10> parent;