diff --git a/src/org/openstreetmap/josm/data/validation/tests/TagChecker.java b/src/org/openstreetmap/josm/data/validation/tests/TagChecker.java index b285e464d3..f42bc69474 100644 --- a/src/org/openstreetmap/josm/data/validation/tests/TagChecker.java +++ b/src/org/openstreetmap/josm/data/validation/tests/TagChecker.java @@ -420,12 +420,12 @@ public static void initializePresets() { List minData = new ArrayList<>(); for (TaggingPresetItem i : p.data) { if (i instanceof KeyedItem) { - if (!"none".equals(((KeyedItem) i).match)) + if (!"none".equals(((KeyedItem) i).match())) minData.add(i); addPresetValue((KeyedItem) i); } else if (i instanceof CheckGroup) { for (Check c : ((CheckGroup) i).checks) { - if (!"none".equals(c.match)) + if (!"none".equals(c.match())) minData.add(c); addPresetValue(c); } diff --git a/src/org/openstreetmap/josm/gui/tagging/presets/TaggingPresetItem.java b/src/org/openstreetmap/josm/gui/tagging/presets/TaggingPresetItem.java index 64255363c4..a60b2c9d36 100644 --- a/src/org/openstreetmap/josm/gui/tagging/presets/TaggingPresetItem.java +++ b/src/org/openstreetmap/josm/gui/tagging/presets/TaggingPresetItem.java @@ -11,6 +11,7 @@ import java.util.EnumSet; import java.util.List; import java.util.Map; +import java.util.RandomAccess; import java.util.Set; import javax.swing.ImageIcon; @@ -170,12 +171,31 @@ public static ImageIcon loadImageIcon(String iconName, File zipIcons, Integer ma */ public static boolean matches(Iterable data, Map tags) { boolean atLeastOnePositiveMatch = false; - for (TaggingPresetItem item : data) { - Boolean m = item.matches(tags); - if (m != null && !m) - return false; - else if (m != null) { - atLeastOnePositiveMatch = true; + if (data instanceof List && data instanceof RandomAccess) { + List items = (List) data; + /* This is a memory allocation optimization, mostly for ArrayList. + * In test runs, this reduced the memory cost for this method by 99%. + * This appears to have also improved CPU cost for this method by ~10% as well. + * The big win for CPU cost is in GC improvements, which was around 80%. + * Overall improvement: 7.6 hours to 4.5 hours for validating a Colorado pbf extract (40% improvement). + */ + for (int i = 0; i < items.size(); i++) { // READ ABOVE: DO NOT REPLACE WITH ENHANCED FOR LOOP WITHOUT PROFILING! + TaggingPresetItem item = items.get(i); + Boolean m = item.matches(tags); + if (m != null && !m) { + return false; + } else if (m != null) { + atLeastOnePositiveMatch = true; + } + } + } else { + for (TaggingPresetItem item : data) { + Boolean m = item.matches(tags); + if (m != null && !m) { + return false; + } else if (m != null) { + atLeastOnePositiveMatch = true; + } } } return atLeastOnePositiveMatch; diff --git a/src/org/openstreetmap/josm/gui/tagging/presets/items/KeyedItem.java b/src/org/openstreetmap/josm/gui/tagging/presets/items/KeyedItem.java index c0bf87968c..41f4606475 100644 --- a/src/org/openstreetmap/josm/gui/tagging/presets/items/KeyedItem.java +++ b/src/org/openstreetmap/josm/gui/tagging/presets/items/KeyedItem.java @@ -51,7 +51,7 @@ public abstract class KeyedItem extends TextItem implements RegionSpecific { * Note that for a match, at least one positive and no negative is required. * Default is "keyvalue!" for {@link Key} and "none" for {@link Text}, {@link Combo}, {@link MultiSelect} and {@link Check}. */ - public String match = getDefaultMatch().getValue(); // NOSONAR + protected MatchType match = getDefaultMatch(); // NOSONAR /** * List of regions the preset is applicable for. @@ -181,6 +181,33 @@ public Usage splitValues(String delimiter) { } } + /** + * Allows to change the matching process, i.e., determining whether the tags of an OSM object fit into this preset. + * If a preset fits then it is linked in the Tags/Membership dialog. + * Note that for a match, at least one positive and no negative is required. + * Default is "keyvalue!" for {@link Key} and "none" for {@link Text}, {@link Combo}, {@link MultiSelect} and {@link Check}. + * @param match The match type. One of none, key, key!, keyvalue, + * or keyvalue!. + * @since 19285 + */ + public void setMatch(String match) { + this.match = MatchType.ofString(match); + } + + /** + * Get the match type for this item + * @return The match type + * @since 19285 + */ + public String match() { + return this.match.getValue(); + } + /** * Computes the tag usage for the given key from the given primitives * @param sel the primitives @@ -221,7 +248,7 @@ protected static Usage determineBooleanUsage(Collection sel, Strin * @return whether key or key+value are required */ public boolean isKeyRequired() { - final MatchType type = MatchType.ofString(match); + final MatchType type = this.match; return MatchType.KEY_REQUIRED == type || MatchType.KEY_VALUE_REQUIRED == type; } @@ -243,7 +270,7 @@ protected String getKeyTooltipText() { @Override public Boolean matches(Map tags) { - switch (MatchType.ofString(match)) { + switch (this.match) { case NONE: return null; // NOSONAR case KEY: