auto merge of #2094 : Manishearth/servo/id-efficiency, r=Ms2ger

This improves the code written for #1822 to use a single linear traversal.

The current code uses a binary search with `CompareDocumentPosition()` for comparing element position, however this method internally calls `traverse_preorder()` (i.e. a linear traversal) so calling this on every pass is quite inefficient.
This commit is contained in:
bors-servo 2014-04-11 17:04:09 -04:00
commit b174a6439b

View file

@ -7,7 +7,6 @@ use dom::bindings::codegen::InheritTypes::{DocumentBase, NodeCast, DocumentCast}
use dom::bindings::codegen::InheritTypes::{HTMLHeadElementCast, TextCast, ElementCast}; use dom::bindings::codegen::InheritTypes::{HTMLHeadElementCast, TextCast, ElementCast};
use dom::bindings::codegen::InheritTypes::{DocumentTypeCast, HTMLHtmlElementCast}; use dom::bindings::codegen::InheritTypes::{DocumentTypeCast, HTMLHtmlElementCast};
use dom::bindings::codegen::DocumentBinding; use dom::bindings::codegen::DocumentBinding;
use dom::bindings::codegen::NodeBinding::NodeConstants::{DOCUMENT_POSITION_CONTAINS, DOCUMENT_POSITION_PRECEDING};
use dom::bindings::js::JS; use dom::bindings::js::JS;
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object}; use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::bindings::error::{ErrorResult, Fallible, NotSupported, InvalidCharacter, HierarchyRequest, NamespaceError}; use dom::bindings::error::{ErrorResult, Fallible, NotSupported, InvalidCharacter, HierarchyRequest, NamespaceError};
@ -677,23 +676,26 @@ impl Document {
// FIXME https://github.com/mozilla/rust/issues/13195 // FIXME https://github.com/mozilla/rust/issues/13195
// Use mangle() when it exists again. // Use mangle() when it exists again.
let root = self.GetDocumentElement().expect("The element is in the document, so there must be a document element.");
match self.idmap.find_mut(&id) { match self.idmap.find_mut(&id) {
Some(elements) => { Some(elements) => {
let new_node = NodeCast::from(element); let new_node = NodeCast::from(element);
let mut head : uint = 0u; let mut head : uint = 0u;
let mut tail : uint = elements.len(); let root: JS<Node> = NodeCast::from(&root);
while head < tail { for node in root.traverse_preorder() {
let middle = ((head + tail) / 2) as int; match ElementCast::to(&node) {
let elem = &elements[middle]; Some(elem) => {
let js_node = NodeCast::from(elem); if elements[head] == elem {
let position = elem.get().node.CompareDocumentPosition(&js_node, &new_node); head = head + 1;
if position == DOCUMENT_POSITION_PRECEDING || position == DOCUMENT_POSITION_PRECEDING + DOCUMENT_POSITION_CONTAINS { }
tail = middle as uint; if new_node == node || head == elements.len() {
} else { break;
head = middle as uint + 1u;
} }
} }
elements.insert(tail, element.clone()); None => {}
}
}
elements.insert(head, element.clone());
return; return;
}, },
None => (), None => (),