Skip to content

Commit f29ede3

Browse files
committed
try to optimize the id/name index by replacing the tree set
1 parent ce7f253 commit f29ede3

File tree

1 file changed

+68
-21
lines changed

1 file changed

+68
-21
lines changed

src/main/java/org/htmlunit/html/HtmlPage.java

Lines changed: 68 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@
4040
import java.util.Locale;
4141
import java.util.Map;
4242
import java.util.Set;
43-
import java.util.SortedSet;
44-
import java.util.TreeSet;
4543
import java.util.WeakHashMap;
4644
import java.util.concurrent.ConcurrentHashMap;
4745

@@ -153,8 +151,8 @@ public class HtmlPage extends SgmlPage {
153151
private transient Charset originalCharset_;
154152
private final Object lock_ = new SerializableLock(); // used for synchronization
155153

156-
private Map<String, SortedSet<DomElement>> idMap_ = new ConcurrentHashMap<>();
157-
private Map<String, SortedSet<DomElement>> nameMap_ = new ConcurrentHashMap<>();
154+
private Map<String, MappedElementIndexEntry> idMap_ = new ConcurrentHashMap<>();
155+
private Map<String, MappedElementIndexEntry> nameMap_ = new ConcurrentHashMap<>();
158156

159157
private List<BaseFrameElement> frameElements_ = new ArrayList<>();
160158
private int parserCount_;
@@ -629,7 +627,7 @@ public ProcessingInstruction createProcessingInstruction(final String namespaceU
629627
@Override
630628
public DomElement getElementById(final String elementId) {
631629
if (elementId != null) {
632-
final SortedSet<DomElement> elements = idMap_.get(elementId);
630+
final MappedElementIndexEntry elements = idMap_.get(elementId);
633631
if (elements != null) {
634632
return elements.first();
635633
}
@@ -1665,9 +1663,9 @@ public <E extends HtmlElement> E getHtmlElementById(final String elementId) thro
16651663
*/
16661664
public List<DomElement> getElementsById(final String elementId) {
16671665
if (elementId != null) {
1668-
final SortedSet<DomElement> elements = idMap_.get(elementId);
1666+
final MappedElementIndexEntry elements = idMap_.get(elementId);
16691667
if (elements != null) {
1670-
return new ArrayList<>(elements);
1668+
return new ArrayList<>(elements.elements());
16711669
}
16721670
}
16731671
return Collections.emptyList();
@@ -1685,7 +1683,7 @@ public List<DomElement> getElementsById(final String elementId) {
16851683
@SuppressWarnings("unchecked")
16861684
public <E extends DomElement> E getElementByName(final String name) throws ElementNotFoundException {
16871685
if (name != null) {
1688-
final SortedSet<DomElement> elements = nameMap_.get(name);
1686+
final MappedElementIndexEntry elements = nameMap_.get(name);
16891687
if (elements != null) {
16901688
return (E) elements.first();
16911689
}
@@ -1703,9 +1701,9 @@ public <E extends DomElement> E getElementByName(final String name) throws Eleme
17031701
*/
17041702
public List<DomElement> getElementsByName(final String name) {
17051703
if (name != null) {
1706-
final SortedSet<DomElement> elements = nameMap_.get(name);
1704+
final MappedElementIndexEntry elements = nameMap_.get(name);
17071705
if (elements != null) {
1708-
return new ArrayList<>(elements);
1706+
return new ArrayList<>(elements.elements());
17091707
}
17101708
}
17111709
return Collections.emptyList();
@@ -1722,14 +1720,14 @@ public List<DomElement> getElementsByIdAndOrName(final String idAndOrName) {
17221720
if (idAndOrName == null) {
17231721
return Collections.emptyList();
17241722
}
1725-
final Collection<DomElement> list1 = idMap_.get(idAndOrName);
1726-
final Collection<DomElement> list2 = nameMap_.get(idAndOrName);
1723+
final MappedElementIndexEntry list1 = idMap_.get(idAndOrName);
1724+
final MappedElementIndexEntry list2 = nameMap_.get(idAndOrName);
17271725
final List<DomElement> list = new ArrayList<>();
17281726
if (list1 != null) {
1729-
list.addAll(list1);
1727+
list.addAll(list1.elements());
17301728
}
17311729
if (list2 != null) {
1732-
for (final DomElement elt : list2) {
1730+
for (final DomElement elt : list2.elements()) {
17331731
if (!list.contains(elt)) {
17341732
list.add(elt);
17351733
}
@@ -1804,14 +1802,14 @@ void addMappedElement(final DomElement element, final boolean recurse) {
18041802
}
18051803
}
18061804

1807-
private void addElement(final Map<String, SortedSet<DomElement>> map, final DomElement element,
1805+
private void addElement(final Map<String, MappedElementIndexEntry> map, final DomElement element,
18081806
final String attribute, final boolean recurse) {
18091807
final String value = element.getAttribute(attribute);
18101808

18111809
if (ATTRIBUTE_NOT_DEFINED != value) {
1812-
SortedSet<DomElement> elements = map.get(value);
1810+
MappedElementIndexEntry elements = map.get(value);
18131811
if (elements == null) {
1814-
elements = new TreeSet<>(DOCUMENT_POSITION_COMPERATOR);
1812+
elements = new MappedElementIndexEntry();
18151813
elements.add(element);
18161814
map.put(value, elements);
18171815
}
@@ -1845,14 +1843,13 @@ void removeMappedElement(final DomElement element, final boolean recurse, final
18451843
}
18461844
}
18471845

1848-
private void removeElement(final Map<String, SortedSet<DomElement>> map, final DomElement element,
1846+
private void removeElement(final Map<String, MappedElementIndexEntry> map, final DomElement element,
18491847
final String attribute, final boolean recurse) {
18501848
final String value = element.getAttribute(attribute);
18511849

18521850
if (ATTRIBUTE_NOT_DEFINED != value) {
1853-
final SortedSet<DomElement> elements = map.remove(value);
1854-
if (elements != null && (elements.size() != 1 || !elements.contains(element))) {
1855-
elements.remove(element);
1851+
final MappedElementIndexEntry elements = map.remove(value);
1852+
if (elements != null && elements.remove(element)) {
18561853
map.put(value, elements);
18571854
}
18581855
}
@@ -2879,4 +2876,54 @@ private void readObject(final ObjectInputStream in) throws IOException, ClassNot
28792876
computedStyles_ = new WeakHashMap<>();
28802877
}
28812878
}
2879+
2880+
private static final class MappedElementIndexEntry {
2881+
private ArrayList<DomElement> elements_;
2882+
private boolean sorted_;
2883+
2884+
MappedElementIndexEntry() {
2885+
// we do not expect to many elements having the same id/name
2886+
elements_ = new ArrayList<>(2);
2887+
sorted_ = false;
2888+
}
2889+
2890+
void add(final DomElement element) {
2891+
elements_.add(element);
2892+
sorted_ = false;
2893+
}
2894+
2895+
DomElement first() {
2896+
if (elements_.size() == 0) {
2897+
return null;
2898+
}
2899+
2900+
if (sorted_) {
2901+
return elements_.get(0);
2902+
}
2903+
2904+
Collections.sort(elements_, DOCUMENT_POSITION_COMPERATOR);
2905+
sorted_ = true;
2906+
2907+
return elements_.get(0);
2908+
}
2909+
2910+
List<DomElement> elements() {
2911+
if (sorted_ || elements_.size() == 0) {
2912+
return elements_;
2913+
}
2914+
2915+
Collections.sort(elements_, DOCUMENT_POSITION_COMPERATOR);
2916+
sorted_ = true;
2917+
2918+
return elements_;
2919+
}
2920+
2921+
boolean remove(final DomElement element) {
2922+
if (elements_.size() == 0) {
2923+
return false;
2924+
}
2925+
2926+
return elements_.remove(element);
2927+
}
2928+
}
28822929
}

0 commit comments

Comments
 (0)