Subject: [PATCH] Fix #23085: Significantly reduce cost of selecting all primitives in a large dataset
Direct CPU cycles were reduced by ~30% and memory allocations were reduced by ~70%.
---
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
diff --git a/src/org/openstreetmap/josm/data/conflict/ConflictCollection.java b/src/org/openstreetmap/josm/data/conflict/ConflictCollection.java
|
a
|
b
|
|
| 173 | 173 | * @return true, if this collection includes a conflict for <code>my</code>; false, otherwise |
| 174 | 174 | */ |
| 175 | 175 | public boolean hasConflictForMy(OsmPrimitive my) { |
| 176 | | return getConflictForMy(my) != null; |
| | 176 | return !conflicts.isEmpty() && getConflictForMy(my) != null; |
| 177 | 177 | } |
| 178 | 178 | |
| 179 | 179 | /** |
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
diff --git a/src/org/openstreetmap/josm/data/osm/DefaultNameFormatter.java b/src/org/openstreetmap/josm/data/osm/DefaultNameFormatter.java
|
a
|
b
|
|
| 29 | 29 | import org.openstreetmap.josm.data.osm.history.HistoryOsmPrimitive; |
| 30 | 30 | import org.openstreetmap.josm.data.osm.history.HistoryRelation; |
| 31 | 31 | import org.openstreetmap.josm.data.osm.history.HistoryWay; |
| | 32 | import org.openstreetmap.josm.data.preferences.BooleanProperty; |
| | 33 | import org.openstreetmap.josm.data.preferences.CachingProperty; |
| 32 | 34 | import org.openstreetmap.josm.gui.tagging.presets.TaggingPreset; |
| 33 | 35 | import org.openstreetmap.josm.gui.tagging.presets.TaggingPresetNameTemplateList; |
| 34 | 36 | import org.openstreetmap.josm.spi.preferences.Config; |
| … |
… |
|
| 48 | 50 | private static DefaultNameFormatter instance; |
| 49 | 51 | |
| 50 | 52 | private static final List<NameFormatterHook> formatHooks = new LinkedList<>(); |
| | 53 | private static final CachingProperty<Boolean> PROPERTY_SHOW_ID = |
| | 54 | new BooleanProperty("osm-primitives.showid", false).cached(); |
| | 55 | private static final CachingProperty<Boolean> PROPERTY_SHOW_ID_NEW_PRIMITIVES = |
| | 56 | new BooleanProperty("osm-primitives.showid.new-primitives", false).cached(); |
| | 57 | private static final CachingProperty<Boolean> PROPERTY_SHOW_VERSION = |
| | 58 | new BooleanProperty("osm-primitives.showversion", false).cached(); |
| | 59 | private static final CachingProperty<Boolean> PROPERTY_SHOW_COOR = |
| | 60 | new BooleanProperty("osm-primitives.showcoor", false).cached(); |
| | 61 | private static final CachingProperty<Boolean> PROPERTY_LOCALIZE_NAME = |
| | 62 | new BooleanProperty("osm-primitives.localize-name", true).cached(); |
| 51 | 63 | |
| 52 | 64 | private static final List<String> HIGHWAY_RAILWAY_WATERWAY_LANDUSE_BUILDING = Arrays.asList( |
| 53 | 65 | marktr("highway"), marktr("railway"), marktr("waterway"), marktr("landuse"), marktr("building")); |
| … |
… |
|
| 142 | 154 | */ |
| 143 | 155 | protected void decorateNameWithId(StringBuilder name, IPrimitive primitive) { |
| 144 | 156 | int version = primitive.getVersion(); |
| 145 | | if (Config.getPref().getBoolean("osm-primitives.showid")) { |
| 146 | | long id = Config.getPref().getBoolean("osm-primitives.showid.new-primitives") ? |
| | 157 | if (Boolean.TRUE.equals(PROPERTY_SHOW_ID.get())) { |
| | 158 | long id = Boolean.TRUE.equals(PROPERTY_SHOW_ID_NEW_PRIMITIVES.get()) ? |
| 147 | 159 | primitive.getUniqueId() : primitive.getId(); |
| 148 | | if (Config.getPref().getBoolean("osm-primitives.showversion") && version > 0) { |
| | 160 | if (version > 0 && Boolean.TRUE.equals(PROPERTY_SHOW_VERSION.get())) { |
| 149 | 161 | name.append(tr(" [id: {0}, v{1}]", id, version)); |
| 150 | 162 | } else { |
| 151 | 163 | name.append(tr(" [id: {0}]", id)); |
| 152 | 164 | } |
| 153 | | } else if (Config.getPref().getBoolean("osm-primitives.showversion")) { |
| | 165 | } else if (Boolean.TRUE.equals(PROPERTY_SHOW_VERSION.get())) { |
| 154 | 166 | name.append(tr(" [v{0}]", version)); |
| 155 | 167 | } |
| 156 | 168 | } |
| … |
… |
|
| 187 | 199 | } else { |
| 188 | 200 | preset.nameTemplate.appendText(name, (TemplateEngineDataProvider) node); |
| 189 | 201 | } |
| 190 | | if (node.isLatLonKnown() && Config.getPref().getBoolean("osm-primitives.showcoor")) { |
| | 202 | if (node.isLatLonKnown() && Boolean.TRUE.equals(PROPERTY_SHOW_COOR.get())) { |
| 191 | 203 | name.append(" \u200E("); |
| 192 | 204 | name.append(CoordinateFormatManager.getDefaultFormat().toString(node, ", ")); |
| 193 | 205 | name.append(")\u200C"); |
| … |
… |
|
| 196 | 208 | decorateNameWithId(name, node); |
| 197 | 209 | |
| 198 | 210 | String result = name.toString(); |
| 199 | | return formatHooks.stream().map(hook -> hook.checkFormat(node, result)) |
| 200 | | .filter(Objects::nonNull) |
| 201 | | .findFirst().orElse(result); |
| 202 | | |
| | 211 | // This avoids memallocs from Stream map, filter and Optional creation. |
| | 212 | for (NameFormatterHook hook : formatHooks) { |
| | 213 | final String checkFormat = hook.checkFormat(node, result); |
| | 214 | if (checkFormat != null) { |
| | 215 | return checkFormat; |
| | 216 | } |
| | 217 | } |
| | 218 | return result; |
| 203 | 219 | } |
| 204 | 220 | |
| 205 | 221 | private final Comparator<INode> nodeComparator = Comparator.comparing(this::format); |
| … |
… |
|
| 274 | 290 | } |
| 275 | 291 | |
| 276 | 292 | private static String formatLocalName(IPrimitive osm) { |
| 277 | | if (Config.getPref().getBoolean("osm-primitives.localize-name", true)) { |
| | 293 | if (Boolean.TRUE.equals(PROPERTY_LOCALIZE_NAME.get())) { |
| 278 | 294 | return osm.getLocalName(); |
| 279 | 295 | } else { |
| 280 | 296 | return osm.getName(); |
| … |
… |
|
| 282 | 298 | } |
| 283 | 299 | |
| 284 | 300 | private static String formatLocalName(HistoryOsmPrimitive osm) { |
| 285 | | if (Config.getPref().getBoolean("osm-primitives.localize-name", true)) { |
| | 301 | if (Boolean.TRUE.equals(PROPERTY_LOCALIZE_NAME.get())) { |
| 286 | 302 | return osm.getLocalName(); |
| 287 | 303 | } else { |
| 288 | 304 | return osm.getName(); |
| … |
… |
|
| 529 | 545 | * @param primitive the primitive |
| 530 | 546 | */ |
| 531 | 547 | protected void decorateNameWithId(StringBuilder name, HistoryOsmPrimitive primitive) { |
| 532 | | if (Config.getPref().getBoolean("osm-primitives.showid")) { |
| | 548 | if (Boolean.TRUE.equals(PROPERTY_SHOW_ID.get())) { |
| 533 | 549 | name.append(tr(" [id: {0}]", primitive.getId())); |
| 534 | 550 | } |
| 535 | 551 | } |
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
diff --git a/src/org/openstreetmap/josm/data/osm/Way.java b/src/org/openstreetmap/josm/data/osm/Way.java
|
a
|
b
|
|
| 634 | 634 | * @since 13033 |
| 635 | 635 | */ |
| 636 | 636 | public boolean hasOnlyLocatableNodes() { |
| 637 | | return Arrays.stream(nodes).allMatch(Node::isLatLonKnown); |
| | 637 | // This is used in various places, some of which are on the UI thread. |
| | 638 | // If this is called many times, the memory allocations can become prohibitive, if |
| | 639 | // we use Java streams. |
| | 640 | // This can be easily tested by loading a large amount of ways into JOSM, and then |
| | 641 | // selecting everything. |
| | 642 | for (Node node : nodes) { |
| | 643 | if (!node.isLatLonKnown()) { |
| | 644 | return false; |
| | 645 | } |
| | 646 | } |
| | 647 | return true; |
| 638 | 648 | } |
| 639 | 649 | |
| 640 | 650 | @Override |
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
diff --git a/src/org/openstreetmap/josm/gui/PrimitiveRenderer.java b/src/org/openstreetmap/josm/gui/PrimitiveRenderer.java
|
a
|
b
|
|
| 47 | 47 | @Override |
| 48 | 48 | public Component getListCellRendererComponent(JList<? extends IPrimitive> list, IPrimitive value, int index, |
| 49 | 49 | boolean isSelected, boolean cellHasFocus) { |
| 50 | | Component def = defaultListCellRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); |
| | 50 | // Use an empty string for the value to avoid expensive Object.toString calls, which will happen again in renderer. |
| | 51 | Component def = defaultListCellRenderer.getListCellRendererComponent(list, "", index, isSelected, cellHasFocus); |
| 51 | 52 | return renderer(def, value, list.getModel().getSize() > 1000); |
| 52 | 53 | } |
| 53 | 54 | |