From f9313a798efbb19c725701e586c1718c1c5660cf Mon Sep 17 00:00:00 2001 From: asvitkine Date: Thu, 26 May 2022 21:03:26 -0400 Subject: [PATCH] Intern attachment-related strings to minimize memory and speed up cloning. (#10470) Intern attachment-related strings to minimize memory and speed up cloning. Java's String.intern() function returns a canonical String object for the given string, such that Strings that share content can use the same instance. This is very relevant for triggers properties, where lots of triggers end up having the same properties set, either via variable expansion or even in older maps, where this was done manually. This also helps tremendously with GameData cloning, since there's much fewer String objects to clone, since the same String instance is pointed to by multiple objects. With this change, bringing up the Battle Calculator on "270BC Wars" goes from ~1.5s to ~0.7s on my machine (the 1.5s is already after many other improvements I landed). Additionally, save game size goes to 860k (from 1.1MB), which is already after compression. RAM use after GC goes to 129M from 192M. These two are both after starting an all-human "270BC Wars" game at the start of the first human turn (after all the barbarian combats). This change also cleans up some unnecessary null checks on attachment setters. --- .../engine/data/gameparser/GameParser.java | 2 +- .../AbstractConditionsAttachment.java | 4 +- .../AbstractPlayerRulesAttachment.java | 2 +- .../attachments/AbstractRulesAttachment.java | 5 +- .../AbstractTriggerAttachment.java | 4 +- .../AbstractUserActionAttachment.java | 2 +- .../triplea/attachments/CanalAttachment.java | 6 +- .../triplea/attachments/PlayerAttachment.java | 2 +- .../PoliticalActionAttachment.java | 2 +- .../RelationshipTypeAttachment.java | 24 +++--- .../triplea/attachments/RulesAttachment.java | 17 ++--- .../attachments/TechAbilityAttachment.java | 4 +- .../triplea/attachments/TechAttachment.java | 2 +- .../attachments/TerritoryAttachment.java | 2 +- .../attachments/TriggerAttachment.java | 76 +++++-------------- .../triplea/attachments/UnitAttachment.java | 30 +++++--- .../attachments/UnitSupportAttachment.java | 4 +- .../attachments/UserActionAttachment.java | 2 +- .../calculator/BattleCalculatorPanel.java | 4 + 19 files changed, 79 insertions(+), 115 deletions(-) diff --git a/game-app/game-core/src/main/java/games/strategy/engine/data/gameparser/GameParser.java b/game-app/game-core/src/main/java/games/strategy/engine/data/gameparser/GameParser.java index add3b50372..5cb3f531c5 100644 --- a/game-app/game-core/src/main/java/games/strategy/engine/data/gameparser/GameParser.java +++ b/game-app/game-core/src/main/java/games/strategy/engine/data/gameparser/GameParser.java @@ -961,7 +961,7 @@ private List> setOptions( xmlUri, attachment, e.getMessage()), e); } - results.add(Tuple.of(name, finalValue)); + results.add(Tuple.of(name.intern(), finalValue.intern())); } return results; } diff --git a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/AbstractConditionsAttachment.java b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/AbstractConditionsAttachment.java index ce98275221..e7b9f665fb 100644 --- a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/AbstractConditionsAttachment.java +++ b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/AbstractConditionsAttachment.java @@ -113,7 +113,7 @@ void setConditionType(final String value) throws GameParseException { if (uppercaseValue.matches("AND|OR|\\d+(?:-\\d+)?")) { final String[] split = splitOnHyphen(uppercaseValue); if (split.length != 2 || Integer.parseInt(split[1]) > Integer.parseInt(split[0])) { - conditionType = uppercaseValue; + conditionType = uppercaseValue.intern(); return; } } @@ -280,7 +280,7 @@ protected void setChance(final String chance) throws GameParseException { + " format: \"1:10\" for 10% chance" + thisErrorMsg()); } - this.chance = chance; + this.chance = chance.intern(); } /** diff --git a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/AbstractPlayerRulesAttachment.java b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/AbstractPlayerRulesAttachment.java index fdad79968f..aaf7382a39 100644 --- a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/AbstractPlayerRulesAttachment.java +++ b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/AbstractPlayerRulesAttachment.java @@ -140,7 +140,7 @@ private void setMovementRestrictionType(final String value) throws GameParseExce throw new GameParseException( "movementRestrictionType must be allowed or disallowed" + thisErrorMsg()); } - movementRestrictionType = value; + movementRestrictionType = value.intern(); } public @Nullable String getMovementRestrictionType() { diff --git a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/AbstractRulesAttachment.java b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/AbstractRulesAttachment.java index 94a496f64f..48810f1f2a 100644 --- a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/AbstractRulesAttachment.java +++ b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/AbstractRulesAttachment.java @@ -161,7 +161,7 @@ private void resetSwitch() { } private void setGameProperty(final String value) { - gameProperty = value; + gameProperty = value.intern(); } private @Nullable String getGameProperty() { @@ -341,6 +341,9 @@ protected void validateNames(final String[] terrList) { if (terrList != null && terrList.length > 0) { getListedTerritories(terrList, true, true); // removed checks for length & group commands because it breaks the setTerritoryCount feature. + for (int i = 0; i < terrList.length; i++) { + terrList[i] = terrList[i].intern(); + } } } diff --git a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/AbstractTriggerAttachment.java b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/AbstractTriggerAttachment.java index c56682db8c..1d3ac71c67 100644 --- a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/AbstractTriggerAttachment.java +++ b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/AbstractTriggerAttachment.java @@ -133,7 +133,7 @@ private void setWhen(final String when) throws GameParseException { if (this.when == null) { this.when = new ArrayList<>(); } - this.when.add(Tuple.of(s[0], s[1])); + this.when.add(Tuple.of(s[0].intern(), s[1].intern())); } private void setWhen(final List> value) { @@ -261,7 +261,7 @@ protected static String getValueFromStringArrayForAllExceptLastSubstring(final S if (sb.length() > 0 && sb.substring(0, 1).equals(":")) { sb.replace(0, 1, ""); } - return sb.toString(); + return sb.toString().intern(); } public static int getEachMultiple(final AbstractTriggerAttachment t) { diff --git a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/AbstractUserActionAttachment.java b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/AbstractUserActionAttachment.java index eb0fd5907d..f31bf6d8a9 100644 --- a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/AbstractUserActionAttachment.java +++ b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/AbstractUserActionAttachment.java @@ -59,7 +59,7 @@ public boolean canPerform(final Map testedConditions) { } private void setText(final String text) { - this.text = text; + this.text = text.intern(); } /** diff --git a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/CanalAttachment.java b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/CanalAttachment.java index 3941ee33b2..85d22b27cd 100644 --- a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/CanalAttachment.java +++ b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/CanalAttachment.java @@ -73,7 +73,7 @@ static CanalAttachment get(final Territory t, final String nameOfAttachment) { } private void setCanalName(final String name) { - canalName = name; + canalName = name.intern(); } public String getCanalName() { @@ -85,10 +85,6 @@ private void resetCanalName() { } private void setLandTerritories(final String landTerritories) { - if (landTerritories == null) { - this.landTerritories = null; - return; - } final Set terrs = new HashSet<>(); for (final String name : splitOnColon(landTerritories)) { final Territory territory = getData().getMap().getTerritory(name); diff --git a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/PlayerAttachment.java b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/PlayerAttachment.java index 991cb2f6f3..c33c8d9c65 100644 --- a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/PlayerAttachment.java +++ b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/PlayerAttachment.java @@ -164,7 +164,7 @@ private Triple> parseUnitLimit( types.add(getUnitTypeOrThrow(s[i])); } } - return Triple.of(max, s[1], types); + return Triple.of(max, s[1].intern(), types); } /** diff --git a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/PoliticalActionAttachment.java b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/PoliticalActionAttachment.java index 23ec16c4f0..8df9ba05a0 100644 --- a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/PoliticalActionAttachment.java +++ b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/PoliticalActionAttachment.java @@ -131,7 +131,7 @@ void setRelationshipChange(final String relChange) throws GameParseException { if (relationshipChange == null) { relationshipChange = new ArrayList<>(); } - relationshipChange.add(relChange); + relationshipChange.add(relChange.intern()); } private void setRelationshipChange(final List value) { diff --git a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/RelationshipTypeAttachment.java b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/RelationshipTypeAttachment.java index 882ce51da5..d7fa865f57 100644 --- a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/RelationshipTypeAttachment.java +++ b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/RelationshipTypeAttachment.java @@ -74,7 +74,7 @@ public void setArcheType(final String archeType) throws GameParseException { case ARCHETYPE_WAR: case ARCHETYPE_ALLIED: case ARCHETYPE_NEUTRAL: - this.archeType = lowerArcheType; + this.archeType = lowerArcheType.intern(); break; default: throw new GameParseException( @@ -109,7 +109,7 @@ private void resetArcheType() { * @param canFlyOver should be "true", "false" or "default" */ private void setCanMoveAirUnitsOverOwnedLand(final String canFlyOver) { - canMoveAirUnitsOverOwnedLand = canFlyOver; + canMoveAirUnitsOverOwnedLand = canFlyOver.intern(); } private String getCanMoveAirUnitsOverOwnedLand() { @@ -135,7 +135,7 @@ private void resetCanMoveAirUnitsOverOwnedLand() { } private void setCanMoveLandUnitsOverOwnedLand(final String canFlyOver) { - canMoveLandUnitsOverOwnedLand = canFlyOver; + canMoveLandUnitsOverOwnedLand = canFlyOver.intern(); } private String getCanMoveLandUnitsOverOwnedLand() { @@ -154,7 +154,7 @@ private void resetCanMoveLandUnitsOverOwnedLand() { } private void setCanLandAirUnitsOnOwnedLand(final String canLandAir) { - canLandAirUnitsOnOwnedLand = canLandAir; + canLandAirUnitsOnOwnedLand = canLandAir.intern(); } private String getCanLandAirUnitsOnOwnedLand() { @@ -174,7 +174,7 @@ private void resetCanLandAirUnitsOnOwnedLand() { } private void setCanTakeOverOwnedTerritory(final String canTakeOver) { - canTakeOverOwnedTerritory = canTakeOver; + canTakeOverOwnedTerritory = canTakeOver.intern(); } private String getCanTakeOverOwnedTerritory() { @@ -222,7 +222,7 @@ private void setUpkeepCost(final String integerCost) throws GameParseException { + thisErrorMsg()); } } - upkeepCost = integerCost; + upkeepCost = integerCost.intern(); } } @@ -250,7 +250,7 @@ private void setAlliancesCanChainTogether(final String value) throws GameParseEx + PROPERTY_TRUE + thisErrorMsg()); } - alliancesCanChainTogether = value; + alliancesCanChainTogether = value.intern(); } private String getAlliancesCanChainTogether() { @@ -281,7 +281,7 @@ private void setIsDefaultWarPosition(final String value) throws GameParseExcepti + PROPERTY_TRUE + thisErrorMsg()); } - isDefaultWarPosition = value; + isDefaultWarPosition = value.intern(); } private String getIsDefaultWarPosition() { @@ -312,7 +312,7 @@ private void setGivesBackOriginalTerritories(final String value) throws GamePars + PROPERTY_TRUE + thisErrorMsg()); } - givesBackOriginalTerritories = value; + givesBackOriginalTerritories = value.intern(); } private String getGivesBackOriginalTerritories() { @@ -341,7 +341,7 @@ private void setCanMoveIntoDuringCombatMove(final String value) throws GameParse + PROPERTY_TRUE + thisErrorMsg()); } - canMoveIntoDuringCombatMove = value; + canMoveIntoDuringCombatMove = value.intern(); } private String getCanMoveIntoDuringCombatMove() { @@ -371,7 +371,7 @@ private void setCanMoveThroughCanals(final String value) throws GameParseExcepti + PROPERTY_TRUE + thisErrorMsg()); } - canMoveThroughCanals = value; + canMoveThroughCanals = value.intern(); } private String getCanMoveThroughCanals() { @@ -403,7 +403,7 @@ private void setRocketsCanFlyOver(final String value) throws GameParseException + PROPERTY_TRUE + thisErrorMsg()); } - rocketsCanFlyOver = value; + rocketsCanFlyOver = value.intern(); } private String getRocketsCanFlyOver() { diff --git a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/RulesAttachment.java b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/RulesAttachment.java index 9b6114bab8..c47b72a814 100644 --- a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/RulesAttachment.java +++ b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/RulesAttachment.java @@ -164,7 +164,7 @@ private void setDestroyedTuv(final String value) throws GameParseException { throw new GameParseException( "destroyedTUV value must be currentRound or allRounds" + thisErrorMsg()); } - destroyedTuv = value; + destroyedTuv = value.intern(); } private @Nullable String getDestroyedTuv() { @@ -216,7 +216,7 @@ private void setBattle(final String value) throws GameParseException { if (battle == null) { battle = new ArrayList<>(); } - battle.add(Tuple.of((s[0] + ":" + s[1] + ":" + s[2] + ":" + s[3]), terrs)); + battle.add(Tuple.of((s[0] + ":" + s[1] + ":" + s[2] + ":" + s[3]).intern(), terrs)); } private void setBattle(final List>> value) { @@ -280,7 +280,8 @@ private void setRelationship(final String value) throws GameParseException { if (relationship == null) { relationship = new ArrayList<>(); } - relationship.add((s.length == 3) ? (value + ":-1") : value); + String str = (s.length == 3) ? (value + ":-1") : value; + relationship.add(str.intern()); } private void setRelationship(final List value) { @@ -474,7 +475,7 @@ private void setUnitPresence(final String value) throws GameParseException { if (unitPresence == null) { unitPresence = new IntegerMap<>(); } - unitPresence.put(value.replaceFirst(s[0] + ":", ""), n); + unitPresence.put(value.replaceFirst(s[0] + ":", "").intern(), n); } private void setUnitPresence(final IntegerMap value) { @@ -498,10 +499,6 @@ private int getTechCount() { } private void setAtWarPlayers(final String players) throws GameParseException { - if (players == null) { - atWarPlayers = null; - return; - } final String[] s = splitOnColon(players); if (s.length < 1) { throw new GameParseException("Empty enemy list" + thisErrorMsg()); @@ -535,10 +532,6 @@ private void resetAtWarPlayers() { } private void setTechs(final String newTechs) throws GameParseException { - if (newTechs == null) { - techs = null; - return; - } final String[] s = splitOnColon(newTechs); if (s.length < 1) { throw new GameParseException("Empty tech list" + thisErrorMsg()); diff --git a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/TechAbilityAttachment.java b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/TechAbilityAttachment.java index b39a9a7369..fdaf1ba833 100644 --- a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/TechAbilityAttachment.java +++ b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/TechAbilityAttachment.java @@ -511,7 +511,7 @@ private void setUnitAbilitiesGained(final String value) throws GameParseExceptio + ABILITY_CAN_BOMBARD + thisErrorMsg()); } - abilities.add(ability); + abilities.add(ability.intern()); } } @@ -673,7 +673,7 @@ private void setAirborneTargettedByAa(final String value) throws GameParseExcept if (airborneTargetedByAa == null) { airborneTargetedByAa = new HashMap<>(); } - airborneTargetedByAa.put(s[0], unitTypes); + airborneTargetedByAa.put(s[0].intern(), unitTypes); } private void setAirborneTargettedByAa(final Map> value) { diff --git a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/TechAttachment.java b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/TechAttachment.java index e27deab4ce..f27dcc93cb 100644 --- a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/TechAttachment.java +++ b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/TechAttachment.java @@ -334,7 +334,7 @@ public boolean getShipyards() { private void setGenericTechs() { for (final TechAdvance ta : getData().getTechnologyFrontier()) { if (ta instanceof GenericTechAdvance && ((GenericTechAdvance) ta).getAdvance() == null) { - genericTech.put(ta.getProperty(), Boolean.FALSE); + genericTech.put(ta.getProperty().intern(), Boolean.FALSE); } } } diff --git a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/TerritoryAttachment.java b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/TerritoryAttachment.java index 7c34dd5274..95c41b3c9c 100644 --- a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/TerritoryAttachment.java +++ b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/TerritoryAttachment.java @@ -430,7 +430,7 @@ void setWhenCapturedByGoesTo(final String value) throws GameParseException { if (whenCapturedByGoesTo == null) { whenCapturedByGoesTo = new ArrayList<>(); } - whenCapturedByGoesTo.add(value); + whenCapturedByGoesTo.add(value.intern()); } private void setWhenCapturedByGoesTo(final List value) { diff --git a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/TriggerAttachment.java b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/TriggerAttachment.java index a03c50083d..2293e32af3 100644 --- a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/TriggerAttachment.java +++ b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/TriggerAttachment.java @@ -382,7 +382,7 @@ private void setActivateTrigger(final String value) throws GameParseException { if (activateTrigger == null) { activateTrigger = new ArrayList<>(); } - activateTrigger.add(Tuple.of(s[0], options)); + activateTrigger.add(Tuple.of(s[0].intern(), options.intern())); } private void setActivateTrigger(final List> value) { @@ -435,7 +435,7 @@ private void setProductionRule(final String prop) throws GameParseException { if (productionRule == null) { productionRule = new ArrayList<>(); } - productionRule.add(prop); + productionRule.add(prop.intern()); } private void setProductionRule(final List value) { @@ -467,7 +467,7 @@ private void resetResourceCount() { } private void setVictory(final String s) { - victory = s; + victory = s.intern(); } private @Nullable String getVictory() { @@ -535,7 +535,7 @@ private void setAvailableTech(final String techs) throws GameParseException { if (availableTech.containsKey(cat)) { tlist.putAll(availableTech.get(cat)); } - availableTech.put(cat, tlist); + availableTech.put(cat.intern(), tlist); } private void setAvailableTech(final Map> value) { @@ -564,7 +564,7 @@ private void setSupport(final String value) throws GameParseException { if (support == null) { support = new LinkedHashMap<>(); } - support.put(name, !remove); + support.put(name.intern(), !remove); } } @@ -585,7 +585,7 @@ private void setResource(final String s) throws GameParseException { if (r == null) { throw new GameParseException("Invalid resource: " + s + thisErrorMsg()); } - resource = s; + resource = s.intern(); } private @Nullable String getResource() { @@ -641,7 +641,7 @@ private void setRelationshipChange(final String relChange) throws GameParseExcep if (relationshipChange == null) { relationshipChange = new ArrayList<>(); } - relationshipChange.add(relChange); + relationshipChange.add(relChange.intern()); } private void setRelationshipChange(final List value) { @@ -678,10 +678,6 @@ private void resetUnitType() { } private void setUnitAttachmentName(final String name) throws GameParseException { - if (name == null) { - unitAttachmentName = null; - return; - } final String[] s = splitOnColon(name); if (s.length != 2) { throw new GameParseException( @@ -707,7 +703,7 @@ private void setUnitAttachmentName(final String name) throws GameParseException && !s[0].startsWith(Constants.SUPPORT_ATTACHMENT_PREFIX)) { throw new GameParseException("attachment incorrectly named:" + s[0] + thisErrorMsg()); } - unitAttachmentName = Tuple.of(s[1], s[0]); + unitAttachmentName = Tuple.of(s[1].intern(), s[0].intern()); } private void setUnitAttachmentName(final Tuple value) { @@ -726,17 +722,13 @@ private void resetUnitAttachmentName() { } private void setUnitProperty(final String prop) { - if (prop == null) { - unitProperty = null; - return; - } final String[] s = splitOnColon(prop); if (unitProperty == null) { unitProperty = new ArrayList<>(); } // the last one is the property we are changing, while the rest is the string we are changing it // to - final String property = s[s.length - 1]; + final String property = s[s.length - 1].intern(); unitProperty.add(Tuple.of(property, getValueFromStringArrayForAllExceptLastSubstring(s))); } @@ -775,10 +767,6 @@ private void resetTerritories() { } private void setTerritoryAttachmentName(final String name) throws GameParseException { - if (name == null) { - territoryAttachmentName = null; - return; - } final String[] s = splitOnColon(name); if (s.length != 2) { throw new GameParseException( @@ -804,7 +792,7 @@ private void setTerritoryAttachmentName(final String name) throws GameParseExcep if (s[1].equals("CanalAttachment") && !s[0].startsWith(Constants.CANAL_ATTACHMENT_PREFIX)) { throw new GameParseException("attachment incorrectly named:" + s[0] + thisErrorMsg()); } - territoryAttachmentName = Tuple.of(s[1], s[0]); + territoryAttachmentName = Tuple.of(s[1].intern(), s[0].intern()); } private void setTerritoryAttachmentName(final Tuple value) { @@ -823,17 +811,13 @@ private void resetTerritoryAttachmentName() { } private void setTerritoryProperty(final String prop) { - if (prop == null) { - territoryProperty = null; - return; - } final String[] s = splitOnColon(prop); if (territoryProperty == null) { territoryProperty = new ArrayList<>(); } // the last one is the property we are changing, while the rest is the string we are changing it // to - final String property = s[s.length - 1]; + final String property = s[s.length - 1].intern(); territoryProperty.add(Tuple.of(property, getValueFromStringArrayForAllExceptLastSubstring(s))); } @@ -869,10 +853,6 @@ private void resetPlayers() { private void setPlayerAttachmentName(final String playerAttachmentName) throws GameParseException { - if (playerAttachmentName == null) { - this.playerAttachmentName = null; - return; - } // replace-all to automatically correct legacy (1.8) attachment spelling final String name = playerAttachmentName.replaceAll("ttatch", "ttach"); final String[] s = splitOnColon(name); @@ -923,7 +903,7 @@ private void setPlayerAttachmentName(final String playerAttachmentName) && !s[0].startsWith(Constants.USERACTION_ATTACHMENT_PREFIX)) { throw new GameParseException("attachment incorrectly named:" + s[0] + thisErrorMsg()); } - this.playerAttachmentName = Tuple.of(s[1], s[0]); + this.playerAttachmentName = Tuple.of(s[1].intern(), s[0].intern()); } private void setPlayerAttachmentName(final Tuple value) { @@ -942,17 +922,13 @@ private void resetPlayerAttachmentName() { } private void setPlayerProperty(final String prop) { - if (prop == null) { - playerProperty = null; - return; - } final String[] s = splitOnColon(prop); if (playerProperty == null) { playerProperty = new ArrayList<>(); } // the last one is the property we are changing, while the rest is the string we are changing it // to - final String property = s[s.length - 1]; + final String property = s[s.length - 1].intern(); playerProperty.add(Tuple.of(property, getValueFromStringArrayForAllExceptLastSubstring(s))); } @@ -996,10 +972,6 @@ private void resetRelationshipTypes() { } private void setRelationshipTypeAttachmentName(final String name) throws GameParseException { - if (name == null) { - relationshipTypeAttachmentName = null; - return; - } final String[] s = splitOnColon(name); if (s.length != 2) { throw new GameParseException( @@ -1021,7 +993,7 @@ private void setRelationshipTypeAttachmentName(final String name) throws GamePar if (!s[0].startsWith(Constants.RELATIONSHIPTYPE_ATTACHMENT_NAME)) { throw new GameParseException("attachment incorrectly named:" + s[0] + thisErrorMsg()); } - relationshipTypeAttachmentName = Tuple.of(s[1], s[0]); + relationshipTypeAttachmentName = Tuple.of(s[1].intern(), s[0].intern()); } private void setRelationshipTypeAttachmentName(final Tuple value) { @@ -1040,17 +1012,13 @@ private void resetRelationshipTypeAttachmentName() { } private void setRelationshipTypeProperty(final String prop) { - if (prop == null) { - relationshipTypeProperty = null; - return; - } final String[] s = splitOnColon(prop); if (relationshipTypeProperty == null) { relationshipTypeProperty = new ArrayList<>(); } // the last one is the property we are changing, while the rest is the string we are changing it // to - final String property = s[s.length - 1]; + final String property = s[s.length - 1].intern(); relationshipTypeProperty.add( Tuple.of(property, getValueFromStringArrayForAllExceptLastSubstring(s))); } @@ -1094,10 +1062,6 @@ private void resetTerritoryEffects() { } private void setTerritoryEffectAttachmentName(final String name) throws GameParseException { - if (name == null) { - territoryEffectAttachmentName = null; - return; - } final String[] s = splitOnColon(name); if (s.length != 2) { throw new GameParseException( @@ -1118,7 +1082,7 @@ private void setTerritoryEffectAttachmentName(final String name) throws GamePars if (!s[0].startsWith(Constants.TERRITORYEFFECT_ATTACHMENT_NAME)) { throw new GameParseException("attachment incorrectly named:" + s[0] + thisErrorMsg()); } - territoryEffectAttachmentName = Tuple.of(s[1], s[0]); + territoryEffectAttachmentName = Tuple.of(s[1].intern(), s[0].intern()); } private void setTerritoryEffectAttachmentName(final Tuple value) { @@ -1137,17 +1101,13 @@ private void resetTerritoryEffectAttachmentName() { } private void setTerritoryEffectProperty(final String prop) { - if (prop == null) { - territoryEffectProperty = null; - return; - } final String[] s = splitOnColon(prop); if (territoryEffectProperty == null) { territoryEffectProperty = new ArrayList<>(); } // the last one is the property we are changing, while the rest is the string we are changing it // to - final String property = s[s.length - 1]; + final String property = s[s.length - 1].intern(); territoryEffectProperty.add( Tuple.of(property, getValueFromStringArrayForAllExceptLastSubstring(s))); } @@ -1342,7 +1302,7 @@ private void setChangeOwnership(final String value) throws GameParseException { if (changeOwnership == null) { changeOwnership = new ArrayList<>(); } - changeOwnership.add(value); + changeOwnership.add(value.intern()); } private void setChangeOwnership(final List value) { diff --git a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/UnitAttachment.java b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/UnitAttachment.java index 1a8259ac22..a217d9451b 100644 --- a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/UnitAttachment.java +++ b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/UnitAttachment.java @@ -533,7 +533,7 @@ void setWhenCapturedChangesInto(final String value) throws GameParseException { if (whenCapturedChangesInto == null) { whenCapturedChangesInto = new LinkedHashMap<>(); } - whenCapturedChangesInto.put(s[0] + ":" + s[1], Tuple.of(s[2], unitsToMake)); + whenCapturedChangesInto.put((s[0] + ":" + s[1]).intern(), Tuple.of(s[2].intern(), unitsToMake)); } private void setWhenCapturedChangesInto( @@ -574,7 +574,7 @@ private void setDestroyedWhenCapturedBy(final String initialValue) throws GamePa if (destroyedWhenCapturedBy == null) { destroyedWhenCapturedBy = new ArrayList<>(); } - destroyedWhenCapturedBy.add(Tuple.of(byOrFrom, getPlayerOrThrow(name))); + destroyedWhenCapturedBy.add(Tuple.of(byOrFrom.intern(), getPlayerOrThrow(name))); } } @@ -968,7 +968,7 @@ private void setSpecial(final String value) throws GameParseException { if (special == null) { special = new HashSet<>(); } - special.add(option); + special.add(option.intern()); } } @@ -994,6 +994,9 @@ private void setCanInvadeOnlyFrom(final String value) { canInvadeOnlyFrom = new String[] {"all"}; return; } + for (int i = 0; i < canOnlyInvadeFrom.length; i++) { + canOnlyInvadeFrom[i] = canOnlyInvadeFrom[i].intern(); + } canInvadeOnlyFrom = canOnlyInvadeFrom; } @@ -1021,7 +1024,11 @@ private void setRequiresUnits(final String value) { if (requiresUnits == null) { requiresUnits = new ArrayList<>(); } - requiresUnits.add(splitOnColon(value)); + final String[] s = splitOnColon(value); + for (int i = 0; i < s.length; i++) { + s[i] = s[i].intern(); + } + requiresUnits.add(s); } private void setRequiresUnits(final List value) { @@ -1042,8 +1049,9 @@ private void setRequiresUnitsToMove(final String value) throws GameParseExceptio throw new GameParseException( "requiresUnitsToMove must have at least 1 unit type" + thisErrorMsg()); } - for (final String s : array) { - getUnitTypeOrThrow(s); + for (int i = 0; i < array.length; i++) { + getUnitTypeOrThrow(array[i]); + array[i] = array[i].intern(); } if (requiresUnitsToMove == null) { requiresUnitsToMove = new ArrayList<>(); @@ -1082,9 +1090,9 @@ private void setWhenCombatDamaged(final String value) throws GameParseException final Tuple fromTo = Tuple.of(from, to); final Tuple effectNum; if (s.length == 3) { - effectNum = Tuple.of(s[2], null); + effectNum = Tuple.of(s[2].intern(), null); } else { - effectNum = Tuple.of(s[2], s[3]); + effectNum = Tuple.of(s[2].intern(), s[3].intern()); } if (whenCombatDamaged == null) { whenCombatDamaged = new ArrayList<>(); @@ -1129,7 +1137,7 @@ private void setReceivesAbilityWhenWith(final String value) { if (receivesAbilityWhenWith == null) { receivesAbilityWhenWith = new ArrayList<>(); } - receivesAbilityWhenWith.add(value); + receivesAbilityWhenWith.add(value.intern()); } private void setReceivesAbilityWhenWith(final List value) { @@ -2339,7 +2347,7 @@ private void resetIsRocket() { @VisibleForTesting public void setTypeAa(final String s) { - typeAa = s; + typeAa = s.intern(); } public String getTypeAa() { @@ -2502,7 +2510,7 @@ private Tuple parseStackingLimit(final String type, final Strin if (!(s[1].equals("owned") || s[1].equals("allied") || s[1].equals("total"))) { throw new GameParseException(type + " value must owned, allied, or total" + thisErrorMsg()); } - return Tuple.of(max, s[1]); + return Tuple.of(max, s[1].intern()); } private void setTuv(final String s) { diff --git a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/UnitSupportAttachment.java b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/UnitSupportAttachment.java index 72dea64e18..0304649492 100644 --- a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/UnitSupportAttachment.java +++ b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/UnitSupportAttachment.java @@ -159,7 +159,7 @@ public UnitSupportAttachment setSide(final String side) throws GameParseExceptio throw new GameParseException(side + " side must be defence or offence" + thisErrorMsg()); } } - this.side = side; + this.side = side.intern(); return this; } @@ -176,7 +176,7 @@ private void resetSide() { @VisibleForTesting public UnitSupportAttachment setDice(final String dice) throws GameParseException { resetDice(); - this.dice = dice; + this.dice = dice.intern(); for (final String element : splitOnColon(dice)) { if (element.equalsIgnoreCase("roll")) { roll = true; diff --git a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/UserActionAttachment.java b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/UserActionAttachment.java index 0be0a59ee0..845b94206d 100644 --- a/game-app/game-core/src/main/java/games/strategy/triplea/attachments/UserActionAttachment.java +++ b/game-app/game-core/src/main/java/games/strategy/triplea/attachments/UserActionAttachment.java @@ -87,7 +87,7 @@ private void setActivateTrigger(final String value) throws GameParseException { if (activateTrigger == null) { activateTrigger = new ArrayList<>(); } - activateTrigger.add(Tuple.of(s[0], options)); + activateTrigger.add(Tuple.of(s[0].intern(), options.intern())); } private void setActivateTrigger(final List> value) { diff --git a/game-app/game-core/src/main/java/games/strategy/triplea/odds/calculator/BattleCalculatorPanel.java b/game-app/game-core/src/main/java/games/strategy/triplea/odds/calculator/BattleCalculatorPanel.java index bfde637751..cb52c74c10 100644 --- a/game-app/game-core/src/main/java/games/strategy/triplea/odds/calculator/BattleCalculatorPanel.java +++ b/game-app/game-core/src/main/java/games/strategy/triplea/odds/calculator/BattleCalculatorPanel.java @@ -30,6 +30,8 @@ import java.awt.Window; import java.awt.event.WindowEvent; import java.text.DecimalFormat; +import java.time.Duration; +import java.time.Instant; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -1052,11 +1054,13 @@ class BattleCalculatorPanel extends JPanel { } setupAttackerAndDefender(); + final Instant t = Instant.now(); calculator = new ConcurrentBattleCalculator( () -> SwingUtilities.invokeLater( () -> { + log.debug("Battle Calculator ready in " + Duration.between(t, Instant.now())); calculateButton.setText("Calculate Odds"); calculateButton.setEnabled(true); calculateButton.requestFocusInWindow();