From 90cbde41f4a3edba290c4af28186afb6e6d0cde4 Mon Sep 17 00:00:00 2001 From: Jens Wille Date: Mon, 11 Apr 2022 17:05:54 +0200 Subject: [PATCH] Avoid unnecessary (and expensive) work when matching path wildcards. (#207, #97) `SimpleRegexTrie` is only used to determine whether a field name matches a pattern. The result of this computation only depends on these two values, not on the underlying data. So we can cache and reuse the result across the whole transformation process. It might be possible to implement the matching in a more optimized way for this particular use case, but it's delegated to `SimpleRegexTrie` for compatibility and maintainability purposes. --- .../main/java/org/metafacture/metafix/Value.java | 14 ++++++++++---- .../org/metafacture/metafix/HashValueTest.java | 4 ---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/metafix/src/main/java/org/metafacture/metafix/Value.java b/metafix/src/main/java/org/metafacture/metafix/Value.java index 57682d1c..29ee231d 100644 --- a/metafix/src/main/java/org/metafacture/metafix/Value.java +++ b/metafix/src/main/java/org/metafacture/metafix/Value.java @@ -21,6 +21,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.ConcurrentModificationException; +import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; @@ -459,9 +460,10 @@ public void remove(final int index) { */ public static class Hash extends AbstractValueType { - private final Map map = new LinkedHashMap<>(); + private static final Map> TRIE_CACHE = new HashMap<>(); + private static final SimpleRegexTrie TRIE = new SimpleRegexTrie<>(); - private final SimpleRegexTrie trie = new SimpleRegexTrie<>(); + private final Map map = new LinkedHashMap<>(); /** * Creates an empty instance of {@link Hash}. @@ -695,8 +697,12 @@ private Stream findFields(final String pattern) { } private T matchFields(final String pattern, final BiFunction, Predicate, T> function) { - trie.put(pattern, pattern); - return function.apply(map.keySet().stream(), f -> trie.get(f).contains(pattern)); + final Map matcher = TRIE_CACHE.computeIfAbsent(pattern, k -> { + TRIE.put(k, k); + return new HashMap<>(); + }); + + return function.apply(map.keySet().stream(), f -> matcher.computeIfAbsent(f, k -> TRIE.get(k).contains(pattern))); } } diff --git a/metafix/src/test/java/org/metafacture/metafix/HashValueTest.java b/metafix/src/test/java/org/metafacture/metafix/HashValueTest.java index 4c859719..579bfbe2 100644 --- a/metafix/src/test/java/org/metafacture/metafix/HashValueTest.java +++ b/metafix/src/test/java/org/metafacture/metafix/HashValueTest.java @@ -16,8 +16,6 @@ package org.metafacture.metafix; -import org.metafacture.commons.tries.SimpleRegexTrie; - import nl.jqno.equalsverifier.EqualsVerifier; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -46,8 +44,6 @@ public HashValueTest() { public void shouldSatisfyEqualsContract() { EqualsVerifier.forClass(Value.Hash.class) .withPrefabValues(Value.class, Value.newArray(), Value.newHash()) - .withPrefabValues(SimpleRegexTrie.class, new SimpleRegexTrie(), new SimpleRegexTrie()) - .withIgnoredFields("trie") .verify(); }