summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/manual.qbk12
-rw-r--r--src/pugixml.cpp14
-rw-r--r--src/pugixml.hpp10
-rw-r--r--tests/test_dom_traverse.cpp22
4 files changed, 54 insertions, 4 deletions
diff --git a/docs/manual.qbk b/docs/manual.qbk
index ea6b5d3..8fb9564 100644
--- a/docs/manual.qbk
+++ b/docs/manual.qbk
@@ -353,6 +353,10 @@ Both `xml_node` and `xml_attribute` have the default constructor which initializ
[#xml_node::comparison]
`xml_node` and `xml_attribute` try to behave like pointers, that is, they can be compared with other objects of the same type, making it possible to use them as keys of associative containers. All handles to the same underlying object are equal, and any two handles to different underlying objects are not equal. Null handles only compare as equal to themselves. The result of relational comparison can not be reliably determined from the order of nodes in file or other ways. Do not use relational comparison operators except for search optimization (i.e. associative container keys).
+[#xml_attribute::hash_value]
+[#xml_node::hash_value]
+If you want to use `xml_node` or `xml_attribute` objects as keys in hash-based associative containers, you can use the `hash_value` member functions. They return the hash values that are guaranteed to be the same for all handles to the same underlying object. The hash value for null handles is 0.
+
[#xml_attribute::unspecified_bool_type]
[#xml_node::unspecified_bool_type]
[#xml_attribute::empty]
@@ -1624,6 +1628,8 @@ Major release, featuring many XPath enhancements, wide character filename suppor
# Added as_utf8 and as_wide overloads for std::wstring/std::string arguments
# Added DOCTYPE node type (node_doctype) and a special parse flag, parse_doctype, to add such nodes to the document during parsing
# Added parse_full parse flag mask, which extends parse_default with all node type parsing flags except parse_ws_pcdata
+ # Added xml_node::hash_value() and xml_attribute::hash_value() functions for use in hash-based containers
+ # Added internal_object() and additional constructor for both xml_node and xml_attribute for easier marshalling (useful for language bindings)
* Performance improvements:
# xml_node::root() and xml_node::offset_debug() are now O(1) instead of O(logN)
@@ -1932,6 +1938,9 @@ Classes:
* `bool `[link xml_attribute::comparison operator>=]`(const xml_attribute& r) const;`
[lbr]
+ * `size_t `[link xml_attribute::hash_value hash_value]`() const;`
+ [lbr]
+
* `xml_attribute `[link xml_attribute::next_attribute next_attribute]`() const;`
* `xml_attribute `[link xml_attribute::previous_attribute previous_attribute]`() const;`
[lbr]
@@ -1978,6 +1987,9 @@ Classes:
* `bool `[link xml_node::comparison operator>=]`(const xml_node& r) const;`
[lbr]
+ * `size_t `[link xml_node::hash_value hash_value]`() const;`
+ [lbr]
+
* `xml_node_type `[link xml_node::type type]`() const;`
[lbr]
diff --git a/src/pugixml.cpp b/src/pugixml.cpp
index febf2eb..1142930 100644
--- a/src/pugixml.cpp
+++ b/src/pugixml.cpp
@@ -3420,7 +3420,12 @@ namespace pugi
return (_attr && _attr->value) ? _attr->value : PUGIXML_TEXT("");
}
- xml_attribute_struct* xml_attribute::internal_object()
+ size_t xml_attribute::hash_value() const
+ {
+ return static_cast<size_t>(reinterpret_cast<uintptr_t>(_attr) / sizeof(xml_attribute_struct));
+ }
+
+ xml_attribute_struct* xml_attribute::internal_object() const
{
return _attr;
}
@@ -4134,7 +4139,12 @@ namespace pugi
return walker.end(arg_end);
}
- xml_node_struct* xml_node::internal_object()
+ size_t xml_node::hash_value() const
+ {
+ return static_cast<size_t>(reinterpret_cast<uintptr_t>(_root) / sizeof(xml_node_struct));
+ }
+
+ xml_node_struct* xml_node::internal_object() const
{
return _root;
}
diff --git a/src/pugixml.hpp b/src/pugixml.hpp
index 8fba12a..9b0d0d6 100644
--- a/src/pugixml.hpp
+++ b/src/pugixml.hpp
@@ -321,8 +321,11 @@ namespace pugi
xml_attribute next_attribute() const;
xml_attribute previous_attribute() const;
+ // Get hash value (unique for handles to the same object)
+ size_t hash_value() const;
+
// Get internal pointer
- xml_attribute_struct* internal_object();
+ xml_attribute_struct* internal_object() const;
};
#ifdef __BORLANDC__
@@ -532,8 +535,11 @@ namespace pugi
// Get node offset in parsed file/string (in char_t units) for debugging purposes
ptrdiff_t offset_debug() const;
+ // Get hash value (unique for handles to the same object)
+ size_t hash_value() const;
+
// Get internal pointer
- xml_node_struct* internal_object();
+ xml_node_struct* internal_object() const;
};
#ifdef __BORLANDC__
diff --git a/tests/test_dom_traverse.cpp b/tests/test_dom_traverse.cpp
index 865b90a..0ee87ed 100644
--- a/tests/test_dom_traverse.cpp
+++ b/tests/test_dom_traverse.cpp
@@ -782,3 +782,25 @@ TEST_XML(dom_internal_object, "<node attr='value'>value</node>")
xml_attribute attr_copy = attr;
CHECK(attr_copy.internal_object() == attr.internal_object());
}
+
+TEST_XML(dom_hash_value, "<node attr='value'>value</node>")
+{
+ xml_node node = doc.child(STR("node"));
+ xml_attribute attr = node.first_attribute();
+ xml_node value = node.first_child();
+
+ CHECK(xml_node().hash_value() == 0);
+ CHECK(xml_attribute().hash_value() == 0);
+
+ CHECK(node.hash_value() != 0);
+ CHECK(value.hash_value() != 0);
+ CHECK(node.hash_value() != value.hash_value());
+
+ CHECK(attr.hash_value() != 0);
+
+ xml_node node_copy = node;
+ CHECK(node_copy.hash_value() == node.hash_value());
+
+ xml_attribute attr_copy = attr;
+ CHECK(attr_copy.hash_value() == attr.hash_value());
+}