summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArseny Kapoulkine <arseny.kapoulkine@gmail.com>2015-05-01 22:47:53 -0700
committerArseny Kapoulkine <arseny.kapoulkine@gmail.com>2015-05-01 22:47:53 -0700
commite4c539a869eb4045711f2b7c2390b0f450be71a1 (patch)
tree8c39f7b771d3bc04aa0d225ebf8c5c3a15420c45
parent3915f7b14430271905f4a4c808725304777e16c4 (diff)
Implement compact_string with shared storage
-rw-r--r--src/pugixml.cpp77
1 files changed, 45 insertions, 32 deletions
diff --git a/src/pugixml.cpp b/src/pugixml.cpp
index f8762bf..70dd037 100644
--- a/src/pugixml.cpp
+++ b/src/pugixml.cpp
@@ -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];
+
+ uint16_t namevalue_base;
- impl::compact_string_fat<4> name;
- impl::compact_string_fat<7> value;
+ 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];
+
+ uint16_t namevalue_base;
- impl::compact_string_fat<4> name;
- impl::compact_string_fat<7> value;
+ impl::compact_string<8, 2> name;
+ impl::compact_string<9, 3> value;
impl::compact_pointer_parent<xml_node_struct, 10> parent;