Skip to content

Commit

Permalink
Use computeIfAbsent() (#1990)
Browse files Browse the repository at this point in the history
Use `computeIfAbsent()`, with constant function variables

---------

Co-authored-by: Jonathan Hedley <jonathan@hedley.net>
  • Loading branch information
Isira-Seneviratne and jhy committed Dec 30, 2023
1 parent 00f8318 commit bf40e9c
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 48 deletions.
2 changes: 2 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@
<ignore>java.io.UncheckedIOException</ignore>
<ignore>java.util.Comparator</ignore> <!-- Comparator.comparingInt() -->
<ignore>java.util.List</ignore> <!-- List#stream() -->
<ignore>java.util.LinkedHashMap</ignore> <!-- LinkedHashMap#computeIfAbsent() -->
<ignore>java.util.Map</ignore> <!-- Map#computeIfAbsent() -->
<ignore>java.util.Objects</ignore>
<ignore>java.util.Optional</ignore>
<ignore>java.util.Set</ignore> <!-- Set#stream() -->
Expand Down
11 changes: 4 additions & 7 deletions src/main/java/org/jsoup/helper/HttpConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import org.jsoup.UncheckedIOException;
import org.jsoup.UnsupportedMimeTypeException;
import org.jsoup.internal.ControllableInputStream;
import org.jsoup.internal.Functions;
import org.jsoup.internal.SharedConstants;
import org.jsoup.internal.StringUtil;
import org.jsoup.nodes.Document;
Expand Down Expand Up @@ -39,6 +40,7 @@
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;
import java.util.zip.Inflater;
Expand Down Expand Up @@ -1109,13 +1111,8 @@ private static LinkedHashMap<String, List<String>> createHeaderMap(HttpURLConnec
if (key == null || val == null)
continue; // skip http1.1 line

if (headers.containsKey(key))
headers.get(key).add(val);
else {
final ArrayList<String> vals = new ArrayList<>();
vals.add(val);
headers.put(key, vals);
}
final List<String> vals = headers.computeIfAbsent(key, Functions.listFunction());
vals.add(val);
}
return headers;
}
Expand Down
40 changes: 40 additions & 0 deletions src/main/java/org/jsoup/internal/Functions.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package org.jsoup.internal;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;

/**
* An internal class containing functions for use with {@link Map#computeIfAbsent(Object, Function)}.
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public final class Functions {
private static final Function ListFunction = key -> new ArrayList<>();
private static final Function SetFunction = key -> new HashSet<>();
private static final Function MapFunction = key -> new HashMap<>();
private static final Function IdentityMapFunction = key -> new IdentityHashMap<>();

private Functions() {
}

public static <T, U> Function<T, List<U>> listFunction() {
return (Function<T, List<U>>) ListFunction;
}

public static <T, U> Function<T, Set<U>> setFunction() {
return (Function<T, Set<U>>) SetFunction;
}

public static <T, K, V> Function<T, Map<K, V>> mapFunction() {
return (Function<T, Map<K, V>>) MapFunction;
}

public static <T, K, V> Function<T, IdentityHashMap<K, V>> identityMapFunction() {
return (Function<T, IdentityHashMap<K, V>>) IdentityMapFunction;
}
}
36 changes: 8 additions & 28 deletions src/main/java/org/jsoup/safety/Safelist.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Thank you to Ryan Grove (wonko.com) for the Ruby HTML cleaner http://github.com/
*/

import org.jsoup.helper.Validate;
import org.jsoup.internal.Functions;
import org.jsoup.internal.Normalizer;
import org.jsoup.nodes.Attribute;
import org.jsoup.nodes.Attributes;
Expand Down Expand Up @@ -304,12 +305,8 @@ public Safelist addAttributes(String tag, String... attributes) {
Validate.notEmpty(key);
attributeSet.add(AttributeKey.valueOf(key));
}
if (this.attributes.containsKey(tagName)) {
Set<AttributeKey> currentSet = this.attributes.get(tagName);
currentSet.addAll(attributeSet);
} else {
this.attributes.put(tagName, attributeSet);
}
Set<AttributeKey> currentSet = this.attributes.computeIfAbsent(tagName, Functions.setFunction());
currentSet.addAll(attributeSet);
return this;
}

Expand Down Expand Up @@ -382,13 +379,8 @@ public Safelist addEnforcedAttribute(String tag, String attribute, String value)
AttributeKey attrKey = AttributeKey.valueOf(attribute);
AttributeValue attrVal = AttributeValue.valueOf(value);

if (enforcedAttributes.containsKey(tagName)) {
enforcedAttributes.get(tagName).put(attrKey, attrVal);
} else {
Map<AttributeKey, AttributeValue> attrMap = new HashMap<>();
attrMap.put(attrKey, attrVal);
enforcedAttributes.put(tagName, attrMap);
}
Map<AttributeKey, AttributeValue> attrMap = enforcedAttributes.computeIfAbsent(tagName, Functions.mapFunction());
attrMap.put(attrKey, attrVal);
return this;
}

Expand Down Expand Up @@ -458,21 +450,9 @@ public Safelist addProtocols(String tag, String attribute, String... protocols)

TagName tagName = TagName.valueOf(tag);
AttributeKey attrKey = AttributeKey.valueOf(attribute);
Map<AttributeKey, Set<Protocol>> attrMap;
Set<Protocol> protSet;

if (this.protocols.containsKey(tagName)) {
attrMap = this.protocols.get(tagName);
} else {
attrMap = new HashMap<>();
this.protocols.put(tagName, attrMap);
}
if (attrMap.containsKey(attrKey)) {
protSet = attrMap.get(attrKey);
} else {
protSet = new HashSet<>();
attrMap.put(attrKey, protSet);
}
Map<AttributeKey, Set<Protocol>> attrMap = this.protocols.computeIfAbsent(tagName, Functions.mapFunction());
Set<Protocol> protSet = attrMap.computeIfAbsent(attrKey, Functions.setFunction());

for (String protocol : protocols) {
Validate.notEmpty(protocol);
Protocol prot = Protocol.valueOf(protocol);
Expand Down
18 changes: 5 additions & 13 deletions src/main/java/org/jsoup/select/StructuralEvaluator.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package org.jsoup.select;

import org.jsoup.internal.Functions;
import org.jsoup.internal.StringUtil;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.NodeIterator;

import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.Map;

/**
* Base structural evaluator.
Expand All @@ -23,19 +25,9 @@ public StructuralEvaluator(Evaluator evaluator) {
threadMemo = ThreadLocal.withInitial(IdentityHashMap::new);

boolean memoMatches(final Element root, final Element element) {
// not using computeIfAbsent, as the lambda impl requires a new Supplier closure object on every hit: tons of GC
IdentityHashMap<Element, IdentityHashMap<Element, Boolean>> rootMemo = threadMemo.get();
IdentityHashMap<Element, Boolean> memo = rootMemo.get(root);
if (memo == null) {
memo = new IdentityHashMap<>();
rootMemo.put(root, memo);
}
Boolean matches = memo.get(element);
if (matches == null) {
matches = evaluator.matches(root, element);
memo.put(element, matches);
}
return matches;
Map<Element, IdentityHashMap<Element, Boolean>> rootMemo = threadMemo.get();
Map<Element, Boolean> memo = rootMemo.computeIfAbsent(root, Functions.identityMapFunction());
return memo.computeIfAbsent(element, key -> evaluator.matches(root, key));
}

@Override protected void reset() {
Expand Down

0 comments on commit bf40e9c

Please sign in to comment.