| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org> | 2 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org> |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * | 7 * |
| 8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
| (...skipping 20 matching lines...) Expand all Loading... |
| 31 #include "core/dom/NodeTraversal.h" | 31 #include "core/dom/NodeTraversal.h" |
| 32 | 32 |
| 33 namespace blink { | 33 namespace blink { |
| 34 namespace XPath { | 34 namespace XPath { |
| 35 | 35 |
| 36 // When a node set is large, sorting it by traversing the whole document is | 36 // When a node set is large, sorting it by traversing the whole document is |
| 37 // better (we can assume that we aren't dealing with documents that we cannot | 37 // better (we can assume that we aren't dealing with documents that we cannot |
| 38 // even traverse in reasonable time). | 38 // even traverse in reasonable time). |
| 39 const unsigned traversalSortCutoff = 10000; | 39 const unsigned traversalSortCutoff = 10000; |
| 40 | 40 |
| 41 typedef WillBeHeapVector<RawPtrWillBeMember<Node>> NodeSetVector; | 41 typedef HeapVector<Member<Node>> NodeSetVector; |
| 42 | 42 |
| 43 NodeSet* NodeSet::create(const NodeSet& other) | 43 NodeSet* NodeSet::create(const NodeSet& other) |
| 44 { | 44 { |
| 45 NodeSet* nodeSet = NodeSet::create(); | 45 NodeSet* nodeSet = NodeSet::create(); |
| 46 nodeSet->m_isSorted = other.m_isSorted; | 46 nodeSet->m_isSorted = other.m_isSorted; |
| 47 nodeSet->m_subtreesAreDisjoint = other.m_subtreesAreDisjoint; | 47 nodeSet->m_subtreesAreDisjoint = other.m_subtreesAreDisjoint; |
| 48 nodeSet->m_nodes.appendVector(other.m_nodes); | 48 nodeSet->m_nodes.appendVector(other.m_nodes); |
| 49 return nodeSet; | 49 return nodeSet; |
| 50 } | 50 } |
| 51 | 51 |
| 52 static inline Node* parentWithDepth(unsigned depth, const NodeSetVector& parents
) | 52 static inline Node* parentWithDepth(unsigned depth, const NodeSetVector& parents
) |
| 53 { | 53 { |
| 54 ASSERT(parents.size() >= depth + 1); | 54 ASSERT(parents.size() >= depth + 1); |
| 55 return parents[parents.size() - 1 - depth]; | 55 return parents[parents.size() - 1 - depth]; |
| 56 } | 56 } |
| 57 | 57 |
| 58 static void sortBlock(unsigned from, unsigned to, WillBeHeapVector<NodeSetVector
>& parentMatrix, bool mayContainAttributeNodes) | 58 static void sortBlock(unsigned from, unsigned to, HeapVector<NodeSetVector>& par
entMatrix, bool mayContainAttributeNodes) |
| 59 { | 59 { |
| 60 // Should not call this function with less that two nodes to sort. | 60 // Should not call this function with less that two nodes to sort. |
| 61 ASSERT(from + 1 < to); | 61 ASSERT(from + 1 < to); |
| 62 unsigned minDepth = UINT_MAX; | 62 unsigned minDepth = UINT_MAX; |
| 63 for (unsigned i = from; i < to; ++i) { | 63 for (unsigned i = from; i < to; ++i) { |
| 64 unsigned depth = parentMatrix[i].size() - 1; | 64 unsigned depth = parentMatrix[i].size() - 1; |
| 65 if (minDepth > depth) | 65 if (minDepth > depth) |
| 66 minDepth = depth; | 66 minDepth = depth; |
| 67 } | 67 } |
| 68 | 68 |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 116 if (sortedEnd != from) { | 116 if (sortedEnd != from) { |
| 117 if (to - sortedEnd > 1) | 117 if (to - sortedEnd > 1) |
| 118 sortBlock(sortedEnd, to, parentMatrix, mayContainAttributeNodes)
; | 118 sortBlock(sortedEnd, to, parentMatrix, mayContainAttributeNodes)
; |
| 119 return; | 119 return; |
| 120 } | 120 } |
| 121 } | 121 } |
| 122 | 122 |
| 123 // Children nodes of the common ancestor induce a subdivision of our | 123 // Children nodes of the common ancestor induce a subdivision of our |
| 124 // node-set. Sort it according to this subdivision, and recursively sort | 124 // node-set. Sort it according to this subdivision, and recursively sort |
| 125 // each group. | 125 // each group. |
| 126 WillBeHeapHashSet<RawPtrWillBeMember<Node>> parentNodes; | 126 HeapHashSet<Member<Node>> parentNodes; |
| 127 for (unsigned i = from; i < to; ++i) | 127 for (unsigned i = from; i < to; ++i) |
| 128 parentNodes.add(parentWithDepth(commonAncestorDepth + 1, parentMatrix[i]
)); | 128 parentNodes.add(parentWithDepth(commonAncestorDepth + 1, parentMatrix[i]
)); |
| 129 | 129 |
| 130 unsigned previousGroupEnd = from; | 130 unsigned previousGroupEnd = from; |
| 131 unsigned groupEnd = from; | 131 unsigned groupEnd = from; |
| 132 for (Node* n = commonAncestor->firstChild(); n; n = n->nextSibling()) { | 132 for (Node* n = commonAncestor->firstChild(); n; n = n->nextSibling()) { |
| 133 // If parentNodes contains the node, perform a linear search to move its | 133 // If parentNodes contains the node, perform a linear search to move its |
| 134 // children in the node-set to the beginning. | 134 // children in the node-set to the beginning. |
| 135 if (parentNodes.contains(n)) { | 135 if (parentNodes.contains(n)) { |
| 136 for (unsigned i = groupEnd; i < to; ++i) { | 136 for (unsigned i = groupEnd; i < to; ++i) { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 163 return; | 163 return; |
| 164 } | 164 } |
| 165 | 165 |
| 166 if (nodeCount > traversalSortCutoff) { | 166 if (nodeCount > traversalSortCutoff) { |
| 167 traversalSort(); | 167 traversalSort(); |
| 168 return; | 168 return; |
| 169 } | 169 } |
| 170 | 170 |
| 171 bool containsAttributeNodes = false; | 171 bool containsAttributeNodes = false; |
| 172 | 172 |
| 173 WillBeHeapVector<NodeSetVector> parentMatrix(nodeCount); | 173 HeapVector<NodeSetVector> parentMatrix(nodeCount); |
| 174 for (unsigned i = 0; i < nodeCount; ++i) { | 174 for (unsigned i = 0; i < nodeCount; ++i) { |
| 175 NodeSetVector& parentsVector = parentMatrix[i]; | 175 NodeSetVector& parentsVector = parentMatrix[i]; |
| 176 Node* n = m_nodes[i].get(); | 176 Node* n = m_nodes[i].get(); |
| 177 parentsVector.append(n); | 177 parentsVector.append(n); |
| 178 if (n->isAttributeNode()) { | 178 if (n->isAttributeNode()) { |
| 179 n = toAttr(n)->ownerElement(); | 179 n = toAttr(n)->ownerElement(); |
| 180 parentsVector.append(n); | 180 parentsVector.append(n); |
| 181 containsAttributeNodes = true; | 181 containsAttributeNodes = true; |
| 182 } | 182 } |
| 183 for (n = n->parentNode(); n; n = n->parentNode()) | 183 for (n = n->parentNode(); n; n = n->parentNode()) |
| 184 parentsVector.append(n); | 184 parentsVector.append(n); |
| 185 } | 185 } |
| 186 sortBlock(0, nodeCount, parentMatrix, containsAttributeNodes); | 186 sortBlock(0, nodeCount, parentMatrix, containsAttributeNodes); |
| 187 | 187 |
| 188 // It is not possible to just assign the result to m_nodes, because some | 188 // It is not possible to just assign the result to m_nodes, because some |
| 189 // nodes may get dereferenced and destroyed. | 189 // nodes may get dereferenced and destroyed. |
| 190 WillBeHeapVector<RefPtrWillBeMember<Node>> sortedNodes; | 190 HeapVector<Member<Node>> sortedNodes; |
| 191 sortedNodes.reserveInitialCapacity(nodeCount); | 191 sortedNodes.reserveInitialCapacity(nodeCount); |
| 192 for (unsigned i = 0; i < nodeCount; ++i) | 192 for (unsigned i = 0; i < nodeCount; ++i) |
| 193 sortedNodes.append(parentMatrix[i][0]); | 193 sortedNodes.append(parentMatrix[i][0]); |
| 194 | 194 |
| 195 const_cast<WillBeHeapVector<RefPtrWillBeMember<Node>>&>(m_nodes).swap(sorted
Nodes); | 195 const_cast<HeapVector<Member<Node>>&>(m_nodes).swap(sortedNodes); |
| 196 } | 196 } |
| 197 | 197 |
| 198 static Node* findRootNode(Node* node) | 198 static Node* findRootNode(Node* node) |
| 199 { | 199 { |
| 200 if (node->isAttributeNode()) | 200 if (node->isAttributeNode()) |
| 201 node = toAttr(node)->ownerElement(); | 201 node = toAttr(node)->ownerElement(); |
| 202 if (node->inDocument()) { | 202 if (node->inDocument()) { |
| 203 node = &node->document(); | 203 node = &node->document(); |
| 204 } else { | 204 } else { |
| 205 while (Node* parent = node->parentNode()) | 205 while (Node* parent = node->parentNode()) |
| 206 node = parent; | 206 node = parent; |
| 207 } | 207 } |
| 208 return node; | 208 return node; |
| 209 } | 209 } |
| 210 | 210 |
| 211 void NodeSet::traversalSort() const | 211 void NodeSet::traversalSort() const |
| 212 { | 212 { |
| 213 WillBeHeapHashSet<RawPtrWillBeMember<Node>> nodes; | 213 HeapHashSet<Member<Node>> nodes; |
| 214 bool containsAttributeNodes = false; | 214 bool containsAttributeNodes = false; |
| 215 | 215 |
| 216 unsigned nodeCount = m_nodes.size(); | 216 unsigned nodeCount = m_nodes.size(); |
| 217 ASSERT(nodeCount > 1); | 217 ASSERT(nodeCount > 1); |
| 218 for (unsigned i = 0; i < nodeCount; ++i) { | 218 for (unsigned i = 0; i < nodeCount; ++i) { |
| 219 Node* node = m_nodes[i].get(); | 219 Node* node = m_nodes[i].get(); |
| 220 nodes.add(node); | 220 nodes.add(node); |
| 221 if (node->isAttributeNode()) | 221 if (node->isAttributeNode()) |
| 222 containsAttributeNodes = true; | 222 containsAttributeNodes = true; |
| 223 } | 223 } |
| 224 | 224 |
| 225 WillBeHeapVector<RefPtrWillBeMember<Node>> sortedNodes; | 225 HeapVector<Member<Node>> sortedNodes; |
| 226 sortedNodes.reserveInitialCapacity(nodeCount); | 226 sortedNodes.reserveInitialCapacity(nodeCount); |
| 227 | 227 |
| 228 for (Node& n : NodeTraversal::startsAt(findRootNode(m_nodes.first().get())))
{ | 228 for (Node& n : NodeTraversal::startsAt(findRootNode(m_nodes.first().get())))
{ |
| 229 if (nodes.contains(&n)) | 229 if (nodes.contains(&n)) |
| 230 sortedNodes.append(&n); | 230 sortedNodes.append(&n); |
| 231 | 231 |
| 232 if (!containsAttributeNodes || !n.isElementNode()) | 232 if (!containsAttributeNodes || !n.isElementNode()) |
| 233 continue; | 233 continue; |
| 234 | 234 |
| 235 Element* element = toElement(&n); | 235 Element* element = toElement(&n); |
| 236 AttributeCollection attributes = element->attributes(); | 236 AttributeCollection attributes = element->attributes(); |
| 237 for (auto& attribute : attributes) { | 237 for (auto& attribute : attributes) { |
| 238 RefPtrWillBeRawPtr<Attr> attr = element->attrIfExists(attribute.name
()); | 238 RawPtr<Attr> attr = element->attrIfExists(attribute.name()); |
| 239 if (attr && nodes.contains(attr.get())) | 239 if (attr && nodes.contains(attr.get())) |
| 240 sortedNodes.append(attr); | 240 sortedNodes.append(attr); |
| 241 } | 241 } |
| 242 } | 242 } |
| 243 | 243 |
| 244 ASSERT(sortedNodes.size() == nodeCount); | 244 ASSERT(sortedNodes.size() == nodeCount); |
| 245 const_cast<WillBeHeapVector<RefPtrWillBeMember<Node>>&>(m_nodes).swap(sorted
Nodes); | 245 const_cast<HeapVector<Member<Node>>&>(m_nodes).swap(sortedNodes); |
| 246 } | 246 } |
| 247 | 247 |
| 248 void NodeSet::reverse() | 248 void NodeSet::reverse() |
| 249 { | 249 { |
| 250 if (m_nodes.isEmpty()) | 250 if (m_nodes.isEmpty()) |
| 251 return; | 251 return; |
| 252 | 252 |
| 253 unsigned from = 0; | 253 unsigned from = 0; |
| 254 unsigned to = m_nodes.size() - 1; | 254 unsigned to = m_nodes.size() - 1; |
| 255 while (from < to) { | 255 while (from < to) { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 273 Node* NodeSet::anyNode() const | 273 Node* NodeSet::anyNode() const |
| 274 { | 274 { |
| 275 if (isEmpty()) | 275 if (isEmpty()) |
| 276 return nullptr; | 276 return nullptr; |
| 277 | 277 |
| 278 return m_nodes.at(0).get(); | 278 return m_nodes.at(0).get(); |
| 279 } | 279 } |
| 280 | 280 |
| 281 } // namespace XPath | 281 } // namespace XPath |
| 282 } // namespace blink | 282 } // namespace blink |
| OLD | NEW |