Skip to content

Commit

Permalink
try to optimize the id/name index by replacing the tree set
Browse files Browse the repository at this point in the history
  • Loading branch information
rbri committed Nov 22, 2024
1 parent ce7f253 commit f29ede3
Showing 1 changed file with 68 additions and 21 deletions.
89 changes: 68 additions & 21 deletions src/main/java/org/htmlunit/html/HtmlPage.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;

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

private Map<String, SortedSet<DomElement>> idMap_ = new ConcurrentHashMap<>();
private Map<String, SortedSet<DomElement>> nameMap_ = new ConcurrentHashMap<>();
private Map<String, MappedElementIndexEntry> idMap_ = new ConcurrentHashMap<>();
private Map<String, MappedElementIndexEntry> nameMap_ = new ConcurrentHashMap<>();

private List<BaseFrameElement> frameElements_ = new ArrayList<>();
private int parserCount_;
Expand Down Expand Up @@ -629,7 +627,7 @@ public ProcessingInstruction createProcessingInstruction(final String namespaceU
@Override
public DomElement getElementById(final String elementId) {
if (elementId != null) {
final SortedSet<DomElement> elements = idMap_.get(elementId);
final MappedElementIndexEntry elements = idMap_.get(elementId);
if (elements != null) {
return elements.first();
}
Expand Down Expand Up @@ -1665,9 +1663,9 @@ public <E extends HtmlElement> E getHtmlElementById(final String elementId) thro
*/
public List<DomElement> getElementsById(final String elementId) {
if (elementId != null) {
final SortedSet<DomElement> elements = idMap_.get(elementId);
final MappedElementIndexEntry elements = idMap_.get(elementId);
if (elements != null) {
return new ArrayList<>(elements);
return new ArrayList<>(elements.elements());
}
}
return Collections.emptyList();
Expand All @@ -1685,7 +1683,7 @@ public List<DomElement> getElementsById(final String elementId) {
@SuppressWarnings("unchecked")
public <E extends DomElement> E getElementByName(final String name) throws ElementNotFoundException {
if (name != null) {
final SortedSet<DomElement> elements = nameMap_.get(name);
final MappedElementIndexEntry elements = nameMap_.get(name);
if (elements != null) {
return (E) elements.first();
}
Expand All @@ -1703,9 +1701,9 @@ public <E extends DomElement> E getElementByName(final String name) throws Eleme
*/
public List<DomElement> getElementsByName(final String name) {
if (name != null) {
final SortedSet<DomElement> elements = nameMap_.get(name);
final MappedElementIndexEntry elements = nameMap_.get(name);
if (elements != null) {
return new ArrayList<>(elements);
return new ArrayList<>(elements.elements());
}
}
return Collections.emptyList();
Expand All @@ -1722,14 +1720,14 @@ public List<DomElement> getElementsByIdAndOrName(final String idAndOrName) {
if (idAndOrName == null) {
return Collections.emptyList();
}
final Collection<DomElement> list1 = idMap_.get(idAndOrName);
final Collection<DomElement> list2 = nameMap_.get(idAndOrName);
final MappedElementIndexEntry list1 = idMap_.get(idAndOrName);
final MappedElementIndexEntry list2 = nameMap_.get(idAndOrName);
final List<DomElement> list = new ArrayList<>();
if (list1 != null) {
list.addAll(list1);
list.addAll(list1.elements());
}
if (list2 != null) {
for (final DomElement elt : list2) {
for (final DomElement elt : list2.elements()) {
if (!list.contains(elt)) {
list.add(elt);
}
Expand Down Expand Up @@ -1804,14 +1802,14 @@ void addMappedElement(final DomElement element, final boolean recurse) {
}
}

private void addElement(final Map<String, SortedSet<DomElement>> map, final DomElement element,
private void addElement(final Map<String, MappedElementIndexEntry> map, final DomElement element,
final String attribute, final boolean recurse) {
final String value = element.getAttribute(attribute);

if (ATTRIBUTE_NOT_DEFINED != value) {
SortedSet<DomElement> elements = map.get(value);
MappedElementIndexEntry elements = map.get(value);
if (elements == null) {
elements = new TreeSet<>(DOCUMENT_POSITION_COMPERATOR);
elements = new MappedElementIndexEntry();
elements.add(element);
map.put(value, elements);
}
Expand Down Expand Up @@ -1845,14 +1843,13 @@ void removeMappedElement(final DomElement element, final boolean recurse, final
}
}

private void removeElement(final Map<String, SortedSet<DomElement>> map, final DomElement element,
private void removeElement(final Map<String, MappedElementIndexEntry> map, final DomElement element,
final String attribute, final boolean recurse) {
final String value = element.getAttribute(attribute);

if (ATTRIBUTE_NOT_DEFINED != value) {
final SortedSet<DomElement> elements = map.remove(value);
if (elements != null && (elements.size() != 1 || !elements.contains(element))) {
elements.remove(element);
final MappedElementIndexEntry elements = map.remove(value);
if (elements != null && elements.remove(element)) {
map.put(value, elements);
}
}
Expand Down Expand Up @@ -2879,4 +2876,54 @@ private void readObject(final ObjectInputStream in) throws IOException, ClassNot
computedStyles_ = new WeakHashMap<>();
}
}

private static final class MappedElementIndexEntry {
private ArrayList<DomElement> elements_;
private boolean sorted_;

MappedElementIndexEntry() {
// we do not expect to many elements having the same id/name
elements_ = new ArrayList<>(2);
sorted_ = false;
}

void add(final DomElement element) {
elements_.add(element);
sorted_ = false;
}

DomElement first() {
if (elements_.size() == 0) {
return null;
}

if (sorted_) {
return elements_.get(0);
}

Collections.sort(elements_, DOCUMENT_POSITION_COMPERATOR);
sorted_ = true;

return elements_.get(0);
}

List<DomElement> elements() {
if (sorted_ || elements_.size() == 0) {
return elements_;
}

Collections.sort(elements_, DOCUMENT_POSITION_COMPERATOR);
sorted_ = true;

return elements_;
}

boolean remove(final DomElement element) {
if (elements_.size() == 0) {
return false;
}

return elements_.remove(element);
}
}
}

0 comments on commit f29ede3

Please sign in to comment.